Agent Harness 是什么:从类比到 12 个核心组件完全指南 第一次听到 Agent Harness 这个名词时我脑子里冒出来的画面是一副骑马用的皮革马具。后来真去搭 Agent 工程化的底座才发现这个命名一点都不随意Agent 是那匹有脑子的马Harness 就是套在马身上、让你真正能驾驭它的整套装置。把这条类比想通之后散落在我项目里的十几个模块忽然串成了一条线——这篇文章就是要把这条线重新捋一遍从类比出发推导出 12 个组件给正在纠结“Harness 到底是什么”“Agent 和 Harness 到底啥区别”的你一份可以直接参考的组件地图。先说清楚这篇内容能解决什么问题。如果你已经能写出一个会调工具、会自己规划步骤的 Agent demo但一放到真实业务里就发现它不可控、不听话、上下文记不住、工具乱调用、出了问题没法复盘那你缺的往往不是更强的模型而是一层 Harness。如果你刚开始接触这个概念想搞明白它和 Agent 的边界这篇文章同样适合你。下面我会用一个贯穿全文的类比把组件一个个拆开讲不堆概念全是我自己落地时踩过的坑和验证过的方式。1. 先用一个类比搞清楚 Harness 到底是什么1.1 骑马的那个人和那副马具骑马这件事真正的难点从来不是“马有没有力气”。马天生会跑但你想让它按你的路线走、在该停的地方停、跑完还能复盘刚才哪段路走岔了光靠马自己是不够的。马具就是为这件事存在的缰绳负责传递方向指令马鞍负责让你稳定地骑在背上肚带负责固定马镫负责给你一个发力点甚至马铃铛还能让你在复杂环境里听到马在哪。Agent 开发也一样。模型本身就具备“思考”和“调用工具”的能力但把这种能力丢进一个真实的业务流程里你会发现少了中间那一层“连接件”。没有这一层模型会忘记前面已经做完的步骤会拿着错误的参数去调接口会在一个死循环里反复打转甚至会编造一个不存在的查询结果。这不是模型不够聪明而是“马”没有被“装好鞍、系好缰绳”。1.2 Agent 是脑子Harness 是骨架和缰绳很多人把 Agent 和 Harness 混在一起其实它们的分工非常清晰。Agent 负责的是“推理与生成”给定当前状态决定下一步做什么、生成什么回复、选择哪个工具。Harness 负责的是“让这一切稳定发生”任务从哪来、状态怎么保存、工具怎么注册、模型怎么路由、结果怎么校验、过程怎么记录。打个比方Agent 是决策者Harness 是让决策落地的执行系统。决策者可以很聪明但如果执行系统是乱的再聪明也会翻车。我见过不少团队把大量精力放在调 Prompt、换更强模型上结果瓶颈却在“两个工具之间状态没同步”这种 Harness 层面的问题。这也是我后来坚持先搭 Harness、再调模型的原因。为什么叫 Harness 而不是 FrameworkFramework 强调的是“框架”给你一套代码结构Harness 更强调“约束与控制”有点像汽车里的安全带——它让你在高速路上跑得再快也不至于失控。理解了这一层后面的组件推导就顺理成章了。2. 从驾驭一匹马推导出 4 类问题、12 个组件要驾驭一匹马稳定地跑完一段路你需要解决四类问题第一方向问题——马往哪走、走哪条路、什么节奏走第二记忆问题——马走到哪了、刚才经历了什么、下次怎么做得更好第三能力问题——马背上带了哪些工具、遇到不同路况换哪匹马、骑手用什么样的口令第四治理与交付问题——跑偏了怎么拉回来、跑完了怎么复盘、换一个赛场这套马具还能不能直接用。这四类问题每组推导出 3 个组件总共正好 12 个。下面逐个推。2.1 方向问题谁来决定下一步做什么如果让马完全自由地跑它会按照自己的本能走而不是按你的目标走。Agent 也是一样如果不加约束它可能跑题、重复操作、过早收工。所以方向问题需要三个层次的机制由谁来决定任务的整体拆解、由谁来决定每一步具体动作、由谁来安排执行节奏。这三个层次对应到工程上就是 Orchestrator任务编排器、Planner规划器、Scheduler调度器。我曾经写过一个没有编排层的 Agent它收到“统计上月所有渠道的订单异常”这个任务后自己拆成了三步但执行完第一步就把第二步忘了最后输出结果缺了一半。这不是模型推理能力的问题是缺少一个“拿着任务清单逐项打钩”的编排层。2.2 记忆问题上下文不是简单的“历史消息”马跑过一段路之后必须知道自己从哪来、要到哪去、刚才哪块石头绊了一下。Agent 的上下文窗口是有限的你不能把全部历史都塞进每次请求里。这时候需要三样东西工作记忆负责当前对话里哪些信息必须保留长期记忆负责把跑完这一趟的经验沉淀下来供以后使用状态记录负责标记“当前处于哪一个阶段、完成度是多少”。对应组件就是 Context Manager上下文管理器、Memory Store长期记忆库、State Machine状态机。这里我踩过一个大坑最初我用一个全局字典存所有中间结果看起来方便实际上并发一高就互相覆盖。后来才明白上下文管理和状态管理不能混为一谈前者管“模型能看到什么”后者管“系统能确认什么”职责必须分开。2.3 能力问题工具、模型、提示词必须统一接进来马背上的工具箱不能每件工具都随便丢在背上得有一个固定的取用规则。Agent 的工具接入也是一样——不同工具参数格式五花八门需要有一个统一的注册、发现、调用入口这就是 Tool Registry工具注册器。同时你很可能不会只用一个模型贵的模型用来做复杂推理便宜的模型用来做格式整理主模型挂了要能快速降级需要一个统一的出口来管理它们这就是 Model Gateway模型网关。最后骑手给马下口令的方式也不能每次随性发挥需要一套经过验证的话术模板这就是 Prompt Manager提示词管理器。很多项目把 Prompt 直接写死在业务代码里每次调一句都得改代码发版。引入 Prompt Manager 之后提示词变成了可配置、可版本管理的资产同样是修改行为成本从半小时降到了两分钟。2.4 治理与交付问题跑得快不如跑得稳马跑得快不重要重要的是该停的时候停得下来。Agent 治理层的核心是 Guardrails安全护栏输出内容要校验、工具调用要鉴权、操作范围要受限。跑完之后还得知道刚才到底发生了什么所以要有 Trace Evaluate链路追踪与评估每一步的输入输出、模型、耗时、成本全部落盘并且能自动对比结果好坏。最后这套马具不能只在自家马厩里能用换一个环境、换一套部署方式也要能装上去这就是 Runtime Adapter运行时适配器。我团队里发生过一次事故Agent 在执行订单退款工具时因为工具入参校验没做好把“数量”字段传成了负数。那一次我们才真正重视 Guardrails它不该只拦“明显违规的内容”更该拦“结构合法但业务上非法的调用”。这类经验只有把治理层当作一等组件去做才不会被发现。3. 12 个核心组件逐个拆解在进入细节之前先给你一张速查表把这 12 个组件的类比和后文关键词列出来方便随时对照。编号组件类比核心职责落地关键01Orchestrator任务编排器领航员决定任务怎么拆、怎么走、何时算完成控制主循环别让模型自己全权指挥02Planner规划器路线图把目标拆成子任务与依赖关系输出结构化计划可校验可行性03Scheduler调度器马夫的作息表管理执行队列、并发、重试控制并发热度做好失败重试04Context Manager上下文管理器马的挎包管理工作记忆的读写、裁剪、摘要控制 Token 成本保留关键信号05Memory Store长期记忆库训练档案沉淀跨会话的经验与事实选好存储注意召回准确率06State Machine状态机马的体检卡明确当前阶段、流转条件、终态状态单写避免并发错乱07Tool Registry工具注册器马背工具箱工具的注册、发现、统一调用统一输入输出协议先校验再执行08Model Gateway模型网关马匹调度站模型路由、鉴权、限流、降级抽象厂商差异设定兜底模型09Prompt Manager提示词管理器口令话术库模板管理、版本管理、按场景组装模板资产化绑定可观测数据10Guardrails安全护栏围栏和安全绳输出校验、工具鉴权、行为边界结构校验与业务规则校验分开做11Trace Evaluate追踪与评估器赛后录像和评分表全链路日志、指标计算、结果评估从第一天就埋点不补12Runtime Adapter运行时适配器可换的蹄铁屏蔽环境差异统一部署接口接口固定环境差异隔离在外部下面按四组展开讲。3.1 任务编排三件套Orchestrator、Planner、Scheduler**Orchestrator任务编排器**是最核心的组件它定义的是“Agent 的主循环”。常见的循环模式包括 ReAct思考-行动-观察、Plan-and-Execute先定计划再逐项执行、多代理协作中的“经理-员工”模式。Orchestrator 不是简单地调用模型而是要决定“什么情况下继续循环、什么情况下终止”。我建议把终止条件显式写出来连续 N 步没有取得进展就该停止而不是单纯依赖模型自己说“我完成了”。**Planner规划器**负责把大目标拆成可执行的小步骤。它和 Orchestrator 的区别在于Planner 只负责“产出计划”不负责“执行计划”Orchestrator 负责“拿着计划推进”。早期项目可以不做 Planner直接把任务交给模型自由发挥但一旦任务复杂度上来自由发挥的失败率会急剧上升。规划结果我建议输出成结构化数据比如带依赖关系的任务列表而不是一大段自然语言否则后续编排程序根本没法稳定解析。**Scheduler调度器**管的是执行粒度多个子任务要不要并行、同时最多跑几个、一个任务失败后是重试还是跳过。它是 Harness 里最容易偷懒的组件很多人用普通 for 循环代替。直到某次所有子任务并发调用同一个上游接口把对方打挂了我才意识到调度器不只是“排顺序”更是“流量闸门”。实现上可以从简单的信号量并发控制开始后续再引入优先级队列。3.2 上下文与状态三件套Context Manager、Memory Store、State Machine**Context Manager上下文管理器**直接决定模型能看到什么。它做三件事把当前对话相关的关键信息拼装成上下文在上下文超过窗口上限时做裁剪或摘要确保不把敏感信息或无关历史塞给模型。这里有个经验裁剪时不要只是“从最早的消息开始删”而要先保留下“终止标志”和“关键约束”。我踩过两次坑都是因为裁剪太狠把系统指令里“已经完成不要继续”的信号裁掉了模型又开始自作主张地执行下一步。**Memory Store长期记忆库**负责跨会话的信息沉淀。它可以存用户偏好、历史任务结果、领域知识。技术上通常是向量数据库加关键词索引的组合。很多人的误区长在这里也可以用来存中间状态。我建议严格区分Memory Store 存的是“语义化的事实和经验”State Machine 存的是“当前任务的执行状态”。如果混在一起语义检索会给状态读写带来很大的不确定性和延迟。**State Machine状态机**是很多人会忽略的隐性组件。Agent 是有状态的等待用户输入、执行工具调用、生成最终回复、异常终止每个状态都有明确的进入和退出条件。有了状态机并发场景下两个任务才不会互相覆盖数据排查问题时你才能准确说出“这个任务死在哪一步”。我团队现在是每个任务实例维护一个只写一次的 state 字段所有状态变更都走同一个接口这个习惯救了我们很多次。3.3 工具与模型接入三件套Tool Registry、Model Gateway、Prompt Manager**Tool Registry工具注册器**是所有工具的统一入口。每个工具在注册时要声明名称、描述、输入参数 JSON Schema、权限等级、超时时间。注册器负责把模型的函数调用结果映射到真实代码。协议统一之后工具的接入成本会大幅下降。例如“查天气”工具和“查库存”工具虽然底层系统完全不同但到 Agent 这边都是“传参数、返回 JSON”模型只关心这两个工具能给它什么信息不关心数据结构差异。注意工具描述写得越准确模型选对工具的几率越高这一步值得花时间锤炼。**Model Gateway模型网关**解决的是多模型问题。它统一封装不同模型供应商的 API向外只暴露一套接口内部做路由、鉴权、限流、降级和成本统计。为什么需要它因为今天你用的模型三个月后大概率会被更强或更便宜的替换。有了网关替换模型只是一个配置变更不需要改动业务代码。更关键的是降级策略主模型超时或限流时网关能自动切到备用模型让服务不至于整体挂掉。这个组件在 demo 阶段可以省上线后必须补。**Prompt Manager提示词管理器**把提示词从代码中抽出来做成可管理、可测试、可版本化的资产。一个合格的 Prompt Manager 至少包含模板渲染、版本号、按场景组装。举个例子同一个“总结”能力在客服场景和数据分析场景下的提示词完全不同Prompt Manager 能把它们分开管理并且在 Trace 中记录“当前回复用的是模板的哪个版本”。这样当模型表现突然变差时你能快速判断是模板改坏了还是模型升级了。3.4 治理与运行三件套Guardrails、Trace Evaluate、Runtime Adapter**Guardrails安全护栏**是 Harness 和“裸调模型”的最大区别。它至少要做三层检查输出内容层检测敏感词、越狱指令、幻觉风险工具调用层校验参数类型、取值范围、权限是否匹配业务流程层判断这个动作在当前状态下是否合理。我在第 2.4 节提过的“数量传负数”事故就是第三层没做。护栏的实现要分阶段用户输入进来时做一次模型输出返回时做一次工具返回结果后做一次。别只挡最后一环越早拦截成本越低。**Trace Evaluate追踪与评估器**是全链路唯一能回答“刚才到底发生了什么”的组件。每次任务运行都应该记录任务 ID、模型名称、Prompt 版本、每一步输入输出、工具调用参数与返回、耗时、Token 消耗、护栏拦截记录。评估要做的是把这些数据聚合成可对比的指标比如任务完成率、工具调用成功率、平均步数。没有这个组件你就是拿着一个黑盒跑业务出问题只能靠猜。补充一句埋点要第一天就做因为事后补的数据结构永远对不上真实需求。**Runtime Adapter运行时适配器**把 Harness 与具体运行环境解耦。你的 Agent 可能跑在本地进程、云函数、容器集群也可能被不同的上游服务调用。Adapter 负责把不同触发方式HTTP 请求、消息队列、定时任务转换成统一的内部任务格式再把结果转换成各自需要的返回值。做的时候记住一条Adapter 只做“翻译”不要在里面写业务逻辑。我之前就遇到过有人把校验逻辑写进 Adapter结果换了一个部署环境后同一套逻辑被复制了三份维护成本直线上升。4. 实操视角怎么把这 12 个组件装进一个真实项目4.1 最小 Harness 骨架先跑通再长肉我知道你现在的想法肯定是12 个组件第一次都要全部实现吗当然不是。我建议的最小化骨架只保留 5 个东西一个主循环对应 Orchestrator 和 Planner 的合体、一个上下文管理器、一个工具注册器、一个模型网关的简化版直接用参数指定模型、一个最简单的护栏。状态机先用字典代替Trace 先打印日志Scheduler 用同步 for 循环这些后续再换成正式组件。下面这个代码是我常用的最小骨架核心是 ReAct 循环class MinimalHarness: def __init__(self, model, tool_registry, context, guardrails): self.model model self.tool_registry tool_registry self.context context self.guardrails guardrails def run(self, task): state {task: task, steps: []} for step in range(10): # Orchestrator 控制步数 messages self.context.build(state) response self.model.generate(messages) if response.is_final_answer(): state[steps].append({type: answer, content: response.content}) return response.content tool_call response.get_tool_call() self.guardrails.check_tool_call(tool_call) # Guardrails 拦截非法调用 result self.tool_registry.invoke(tool_call) # Tool Registry 统一调用 state[steps].append({type: tool, call: tool_call, result: result}) self.context.append(tool_call, result) # Context Manager 更新上下文这段代码把 12 个组件的边界全部画出来了for step in range(10)是简化版的编排器state是简化版的状态机self.context是上下文管理器self.tool_registry是工具注册器self.guardrails是护栏。你完全可以在 LangGraph、AutoGen 这类现成框架上跑通同样结构具体用哪个不关键关键是职责边界要一致。从最小骨架到完整形态我推荐的填充顺序是先补状态机因为并发出问题最致命再补 Trace 埋点因为越早积累数据越好接着补 Prompt Manager把提示词收拢起来最后补 Scheduler 和 Runtime Adapter这两个是性能和部署层面的优化。4.2 组件之间的“通信”怎么做才不乱很多人一看到“组件”就套用前端组件的思维想着父传子、子传父、事件总线。Harness 里完全不是这套逻辑。它更像是后端微服务之间的显式数据流数据通过调用参数传入通过返回值传出需要共享核心状态时走统一的状态管理接口而不是互相之间随意传引用。组件通信的三种常见方式我按优先级排了一下一是显式参数传递调用方把需要的对象通过构造函数或方法参数传给目标组件最容易追踪二是共享状态对象所有组件共同读写一个明确定义的任务上下文对象但必须规定好哪些字段只读、哪些字段只写三是事件或消息总线适合跨进程场景但调试成本会高一些。依赖方向也很有讲究。我吃过一次循环依赖的亏Context Manager 为了裁剪上下文去调 Model Gateway 做摘要而 Model Gateway 的日志又要依赖 TraceTrace 又反过来读 Context 里的数据。最后改成了单向依赖上层组件可以依赖下层组件下层组件绝不知道上层存在。类似地Tool Registry 不应该反向调用 Orchestrator否则你就没法换掉任何一个组件而不牵连全局。还有一个容易踩的坑是组件内部状态和 Agent 全局状态混用。前端的组件可以有自己的 localStorage、sessionStorage但 Harness 这边不应该允许每个组件私自保存 Agent 的运行状态。所有状态必须显式放在任务上下文或 State Machine 里。否则排查问题时你会遇到“为什么同一个任务在两个请求中表现完全不同”的幽灵问题。4.3 常见问题排查与避坑速查表最后把这几年沉淀下来的排查经验整理成一张表遇到类似症状可以先对号入座。现象根因解决办法Agent 反复调用同一个工具停不下来上下文裁剪太狠丢失了“已完成”的标志或终止条件判断过于依赖模型自觉在 Context Manager 中保留终止标志Orchestrator 设置连续无进展次数上限工具返回结果太大直接撑爆上下文Tool Registry 只透传原始结果没有做压缩或摘要在工具层增加 result summarizer按需截断或总结并发一高任务之间互相覆盖中间数据State Machine 缺位多个任务共享同一个可变状态对象每个任务实例单独持有 state状态变更走统一接口并加锁切换模型后 Agent 行为大变Prompt 与模型耦合缺少独立 Prompt Manager把提示词模板化、版本化切换模型后跑一遍回归集工具调用参数格式合法但业务上非法Guardrails 只做了结构校验没做业务规则校验在护栏中增加业务规则层针对关键工具编写断言线上出问题后无法定位是哪一步导致的Trace 埋点缺失日志分散在多个组件里统一打点记录事件 ID、模型名、Prompt 版本、工具调用前后结果部署环境一变Agent 逻辑跟着变Runtime Adapter 中混入了业务逻辑让 Adapter 只做协议转换业务校验放 Guardrails模型调用成本飙升Model Gateway 没有做模型路由所有请求都走大模型按任务难度分流简单任务走小模型复杂任务走大模型5. 最后聊几句个人体会做 Agent 工程化这几年我最深的一个感受是Harness 的价值不是一开始就能看见的它是在事故中慢慢显现的。你单独看每个组件好像都可以用“简单的 if-else”代替但当你面对 10 万次调用、多个模型、几十个工具、随时可能出错的网络和上游系统时缺少这些组件的代价会被无限放大。所以我的建议是不要迷信 12 这个数字也不要一上来就追求每个组件都做到完美。先把最小骨架跑通让一个真实业务在它上面稳定运行然后每遇到一个新问题就打开对应的那层抽屉补上对应的组件能力。过程中你会慢慢发现组件数量其实不重要重要的永远是那件事——你要能控制住 Agent而不是让 Agent 带着项目乱跑。如果你正在为自己的项目设计 Harness不妨先把这篇文章里的组件清单打印出来对照你现在已有的代码逐个问一句“这个职责谁负责”。大部分情况下你很快就能找到最缺的那一块然后你的 Agent 会在那个瞬间开始变得不一样。