乐于分享
好东西不私藏

每个 AI 开发者都需要的 7 个 Agent Harness 组件

每个 AI 开发者都需要的 7 个 Agent Harness 组件

每个 AI 开发者都需要的 7 个 Agent Harness 组件

作者:AI拉呱(Errol Yan)
定位:AI领域深度内容与实战方法分享

你的 agent 在生产里离不开的“基础设施层”,但多数工程师从来没搭过

你的 agent 刚刚在一次查询里向用户计费 38 美元。

不是因为它做了什么复杂操作,而是因为它把同一份文档连续总结了 47 次:它发现自己已经做过,于是又做了一遍;没有崩溃、没有告警,只有循环在转、账单在涨。

你去查模型日志:模型按训练表现得“完全正常”。

问题在于:模型周围那一层没有任何机制记住它做过什么——没有状态文件、没有停止条件、没有“重复检测”。系统没有办法对它说:

“我们来过这里。”

这就是 demo 和生产级 agent 的分水岭。

本文将解释:要把 AI agent 做到可靠可控,你需要的 7 个 Harness 组件。

那个没人提醒你的鸿沟

做一个“只成功一次”的 agent,真的很容易:调用 LLM、给它几个工具、让它循环跑起来。20 行 Python 就能出一个看起来很干净的 demo。

然后你上线。真实用户会输入你没见过的东西。

工具返回空结果;跑了 40 分钟上下文开始溢出;两个子代理互相打架;模型决定对某一步无限重试。

demo 里看不见的一切,都会在生产里变成故障。

问题不在模型质量,在 harness 质量。

“没有 harness 的模型,就像只有大脑没有神经系统:它能思考,但无法可靠地行动。”

Agent = Model + Harness

这个框架会改变你构建系统的方式。

Agent = Model + Harness

  • • Model:推理、语言、决策
  • • Harness:让模型能够可靠行动所需的一切

如果你不是在训练/换模型,那你在做的就是 harness。

Harness 指的是:包裹模型的每一行代码、每一份配置、每一个执行 hook——它把“文本生成器”变成“真正能干活的系统”。

模型负责决定“做什么”;harness 负责确保它能安全、可重复、可规模化地完成。

多数工程师把 90% 精力花在模型上:更好的 prompt、更新的模型、更多例子。但生产失败几乎总藏在那被跳过的 10%。

真正关键的 7 个组件

1. 控制循环(Control Loop)

循环是 agent 的心跳。没有循环,你只会得到一次模型调用 + 一次回复——那不是 agent,只是聊天机器人。

这个循环负责:运行模型→读取输出→执行工具调用→把结果回填上下文→重复,直到模型不再调用工具,或触发步数上限。

一个典型循环(伪代码):

while agent_is_running:
    response = call_model(context)

    if response.has_tool_calls:
        results = execute_tools(response.tool_calls)
        append_to_context(results)
        continue

    if response.is_final_answer:
        return response.content

    if step_count > MAX_STEPS:
        return "Task incomplete. Max steps reached."

MAX_STEPS 这行不是可选项,它就是“良性 agent”和“38 美元事故”的差别。你应该在写第一个工具之前就把它内建。

糟糕的循环比没有循环更糟:没有停止条件、没有状态追踪、没有重复工具调用检测,会让模型对一个已经完成的任务无限工作。

2. 状态管理(State Management)

模型默认是无状态的:每次 API 调用都是“重新开始”。如果 harness 不显式记录发生过什么,agent 就不知道自己做过什么、哪些成功、卡在了哪一步。

你需要两类状态:

  • • 会话状态(Session state):这次对话里发生的事情(对话历史、工具结果、当前步数)
  • • 持久状态(Persistent state):会话结束后仍要保留的事情(长任务进度、已完成子任务、已处理文件等)

最简单可用的生产级状态存储就是一个 JSON 文件:记录任务进度、已处理项、当前状态。它可读、可调试、进程重启后仍存在,而且不需要额外基础设施。

示例:

{
  "task_id": "refactor-auth-module",
  "completed_files": ["auth.py", "middleware.py"],
  "pending_files": ["routes.py", "tests/test_auth.py"],
  "current_step": 3
}

对一个跨大型代码库工作的编码 agent 来说,这个文件能让它持续推进,而不是每轮都重复编辑同一个文件。再叠加 Git,你还能做版本追踪、回滚错误、分支实验。

3. 记忆(Memory)

State 记录的是 agent 这次会话做了什么;Memory 记录的是它跨会话“知道什么”。

短期记忆就是对话历史:每条消息、工具调用、结果被追加到列表里,作为上下文传给模型。

**这很容易实现,但如果不管理,成本会越来越高。**随着列表增长,token 成本上升,性能在触达硬上限之前就会开始退化。

长期记忆更难:一个帮你写代码的 agent 应该记得你偏好显式错误处理;一个客服 agent 应该知道某位客户上周有过账单问题。长期记忆通常存在向量数据库里做语义检索,或者用结构化文件记录明确事实。

一个成熟的生产模式:

会话开始:

  1. 1. 加载 AGENTS.md 或项目记忆文件 → 注入 system prompt
  2. 2. 基于当前任务检索相关记忆 → 作为上下文补充

会话进行中:

  1. 1. 维护滚动对话历史

会话结束:

  1. 1. 总结关键学习点 → 写回记忆存储

harness 负责 1、2、4。模型不会、也不该“自己管理记忆”。

没有长期记忆的 agent 每次运行都要重新学习上下文。用户会感知到“它在忘记我”,哪怕模型能力足够——这是一种信任侵蚀,而它是 harness 问题,不是模型问题。

4. 工具与 bash 逃生舱(bash escape hatch)

**工具把语言变成行动。**没有工具,模型只能说“我会去做”;有工具,它才能真的去做。

工具设计比工具数量更重要:每加一个工具,都会增加上下文负担(工具描述要进 prompt),也会提高模型选错工具的概率。三把描述清晰的工具,往往比十五把描述含糊的工具更强。

好的工具描述必须回答 3 个问题:

  • • 这个工具到底做什么?
  • • 我什么时候应该用它(不仅是“能用”)?
  • • 输出长什么样,我如何判断它成功了?

bash 逃生舱是一个改变上限的架构点:你不需要预先设计所有工具,而是给 agent bash 权限,让它按需临时写工具。这也是 Claude Code 能处理开放式任务的关键:模型不被固定工具集限制,它可以自己设计所需工具。

**代价是安全性。**一旦 bash 在场,sandbox 隔离就不再是可选项。

让 agent 生成的代码在本地直接跑是有风险的;而单一环境也无法支撑并发工作负载。sandbox 能提供安全隔离执行:跑代码、装包、读写文件,同时不触碰宿主机。它可以按需启动、并行扩展、完成后销毁。

**配置良好的 sandbox 还应该自带默认能力:**语言运行时、git CLI、测试运行器、浏览器等。这样 agent 才能自验证:写代码→跑测试→看日志→修失败。harness 负责搭环境,模型负责使用。

5. 上下文管理(Context Management)

上下文腐烂(context rot)是最隐蔽的生产故障之一。

agent 前 40 分钟表现很好,突然开始忽略自己的 system prompt。没有崩溃、没有错误。只是上下文窗口逐渐填满,关键指令被埋进中间,模型慢慢不再关注它们。

harness 决定模型能看见什么,模型自己不会管理。

生产中真正有效的 3 个模式:

Compaction(压缩/摘要):当上下文窗口逐渐填满时,把更早历史摘要,而不是直接丢弃。关键约束:永远不要压缩原始任务定义或 system prompt;其他内容都可以谈判。

工具输出截断(Tool output truncation):避免工具返回的超长结果淹没上下文。比如 fetch 直接返回 50 页原文,会吃掉全部预算。harness 应保留开头与结尾 N 个 token,把完整输出落盘,并给模型一个指针(需要时再读取)。

渐进式披露的 skills(progressive disclosure):解决启动阶段膨胀问题。会话一开始就加载所有工具描述,会在 agent 干活之前就把上下文撑爆。更好的方式是按需加载:当模型决定需要某项能力时,再加载对应 skill 的 front-matter。实践中,50 个按需加载的技能,经常比 10 个一开始就全塞进上下文的工具更强。

生产规则:system prompt 与任务定义必须始终可见;在动它们之前先压缩历史。

6. 规划(Planning)

没有规划的模型会走“眼前最显然”的下一步,哪怕那并不是通往目标的连贯路径。

简单任务还好;复杂多步任务会变得混乱:步骤顺序错、重复做、跳过隐含步骤。agent 能力很强也会失败,因为没人给它一个可执行的结构。

最简单、且在生产里确实有效的修复是:计划文件(plan file)模式

示例:

task: Migrate database schema from v1 to v2
steps:
  - Backup current schema         [ ]
  - Generate migration script     [ ]
  - Run migration on staging      [x]
  - Verify data integrity         [ ]
  - Run migration on production   [ ]
  - Update documentation          [ ]
current_step: 4

harness 在每一轮循环开始时把计划注入上下文;agent 完成一步就打勾。会话结束后计划仍存在;下次恢复时它能准确知道自己在哪。

自验证(self-verification)是闭环:每完成一步,先验证结果再进入下一步。harness 可以强制执行,例如跑测试套件并把失败反馈给模型。写完迁移脚本就去 staging 验证的 agent,会比“写完就假设正确”的 agent 可靠得多。

Ralph Loop 值得记住:当 agent 在长任务里耗尽上下文窗口却未完成目标时,Ralph Loop 会通过 hook 截获退出,把原始目标注入一个新的上下文窗口,强制继续。文件系统让这成为可能:新上下文读取上轮状态。这是跨多个上下文窗口的长程自治的关键机制之一。

7. 错误处理(Error Handling)

真实世界不会配合你:工具会失败、API 会限流、文件会缺失、模型偶尔会返回无法解析的输出。

没有显式错误处理,agent 遇到这些情况只有两个糟糕选择:要么崩溃,要么假装没发生,围绕错误自信地产生幻觉。两者都是生产事故。

你需要把错误路径写清楚:

工具失败:

  • • 可重试?(超时、限流)→ 指数退避
  • • 数据错误?→ 换一种方案
  • • 权限错误?→ 升级到人

模型输出格式不合规:

  • • 用明确的格式提醒重试
  • • 连续失败 3 次 → 启用结构化输出强制

Agent 出现循环:

  • • 步数计数器触发 → 强制停止
  • • 检测到重复的相同工具调用 → 中断并重定向

置信度低:

  • • 标记为异步人工复核
  • • 等待期间不要阻塞用户

升级路径(escalation path)是最重要但多数 harness 缺失的部分:懂得何时停下来求助的 agent,在生产里往往比“永远要自己完成”的 agent 更有用。上线前就要定义清晰的置信度阈值。

每个工具调用都必须有明确的失败行为:不是“优雅处理错误”,而是非常具体——空结果做 X,报错做 Y,超时做 Z。

一条真实 trace:生产级 agent 内部到底发生了什么

用户输入:“总结过去一个月 EU AI 监管相关新闻报道的主要论点。”

Step 1:生成计划

  • • 搜索最近 30 天 EU 监管相关新闻
  • • 读取 Top 5 结果
  • • 提取论点簇(argument clusters)
  • • 汇总成结构化摘要

Step 2:检查状态

  • • 无既有进度
  • • 步数计数器初始化为 0

Step 3:调用搜索工具

  • • 返回 8 篇文章
  • • harness 把每篇截断到 500 tokens → 加入上下文

Step 4:对 Top 5 调用 fetch_url()

  • • 全文落盘
  • • agent 拿到摘要 + 文件指针

Step 5:检查上下文

  • • 容量使用 60%,无需 compaction

Step 6:综合

  • • agent 发现 3 个主要论点簇 → 写入上下文

Step 7:验证

  • • 检查文章日期
  • • 发现 2 篇超过 45 天 → 标记
  • • 用更严格的时间过滤重新搜索 → 补 2 篇新文章

Step 8:最终输出

  • • 带引用的结构化摘要
  • • 步数:9,MAX_STEPS:20

Step 9:更新状态

  • • 计划文件:所有步骤完成
  • • 关键发现写入记忆存储(供后续会话使用)

模型负责写摘要;harness 负责状态追踪、上下文管理、验证、步数限制、记忆落盘。9 步、无需人工干预、结果正确。

这才是 harness 的价值。它不性感,但它决定了系统是否“可靠”。

你会被哪些边界情况坑到

**即使有工具也会幻觉。**agent 明明有搜索工具,却用训练数据直接回答。常见原因是工具描述没有说明“何时必须调用”,只说了“可以调用”。修复:明确哪些问题在回答前必须先调用工具。

**无限循环。**模型在空结果后用轻微变体重复调用同一工具,把“空”当成“再试一次”,而不是“这条路不对”。修复:检测重复的相同工具调用,及时中断并给重定向提示。

**上下文溢出。**前 30 分钟很强,之后开始忽略指令。上下文慢慢填满,system prompt 被埋住,性能无声退化。修复:compaction 策略 + 硬规则:任务定义始终出现在上下文开头与结尾。

**工具误用。**先写后读、删除代替归档等,往往源于工具描述对前置条件不清晰。修复:工具描述要写“何时不要用”,不只写“何时用”。

**延迟爆炸。**一串看似合理的工具调用串行执行,变成 45 秒响应。修复:可并行的工具调用并发执行;在动模型之前先测量哪些 harness 选择引入了延迟。

多数工程师没意识到的一点:模型与 harness 的耦合

像 Claude Code 这类现代编码 agent,往往是在“模型 + harness 联合运行”的环境里做后训练:文件系统操作、bash 执行、规划等能力,一部分来自在 harness 环境里被奖励出来的行为。

这会带来一个副作用:

即便你把工具逻辑换成“等价实现”,模型表现也可能变差。比如模型是在特定 patch 格式上训练出来的,你换一种 patch 格式,即便逻辑一致,它也会更容易出错。harness in the loop 的训练,会形成对特定 harness 设计的“拟合”。

**实践影响:**开箱即用的 harness 不一定对你的任务最优。同一个模型,在不同 harness 里可能有可测量的排名差异。

多数团队从来没做过 harness 优化——而真实性能红利往往就藏在这里。

什么时候不该用 agent

agent 不是“万能升级”,它比很多人愿意承认的更常是错的工具。

  • • 当同样输入总会走同样步骤并得到同样输出时,用确定性 pipeline:硬编码,更快、更便宜、更可靠。
  • • 当错误代价是“删除生产数据”或“把邮件发错人”时,加显式人工关卡:把 agent 的建议与执行拆开。
  • • 当输入是结构化、处理是规则型时,别用 agent 增加复杂度。

“Agent 不是 workflow 的升级版,它是另一类问题的另一把工具。先判断问题类型。”

过度工程的最明显信号:你的流程每一步只有一个正确动作、路径完全明确,而你想上 agent 的主要原因是“看起来很酷”。确实很酷,也确实很容易过度。

从零开始,应该按什么顺序搭?

按这个顺序加,每一层解决该阶段最常见的故障:

  1. 1. **带步数上限的控制循环。**先于任何工具。MAX_STEPS = 10 能在事故发生前就阻止通宵扣费。
  2. 2. **状态文件。**用 JSON 记录发生了什么、下一步是什么;每轮循环开始都读取。
  3. 3. **工具集。**3–5 个,描述清晰;只有在明确缺口出现时才加新工具。
  4. 4. **错误处理。**上线前就为每个工具定义失败行为。
  5. 5. **上下文 compaction。**当你观察到长会话退化时再加,而不是一开始就复杂化。
  6. 6. **记忆(Memory)。**当用户开始感觉 agent “忘记了它该记得的事”时再加。
  7. 7. **规划(Planning)。**当任务跨会话或超出单个上下文窗口时加。

这个顺序不是随便排的:你如果没有第 2 步就直接做第 6 步,会在错误方向上调试。

最后一句

一个做得好的 agent,价值不在于“所有事情都顺利时它能做什么”,而在于“出问题时它会怎么做”。

随着模型进步,今天在 harness 里的部分能力会被模型原生吸收:规划与自验证可能不需要那么多提示支撑,有些 harness 复杂度确实会变得多余。

但围绕模型智能做的工程化设计——合适工具、持久状态、上下文管理、验证回路——会让任何模型更有效。这不是补模型短板,这是系统设计。

模型每几个月就变强一次;harness 是你能掌控的部分。

“模型不是你的 agent,harness 才是。值得投入的也是 harness。”


关注 AI拉呱

如果这篇内容对你有启发,欢迎关注「AI拉呱」,获取更多 AI 前沿洞察、实战教程与趋势解读。

下期在看

下期将继续带来该主题的进阶拆解与实操案例,建议先收藏本文,避免错过更新。