解剖 Agent Harness:驱动 AI 代理运行的引擎

Harness 是让模型变成 Agent 的「操作系统」。拆解 agent 主循环、上下文管理、工具调度、记忆、权限与 MCP 六大组件,附最小实现思路与自建 vs 现成取舍。

一句话理解 Harness

很多人以为「AI Agent」就是「把提示词发给大模型」。但在工程上,让 Agent 真正可靠地完成任务,你需要一套循环引擎——它负责替 Agent 不断「思考 → 调用工具 → 拿结果 → 再思考」,直到任务完成。这套引擎就是 Harness(代理运行时 / 编排层)

你可以把它理解成 Agent 的操作系统:模型是 CPU,Harness 是调度器。没有 Harness,模型只是「会生成文字的 API」;有了 Harness,模型才变成「能自己干活的 Agent」。

为什么需要 Harness

直接调模型 API 做一件事,你会立刻撞上几个麻烦:

  1. 模型说「我要调用工具」,你得手动解析输出、执行工具、把结果塞回下一轮请求——这个样板代码极其繁琐
  2. 多轮交互时,历史怎么维护、上下文怎么不爆?
  3. 工具出错要不要重试?什么时候该停?循环会不会死?
  4. 权限怎么控制?高危工具怎么拦?

这些「循环之外」的脏活累活,正是 Harness 解决的。你写业务逻辑,Harness 处理循环与基建。

Harness 的核心组件

一个完整的 Harness 通常包含这几块,缺一不可:

1. Agent 主循环(Tool-use Loop)

这是地基。每次迭代:

  1. 把「系统提示 + 历史 + 工具定义 + 用户消息」交给模型
  2. 模型返回文本或 tool_use
  3. 如果是工具调用,Harness 执行工具,把结果以 tool_result 塞回上下文
  4. 回到第 1 步,直到模型给出最终答案

一个最小 Harness 的伪代码,其实就这么短:

def run_agent(model, system, tools, user_msg):
    messages = [{"role": "system", "content": system}, {"role": "user", "content": user_msg}]
    for _ in range(MAX_ITER):
        reply = model(messages, tools=tools)
        if reply.has_tool_use():
            for call in reply.tool_uses:
                result = exec_tool(call)          # 执行工具
                messages.append(tool_result(call, result))  # 塞回上下文
        else:
            return reply.text                     # 没有工具调用,结束

听起来简单,但实现细节全在这:工具结果怎么格式化、什么时候该停、出错要不要重试、上下文爆了怎么办。Agent SDK 的 tool_runner 就是帮你把这个循环跑起来,不用自己手写。

2. 上下文窗口管理

Agent 最贵的资源不是 token,是上下文。Harness 必须回答:

  • 历史太长怎么办 → 压缩、摘要、滑动窗口
  • 中间结果要不要全保留 → 只保留对后续有用的
  • 怎么让重复前缀不重复计费 → Prompt Caching

上下文管得好,Agent 就「清醒」;管不好,Agent 就「失忆」——后半程开始胡说。

3. 工具调度

Agent 的能力上限 = 它拥有的工具质量。Harness 负责:

  • 把工具定义(schema)传给模型
  • 执行工具、捕获结果
  • 管理工具间的依赖、并发、超时
  • 把工具返回的原始数据整理成模型看得懂的形式

4. 记忆

Harness 让 Agent 跨任务「记得住」——项目规范、历史决策、用户偏好。可能是向量库,也可能只是一个结构良好的配置文件(比如 Claude Code 的 CLAUDE.md)。记忆决定了 Agent 是「每次从零开始」还是「越用越懂你」。

5. 权限与沙箱

高危工具(删文件、发请求、部署)需要护栏。Harness 做权限校验、确认提示、最小工具集。这是工程上最容易忽略、却最要命的一块。 一个没有权限控制的 Agent,等于把核按钮交给了它。

6. MCP

MCP(Model Context Protocol)是个标准化接口:让 Agent 通过统一协议连接外部工具和数据源。Harness 实现了 MCP client 端,Agent 就能即插即用地接入各种 MCP server,而不必为每个工具写私有协议。好处是生态——别人写好的 MCP server,你能直接复用。

自建 vs 用现成

你可能会想「我要不要自己写个 Harness?」

| | 现成(Claude Code / Agent SDK) | 自建最小 Harness | |---|---|---| | 上手 | 快,开箱即用 | 慢,要自己搭 | | 稳定性 | 高,踩过坑 | 低,坑要自己踩 | | 定制性 | 受限 | 完全可控 | | 场景 | 大多数产品化需求 | 特殊编排、多 Agent 协作、教学 |

我的建议:先彻底用熟现成的,理解它的取舍,再决定要不要自建。别为了「显得高级」而造轮子。

设计取舍

  • 窗口大小 vs 记忆深度:上下文给得越多越准,但越贵越慢。找平衡点。
  • 循环迭代 vs 成本:多迭代几次可能更对,但 token 成倍涨。给循环设上限。
  • 自由度 vs 可控性:工具越开放 Agent 越强,但也越危险。权限永远是护栏。
  • 响应式 vs 主动性:是「你问它答」,还是「它自己觉得该干了就干」?主动性越强,越需要护栏。

自建一个最小 Harness 的思路

如果你真想理解 Harness,从零搭一个最小版是最好的方式:

  1. 先不管工具,只写「调模型 → 返回文本」的最简循环
  2. 加工具:定义工具 schema,解析模型的 tool_use,执行,塞回结果
  3. 加护栏:迭代上限、超时、错误重试
  4. 加记忆:把系统提示从硬编码改成可持久化
  5. 加权限:给高危工具加确认机制

每一步都亲自动手,你就能真正理解为什么 Harness 是 Agent 的「操作系统」。这也正是我推荐的进阶路径——理解它,然后决定用现成的还是自己造。

一句话总结

Harness 是把模型变成 Agent 的「操作系统」。真正的 Agent 工程,80% 的功夫都花在 Harness 上——上下文怎么管、工具怎么给、记忆怎么存、权限怎么设。理解了 Harness,你就理解了 Agent 是怎么「活」起来的。