Agent Harness 是什么?拆解智能体运行时的 12 个核心组件 Agent Harness 这个词在 Agent 开发圈里出现频率越来越高但很多人对它的理解还停留在“不就是给大模型套了个循环吗”。真正把 Harness 拆开看你会发现它是一套由无数组件组成的运行时体系比 Agent 本体复杂得多。这篇文章我想用一个比较省力的方式帮你建立整体认知先找一个所有人都熟悉的类比把它映射到工程组件上再倒推回来。适合刚接触 Agent 开发的工程师也适合一直搞不清 Harness 和 Agent 有什么区别、不知道一个生产级智能体到底需要哪些组件的技术负责人。1. 先搞清楚Harness 到底是什么它和 Agent 有哪些区别1.1 从“挽具”的本意聊起Harness 这个英文词原意是马的挽具、拉车的背带后来引申为“把某种力量驾驭起来使用”。软件圈借这个词其实就是形容“把模型、工具、记忆、外部服务绑在一起运行的那层支架”。这个比喻很准确。你有一个很强的大模型但它本质上只是“大脑”它不负责吃饭喝水不负责拿东西也不负责记住自己讲过的话。真正能干活的东西是把大脑架在一套系统里让它能看资料、能调工具、能带着上下文跑完整个长任务。这套系统就是 Agent Harness。我见过不少朋友做 Agent 项目第一版代码就是“while True: 调一次模型”调完拿到结果就结束。这种玩意严格讲不叫 Harness就是个脚本。等任务一复杂你会发现缺的东西越来越多谁来规划步骤谁记上下文工具调用失败怎么办模型乱答怎么拦这些问题全都要由 Harness 里的组件来回答。1.2 Agent 和 Harness 的差别赛车手与赛车很多人把 Agent 和 Harness 混着用我建议用赛车来理解Agent 是坐在车里的赛车手他有目标、有决策能力、知道下一步该做什么Harness 是整辆赛车包括引擎、变速箱、仪表盘、刹车、通讯设备缺一个都没法开完整场比赛。没有赛车的赛车手再厉害也只能原地站着没有赛车手的赛车本质上就是一堆铁。实际工程里Agent 是运行时里的决策节点Harness 是让这个决策节点能持续运转的整个支撑层。为了更直观我列一个对比表维度AgentAgent Harness核心角色决策主体支撑主体运转的整套系统典型组成模型调用 提示词 基本工具逻辑循环调度、规划、记忆、工具注册、执行、状态、护栏、观测、沙箱等类比赛车手一整辆赛车常见实现AutoGPT 里的 AgentExecutor、OpenAI AssistantsLangGraph、CrewAI、Mastra、自研 Runtime 等职责边界决定“做什么”保证“做得动、做得完、出错能兜底、复盘有依据”实际项目里两者经常不分家因为框架里一个 Agent 节点往往已经把循环和支撑逻辑耦合进去了。但我一直觉得理解职责域比抠名词更重要。你心里能分清“哪些逻辑属于决策、哪些属于支撑”后面设计任何架构都不会乱。1.3 什么情况下你需要真正引入 Harness如果你的功能就是“用户提问 - 模型回答”一次调用就结束那真的不需要 Harness。但一旦出现下面这些信号就得认真考虑任务需要多步才能完成比如先调研再总结再发邮件需要调用外部工具比如搜索、查数据库、操作文件、执行代码中间结果可能是错的需要重试、修正或换一种方案需要跨会话或有长任务的“短期记忆”出问题后你要能查清楚是哪一步导致的而不是让 Agent 当黑盒。客服机器人、代码智能体、数据分析 Agent 基本都属于这种情况。一个生产级的 Agent 背后至少有一个能承接复杂流程的 Harness只是你没意识到而已。2. 选一个类比把 Harness 看作一家公司的经营体系2.1 为什么是公司而不是流水线我之前讲组件喜欢用“流水线”来比喻后来发现不准确。流水线只能表达“按顺序处理”没法解释 Agent 面对新情况时的动态调整也不能体现“复盘、风控、容错”这些支撑职责。公司不一样。一家公司天生就有分工、有流程、有风控、有总结复盘。董事会做决策、战略部做规划、行政管档案、采购管供应商、一线员工干活、法务做合规、后勤处理事故、监控中心记录一切。这跟 Agent Harness 的职责域高度相似。所以下面的推导我全部用“公司”来指代 Harness。你只需要记住一个公式Harness 一家公司的经营体系Agent 这家公司的 CEO。2.2 公司部门到 Harness 组件的总映射先把总表放这里后面逐个细讲。生命周期阶段公司角色Harness 组件一句话职责想决策层CEO核心调度器决定下一步做什么驱动主循环想决策层战略部规划器拆解目标、规划步骤、修订计划想决策层董事会秘书模型适配层对接各种大模型统一通信协议备准备层档案室记忆系统存取短期工作记忆和长期事实备准备层信息助理上下文管理器控制模型每轮真正看到的信息量备准备层采购部工具注册表登记外部工具公示调用方式和参数做执行层一线员工工具执行器实际调用工具并取回结果做执行层财务部状态管理器记录任务进度、变量、已完成的步骤做执行层法务/风控安全护栏执行前后检查合规、权限、敏感内容护保障层人事/培训错误处理与恢复捕获异常、重试、降级、换方案护保障层监控中心日志与可观测性记录全部调用、追踪链路、统计成本护保障层隔离车间沙箱环境把危险操作隔离在受限环境里跑这张表其实是全文的骨架后面就是围绕它展开。2.3 “为什么是 12 个组件”的推导逻辑你可能会问为什么不是 10 个也不是 15 个这里有一个非常实用的推导方法把任何 Agent 的运行过程切成四个阶段——想、备、做、护。每个阶段问三个问题谁是核心决策角色它依靠什么资源出了风险和错误谁来兜底每阶段 3 个组件4 个阶段就是 12 个。这个推导逻辑比死记组件清单强多了。以后你往 Harness 里加任何东西只需要问自己这个组件属于哪个阶段、解决什么问题。如果某个阶段一个组件都没有那你的系统一定有隐患。3. 12 个组件逐个拆解职责、类比和真实落地3.1 决策层三件套调度器、规划器、模型适配器组件 1核心调度器Orchestrator这是整个 Harness 的心脏对应公司的 CEO。它的职责是驱动主循环拿到任务后决定“现在该做什么”调用相应的组件收集结果再决定“下一步做什么”直到任务完成或触发终止条件。真实落地时常见的技术形态是 ReAct Loop推理-行动-观察循环或者是 LangGraph 里的 StateGraph 节点循环。你写 Agent 时那个最外层的 while 循环本质上就是调度器。我踩过的最大的坑是忘记设终止条件。模型在对话中很容易陷入“我再试一次”的循环如果没有最大步数、成本上限或明确的结束信号一次任务能把预算烧穿。所以调度器必须内置最大迭代步数、单任务 token 预算、优先级规则并且在模型重复输出同一动作时强制中断而不是硬跑。组件 2规划器Planner对应公司里的战略部负责把一个大目标拆成若干可执行的小任务并确定依赖关系。比如“调研三家公司并输出报告”这个任务规划器会拆成搜索资料 - 提取关键信息 - 对比分析 - 生成报告。技术实现上有 Plan-and-Execute先规划再逐项执行、思维树 ToT、以及 MetaGPT 那一类角色任务拆分。规划器的设计有个取舍一次性规划 vs 逐步规划。一次性规划对简单任务效率高对复杂任务容易因为初始假设错误导致全线崩盘。我现在的习惯是混合式先粗粒度规划执行中动态调整细粒度步骤。如果你写死一个计划让 Agent 盲目执行一旦中途环境变了整个任务就废了。组件 3模型适配层Model Adapter / LLM Gateway对应董事会秘书——CEO 不可能自己直接跟所有外部机构对接需要一个统一传话的人。技术上模型适配层负责把 OpenAI、Anthropic、Gemini、本地 Ollama 等不同模型封装成统一接口屏蔽消息格式、工具调用协议、token 计量方式的差异。现实中你会发现不同厂商的工具调用格式完全不一样OpenAI 用tool_callsAnthropic 用tool_use解析逻辑无法直接复用。这个组件被很多人忽略直到切换模型才痛苦。我建议一开始就把模型调用抽象成统一接口哪怕你当前只用一个厂商。反例是我见过有项目直接在业务代码里写 OpenAI SDK后来要兼容本地模型改到怀疑人生。3.2 准备层三件套记忆、上下文、工具注册组件 4记忆系统Memory对应公司的档案室。Agent 在长任务里需要记住“刚才查到了什么”“用户偏好是什么”否则每一步都像失忆了一样重来。记忆可以分两层短期工作记忆就是当前对话的上下文长期记忆则把重要事实存入外部存储比如向量数据库、摘要文件、结构化数据库。常见实现有向量检索Chroma、PGVector、摘要记忆链、mem0 这类记忆中间件。记忆系统的关键不是“怎么存”而是“什么该存、什么不该存”。我早期天真地以为把所有中间结果都存进长期记忆就是“记忆增强”结果模型反复引用早期错误结论这就是典型的记忆污染。现在我会在写入记忆前做一层判断只有已经验证过的事实、明确的用户偏好、已完成任务的结论才有资格进长期记忆。组件 5上下文管理器Context Manager这个组件经常和记忆系统混淆但两者职责确实不同。记忆系统管“存什么、怎么取”上下文管理器管“这一轮模型到底能看到什么”。大模型的上下文窗口是有限的你不能把整个档案室都搬给 CEO 看。上下文管理器要做的事包括滑动窗口截取最近几轮对话、对早期内容做摘要压缩、从长期记忆中检索 top-k 相关片段并控制在模型输入的 token 预算内。这里有一个很反直觉的经验上下文不是越全越好。把历史全部塞进去模型确实能看到更多信息但它对关键指令的跟随能力会迅速劣化。你应该像给 CEO 准备汇报材料一样只精选重点。压缩摘要时也要注意不是简单地“把对话变短”而是保留“动作 结果 结论”否则压缩完的信息对后续决策毫无帮助。组件 6工具注册表Tool Registry对应采购部的供应商名录。Agent 能调用哪些工具、每个工具的参数是什么、入参出参格式如何都由工具注册表来管理。真实落地时工具注册表就是一份工具清单每个工具包含名称、描述、参数 JSON Schema、执行权限等级。LangChain 的tool装饰器、OpenAI Function Calling 的tools参数本质上都是往这个表里塞记录。工具注册表最容易被低估的是描述质量。描述写得模糊模型就会乱用甚至不调用。比如“search”和“search_web”两个工具如果描述都是“搜索”模型根本不知道区别。你要写明“search_web 用于搜索公网网页内容search_db 用于查询内部产品数据库”模型才能做出正确路由。工具多了之后还可以做分组——先让模型选组再让模型选工具这样比直接给 30 个扁平清单要稳得多。这跟前端“动态组件加载”“组件注册”的思路其实很像提前把可用能力注册好运行时按需取用。3.3 执行层三件套工具执行、状态管理、护栏组件 7工具执行器Tool Executor对应一线员工。模型只是“说”要调用工具真正去调用函数的、发 HTTP 请求的、开子进程的是工具执行器。执行器要处理几类脏活参数校验模型经常传错类型、执行超时外部接口卡死不能拖垮整个任务、结果截断工具返回 10 万字的 HTML你不能全塞给模型、并行执行多个独立工具调用同时跑可以大幅提速。最痛的经验是结果回写。工具执行完拿到结果必须结构化地写回上下文同时标注工具名、执行状态和关键内容。很多初学者只调工具不存结果下一步模型决策时根本看不到刚才查到了什么于是反复调用同一个工具。这个我在第 4 部分会展开讲。组件 8状态管理器State Manager对应财务部。整个任务执行到哪里了、已完成哪些步骤、哪些变量是当前值都需要状态管理器记录而不是散落在各个局部变量里。LangGraph 里的 State 就是典型实现——每个节点执行完返回新的状态下次节点读取最新状态。状态管理还支持断点续跑和人工介入任务执行到某一步需要人工审批先持久化状态人批完再恢复。这对生产级 Agent 几乎是刚需尤其是涉及支付、删除、对外发布等高风险动作。踩坑提示状态结构要尽量扁平、可序列化。别把模型对象、数据库连接这种东西直接塞进 state否则一旦要序列化保存就崩。多线程并行更新同一字段时要小心丢更新多轮任务的状态最好设计成“追加式事件列表”而不是一个被反复覆盖的变量。组件 9安全护栏Guardrails对应法务/风控。每一步行动都要经过审查能不能做、权限够不够、内容合不合规。护栏通常分三层输入层检测用户提示词里的注入攻击prompt injection执行层校验工具调用权限、域名白名单、危险操作拦截输出层检查生成内容是否包含敏感信息是否泄漏隐私。关键操作还要加 human-in-the-loop也就是人工审批环节。比如 Agent 要发送邮件、删除用户数据先挂起人工确认后才执行。护栏的设计难度在于平衡。太松等于没有太严又会把 Agent 卡死。我见过一个项目护栏拦掉了所有“删除”类工具结果 Agent 在处理退货流程时反复尝试删除订单又被拦最后原地打转。解法是护栏拒绝时不要只抛一个“not allowed”就完事要返回结构化的拒绝原因和建议的替代路径让模型能自己调整方案。这比简单粗暴的错误信息有用得多。3.4 保障层三件套错误处理、观测、沙箱组件 10错误处理与恢复Error Handler对应人事/培训部门——员工干砸了不能直接开除先看是能力问题还是环境问题决定重试、换人、还是上报。Agent 运行中会碰到各种错误模型 API 限流、工具超时、工具返回脏数据、模型输出不符合预期格式。错误处理器要做的决策依次是能不能重试指数退避避免被限流要不要换方案比如在线搜索失败退回本地知识库要不要换模型当前模型理解不了fallback 到更强的模型最后才考虑终止并上报。这里有个严重的副作用问题重试工具调用前必须确认工具是否幂等。发邮件、扣款这类操作重试两次就等于执行两次后果不可控。我的习惯是在状态管理器里记录“哪些 action 已经执行、不可重复执行”重试前先查一下。组件 11日志与可观测性Observability对应监控中心/会议记录员。每一轮模型调用prompt、completion、token 数、耗时、每一次工具调用参数、结果、状态、每一次状态变更都要被记录在案。工具方面有 LangSmith、Langfuse、AgentOps也可以直接用 OpenTelemetry 做分布式追踪。日志的价值不只是事后 debug更是质量评测——你以后优化 prompt、优化工具描述都得靠这些日志对照实际表现。我最大的教训是日志一定要有 trace_id 串联。并行任务里如果每个步骤各自打日志没有统一请求 ID出了问题根本没法复盘。还有就是要记录压缩前的完整上下文否则一旦上下文管理器压缩出错你连复现都做不到。成本统计也需要放在这一层按任务聚合 token 消耗监控预算。组件 12沙箱环境Sandbox对应严格隔离的车间/演习场。所有有副作用的操作——执行代码、操作文件系统、访问网络、运行下载的程序——都应该在隔离环境里跑。技术实现包括 Docker 容器、云沙箱比如 E2B、子进程加资源限制。要知道模型生成的代码可能是错的也可能是被 prompt injection 诱导的恶意代码如果你让它在宿主机上直接跑后果不堪设想。沙箱配置时我建议默认策略是拒绝网络请求按需开放白名单域名。同时要给执行时间、内存上限、CPU 上限加限制否则一个死循环代码就能耗光服务器资源。很多团队上线前觉得“我的 Agent 只查数据库不需要沙箱”结果模型被用户一句话诱导去读服务器上的敏感文件那时候再补就晚了。4. 一次完整任务的组件协同从调研竞品到发送报告4.1 任务设定只看清单理解不了组件怎么配合跑一遍最直观。假设我们有一个生产级 Harness配置了 web_search 搜索工具和 email 发送工具要执行的任务是调研 A、B、C 三家竞品的定价策略整理成 Markdown 表格发送到指定邮箱。4.2 一次完整执行过程下面按步骤走括号里标注对应组件用户提交任务。核心调度器1接收任务初始化状态管理器8state {task: ..., stage: plan}。规划器2把任务拆成子任务搜索竞品 A、搜索竞品 B、搜索竞品 C、提取价格对比、生成 Markdown、发送邮件。模型适配层3把当前计划和之前的对话历史封装成请求发给大模型。模型决定“先搜索竞品 A”。工具注册表6确认存在 web_search 工具返回调用 schema。安全护栏9通过校验web_search 在白名单内且本次搜索域名无敏感标记。工具执行器7真正调用搜索 API。这一步如果涉及代码执行沙箱12会介入但普通 HTTP 搜索暂时不需要。搜索结果返回共 20 条。上下文管理器5判断内容过长做摘要压缩只保留 3 条关键定价信息写回上下文。记忆系统4把“竞品 A 的定价区间是 100-200 元”这类事实写入短期记忆后续竞品对比时直接查。状态管理器8更新进度stage: search_done, done: [A]进入下一轮循环。调度器1继续循环依次处理竞品 B、竞品 C。每次搜索、压缩、写记忆、更新状态的过程都一样。所有搜索完成模型开始生成 Markdown 表格。生成前护栏9检查输出内容不包含内部数据生成后工具执行器7调用 email 工具发送邮件。email 接口第一次 503 超时。错误处理器10按指数退避重试第二次成功。记忆系统4记录email_sent: true防止后续误重发。日志与可观测性11早已把每一步模型调用、工具调用、状态变更打上同一个 trace_id 保存下来。调度器1收到 finish 信号结束循环返回最终报告。这个流程看下来你会发现组件之间其实是在“接力”调度器发起、规划器拆解、模型适配器沟通、上下文管理器裁剪、工具执行器落地、状态管理器记账、护栏把关、错误处理器兜底、观测器留痕。4.3 协同中最容易被忽略的三个衔接点第一工具结果回写。模型做出调用工具的决定后工具执行器拿到结果必须把结果结构化成“工具名 状态 关键内容”写回上下文。这一步相当于前端组件通信里的“子传父”——工具是子组件上下文是父组件。回写得不好等于子组件改了数据但父组件没刷新模型下一轮就失忆了。第二状态与分支的处理。Agent 任务不是一条直线中间会出现分支竞品 A 搜索成功、竞品 B 搜索失败待重试、用户插话要求改格式。状态管理器需要把这种“部分完成、部分待办、部分失败”的复杂情况记录下来而不是简单存一个布尔值。第三重试的幂等校验。email 工具第一次失败后重试要确认状态里没有email_sent: true标记。否则模型会因为没收到成功响应而重复发送同一封邮件这就是线上事故了。4.4 最小主循环长什么样下面是我在项目里常用的一个最小 Harness 骨架用 Python 伪代码表示class Harness: def __init__(self, model, tools, memory): self.llm model # 组件3模型适配层 self.registry ToolRegistry(tools) # 组件6工具注册表 self.memory memory # 组件4记忆系统 self.state {steps: []} # 组件8状态管理器 self.observer Logger() # 组件11日志观测 def run(self, task): self.state[task] task for step in range(MAX_STEPS): # 组件1核心调度器 prompt self.build_prompt() # 组件5上下文管理 action self.llm.decide(prompt) if action.type finish: return action.output tool self.registry.get(action.name) result tool.execute(action.arguments) # 组件7工具执行器 self.state[steps].append({ action: action, result: result, status: done }) self.observer.log(step, action, result) raise TimeoutError(max steps exceeded)这只是骨架但你能看到 12 个组件里已经有了 6 个。剩下的规划器、护栏、沙箱、错误处理、上下文高级压缩等都是在这个骨架上逐步加厚的。5. 从 12 个组件到落地选型、最小集和排坑经验5.1 自研 Harness 还是用现成框架这是每个做 Agent 的人都会纠结的问题。我的建议是除非你的场景特殊到现有框架都套不上否则先用现成框架跑通业务再考虑自研。因为 Agent 应用最大的成本从来不是控制流而是业务逻辑、工具质量和评测体系。我按自己的经验给主流框架做个对比框架核心抽象适合场景注意点LangGraph图状态编排复杂控制流、需要人工审批、状态持久化要求高概念多上手曲线陡LlamaIndex Workflow事件驱动数据检索 RAG 结合紧密的任务组件通信靠事件调试要习惯CrewAI角色协作多个 Agent 扮演不同角色协同角色边界要清楚不然互相抢活AutoGen对话式多 Agent需要多个 Agent 互相讨论/辩论会话轮次会膨胀成本高Mastra原生 TS 工作流 Agent前端和 Node 团队做全栈应用生态相对较新OpenAI Agents SDK轻量 Runner 工具快速验证想法、简单工具调用复杂流程控制力弱一些选型的时候不要看 GitHub Star 数看你的核心需求要人工审批就选支持状态持久化的要跟现有 TS 技术栈融合就选 Mastra要做研究型多角色协作就选 CrewAI/AutoGen。框架只是脚手架12 个组件该补的还得补。5.2 最精简的 Harness 至少要有五件事如果你只是想快速做一个轻量 Agent不需要一上来就搭齐全套 12 个组件。但下面五件事是底线一个能跑循环的调度器负责决定下一步做什么并判断何时结束一个模型适配层负责和 LLM 通信、解析结果一份工具清单哪怕只有一个工具也要有清晰 schema一个工具执行入口能实际调用工具并把结果传回来一个状态对象存住当前进度和中间结果。第六个我会立刻补上日志。没有日志后续所有优化和排错都是盲人摸象。规划器、记忆系统、护栏、沙箱可以等项目跑通后再逐步加。不过上线前一定要补护栏和沙箱这两个属于“出事才值钱”的组件宁可提前。5.3 实操中踩过的坑这些坑都是我真实踩过或帮别人排查过的按频率排序提一下上下文爆掉。工具返回大段文本不裁剪直接塞进上下文。一次搜索就能吃掉 2 万 token三轮之后模型开始忽略系统指令回答完全跑偏。现在我对每个工具结果都强制截断超过 2000 字符就摘要单轮上下文预算在调度器里写死。模型反复调用同一个工具。最常见的原因是工具结果没有正确回写模型看不到“已经查过了”。另一个原因是工具失败后错误被代码吞掉模型不知道失败了于是反复尝试。处理方式是工具结果和错误信息都显式放回上下文并且带执行状态。重试产生副作用。发邮件超时重试结果邮件发了两遍。后来我在状态里加了一个action_status字段外部副作用类工具执行前先检查是否已执行过保证幂等。工具描述不清晰。接了一个开源 Agent里面同时有search和google_search两个工具描述都写着“搜索”模型随机调。我把描述改成了“search 查内部知识库”“google_search 查公网内容”并把工具按类别分组准确率立刻上来了。记忆污染。早期把模型总结的“初步猜测”也写进长期记忆结果后面的任务不断引用这个错误猜测。现在记忆写入规则是只有用户明确表达的信息、已完成的工具调用结果、确定的事实性结论可以写入长期记忆推测性的东西一律只放短期上下文。日志没有 trace 串联。多 Agent 并行跑的时候A 智能体的日志和 B 智能体的日志混在一起没有统一 trace_id定位一次诡异 bug 花了一整天。后来所有日志都强制带 trace_id并继承到子任务。护栏拦截导致任务卡死。Agent 要删除一张临时表护栏拦截后抛了个异常模型不知道发生了什么只能不停重试。现在护栏拦截时返回结构化信息“操作被拦截原因是权限不足建议改用 XX 方式”模型就能自己调整。沙箱没限制网络。测试代码执行工具时模型生成了一段curl命令沙箱又没断外网差点把内部服务的接口探测了一遍。从那以后沙箱的默认策略就是禁网需要联网的工具单独申请白名单。最后再说一个我的小习惯每次接触一个新框架我会先按“想、备、做、护”四个阶段把它的组件列一遍给每个组件标出在框架源码里的对应模块和接口。这个动作花不了十分钟但能让你快速摸清整个框架的设计思路而不是被各种抽象名词绕晕。Agent Harness 这个东西说复杂也复杂说简单也简单。复杂在组件多、协同链路长简单在只要抓住“决策、准备、执行、保障”这条主线所有组件的位置和职责都很清晰。希望这篇拆解能让你在搭建自己的 Agent 系统时心里先有一张完整地图而不是照着别人的 demo 一顿复制复制完还不知道哪里会崩。