📚进度:0/670%
Agent Harness Engineering:把裸模型变成能干活的系统
模型决定推理下限,Harness 决定产品上限。真正的 Agent 工程,不是只调用 LLM API,而是给模型配好工具、权限、状态、记忆、通道、反馈和评测。
什么是 Agent Harness
可以把 Agent 拆成两部分:
text
Agent = Model + Harness- Model:负责理解、推理、生成、选择动作。
- Harness:负责把模型放进真实工作环境,提供工具、上下文、权限、状态、日志、回放、评测和人类反馈。
同一个模型,放在聊天窗口里只是问答助手;放进好的 harness 里,才可能成为能长期执行任务的 Agent。
为什么 Harness 重要
很多 Agent demo 失败,不是模型不够强,而是 harness 太弱:
- 工具描述含糊,模型经常选错工具
- 工具返回太长,污染上下文
- 没有权限分级,危险动作不可控
- 没有 session store,任务中断后无法恢复
- 没有 trace,失败后无法复盘
- 没有 eval,改动后不知道能力是否退化
- 没有成本上限,循环调用工具烧 token
Harness Engineering 的核心问题是:
如何设计一个运行环境,让模型能稳定、可控、可观测地完成真实任务?
七层模型
text
L7 自驱层(heartbeat / cron) 让 Agent 自己找活干
L6 通道层(CLI / Web / IM / Email)让 Agent 进入真实入口
L5 人格层(SOUL / policy) 让 Agent 跨模型不漂移
L4 记忆层(JSONL / SQLite / vector)让 Agent 记得上下文和偏好
L3 工具层(tools / skills / MCP) 让 Agent 真的能干活
L2 循环层(agent loop) 让 Agent 能持续观察和行动
L1 模型层(provider abstraction) 让 Agent 不绑死一家模型初学者不要一开始就搭七层。第一周只需要跑通 L1 + L2 + L3:
- 模型能调用
- agent loop 能持续执行
- 工具能注册、执行、返回结果
后面的 memory、channel、heartbeat 都应该在真实需求出现后再加。
L1:模型层
目标:换模型不用改业务代码。
关键做法:
- 所有模型调用统一走
call_model(messages, tools, config) - provider 配置外置,支持 OpenAI / Anthropic / Gemini / 本地模型切换
- 输出统一成内部事件格式,例如
message,tool_call,final,error - 记录 token、延迟、模型名、请求 id
面试常问:
为什么不能直接在业务代码里到处调 SDK?
回答重点:
- provider 行为不同,必须做统一抽象
- 便于模型路由和 fallback
- 便于统计成本和排查问题
L2:循环层
目标:从一次问答变成持续工作。
最小 agent loop:
python
for step in range(max_steps):
response = call_model(messages, tools)
if response.type == "final":
return response.content
if response.type == "tool_call":
result = run_tool(response.tool_call)
messages.append(format_tool_result(result))
continue
raise MaxStepsExceeded()必须有:
- 最大步数
- 超时
- 工具错误回传
- stop condition
- interrupt / resume 设计
- trace id
进阶设计:
- 一个 turn 可以包含多个 tool call
- 支持用户中途 steer
- 支持 context compaction
- 支持任务暂停和恢复
L3:工具层
目标:让 Agent 不只聊天,还能读取、搜索、计算、写入和调用外部系统。
工具设计原则:
| 原则 | 说明 |
|---|---|
| 名称语义互斥 | 不要让 search_docs 和 find_docs 同时出现 |
| description 面向模型 | 让模型知道什么时候用、什么时候不用 |
| schema 严格 | JSON Schema / enum / required 字段要清楚 |
| 返回可控 | 大结果分页、截断、摘要、附来源 |
| 最小权限 | 工具只暴露完成任务所需的最小能力 |
| 可观测 | 每次调用记录参数、结果、耗时、错误 |
推荐结构:
python
TOOLS = {
"search": search_tool,
"read_file": read_file_tool,
"write_file": write_file_tool,
}新增工具应该是加一项注册,而不是改一坨 if-elif。
L4:记忆层
目标:让 Agent 在任务、会话和长期偏好之间保持连续性。
三类记忆:
| 类型 | 存什么 | 常见实现 |
|---|---|---|
| Working memory | 当前任务的短期状态 | messages / scratchpad |
| Episodic memory | 过去发生过什么 | JSONL / SQLite |
| Semantic memory | 用户偏好、事实、知识 | 向量库 / hybrid search |
不要过早上向量库。很多个人项目用 JSONL + SQLite 就能跑很久。
关键问题:
- 谁决定什么值得存?
- 写入门槛是什么?
- 什么时候合并、遗忘、压缩?
- 召回结果如何防止污染当前上下文?
L5:人格层
目标:让 Agent 的行为风格和边界跨模型保持稳定。
可以沉淀:
- 项目规则:
AGENTS.md/CLAUDE.md - 行为原则:
SOUL.md - 安全策略:policy / permission config
- 输出风格:templates
人格层不是玄学,它解决的是:
- 换模型后风格漂移
- 多入口回复不一致
- 风险场景没有统一边界
- 项目协作规则反复遗忘
L6:通道层
目标:让 Agent 不只躲在终端里,而是进入用户真实入口。
常见通道:
- CLI
- Web app
- Slack / 飞书 / Discord / Telegram
- GitHub Action
- 定时后台任务
设计原则:
- agent core 和 channel adapter 分离
- 不同通道共用 session / permission / trace
- 先把一个通道用透,再加第二个通道
L7:自驱层
目标:让 Agent 从“踹一下动一下”变成能主动检查任务。
常见方式:
- heartbeat
- cron
- queue worker
- webhook
- monitor
谨慎使用:
- 自驱层会放大成本
- 会放大错误动作
- 需要更强权限边界
- 需要更完整 trace 和告警
第一个月建议先关掉自驱层,等 eval 和权限成熟后再加。
可靠性六件套
| 机制 | 做什么 | 不做的后果 |
|---|---|---|
| Idempotency | 工具调用带幂等 key | 重启后重复发邮件、重复写入、重复扣款 |
| Timeout + Circuit Breaker | 每个工具有超时,连续失败后熔断 | trajectory 被慢工具拖垮 |
| Rate Limit Aware Retry | 指数退避、jitter、多 provider fallback | 限流后整个系统挂掉 |
| Cost Guard | 每个 trajectory 设置 token / 金额上限 | bug 无限循环烧成本 |
| Permission Tier | 读自动、写 dry-run + 人审、不可逆显式确认 | Agent 执行危险动作 |
| Observability | 记录 prompt、tool call、result、token、延迟 | 出问题无法回放和归因 |
Evaluation Harness vs Agent Harness
这两个概念容易混:
| 概念 | 解决什么 |
|---|---|
| Agent Harness | 让模型能在真实环境里工作 |
| Evaluation Harness | 评估模型或 Agent 是否完成任务 |
二者关系:
- Agent Harness 产生 trajectory
- Evaluation Harness 读取 trajectory、输出分数和失败归因
- 生产级系统里,评测和治理都依赖 trace
相关文档:
面试速查
| 问题 | 回答框架 |
|---|---|
| 怎么设计一个 Agent? | workflow vs agent -> loop -> tools -> context -> memory -> permission -> eval |
| 上下文太长怎么办? | 分层、压缩、检索、工具结果后处理、cache-friendly 结构 |
| 工具选错怎么办? | 改 description、拆/合工具、加 router、few-shot、看 trajectory |
| 什么时候用 multi-agent? | 子任务独立性强、上下文隔离有收益、最后能汇总 |
| 成本怎么控制? | 模型路由、prompt 瘦身、context 压缩、prefix cache、cost guard |
| HITL 怎么设计? | pre-turn、mid-turn、post-turn;读自动、写审查、不可逆确认 |
最小实现 checklist
- [ ]
call_model()provider 抽象 - [ ] agent loop 有最大步数和超时
- [ ] tools 用注册表管理
- [ ] 工具 schema 严格,返回可控
- [ ] 每步记录 trace id、tool call、result、latency、token
- [ ] 高风险工具有 permission tier
- [ ] session 可以保存和恢复
- [ ] 至少 20 条 eval case
- [ ] README 写清运行、配置、限制和扩展方式
学习顺序
- 先手写一个最小 agent loop
- 加 3 个工具,跑通 dispatch 表
- 加 trace,能复盘每一步
- 加 context compaction 和 cost guard
- 加 permission tier
- 加 memory
- 加 eval
- 最后再考虑 multi-agent、browser、channel 和 heartbeat