Agent Harness 入门教程
认识完整的 Agent 执行链路、工程模块与学习方法。
内容同步:2026年10月25日 · 文档版本 16
这门课要解决什么问题
很多人第一次做 Agent,都会从“调一次模型 API”开始:
const answer = await model.chat('帮我分析这份数据');
这在 demo 里没问题。真正的 Agent 任务通常是这样的:
分析近 30 天的风险事件,找出 Top 10 实体,给出证据引用,最后把结论通知负责人。
这个任务包含:
- 多轮推理。
- 多次工具调用。
- 上下文增长。
- 数据库查询。
- 引用校验。
- 通知动作。
- 权限和人审。
- 成本、耗时和审计。
把这些工程问题组织起来的运行时,就是 Agent Harness。
先记住几个概念
| 概念 | 含义 | 为什么重要 |
|---|---|---|
| Session | 一次任务的上下文归属 | 决定历史消息和工具结果挂在哪 |
| Run | 一次逻辑任务 | 调度、恢复、计费、审计的单位 |
| Prompt | Prompt 约束 | 告诉模型目标、边界和输出方式 |
| Tool | 外部能力入口 | 查数据、读文件、调用 API |
| Context | 模型可见信息 | 决定注意力和成本 |
| Validator | 输出校验器 | 防止错误结果进入下游 |
| Action | 外部副作用 | 发通知、写数据、执行代码 |
| Observability | 观测与审计 | 还原一次 run 的完整链路 |
从一个真实任务开始
任务:
分析近 30 天的风险事件,输出 Top 10 实体和证据引用。
如果直接把所有数据塞给模型:
30 亿行事件
-> 全部放入 prompt
-> 上下文超限
-> 成本失控
-> 关键约束被稀释
这显然不可行。
正确做法是:
- 建一个 session。
- 组装 prompt,明确只输出 Top 10。
- 模型决定调用查询工具。
- 工具先查聚合表。
- 返回 10 个实体和 evidenceWindowIds。
- 结果写回上下文。
- 模型继续分析。
- 输出结构化 JSON。
- validator 校验引用。
- 如果需要通知负责人,生成 action proposal,再进入审批和执行。
这就是 Agent Harness 的核心循环。
完整执行链路
流程图加载中…
这条链路里,每一步都可能出错:
| 步骤 | 可能问题 | 后果 |
|---|---|---|
| Session | 并发写入、恢复失败 | 上下文交错或丢失 |
| Prompt | 目标模糊、无版本 | 行为漂移 |
| Tool | 返回过大、无超时 | 成本失控或任务挂死 |
| Context | 原始数据塞满 | 注意力被稀释 |
| Output | 引用伪造、结构错误 | 错误结论进入下游 |
| Action | 无幂等、无人审 | 重复通知或越权操作 |
| Observability | 无 runId | 无法定位失败 |
Agent Harness 工程师的工作,就是把这些风险逐层收口。
为什么不能只靠 Prompt
Prompt 可以告诉模型:
每个结论必须引用证据。
但模型仍可能:
- 编一个不存在的 windowId。
- 忽略“最多 10 个实体”。
- 把“没查到”写成“没有风险”。
- 输出一段自由文本,系统无法解析。
所以生产系统需要四层约束:
| 层 | 作用 |
|---|---|
| Prompt | 引导目标 |
| Tool schema | 限制参数和返回 |
| Output schema | 限制结果结构 |
| Runtime validator | 校验引用、权限、业务规则 |
Prompt 是引导,不是安全边界。
为什么不能把所有数据给模型
上下文越长,成本越高,但质量不一定更好。
一个典型事故链:
工具返回 10 万行
-> 上下文膨胀
-> 关键约束被稀释
-> 触发 compaction
-> 摘要丢任务状态
-> 模型重复查询
正确做法是给模型:
- 结论。
- 稳定引用。
- 数据覆盖状态。
- 未解决问题。
不是原始世界。
例如:
{
"summary": {
"topRiskEntityCount": 10
},
"refs": [
{
"entityId": "entity-9182",
"evidenceWindowIds": ["win-1001"]
}
]
}
工具结果有两条去向
一次 tool call 会产生两类结果:
| 结果 | 去向 | 说明 |
|---|---|---|
| 模型可见结果 | Context | 供下一轮推理 |
| 观测结果 | Observability | 记录耗时、大小、状态 |
这两条不能混。
如果把日志和原始 payload 也塞进上下文,会直接放大成本。如果把业务结果只写日志,模型又无法继续推理。
外部动作必须经过校验
模型可以建议“通知负责人”,但不能直接执行。
正确链路:
模型输出
-> 结构化 proposal
-> schema / 引用 / 权限校验
-> 人审或自动策略
-> Action Executor
-> terminal result
-> audit
这样即使模型输出错误,最多只会得到一个被拒绝的 proposal,而不是不可审计的外部副作用。
模块地图
后续文档按工程演进顺序展开。08 到 11 更贴近实际业务落地,12 和 13 是后置的工程收尾能力:
| 文档 | 解决的问题 |
|---|---|
| 02 - Session 管理 | 并发写入、任务生命周期、恢复 |
| 03 - Prompt Engineering | 目标模糊、输出不可解析、版本漂移 |
| 04 - Tool Calling 与 Function Calling | 工具返回过大、调用失控、错误无法自救 |
| 05 - Context Engineering | 上下文膨胀、压缩后重做任务 |
| 06 - RAG 与知识库 | 引用过期、租户隔离、记忆污染 |
| 07 - 数据库设计与查询优化 | 十亿级数据查询、索引、聚合和证据 |
| 08 - Multi-Agent 协作 | 上下文隔离、子任务失败、并发控制 |
| 09 - Observability | 无法还原 run、无法定位失败 |
| 10 - 任务调度与容错 | 任务挂死、取消不彻底、旧 worker 覆盖 |
| 11 - Sandbox 与安全 | 命令逃逸、凭据泄漏、资源失控 |
| 12 - 输出校验与动作执行 | 引用伪造、外部动作重复执行 |
| 13 - LLM Gateway | 模型耦合、usage 缺失、限流和降级 |
新人学习路径
第一步:能画出完整链路
过关标准:
能解释用户请求如何变成 run,模型如何调用工具,工具结果如何进入上下文,输出如何被校验,动作如何被审计。
第二步:能定位一次失败
你需要能回答:
- 是模型慢,还是工具慢?
- 是 prompt 模糊,还是 tool schema 不严?
- 是上下文膨胀,还是压缩丢了状态?
- 是引用伪造,还是 validator 没检查?
- 是动作未幂等,还是取消没传播?
第三步:能加一个安全工具
一个新工具上线前,至少要确认:
- 输入有 schema。
- 输出有上限。
- 错误有稳定 code。
- 有 timeout。
- 有权限策略。
- 有观测事件。
- 是否需要人审。
常见故障排查
| 现象 | 先查什么 | 常见原因 |
|---|---|---|
| 任务一直不结束 | run 状态、预算、timeout | 没有最大轮数或工具挂死 |
| 成本突然上涨 | usage 和 tool output size | 工具返回过大或上下文累积 |
| 模型重复查询 | compaction summary 和 refs | 压缩丢任务状态 |
| 回答质量下降 | 上下文长度和关键约束位置 | 噪声过多 |
| 取消后仍有副作用 | action 状态机 | pending action 未阻断 |
| 报告缺字段 | subtask 状态和 schema | 子任务失败被忽略 |
| 无法定位失败 | runId / toolCallId | 观测缺少关联字段 |
上线前检查
- run 有唯一 owner。
- prompt 有版本。
- 工具有 schema、预算和 timeout。
- 上下文有裁剪和压缩策略。
- 输出有 schema 和引用校验。
- 外部动作有幂等和人审。
- 有模型 usage 和 tool 观测。
- 取消能传播到模型、工具和动作。
- 代码执行有真实沙箱。
- 失败可以通过 runId 还原。
一页总结
Agent Harness 的核心不是“多调几次模型”,而是控制复杂度:
一个任务,一个 run。
一个工具调用,一个预算。
一个结果,一次校验。
一个动作,一个审计。
先把这条主线跑通,再进入后续模块。