大模型本身只能输出文本,为什么有的 AI 助手却能查资料、改文件,还能根据报错继续尝试?实际执行这些动作的是模型之外的软件:它接收模型提出的工具请求,检查是否允许执行,调用工具,再把结果交回模型。包裹模型、组织这一过程的运行时与控制层,就是 Agent Harness。模型提供理解、判断和生成能力,harness 让这些判断能够影响外部环境,并在拿到反馈后继续工作。
模型说要查天气,谁真正发出请求?
向助手提出“查一下北京今天的天气,判断出门要不要带伞”。如果只有一次普通模型调用,模型可以生成一句回答,却不能凭空取得今天的实况。即使回答中出现“正在查询天气”,这句话也没有向天气服务发出网络请求。要真正查询,外部程序必须提供天气工具,并把工具名称、用途和参数格式放进模型的输入。模型才有机会生成这样的工具请求:
{"tool": "get_weather", "arguments": {"city": "北京"}}
这份 JSON 表示要做什么,不表示事情已经做完。harness 收到请求后,查找 get_weather 对应的函数,核对参数和权限,再由函数访问天气服务。假设服务返回“北京,有雨”,harness 把这条结果加入消息历史,并再次调用模型。模型这次看到了查询结果,便可以据此建议带伞。

图中两次访问模型的输入不同:第一次有问题和工具说明,第二次多了实际观察到的天气。工具结果必须回填,否则模型不会因为外部程序查过天气,就自动知道查到了什么。将“调用模型—执行动作—提供观察结果”反复进行,形成了 agent loop,也就是智能体的执行循环。工具返回的报错同样是一份观察结果:模型看到具体错误后,可以在下一轮据它决定下一步。循环在外部程序里,下一步做什么通常由模型根据当前输入决定。
用 Python 风格伪代码,可以直接看到职责分开的位置。model 表示模型接口,dispatch_allowed_tool 表示核验并执行已注册工具的外部函数;返回值约定为回答或工具请求两种类型:
messages = [user_request]
for turn in range(turn_limit):
response = model(messages, tool_descriptions)
messages.append(response)
if response.kind == "answer":
return response.text
result = dispatch_allowed_tool(response.name, response.arguments)
messages.append(tool_result(result))
return "已到执行上限,任务尚未完成"
模型生成 response,程序执行工具、维护 messages,也由程序限制循环次数。最后一行的“尚未完成”很重要:达到上限只是停止运行,不能据此宣称天气已经查到。工具失败时,也需要让模型看到失败信息;模型看到报错后可以据此决定是否重试、更换工具或调整计划。若运行时判定不应继续,或已达到执行上限,则由运行时终止并报告原因,而不是把失败伪装成成功的工具结果。
这就是 Agent = Model + Harness 想表达的工程分工。对以语言模型为核心的 agent,可以把模型之外、支持任务执行的代码、配置和逻辑归入 harness。所谓“模型只预测下一个 token,其余靠 harness”,强调的是生成与执行的区别:token 是模型逐步生成内容的基本单位,工具请求也是生成出来的内容。它不意味着模型没有推理或规划能力;理解需求、选择工具和写出计划仍依赖模型,而发请求、保存结果和强制停止要由软件落实。
循环之外,还要保存什么、限制什么?
北京查完后,用户追问“上海呢?”如果处理这次追问时只向模型传入这三个字,模型可能缺少正在讨论天气的背景。harness 需要选取此前的问题、工具结果和当前追问,组成新的输入。这是上下文管理:决定本次模型究竟看到什么。消息历史可以留在会话状态里;历史很长时,还需要决定保留哪些内容、哪些结果放到文件中按需读取,而不是无限追加。
如果用户希望下次新会话仍记住“我常住北京”,仅保存本轮消息还不够。harness 可以将这项偏好写入持久文件,并在相关任务开始时读取、加入上下文。保存了记忆,不等于模型已经看到了记忆。就像记事本里写了偏好,不翻开看就不会影响当前决定。信息必须再次进入当前输入才会影响本次回答;这类外部记忆也没有改写模型权重。文件工作区同时可以保存天气报告和中间结果,使任务产物不必全部留在对话里。
当任务从“回答天气”变成“比较两座城市、写出行报告”,还会出现步骤与执行范围的问题。模型可以提出“先查北京,再查上海,最后写报告”的计划;harness 提供计划记录与进度保存,让后续调用能看到哪些步骤已经完成。规划不是每个简单任务都要经过的独立阶段,但在多步任务中,仅有一段计划文字无法替代实际查询和完成状态。
常见职责可以按它们解决的问题整理,而不是当成每个实现都必须安装的五个模块:
| 职责 | 在天气任务中具体负责什么 |
|---|---|
| 执行循环 | 继续调用模型、接收动作请求,并在回答完成、达到上限或人工中断时停止 |
| 工具接入与执行 | 把天气查询、文件读写等操作暴露给模型,执行请求并返回结果 |
| 上下文、状态与记忆 | 保存进度,选择本轮输入,按需读取跨会话信息 |
| 沙箱与权限 | 限定工具可以访问哪些文件、网络或执行环境,必要时等待人工批准 |
| 规划支持 | 保存模型生成的步骤和进度,让后续判断能参考未完成事项 |
这些职责怎样在一次动作中配合,可以放到同一张关系图中看。箭头上的文字分别表示读取、调用与结果回填,并不是五个模块依次运行的固定流水线。

图中工具前面有权限检查,是因为“模型认为应该做”与“系统允许做”是两回事。读取天气和覆盖已有报告带来的影响不同;运行时可以允许前者,而让后者等待确认。沙箱则限定操作发生的环境,例如让代码在隔离环境中运行,而不是任意访问宿主机。权限回答能否执行,隔离回答执行时能接触到什么,两者不能靠提示词里的“请小心”替代。
因此,harness 的“控制层”不是抽象地让模型更听话,而是在具体位置决定:输入组装哪些信息,请求能否执行,结果怎样保存,任务何时继续或停止。模型负责提出判断,外部程序把其中允许的动作变成真实操作,并让后续判断有结果可依据。
框架、运行时与多 agent 编排怎么区分?
有模型接口、工具库和消息存储组件,是否就已经有了 harness?还要看它们是否组成实际运行任务的程序。framework,也就是框架,通常提供可复用组件和组织代码的方式;harness 强调一组已经配合工作的运行时行为。前者更像积木,后者更像装配后能工作的成品。回到天气助手,能够导入天气函数还不够,还得有人负责把工具说明传给模型、执行返回的请求、回填结果,并决定停止条件。
这不是说框架没有运行时,也不是说 harness 必须是命令行产品。框架可以提供现成执行循环;harness 也可以作为库交给其他程序嵌入。两者比较的是侧重点:一个强调用什么组件构建应用,一个强调应用运行任务时如何行动。开发者完全可以使用框架构建自己的 harness,或者接入已有 harness,再补充业务工具和权限规则。
如果天气助手又委托研究 agent 查询信息、委托写作 agent 整理报告,问题会多一层:谁分配任务,谁等待谁,研究结果怎样交给写作方?这是多 agent 编排重点处理的协作关系。与之相比,harness 的执行职责关注一个执行者拿到任务后,怎样访问模型、调用工具、保存状态和处理反馈。前者说明多个执行者如何配合,后者说明执行者如何工作。
但不能据此画一条“harness 只能有一个 agent”的硬边界。harness 可以内置子代理委托与结果交接;LangGraph、CrewAI 这类常用于状态流程或角色协作的框架,也可能参与运行时的构建。产品能力会重叠,单 agent 与多 agent 不是互斥的产品标签。辨认架构时,要分开看具体代码承担的是工具执行、状态保存,还是任务分配与结果交接。
对于同一个天气任务,这些名称各有明确所指:模型判断该查哪座城市;工具函数取得天气;harness 组织调用、回填与停止;构建它的框架提供可复用组件;需要多个执行者协作时,编排逻辑安排分工。用户看到的是助手完成了一项任务,实际发生的则是模型生成、外部执行和反馈处理之间的一次次交接。
评论