Agent 系列日记 5:为什么 Skill 路由比 ReAct 控制器更适合个人助理
从 luck-agent 到 Hermes-lite,我花了两年时间才想清楚这个问题:80% 的请求不需要"思考",只需要"路由"。
回顾:ReAct 控制器模式的困境
2024 年做 luck-agent 的时候,我采用的是经典的 ReAct 模式(Reasoning + Acting):
用户输入 → 大模型推理(意图识别 → 规划 → 工具选择 → 执行)→ 输出
所有请求,不管简单还是复杂,都走同一个推理链。一个"查 QPC 里有没有 VPS 相关的记录"的请求,也要经过:
- 理解自然语言
- 判断意图类别
- 选择工具(search_qpc)
- 构造查询参数
- 执行并解释结果
问题很明显:
- Token 消耗大:每次推理要带上完整的 system prompt + 工具定义,光上下文就吃掉 3000-5000 token
- 延迟高:一个简单查询要等模型完成完整推理链,响应时间 3-8 秒
- 上下文窗口压力:随着工具数量增加(现在 Hermes-lite 有 20+ 个工具),system prompt 越来越大
我当时就在知识库里记了一条:
“对于个人助理场景,相比最初的 ReAct 控制器模式,Skill 技能路由更适合当前 luckagent:80% 请求是固定模式,不需要复杂推理,技能比 Agent 更稳定,成本更低,响应更快。”
Skill 路由的核心思想
一句话:预定义技能映射,轻量分类先路由,只加载需要的工具和 prompt。
用户输入 → 轻量路由(关键词/意图 → 技能)→ 加载专用 prompt + 工具 → 执行
路由表设计
# 简化版路由逻辑
ROUTING_RULES = {
"qpc": {
"keywords": ["QPC", "知识库", "记一下", "记录"],
"skill": "qpc",
"tools": ["feishu_bitable_read", "feishu_bitable_write"],
"prompt": "qpc_skill_prompt" # 只加载 QPC 相关的 prompt
},
"vps": {
"keywords": ["VPS", "服务器", "防火墙", "Docker"],
"skill": "gcp-vps-ops",
"tools": ["terminal", "read_file"],
"prompt": "vps_skill_prompt"
},
"blog": {
"keywords": ["博客", "文章", "Hugo", "发布"],
"skill": "hugo-blog",
"tools": ["terminal", "read_file", "write_file"],
"prompt": "blog_skill_prompt"
}
}
对比:同样"查 QPC"操作
| 指标 | ReAct 模式 | Skill 路由 |
|---|---|---|
| 上下文 token | ~4000(全量工具定义) | ~800(仅 QPC 相关) |
| 首次响应延迟 | 3-8s | 0.5-1.5s |
| 工具调用次数 | 2-3 次(推理+执行) | 1 次(直接执行) |
| 准确率 | 92%(模型可能选错工具) | 98%(路由确定性高) |
Hermes-lite 的 Skill 实现
Hermes-lite 的 skill 系统是这样工作的:
Agent 的记忆:Hermes-Lite 如何用 5 层结构解决「鱼的难题」
人类 chatbot 最尴尬的瞬间:第二次见面完全不认识你。Agent 的记忆系统怎么同时做到持久化、低成本、不丢上下文?我深入 Hermes-Lite 源码写了一个月,拆解出 5 层架构。
从「鱼的难题」开始
用过 ChatGPT 的人都知道一个痛:下次打开,它完全不记得你了。
对一次性聊天这没问题。但对个人助理——帮你管理 200 条知识库、追踪几个项目的进度、记住你的偏好——这等于每次都要把整段友情重来。
我做 QPC(个人知识库)时就被这个问题卡过。后来折腾 Hermes-Lite、nanobot,逐步摸到一条可行的路。这篇文章从 Hermes-Lite 的实际源码出发,拆解它的 5 层记忆架构,看看一个 Agent 是怎么解决「鱼的难题」的。
总览:5 层架构
┌─────────────────────────────────────────────┐
│ Layer 1: 持久记忆 (MEMORY.md / USER.md) │ ← 跨会话,纯文本
├─────────────────────────────────────────────�
│ Layer 2: 会话压缩 (ContextCompressor) │ ← 长对话不爆
├─────────────────────────────────────────────┤
│ Layer 3: 会话检索 (session_search + FTS5) │ ← 历史不丢
├─────────────────────────────────────────────�
│ Layer 4: 增量写入门控 (Nudge 机制) │ ← 该记就记
├─────────────────────────────────────────────�
│ Layer 5: 原子性保障 (fcntl + 临时文件) │ ← 不丢不坏
└─────────────────────────────────────────────┘
每一层解决一个独立问题,层与层之间不耦合。下面逐层拆解。
Agent 日记系列(二):探秘 Agent 的大脑中枢:主控制器与生命周期
主控制器是 Agent 的"大脑"——它决定何时思考、何时行动、何时停止。理解主控制器的设计,就理解了 Agent 的运作范式。
核心循环(Core Loop)
主控制器的本质是一个状态机:
接收输入 → 理解意图 → 选择工具 → 执行调用 → 处理结果 → 判断是否结束 → 输出/继续
这个循环的关键设计点:
1. 意图识别
不是简单的关键词匹配,而是结合上下文、历史、用户状态的综合判断。同一个"搜索一下",在项目初期是搜技术方案,在部署阶段是搜报错日志。
2. 工具路由
主控制器维护一个工具注册表(Tool Registry),包含:
- 工具名 + 描述(供 LLM 选择)
- 参数 schema(JSON Schema)
- 权限等级(只读 / 可写 / 危险)
- 超时策略
路由逻辑:LLM 输出 tool_call → 控制器校验权限 → 注入上下文 → 执行 → 截断超长输出 → 返回结果。
3. 终止条件
这是最容易被忽略的环节。Agent 必须知道"够了":
- 显式终止:用户说"停"或任务完成标记
- 隐式终止:连续 3 次工具调用返回相同/空结果
- 预算终止:token 消耗超过阈值,强制总结当前进展
生命周期管理
会话级生命周期
创建 → 活跃 → 空闲 → 重置 → 销毁
- 创建:加载用户上下文、历史摘要、可用工具列表
- 活跃:正常处理请求,维护对话历史
- 空闲:N 分钟无请求后,压缩历史为摘要
- 重置:用户显式
/new,清空当前会话但保留记忆 - 销毁:服务重启或长时间无活动
任务级生命周期
一个复杂任务可能跨多轮: