第一次在 GitHub 上搜到 Agent Harness 这个关键词的时候,我是真的愣住了。当时我正准备给自己做的 Agent 套一层“正式工程化”的外壳,结果文档里满屏 harness、runtime、scaffold 混在一起,看半天不知道它们在说什么。问了团队一圈,有人说是框架,有人说是中间层,还有人干脆说这就是一个库的命名方式。
直到我翻到英文里 harness 这个词的本义才一下子通了——它是“马的挽具”,是套在牲畜身上那套完整的皮带、绳索和铁环。这个直觉很重要:Agent 是那匹会思考的马,Harness 是套在马身上的整套器具。没有它,马照样能跑;但没有它,你拉不动货、停不下来,也不知道马今天跑了多少路、吃了几斤草。
这篇文章我打算换一种写法,不是贴一份组件清单完事,而是用马车和挽具这个类比,一个一个推导出 Agent 系统的 12 个核心组件。推导完之后你会发现,其实组件不是谁发明的,是每个想把 Agent 搞到生产环境的人,都会在踩坑之后被“逼”出来的东西。
1. harness 到底是什么:先解决“和 agent 的区别”这个基本困惑
1.1 词源直觉:Harness 本来就不是软件词
很多人第一次接触 Agent Harness 会觉得这是个新造术语,其实它的词根特别老。Harness 在英文里最古老的用法,就是“马的挽具”或者“铠甲”,特指把马和马车连成一套可操控系统的物理装置。
你去看 18 世纪的马车图就明白了:马、缰绳、马轭、车辕、皮带扣,这堆东西合起来叫 harness。它起着三个核心作用:
- 传导:马的力气不能凭空变成车的牵引力,必须通过马轭和车辕传递;
- 约束:马要往左还是往右,不能全靠它自觉,缰绳必须存在;
- 保护与供给:长途运输时,马鞍要舒服、草料袋要有位置挂,整个系统才不会半路散架。
软件世界借用这个词,我认为非常精准。一个 Agent 模型本身具备推理能力,但模型的输出不能直接变成服务能力,模型运行过程中的上下文、工具、权限、日志也全都处于“裸奔”状态。Agent Harness 就是解决传导、约束、供给三件事的外围层。它不负责“思考”,但它负责让“思考”能在可控的环境里变成行动。
1.2 Agent 和 Harness 的分工边界
网上搜 Agent Harness,最常见的关联问题就是“harness 和 agent 区别到底在哪”。我用一张表来理清这个边界:
| 对比维度 | Agent | Harness |
|---|---|---|
| 角色定位 | 大脑,负责意图与决策 | 载体与环境,负责支撑与管控 |
| 核心输出 | 推理结果、动作序列 | 运行状态、日志、监控、安全边界 |
| 类比 | 马 | 挽具 |
| 只有它会怎样 | 能写一次性的脚本,但是乱跑 | 空配置系统,无法产生智能行为 |
| 典型实现材料 | LangChain Agent、OpenAI Function Calling、自研 LLM 推理循环 | LangGraph、LiteLLM、Guardrails、缓存和观测系统 |
| 使用者视角 | 你问它什么、它做什么 | 你管它怎么运行、怎么记录、怎么控制 |
我的经验是,很多团队把 Agent 和 Harness 混在一起写,最后代码里全是推理逻辑,却找不到任何地方去插“权限检查”和“日志”。这就是边界不清的典型症状。大原则是:Agent 回答“做什么”,Harness 回答“在什么条件下做、做完怎么记住、出事怎么追溯”。
1.3 没有 harness 时,你会遇到的真实事故
如果只把 Agent 做出来就直接扔到生产环境,典型事故是这三件:
第一,Agent 拿到了一个“批量删除”工具,因为它本身只是个模型,认为删除用户数据是合理的下一步。没有权限护栏,模型可以直接执行危险操作。我曾见过一个 demo 因为 Agent 自己构造了一个 shell 命令,差点把测试环境的数据清了,从那以后我在任何 Agent 项目里都优先加刀闸机制。
第二,同一个问题被反复询问,每次调用模型都产生完整推理费用。一次对话里问三遍相似的产品推荐,模型没有缓存概念,每次都重新跑一遍模型,账单蹭蹭涨。你怪模型不聪明没有用,问题在于 Harness 层没有做结果复用。
第三,一次多步工具调用失败之后,你根本找不到是哪一步出的问题。没有 trace,没有节点日志,只有模型最终一句“抱歉我无法完成”。这种问题排查起来简直是灾难,最后只能靠打印中间变量硬调,效率极低。
这三件事的共同点就是:马本身不坏,问题是没人给它套挽具。
2. 一个类比就能推导出整套 Agent Harness:马车挽具系统
2.1 为什么“类比推导”能成立
很多文章喜欢直接罗列“Agent 系统的十大组件”,然后逐个解释,读者看着看着就陷入了记名词的困境。原因在于组件之间没有推导关系,它们是平铺的。
我这篇换个思路:先建一套马车系统的完整图景,然后让 Agent 系统的组件从这套图景里“长出来”。马车要跑长途运输,除了马本身,还需要什么?这个问题一步步答完,12 个组件就全出来了。组件不是靠背的,是被需求逼出来的。
2.2 类比设定:仓库的第一次策马
想象你有一批货物要从 A 城运到 B 城,你买了一匹好马(Agent 模型)。这匹马智力很高,知道怎么走、怎么拐弯、怎么躲坑,但你要让它真正把货拉过去,需要把整套“外围装备”备齐:
- 马身上的挽具、马轭、鞍座,不装这些东西,力气根本传不到车上;
- 缰绳和嚼子交在你手里,不然你无法指挥方向;
- 货物要绑牢,载重不均衡,走几步就翻车;
- 路上要有备用蹄铁,马掌磨破了这趟活就得停;
- 要防惊马,要能急刹,不然进集市就出人命;
- 还得有人记账,每天跑了多少里、喂了多少草、换了几个马掌,都得有记录。
这套需求一层层套下来,对应的软件组件就完整了。
2.3 从“跑通”到“跑好”,需求的层次递进
类比还有个额外好处:能帮你想清楚组件的建设顺序。
- 第一层:能跑。这是 demo 阶段,马 + 车 + 一段缰绳就够了。对应到 Agent 项目,就是用模型 API 调用 + 一个工具函数,来回 loop 几遍就算跑通;
- 第二层:能控。要跑真实任务,就需要缰绳、刹车、导航。对应模型网关、护栏策略、任务规划引擎;
- 第三层:能养。跑起来之后要长期维护,就需要记录里程、补给定点、维修站。对应可观测、缓存、状态管理;
- 第四层:能规模化。多匹马编队、多驿站协同、统一调度。对应多 Agent 编排、统一评估体系。
这就是为什么很多项目写着写着突然觉得系统“不稳”,本质上是它停留在第二层之前,却试图做第四层的事。组件的出现从来不是装饰,是每个阶段的稳定性需求倒逼的。
3. 从挽具推导出的 12 个组件:逐个拆解
3.1 先放一张“挽具零件 - Agent 组件”总览表
下面这张表是全篇的地图。左边是马车系统的零件,右边是对应的软件组件,右列最后一句是核心职责。可以保存下来,写代码时对照着看。
| 序号 | 挽具零件/角色 | 软件组件 | 一句话职责 |
|---|---|---|---|
| 1 | 挽具总装配工 | 配置中心(Config & Secret Center) | 管理环境差异、密钥、模型参数 |
| 2 | 马轭与车辕 | 运行时内核(Runtime Core) | 维护执行循环、事件调度、生命周期 |
| 3 | 鞍座 | 状态管理器(State Manager) | 管理上下文、会话、快照 |
| 4 | 缰绳与嚼子 | 模型网关(Model Gateway) | 统一模型接入、路由、重试与回退 |
| 5 | 马夫的号令 | 指令管道(Instruction Pipe) | 分层组装 system prompt 与行为约束 |
| 6 | 车厢里的路线图 | 任务规划引擎(Task Planner) | 拆解目标、编排子任务、支持 replan |
| 7 | 马蹄铁 | 工具注册表(Tool Registry) | 技能注册、参数校验、调用路由 |
| 8 | 刹车 | 护栏策略(Policy / Guardrails) | 权限边界、审批流、预算控制 |
| 9 | 减震弹簧 | 缓存层(Cache) | 相似请求命中、prefix 复用、结果复用 |
| 10 | 马铃 | 可观测模块(Observability) | trace、日志、指标,回答“发生了什么” |
| 11 | 粮草袋 | 记忆系统(Memory) | 短期上下文策略 + 长期信息检索 |
| 12 | 驿站账本 | 评估与反馈(Evaluation) | 回归测试、质量评分、数据回流 |
这张表看一眼就够了,下面的小节才是真正要带走的内容。
3.2 骨架三兄弟:运行时内核、状态管理器、配置中心
先说总装层,这层建模的是“马车上最基础的结构件”,没有它们整个装置立不起来。
**运行时内核(Runtime Core)**是最核心的组件,它干的事就是那个永远存在的循环:观察当前状态 → 让模型思考 → 执行工具调用 → 更新状态 → 判断是否继续。很多人把这段逻辑直接写在业务代码里,导致每个入口都要重来一遍。更好的做法是把这层抽象成事件循环,提供钩子(hook),让业务只关心策略,不关心内部循环。LangGraph 本质上就是把这段循环图式化,让循环的分支和终止条件变得可见。
**状态管理器(State Manager)**解决的是“这匹马现在处于什么状态”。Agent 系统必须知道当前上下文、历史对话、中间变量、任务进度。我见过最土但最容易踩坑的写法是状态全放内存,进程一重启全部丢失。生产环境至少要把状态持久化到数据库,同时做上下文长度的自动裁剪和摘要化。尤其做多轮对话时,状态管理器必须支持快照恢复,否则一次网络抖动整个任务就要重新开始。
**配置中心(Config & Secret Center)**看着不起眼,但它保证整个 harness 在不同环境(开发、测试、生产)的切换是干净的。模型名称、temperature、max_tokens、API key、工具开关,统一从配置中心读取。很多安全泄露事故都源于把 key 写死在代码里——一旦被推到公共仓库,整个项目就裸奔了。团队里我建议至少要有一个配置文件 + 一个密钥库,哪怕刚开始用环境变量 + 本地的加密文件也行。
3.3 控制四线:模型网关、指令管道、规划引擎、工具注册表
这一层等于缰绳、马夫号令、路线图和马蹄铁,是 Agent 真正的主控回路。
模型网关的价值只有一个:你不能被任何一家模型厂商绑死。直接调用某个模型的 SDK 很方便,但之后要换更强的模型、要接内网模型、要在多家模型之间做 failover 时,你会想骂人。模型网关提供统一的调用接口,背后路由到各家厂商,统一处理重试、限流和成本统计。在我现在的项目里,模型层通过网关暴露一个 Chat 接口,业务完全不用知道当下跑的是哪家模型。
指令管道是很多入门项目最轻视的部分。System prompt 如果写死在代码里,等你想灰度一套新提示词时,只能复制一个新分支去改,改完发现老版本没法回滚。我建议把提示词拆成三层:平台级固定规则(安全红线、角色设定)、场景级模板(客服、写作、编程等)、临时级注入(用户任务说明)。三层按优先级合并,任何一层改动都能独立留痕、回滚。这比在代码里写一长串 prompt 字母串健康得多。
任务规划引擎解决的是“马怎么从这站走到下一站”。简单任务当然不需要规划,但拆解目标是 Agent 系统有没有生产价值的分水岭。规划引擎干两件事:把大目标拆成可执行的子任务序列,并在执行中根据观察结果决定是否重新规划。产出物尽量是结构化数据(比如 JSON 数组),这样后续的 trace 和人工审核都比较方便。
工具注册表是 Agent 的“手”。每个工具必须有标准的函数描述(name、description、parameters),必须有入参校验,最好是带版本号。没有 schemas,模型就不知道什么场景可以用;没有参数校验,人类用户可以传坏数据进来导致工具出错。这里有个很容易犯的错误是:工具描述写得太泛,比如写“查询用户信息”,结果模型在不知道要不要查的时候也去查了。描述是给模型看的说明书,要写清楚适用条件、副作用、可逆性。
3.4 保命三件套:护栏策略、缓存层、可观测模块
这一层对应刹车、减震弹簧和马铃,属于不直接产生智能、但对于生产环境不可或缺的“防御性组件”。
护栏策略是我个人最看重的组件,因为 Agent 出事的代价往往是不可逆的。护栏分三个层级:规则级(拒绝执行黑名单操作)、模型级(对模型输出做二次判断)、人工级(高风险操作必须审批放行)。我自己的项目里最低限度会加一条:所有删除类操作都需要二次确认,不管是用户还是 Agent 发起的。护栏的粒度不需要一开始做得很重,先从白名单和黑名单开始,慢慢叠加规则引擎。
缓存层是省钱的利器。LLM 调用贵和慢是常态,但很多请求其实是高度重复的。缓存有两种思路:一种是 Semantic Cache,把用户输入转换成向量,相似问题直接返回历史结果,适合查资料型的 Agent;另一种是 Prefix Cache,把固定 system prompt 和常用工具说明放在前面,让模型服务商直接命中 prompt 缓存,也能省一大截。需要特别注意缓存键的设计:提示词模板一旦更新,旧缓存必须失效,否则新规则永远不生效,整出幽灵行为。
可观测模块是排查问题的眼睛。至少要为每一次“模型调用”和“工具调用”打点记录四件事:输入、输出、耗时、成本。在此基础上形成 trace,把用户请求、任务规划、模型响应、工具结果连成一条完整的链。现代工具链里 OpenTelemetry 是标准底座,也可以直接用外部平台提供的 trace 功能。没有这套东西,Agent 复盘就是靠瞎猜。
3.5 车队两本账:记忆系统和评估与反馈
最后两个组件对应粮草袋和驿站账本。它们是长期运营的根本,但往往被排在路线图最后。
记忆系统要明确区分短期记忆和长期记忆。短期记忆由状态管理器负责,就是当前对话轮次里的上下文;长期记忆是跨会话留存的知识,比如用户偏好、历史任务结论、领域术语表。实现长记记忆比较成熟的做法是:先写一个 summary,然后向量化存储,检索时做相关性过滤。我踩过的坑是无差别全量写入记忆,导致记忆库噪声巨大,模型检索时被一堆无关历史干扰判断。现在我的策略是设定记忆价值阈值,只有高价值信息才写入,并通过上下文重排提升相关性。
评估与反馈是兜底质量的最后一道关卡。没有评估手段,你根本无法回答“这次改动到底让 Agent 变好了还是变坏了”。搭建最小可用的评估框架只需要三步:准备 50~100 条典型问题集,定义评分维度(正确性、工具调用的合理性、拒绝违规请求的准确性),然后每次改动 prompt 或工具后跑一遍回归集,比较分数变化。这部分数据积累起来之后,还可以回流到人工审核队列,形成持续改进的闭环。
4. 跑通一次真实任务:12 个组件如何协同工作
单看每个组件还是不够,我们用一个具体例子把整个 harness 串起来:让 Agent 自动生成一份竞品分析报告。
任务从用户在对话界面输入“帮我分析一下 A 产品近期在市场上的竞品动态”开始。
第一步,配置中心登场。系统从配置中心读取当前环境选择的是哪家模型、temperature 是多少、A 产品对应的 API 权限范围是哪些。这里已经隐含了安全管理:像“分析类”任务本身是只读的,所以后续护栏策略会允许相关工具执行。
第二步,运行时内核启动一个执行循环,状态管理器创建会话快照,初始上下文包含用户请求和当前时间。指令管道此时注入三层提示词:平台层“你是资深市场分析师,禁止编造数据”,场景层“输出使用结构化报告模板”,临时层“重点分析最近两周的公开动态”。
第三步,任务规划引擎把“生成竞品报告”拆成子任务序列:收集竞品名称列表 → 检索近期新闻 → 抓取流量趋势 → 汇总成报告。这一步生成的 JSON 序列会交给运行时内核去逐步执行。
第四步,执行到“检索新闻”时,工具注册表开始起作用。模型判断需要调用“新闻检索工具”,网关把请求路由到模型,模型生成带参数的 tool call,工具注册表校验参数合法,调用真实新闻 API。返回值被塞回上下文。
第五步,这里可能命中缓存。如果同一竞品的关键词在过去 24 小时内被检索过,缓存层直接返回历史结果,不重复打新闻 API,也不重复调用模型。省下来的钱会在成本追踪里体现。
第六步,护栏策略始终在跑。比如新闻检索工具要求“仅限国内公开信息源”,如果模型试图调用外部敏感接口,护栏直接拦截并提示重新规划。这一步在日志里会生成一条“拦截事件”。
第七步,报告生成完毕后,可观测模块把整条执行链(用户请求 → 规划 → 模型调用 → 工具结果 → 最终报告)记录成一条 trace,标注每一步耗时和成本。这部分数据稍后就能用来回答“这次执行花了多少钱、哪一步最慢”。
第八步,记忆系统将报告摘要和用户偏好(“喜欢简洁版报告”)写入长期记忆。下次用户再来问同类问题,模型能快速调用历史结论,减少重复检索。
第九步,人工把这个结果标记为优秀,进入评估反馈模块。这份标注数据用于下一轮回归测试,同时可以当作 few-shot 样例来优化指令管道。
整个过程看下来,12 个组件不是接力棒,而是并行护网的一部分。有的在跑,有的在看,有的在记录。任何一个环节缺失,整个链路就会出现一个或大或小的孔洞。
5. 落地实践:自研一套 Agent Harness 的最小配置与避坑路线
5.1 得先想清楚:不是每个系统都需要 12 个组件
如果你只是做个人工作流里的小 Agent 脚本,把运行时内核、状态管理器、工具注册表做出来就够了。组件数量的多少是看约束的:单用户、低风险、可容忍失败的项目,护栏和缓存可以先不做;多租户、高并发、有数据合规要求的系统,从第一天起就必须把护栏和可观测模块搭上。
我自己的判断标准很简单:系统会不会因为一次模型输出错误导致不可接受的后果?会,就上护栏;不会,就先跑通主流程再说。这样你既不会被“十二组件”的架子压垮,也能在真正需要时知道往哪补。
5.2 我踩过的三个坑
第一坑是 Harness 和 Agent 逻辑混写。以前我图省事,把权限判断直接写在模型调用函数里,结果每次模型返回格式一变,权限逻辑就要跟着改。正确做法是把护栏做成中间件,让运行时内核在执行工具前统一调用,职责彻底分开。混写的结果看起来是“能跑”,但改起来极其痛苦。
第二坑是缓存键设计得太粗糙。我一开始用用户问题原文做缓存键,结果同一问题换个标点就缓存失效;后来改成按语义向量做相似度匹配,但忘了把提示词模板版本号嵌入缓存键。上线新提示词后,旧缓存命中导致新规则不生效,排查了很长时间才发现是缓存问题。任何跟策略相关的缓存,键里面必须带版本号。
第三坑是评估集建了但不维护。早期我建了 50 条评估集跑了几次回归,之后再也没更新。直到某次模型接口升级,跑完评估发现分数掉了 20 个百分点。从那以后我们的规则是:每次上线新的工具或提示词,必往评估集里加至少 5 条新样例,防止样本失真。
5.3 自研、组合还是全托管:我的建议路线
现在市面上的选择足够多,没必要从零造轮子。我的推荐路线是:
- 运行时内核和状态管理可以用 LangGraph 这类编排工具来搭,把事件循环和状态持久化的问题交给它处理,省下大量底层琐碎工作;
- 模型网关直接接 LiteLLM 这类工具,多模型路由、重试、成本记录全帮你收口;
- 护栏这块比较难买现成的,需要结合自己的业务规则先做一个最小版本,至少包含黑名单和审批机制;
- 可观测平台可以先用外部的 trace 产品,比如 LangSmith 或者基于 OpenTelemetry 自己接到监控面板上;
- 记忆系统可以直接用向量数据库产品或成熟的记忆框架,但记忆价值判断的逻辑一定要自己控制;
- 评估反馈这个组件,外部工具只能提供测试框架,评估集和评分标准必须自己建。
这套组合方案大概一周内能把骨架立起来,之后迭代时会比全自研顺畅得多。
结尾
说实话,我第一次接触 Agent Harness 时,也被“这到底是框架还是模板”的困惑卡了一阵。真正动手搭了一遍之后我的体会是:Harness 不是一层可有可无的胶水,而是你和你 agent 之间的一道可控安全带。它决定了你斗胆放进生产环境的 Agent,是可控的、有记录的、能快速恢复的,还是一个随时可能闯祸的不可控模型实例。
最后再分享一个小技巧:当你看任何一个新开源 Agent 工程时,可以先试着把它提供的模块往我这张 12 组件表里套一遍。哪个有、哪个没有、哪个弱,项目定位和能力边界基本就清楚了。这个“组件地图”的思考方式,比记住任何一份代码库清单都更有长期价值。