Skip to content

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:

  1. 模型能调用
  2. agent loop 能持续执行
  3. 工具能注册、执行、返回结果

后面的 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_docsfind_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
  • Email
  • 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 写清运行、配置、限制和扩展方式

学习顺序

  1. 先手写一个最小 agent loop
  2. 加 3 个工具,跑通 dispatch 表
  3. 加 trace,能复盘每一步
  4. 加 context compaction 和 cost guard
  5. 加 permission tier
  6. 加 memory
  7. 加 eval
  8. 最后再考虑 multi-agent、browser、channel 和 heartbeat

Released under the MIT License.