Agent 原理、架构与工程实践
内网的一篇文章,感觉对正在搭建的个人 Agent 助手很有启发,偷偷做一下笔记。
Agent Loop
感知、决策、行动、反馈四个阶段循环,直到任务被认为完成或者其他中止条件。
const messages = [{ role: 'user', content: userQuery }];
while(true) {
const rsp = await llm.chat({
model,
messages,
});
if (isToolUse(rsp)) {
const toolResult = callTool(extractToolArgs(rsp.content));
messages.push({ role: 'assistant', content: rsp.content });
messages.push({ role: 'user', content: toolResult });
continue;
}
if (isConsideredDone(rsp)) {
return rsp.content;
}
throw new Error("Undefined behavior");
}基本上,从最小实现到一路扩展子Agent、上下文压缩、工具&skills加载、记忆系统,主循环的结构一般不会大改,通过扩展工具集、调整系统提示和持久化状态,在循环外处理状态和边界。
Workflow 和 Agent区别
| 维度 | Workflow | Agent |
|---|---|---|
| 控制权 | 代码预设执行流 | LLM 动态决策,一般需配合测试验证步骤以维持稳定性 |
| 执行方式 | 相对固定,错误走错误分支 | 按需选择工具,出错模型可尝试自愈 |
| 状态&记忆 | 显式状态机,状态流转清晰 | 隐式上下文,状态可能在对话历史中累积 |
| 维护成本 | 改流程需要改代码并重新部署 | 通常调整系统提示即可 |
| 可观测性 | 日志定位节点即可 | 需完整执行记录理解决策链,轮数不固定 |
| 人类介入 | 需要预设节点介入 | 理论上可以在任意轮次介入或接管 |
| 适用场景 | 流程固定、输入边界清晰 | 需要中间推理和灵活性 |
常见控制模式
没有银弹。
提示链:任务拆分成顺序步骤,每步处理上一步输出,中间可加代码检查点,适合生成后翻译、先列大纲再写正文这类线性流程;
路由:对输入分类,定向到对应的专用处理流程,简单问题走轻量模型,复杂问题走强模型,技术咨询和账单查询分派到不同逻辑;
并行:两种变体:分段法把任务拆成独立子任务并发跑,投票法把同一任务跑多次取共识,适合高风险决策或需要多视角的场景;
编排/工作( Orchestrator/Worker):中央模型动态分解任务,委派给工作者,再综合结果;
评估/优化(Evaluator/Optimizer):生成器产出,评估器反馈,循环直到达标。适合翻译、写作这种质量标准相对模糊的任务。
Harness 比模型更重要
Harness 指围绕 Agent 构建的测试、验证与约束基础设施,至少包括:验收基线、执行边界、反馈信号和回退手段。
基模固然重要,但决定系统能不能稳定运行的,往往是这些外围工程条件。(这个判断对于编码这种高可验证任务成立,但在开放式研究、多轮协商这类 弱验证任务里,模型的上限依然更关键。)
| 目标清晰度/验证方式 | 人工 | 自动化 |
|---|---|---|
| 清晰 | 任务清晰,瓶颈是人工验证的速度 | 目标明确,结果可验证 |
| 模糊 | Agent 几乎没有发挥 | 有自动化反馈,但目标模糊 |
Harness 要做的就是把任务推进右上角,让对错有机器可以执行的判断标准,而不是靠人盯👀。
上下文工程与稳定性
分层架构
- 常驻层:身份定义、项目约束、禁止项、每轮会话都必须遵守的内容,保持短、可执行、不可变;
- 按需加载:Skills和领域知识,描述符常驻,完整内容触发时再注入,有卸载机制;
- 运行时注入:当前时间、会话ID、用户ID等动态信息;
- 持久记忆:跨会话经验(语义经验、长期经验)持久化,不直接进入系统提示,按需加载;
- 系统约束:凡是可以用hooks、代码规则或工具参数约束表达的内容,都应交给外部系统处理,而不是让模型反复读取。
常见压缩策略
| 策略 | 成本 | 丢什么 | 适用场景 |
|---|---|---|---|
| 滑动窗口 | 极低 | 早期上下文 | 简短对话 |
| LLM摘要 | 中 | 细节、保留策略 | 长任务、关键决策 |
| 工具结果平替 | 极低 | 工具原始输出 | 工具调用密集型 |
Prompt Caching
推理框架的前缀缓存特性 —— Transformer attention 会为每个token计算K/V对,如果当前请求的输入前缀和之前某次请求完全一致, 这部分K/V就不需要重新计算,直接从缓存读取。这部分命中的前提是前缀完全一致,任何一个token不同都会破坏匹配, 所以缓存友好型的设计核心是维护前缀的稳定性。
Skill/工具的描述累积成本
见下方工具设计章节。
文件系统为什么适合做上下文接口
Cursor 称之为 Dynamic Context Discovery。工具调用经常返回大JSON,几次搜索提取就能堆出成千上万 token,不如直接写入文件, 让 Agent 通过 rg 这类工具或者脚本/规则读取,工具写文件,Agent 读文件,开发者也可以直接查看。
同样的思路也适用于长任务压缩,压缩触发时,不直接丢弃历史,而是把聊天记录完整保留为文件,摘要里只引用文件路径,后续如果 Agent 发现缺少细节,仍然可以回到文件中检索,这样压缩就变成了一种有损但可追溯的操作,而不是一次不可恢复的截断。
工具设计
早期少量面向API Endpoint的细粒度工具——语义化工具——进阶工具调用体系:
- 动态工具发现:按需发现工具,降低长描述累积成本,间接提高准确率;
- 代码编排:别让中间数据一轮轮通过模型,而是让模型用代码编排多个工具调用,中间结果仅在执行环境中存在,不进入LLM上下文,可以大幅度优化token消耗;
- 示例驱动:JSON Schema 可以描述参数类型,但不能很好地表达调用场景和调用方式,加入示例可以提升工具准确率。
符合ACI(Agent-Computer-Interface,工具顺应 Agent 的目标原则,而不是面向底层API。把目标动作说&做完整)的工具:边界明确、参数防错、定义里给到示例,出错了给出修正建议。
记忆系统
从记忆的角度理解上下文构成:
- 工作记忆,上下文窗口:当前任务所需的最小信息,token 有限,得主动管理;
- 程序性记忆,Skills:怎么做某件事,操作流程、领域规范,按需加载不常驻;
- 情景记忆,会话历史:磁盘持久化,支持跨会话检索;
- 语义记忆,MEMORY.md:重要事实,注入系统提示。
何时触发记忆整合
启发式规则,比如tokenUsage / maxTokens >= 0.5。
逐步放开 Agent 自主度
这个“自主度”不是说少几次“human-in-loop”,而是让 Agent 能在更长时间跨度内稳定推进任务,前提也不是直接放权,而是补齐状态外化基础设施:
- 支持长任务跨 session:把内部状态转化为持久化的文件、数据库记录等;
- 防止“lost in the middle”:任务状态要显式记录为外部对象。
多 Agent 组织
先有任务图和隔离边界再引入并行,协议先于协作,子Agent只报告结果,细节停留在子Agent自己的上下文中。
交叉验证
防止一个 Agent 带偏,其他 Agent 跟着强化,最后整个链路收敛到同一个高置信度的错误结果。
Agent 评测
常用指标
| 指标 | 含义 | 场景 |
|---|---|---|
| Pass@k | k次至少一次正确 | 探索能力上限,能力突破时重跑 |
| Pass^k | k次全部正确 | 回归验证 |
常见评分策略
| 类型 | 典型做法 | 确定性 | 适用场景 |
|---|---|---|---|
| 代码评分 | 字符串匹配、结构对比、工具验证 | 高 | 有明确正解的场景 |
| 模型评分 | 打分、排序、投票共识 | 中 | 语义质量、风格、推理过程 |
| 人工评分 | 专家抽样审查、人工标注 | 可靠但低效 | 建立基准、校准自动 judge 过程 |
看“Agent怎么说”和“看系统最后变成什么样“是两件事,Anthropic 机票预定的例子:模型发现了航司政策里的漏洞,为用户找到了更便宜的方案,如果只按照预设路径打分,这次运行会判失败。
可观测性
Trace里需要记录什么?
- 完整的Prompt,包含系统提示;
- 多轮交互的完整 messages[];
- 每次工具调用+参数+返回值;
- 推理链、thinking;
- 最终输出;
- token 消耗;
- 延迟。
人工标注校准&模型自动打分两层都需要做,只做自动化验证,评分标准可能偏离,只做人工验证,规模上覆盖不了真实流量。
OpenClaw 的启示
安全边界先于功能
安全性与可用性的兜底
Prompt 注入
按照 source-sink 拆解,不可信输入从哪来都是 source,最终可能触发的危险操作是 sink,让 Agent 即使被注入,也没有机会把危险动作执行出去:
- 最小权限;
- 敏感操作显式确认;
- 标注外部内容边界;
- 关键路径加独立模型验证。
Provider 故障切换
模型服务是不稳定的。
常见反模式
| 反模式 | 问题 | 怎么修 |
|---|---|---|
| 系统提示当知识库 | 越来越长,lost in middle | 上下文工程 |
| 工具数量失控 | Agent 频繁选错工具 | 合并重叠工具、明确命名空间 |
| 缺少验证机制 | Agent 说完成了,但没法验证 | 每类任务绑定可执行的验收标准 |
| 多 Agent 边界不清晰 | 状态漂移,故障归因困难 | 明确角色和权限,worktree 隔离,设置 maxTurns |
| 记忆不整合 | 长对话后决策质量下降 | 监控上下文占用,超阈值自动触发整合 |
| 缺少评测 | 修了A,挂了B | 每个真实失败案例立即转为测试用例 |
| 过早引入过多 Agent | 协调开销超过并行收益 | 先建立任务图,验证单 Agent 上限后再拓展 |
| 约束靠期望不靠机制 | 规则在文档里,Agent 选择性遵守 | Linter/Hook |