
Agent Harness 是什么从一次 Tool Calling 看懂 Agent 是怎么跑起来的最近在学习 Agent 开发时经常看到一个词Agent Harness。一开始我对它的理解也比较模糊Agent Harness 到底是什么它和 LLM、Tool、Agent 又是什么关系后来从最简单的 Tool Calling 开始梳理发现理解 Harness 最好的方式不是背定义而是看一个 Agent 真正运行起来以后会遇到哪些问题1. LLM 其实不会真正执行工具假设用户问帮我查询一下今天上海的天气。我们给 LLM 提供一个工具get_weather(city)模型可能返回{tool:get_weather,arguments:{city:上海}}这里需要注意LLM 并没有真正执行get_weather()。它只是做出了一个决定“下一步我想调用 get_weather。”真正执行工具的是模型外部的程序。因此可以简单理解为LLM ↓ 负责思考、推理、决定下一步做什么 Tool ↓ 负责真正执行操作2. Tool 到底是谁执行的模型产生 Tool Call 之后外部程序需要调用 LLM ↓ LLM 决定调用 Tool ↓ 程序执行 Tool ↓ 得到 Tool Result ↓ 把结果重新交给 LLM ↓ LLM 继续思考最简单的代码逻辑大概是whileTrue:responsecall_llm(messages)ifresponse.need_tool:tool_nameresponse.tool_name argumentsresponse.arguments resulttools[tool_name](arguments)messages.append(response)messages.append(result)else:returnresponse于是就形成了一个最基本的Agent LoopAgent 循环用户 ↓ LLM ↓ Tool Call ↓ 执行 Tool ↓ Tool Result ↓ LLM ↓ 继续调用 Tool / 返回答案3. 只有 Agent Loop 够吗显然不够。如果真的把 Agent 放到实际项目里运行很快就会出现各种问题。3.1 Agent 一直调用工具怎么办比如LLM ↓ Tool ↓ LLM ↓ Tool ↓ LLM ↓ Tool ↓ ……一直停不下来。最简单的办法就是增加限制MAX_ROUNDS8forroundinrange(MAX_ROUNDS):...例如最多允许执行 8 轮。这样可以防止 Agent 陷入无限循环。3.2 Agent 一直重复调用同一个 Tool 怎么办例如第 1 轮 search(Agent Harness) 第 2 轮 search(Agent Harness) 第 3 轮 search(Agent Harness)这显然是在浪费资源。因此可以记录已经执行过的调用executed_toolsset()每次执行前生成一个标识工具名 参数如果已经执行过就不再重复执行。当然实际项目中还需要考虑参数顺序不同参数规范化同义参数有副作用的 Tool 不能只靠简单去重所以真正工程中的重复调用检查会更加复杂。3.3 Agent 选错 Tool 怎么办假设系统中存在get_weather search_web search_file query_database用户只是想查询天气但模型却选择了错误的工具。因此需要考虑Tool 的描述是否清晰应该给模型提供哪些 ToolTool 很多时如何筛选如何提高工具选择的准确率这就涉及工具筛选和工具路由Tool Routing。3.4 Tool 一个一个执行太慢怎么办假设 Agent 同时需要执行三个互不依赖的任务Tool A2 秒 Tool B3 秒 Tool C2 秒如果串行执行A → B → C 大约需要 7 秒如果三个任务之间没有依赖关系则可以并行├── Tool A ├── Tool B └── Tool C 大约只需要 3 秒因此 Agent 还需要考虑 Tool 的并行执行。当然并不是所有 Tool 都可以并行。如果 B 必须依赖 A 的结果A ↓ B那就只能按照依赖关系执行。3.5 Tool 执行失败怎么办真实环境中的 Tool 不可能永远成功。例如网络请求失败 接口异常 执行超时 数据库连接失败因此还需要超时处理 重试机制 异常处理否则一个 Tool 出错整个 Agent 就可能直接崩掉。3.6 Agent 说完成了但任务真的完成了吗这是一个很重要的问题。例如用户要求修复 Bug并确保所有测试通过。Agent 的执行过程修改代码 ↓ 运行测试 ↓ FAILED ↓ “任务完成”显然不合理。所以不能只相信“模型说自己完成了。”还需要真正检查用户目标是否满足。例如用户要求测试必须通过 ↓ 运行测试 ↓ FAILED ↓ 任务没有完成 ↓ 继续修改 / 重新规划这就是任务验证Verification。3.7 执行很多轮还是完成不了怎么办假设 Agent 已经达到最大 8 轮第 1 轮 第 2 轮 ... 第 8 轮任务依然没有完成。这时候不能直接告诉用户“任务完成。”而应该进行兜底例如任务未完全完成。 已经完成 1. 定位问题 2. 修改部分代码 尚未完成 1. 测试仍然失败 失败原因 xxx也就是说既要防止 Agent 一直执行也要防止 Agent 没完成却假装完成。3.8 多个 Tool Result 对错了怎么办如果同时调用多个 ToolTool Call A Tool Call B Tool Call C返回顺序可能并不是A → B → C可能变成B → C → A因此需要一个唯一的调用 ID。例如Tool Call A ─── call_id_001 ↓ Tool Result ─── call_id_001通过call_id将 Tool Call 和 Tool Result 一一对应。这样即使多个 Tool 并发执行、返回顺序发生变化也能知道每一个结果对应的是哪一次调用。3.9 上下文越来越长怎么办Agent 执行几十轮以后Context 可能变成用户问题 Tool Call Tool Result Tool Call Tool Result 错误日志 搜索结果 代码 ……内容会越来越多。如果全部保留不仅会消耗大量 Token还可能影响模型后续判断。因此需要进行Context Management上下文管理例如删除不再需要的信息压缩历史内容只保留关键结果需要时再加载相关信息4. Agent Harness 到底是什么现在再回头看 Harness就比较容易理解了。最开始我们可能只有while True: LLM ↓ Tool ↓ Result但是随着 Agent 真正开始执行复杂任务我们不断遇到问题遇到的问题简单的解决思路一直调用工具停不下来设置最大执行轮数 / 停止条件重复调用同一个 Tool重复调用检查选错 Tool工具筛选 / 工具路由Tool 一个个执行太慢并行执行Tool 执行失败超时 / 重试 / 异常处理任务没完成却结束任务完成验证达到执行上限仍未完成失败兜底Tool Result 对应错误使用 call_id 一一对应上下文越来越长上下文管理于是这个简单的 Agent Loop 周围逐渐增加了越来越多的运行和控制机制。这些围绕模型让 Agent 能够更加可靠地执行任务的机制可以帮助我们理解Agent Harness。可以简单画成┌──────────── Agent Harness ────────────┐ │ │ │ Context │ │ ↓ │ │ LLM │ │ ↓ │ │ Tool Calling │ │ ↓ │ │ Tool Execution │ │ ↓ │ │ Tool Result │ │ ↓ │ │ Continue / Retry / Stop │ │ │ │ │ └──────→ LLM │ │ │ └──────────────────────────────────────┘因此我目前对 Agent Harness 的简单理解是Agent Harness 是围绕模型建立的一套运行和控制机制用来让模型能够持续、可靠地使用工具完成任务。5. LLM、Tool、Harness 和 Agent 的关系为了方便理解可以暂时这样类比LLM → 大脑负责思考 Tool → 手和眼睛负责真正执行操作 Harness → 运行和控制系统 Agent → 最终能够自主完成任务的整个智能系统因此可以粗略理解为Agent ≈ LLM Tools Harness这里使用≈是因为不同项目对于 Agent、Runtime、Harness 等概念的边界并不完全一致。重点不是死记定义而是理解它们分别解决什么问题。6. 一个最小版 Agent Harness如果把前面的内容简单组合起来一个最基础的 Agent Harness 伪代码可以写成MAX_ROUNDS8executed_toolsset()forroundinrange(MAX_ROUNDS):# 1. 调用 LLMresponsecall_llm(messages)# 2. 如果模型不需要调用 Toolifnotresponse.need_tool:returnresponse# 3. 获取 Tool 和参数tool_nameresponse.tool_name argumentsresponse.arguments# 4. 检查是否重复调用keytool_namestr(arguments)ifkeyinexecuted_tools:continueexecuted_tools.add(key)# 5. 执行 Tooltry:resulttools[tool_name](arguments)exceptException:resultTool 执行失败# 6. 把 Tool Result 放回上下文messages.append(response)messages.append(result)# 7. 达到最大轮数仍然没有完成return任务未完全完成需要进行兜底处理这当然只是一个非常简化的例子。但已经能够看到 Harness 最基本的作用控制 Agent Loop 执行 Tool 管理 Tool Result 限制执行次数 处理异常 提供失败兜底真实的 Agent Harness 还会复杂得多。7. 总结学习 Agent Harness 后我最大的一个理解是一个真正可用的 Agent并不是简单地给 LLM 接几个 Tool。最简单的LLM → Tool → Result → LLM只是起点。当 Agent 真正执行复杂任务时会逐渐遇到循环控制 工具选择 重复调用 并行执行 错误重试 任务验证 失败兜底 上下文管理 ……Agent Harness 的很多设计本质上就是为了解决这些实际工程问题。所以相比于直接背“Agent Harness 包含哪些模块”我更喜欢从另一个角度理解如果我要让一个 Agent 真正在生产环境里持续干活它会遇到什么问题这些问题又应该怎么解决理解这些问题以后Harness 的很多设计也就自然能够理解了。