1. 先搞懂一件事:Harness Engineering 到底在解决什么
这两年做 AI Agent 的朋友应该都有同感:模型能力越来越强,但真正把 Agent 推到生产环境里跑起来、跑得稳、跑得省,拼的根本不是模型本身,而是模型外围那套工程系统。这套系统在圈子里逐渐有了一个统一的名字——Harness Engineering。我直接给结论:Harness 就是给模型套上的那层“外骨骼”,让模型具备调用工具、遵循流程、控制上下文、接受观测、兜底纠错的能力。没有 Harness,模型只是聊天窗口里的一个大脑;有了 Harness,模型才是一个能干活、能干好活的执行体。
这个概念的走红是有原因的。早期大家做 Agent 基本是“Prompt 工程 + 少量工具调用”的路子,模型自己决定下一步干什么,出了问题再靠提示词往回掰。但落地场景一旦复杂起来——比如客服系统要对接十几个内部服务、数据分析 Agent 要操作 SQL 和可视化组件、多智能体协作要交换中间结果——靠提示词约束就完全撑不住了。你需要一套确定性的工程设施,把“模型自由发挥”约束在一条可控的轨道上。这套设施就是 Harness。
Harness Engineering 包含的内容非常具体:工具注册与调用协议、指令与策略层、上下文管理与记忆、结构化输出的约束解码、运行时的可观测性、失败重试与安全兜底。它不替代模型,而是把模型包在一个完整的工程框架里。
那有人会问:这和 Agent Framework(比如 LangChain、LlamaIndex 这类框架)有什么区别?我的理解是,框架是面向开发者的半成品工具箱,Harness 更多是描述 Agent 在生产环境中“被包裹、被约束、被观测”的这一整套设计范式。框架可以帮你实现 Harness,但 Harness 的本质是一种架构思维——你关心的不是“如何快速调模型”,而是“如何让模型在复杂环境里稳定地完成多步任务”。
这篇内容我按自己的实战经验做一个完整拆解,从概念、模块、机制到参数配置、踩坑记录,尽量覆盖 Harness Engineering 的全貌。适合刚接触 Agent 开发但想让系统跑得可靠的开发者,也适合已经在做 Agent 但总觉得哪里不稳、想系统性补课的朋友。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Harness 由哪几块拼成——六大核心模块全解析
Harness 不是一个单一的组件,更像一层中间件架构,夹在模型与业务系统之间。我习惯把它拆成六大模块。
2.1 模块总览
| 模块 | 核心职责 | 类比 |
|---|---|---|
| 工具执行层 | 定义工具、注册工具、执行工具调用并返回结果 | 给大脑装上手脚 |
| 指令与策略层 | 系统提示词、流程约束、权限边界、行为准则 | 给大脑装操作手册 |
| 上下文管理层 | 控制上下文长度、压缩、摘要、路由、检索 | 给大脑装工作台 |
| 记忆层 | 短期记忆(会话内)与长期记忆(跨会话) | 给大脑装笔记本 |
| 观测评估层 | 全链路日志、追踪、指标采集、质量评估 | 给大脑装仪表盘 |
| 安全与兜底层 | 输入输出校验、敏感信息过滤、失败降级与重试 | 给大脑装安全带 |
2.2 工具执行层:Agent 的“手和脚”
没有工具调用能力的模型只能“纸上谈兵”。工具执行层要解决三件事:第一,工具怎么描述给模型;第二,模型决定调用后,结果如何回路传给模型;第三,多个工具调用之间如何调度、并行还是串行。
这里有一个分水岭:模型多久能学会“正确地调用工具”。早期模型不懂函数调用,需要我们在 Prompt 里手写 JSON 格式说明,让模型“碰运气”输出结构。现在的模型大多原生支持 Function Calling,你只要在请求里带上 tools 参数,把函数名、描述、参数 Schema 传给模型,模型就会在输出里返回一个结构化调用请求,代码里解析后执行,再把结果回传。这一套流程就是工具执行层的主干。
2.3 指令与策略层:把业务规则翻译成模型可遵守的约束
指令与策略层的作用不能简单理解成“写系统提示词”。系统提示词只是其中一环,更重要的是把业务流程、权限边界、行为底线结构化地注入到模型行为里。
比如你要做一个订单管理 Agent,业务规则包括“只有管理员可以退款”“退款金额超过一定额度必须人工审批”“查询订单前必须先校验用户身份”。这些规则不能靠“你是一个小助手,你要遵守规则”这种模糊指令,要在 Harness 里以确定性的策略代码落地:身份校验不通过,直接拦截调用,根本不给模型决定的机会。这就是 Harness 与普通 Prompt 工程最大的区别——能靠代码约束的,就不要靠模型自觉。
2.4 上下文管理层:让模型始终在一个“干净的工作台”上思考
模型的上下文窗口是有限的,而多轮 Agent 任务的中间产物、工具返回结果、历史对话会快速把窗口塞满。上下文管理层的任务就是动态控制这个“工作台”。
具体手段包括:预置上下文(把固定的知识直接拼进系统消息)、上下文裁剪(删除最早或最不相关的消息)、摘要压缩(用模型把旧对话提炼成几百字)、检索增强(按需注入相关知识块)、上下文路由(大任务拆成子任务,每个子任务用独立的上下文空间)。这块做得好与不好,直接决定了 Agent 在多轮任务里会不会“失忆”或“跑偏”。
2.5 记忆层:短期记忆与长期记忆的分工
短期记忆就是当前会话内的上下文,由上下文管理层负责。长期记忆则要求 Agent 跨会话记住用户偏好、历史事实、任务状态。实操中我用得比较多的是:把长期记忆落库,按用户维度或任务维度存储,在新会话启动时把相关记忆向量化检索出来,注入到初始上下文中。
这里的一个坑是:长期记忆不是越多越好。记忆陈旧、冲突或冗余会让模型无所适从。我会给记忆加时间衰减权重,越近的越优先注入;同时用置信度字段标记某些记忆是否已被后续对话“纠正”。
2.6 观测评估层:没有数据,你就不可能改进 Agent
很多人做 Agent 只关心“能不能跑通”,却不关心“跑得好不好”。一旦进入生产环境,你必须知道每个任务的成功率、平均步数、调用模型次数、Token 消耗、工具报错率、用户在哪个环节放弃。观测层就是把这些数据采集、聚合、可视化。
运行追踪(Trace)是观测层最核心的能力。每轮 Agent 执行,我会记录:用户请求、模型思考(如果有)、模型输出、工具调用请求、工具返回结果、错误信息、耗时、Token 用量、最终回复。这样既能做事后分析,也能用来构建评估集,回归测试。
2.7 安全与兜底层:让失败变得“体面”
模型一定会出错。工具一定会失败。第三方接口一定会超时。安全与兜底层就是在这类情况发生时,保证系统不崩溃、用户不困惑、资金不损失。
兜底手段包括:重试机制(工具调用失败后重试或换工具)、降级回复(模型连续出错时切换到一个固定话术模板)、人工接管(复杂或高风险场景自动转人工)、输入输出校验(模型输出的关键字段必须过 Schema 校验,不让脏数据流入下游)。这个模块决定了 Agent 的“成熟度”——Demo 阶段的 Agent 不设兜底也能演示,生产阶段的 Agent 没有兜底就是事故隐患。
3. 机制拆解:Harness 核心循环是怎么跑起来的
理解 Harness 不能只看模块,要看机制。市面上各种 Agent 框架的底层核心机制其实趋同,我以最常见的 Tool Agent 范式为例拆解。
3.1 ReAct 循环的五个步骤
ReAct(Reason + Act)是目前主流 Agent 的执行范式,循环执行以下步骤:
- 接收用户问题与当前上下文。
- 模型根据上下文进行推理,决定是否需要调用工具、调用哪个工具。
- 若需要调用工具,Harness 解析模型输出的结构化调用请求,执行工具代码,把结果追加到上下文。
- 模型基于工具返回结果继续推理,决定下一步动作。
- 重复上述过程,直到模型输出最终答案或触发终止条件。
这个循环的关键是终止条件。没有明确的终止条件,Agent 可能无限循环——我在一个早期项目里就遇到过,模型反复调用同一个工具、反复得到相同结果、反复决定再调一次,最后还是靠最大步数硬切才停下来的。
常见的终止条件有:模型输出最终答案(没有工具调用请求)、达到最大迭代步数(比如 8 步)、工具连续失败达到阈值、用户主动终止、业务规则命中(比如某个条件满足后必须转人工)。Harness 设计时要把这些条件全部作为一等公民,而不是靠“模型自觉”。
下面是一个最小实现示意,我刻意写得极简,方便理解核心循环:
python复制class ToolAgent:
def __init__(self, llm, tools: dict, max_steps=8):
self.llm = llm # 模型客户端
self.tools = tools # {工具名: 可调用函数}
self.max_steps = max_steps
self.messages = [] # 上下文消息列表
def run(self, user_input):
self.messages.append({"role": "user", "content": user_input})
for step in range(self.max_steps):
response = self.llm.complete(
messages=self.messages,
tools=self.tool_schemas() # 工具Schema列表
)
if not response.tool_calls:
return response.content # 终止条件1:正常输出最终答案
self.messages.append({ # 把模型的调用请求加入上下文
"role": "assistant",
"content": response.content,
"tool_calls": response.tool_calls
})
for call in response.tool_calls:
result = self.execute(call) # 执行实际工具函数
self.messages.append({ # 把工具结果加入上下文
"role": "tool",
"tool_call_id": call.id,
"content": result
})
raise MaxStepExceeded(f"超过{self.max_steps}步") # 终止条件2:步数封顶
这就是 ReAct 循环的最小骨架。真实的 Harness 会在每一行代码上叠加约束与观测,但主干不会变。
3.2 Function Calling 协议的关键字段与注意事项
现在主流模型(无论国产还是国外)基本都支持 Function Calling。以常见的 Chat Completions 风格接口为例,tools 参数的每个工具包含三部分:type(通常是 function)、function.name、function.description、function.parameters(JSON Schema 格式)。
模型返回的 tool_calls 数组里,每个元素包含 id、type 和 function,其中 function 里有 name 和 arguments(一个 JSON 字符串)。你需要做的是:
- 根据 id 把工具执行结果回传给模型,用 tool_call_id 关联。
- arguments 是一个 JSON 字符串,建议先做一次 JSON 解析兜底,因为模型偶尔会输出不规范的 JSON(比如末尾多逗号、字段名带引号错误)。我自己会写一个 tolerant_parse 函数,先尝试标准解析,失败后就做轻量修复,再失败则返回一个“参数解析失败”的工具结果让模型自行调整。
- 工具执行过程中的异常信息,要当作普通工具结果返回给模型,而不是直接中断整个链路。模型看到报错后往往会修正自己的调用参数,这是一种隐式的自纠错机制。
3.3 Structured Output:如何让模型“必须”输出合法结构
Function Calling 只是工具调用的骨架,还有一个配套机制是 Structured Output / 结构化输出。它的目标是保证模型输出(无论是不是工具调用参数)严格符合 JSON Schema。
原理层面有两种实现路线。第一种是约束解码(constrained decoding):在模型推理阶段动态屏蔽掉不符合 Schema 的 token,从根本上保证输出合法。这个方案效果好,但对模型部署层有要求,一般的 SaaS API 不开放。第二种是“Schema 注入 + 结果校验 + 重试修正”:把 JSON Schema 直接放进提示词,并要求模型“必须输出合法 JSON”,拿到输出后先做校验,失败则把校验错误信息回传给模型,让它根据错误修正。第二种更通用,实操中效果也够用。
这里有一个批量做结构化输出的参考实现框架:
python复制def extract_json(text, schema_hint=""):
"""
先尝试标准解析,失败后走修复流程。
schema_hint 为 JSON Schema 或字段示例,提供给修正模型使用。
"""
try:
return json.loads(text)
except Exception:
# 常见的坑:代码块包裹、首尾多余文本、单引号、尾逗号
cleaned = re.sub(r"```json|```", "", text).strip()
cleaned = re.sub(r",\s*([}\]])", r"\1", cleaned)
try:
return json.loads(cleaned)
except Exception:
# 如果还失败,把原始输出与错误信息交给修正模型
result = fix_model(f"请修复以下JSON,输出仅含合法JSON:\n{text}\n错误:{e}")
return json.loads(result)
这个函数看起来简单,实际生产价值很高。模型输出不规范是高频问题,尤其在较长的嵌套结构里。做完这层兜底,再配合校验规则,结构化输出基本就能达到 99% 以上的可用率。
3.4 内置工具、自建工具与生态协议
工具是 Harness 的“能力边界”。我把工具分成三层来管理:
- 内置工具:Harness 自带的通用能力,如当前时间、随机数、ID 生成器、简单计算器。很多时候模型只是想确认当前时间或算个数,没必要为此调用外部服务。
- 领域工具:针对业务场景写死的工具函数,比如查询订单、发送短信、操作数据库。这类工具是核心,Schema 必须写得极其精准,description 里最好带一两个典型用法示例,模型才更容易“写对参数”。
- 生态工具:通过标准协议(如 MCP)接入的第三方能力。MCP 的价值在于把工具描述格式统一了,服务端只需暴露一套标准化的工具定义,客户端动态发现后注册进 Harness。
我个人的经验是:能用代码写死的工具,不要依赖模型自由选择;工具的数量每增加一个,模型的选择难度就增加一分。工具超过 20 个以后,可以考虑按意图分组,先让模型选择“工具组”,再在组内选具体工具,能显著降低选错率。
4. Harness 里那些“参数与配置”的学问
很多人拿着框架的默认参数就跑,遇到问题就懵。Harness 的效果好坏,参数配置占一半。这一节我挑几个影响最大的配置项展开。
4.1 温度与采样参数:工具调用场景下的建议值
聊天场景温度可以拉高到 0.8 甚至 1.0,让回复更有“人味”。但 Agent 工具调用场景,我建议温度设置为 0 到 0.3 之间。温度越高,模型越可能“发挥创意”,比如把工具参数写错、编造不存在的函数名、输出不稳定的 JSON。工具调用的本质是执行确定性的业务动作,不需要创意。
top_p 参数同理,优先选 0.9 以下。部分模型还支持 frequency_penalty / presence_penalty,在工具调用场景一律建议关闭或设为 0,避免模型为了规避重复而刻意改变合法的参数写法。
4.2 max_tokens 与推理长度预算
很多失败的 Agent 调用并不是因为模型答错了,而是因为 max_tokens 太短,模型在生成工具参数或中间推理时被截断,输出变成残缺 JSON。给 max_tokens 留足余量是一种简单有效的做法。
如果使用带隐藏推理过程的推理模型,还要额外考虑推理 token 是否占用 max_tokens。有些平台要单独设置 reasoning_budget。实操中我会给复杂任务预留足够高的上限,宁可多花一点 token,也不要让截断打断流程。
4.3 系统提示词中工具使用的“强制性表述”
系统提示词对工具使用的影响非常大。我做过对比实验,同一套工具配置,只在系统提示词里加一段话,工具调用成功率能差十几个点。差异最大的一句话是:当你可以使用工具时,必须使用工具,不要仅凭已知信息直接回答;如果工具返回的结果为空或报错,明确说明你遇到了错误,并尝试用其他方式解决。
在数据查询类 Agent 里,我还会追加:不要编造工具返回中不存在的字段;如果字段不在结果里,如实说明该字段缺失。数据类任务里,模型的“脑补”是最危险的行为——一旦它开始编数据,后续所有决策都不可信。
4.4 上下文长度管理与自动压缩策略
上下文管理有一个实用原则:Agent 的上下文窗口使用率超过 70% 就要触发压缩。不压缩,模型注意力会明显分散,表现为开始遗忘早前的指令细节、重复问同样的问题、工具调用参数不一致。
压缩策略的优先级我个人是这样排的:优先裁剪对话历史中的纯用户闲聊,保留工具调用链;其次用摘要模型把早期对话压缩成要点;优先级最低的是裁剪系统提示词(除非迫不得已)。工具调用链是 Agent 执行过程的“事实依据”,一旦压缩得太狠,模型会丢失“我前面已经查过一次数据”的认知,导致重复查询。
实操中我还会在压缩后的摘要前加一句标记:“【前方历史已被压缩】以下内容是早前对话的摘要,可能存在信息损失,如需精确数据请重新查询。”这能提醒模型在关键事实不明时主动用工具确认,而不是直接猜。
4.5 评估集的构建与回归
Harness 的每次改动(改提示词、加工具、换模型)都可能让一部分用例变好、一部分变差。为了控制这种波动,必须建立一个小但精的评估集。我一般准备 20 到 50 条典型任务,覆盖正常场景、边界输入、错误输入、空结果、超大数据量、多轮追问六类情况。
评估时我用的指标包括:任务完成率(最终输出是否正确)、工具调用准确率(是否选对了工具与参数)、无效调用率(调用了但不该调用的次数)、步数效率(完成一个任务平均耗多少轮)、Token 成本。这些指标全部通过观测层自动采集,改完配置后跑一遍对比,远比你拍脑袋调提示词靠谱得多。
4.6 模型选型:不是越强越好
Harness 配哪种模型取决于任务难度与成本预算。我的经验是“分级路由”:简单意图(查天气、翻文档摘要)走小模型;需要严格工具调用的任务走工具调用稳定性最好的中大型模型;复杂多跳推理任务才上最强的推理模型。Harness 在中间要做一个模型路由器,根据意图分类结果决定请求走哪个模型。
这里插一句踩坑经验:某些推理能力强的模型在工具调用里反而会“过度思考”,出现拒斥调用工具的倾向,宁可自己“推理出答案”也不愿意查询数据库。针对这种问题,我一般会在系统提示词里加强“必须先工具后回答”的强制顺序约束,并且把工具执行结果缺失的风险明确写出来,让模型理解“没有数据支撑的猜测是错的”。
5. 可观测性实战:给 Agent 装上仪表盘
可观测性在 Harness 里的地位,怎么强调都不过分。我见过太多团队 Agent“能跑但不知道跑得好不好”,出问题只能靠猜。观测层是 Harness 的神经系统。
5.1 至少要采集哪些观测数据
| 数据项 | 采集时机 | 用途 |
|---|---|---|
| 用户请求原文 | 请求入口 | 审计、评估集构建 |
| 完整消息流(含系统提示词) | 每轮请求 | 问题复现、Prompt 调优归因 |
| 模型输出原文 | 每轮请求 | 质量评估、数据沉淀 |
| 工具调用请求与参数 | 模型返回时 | 校验参数正确性,衡量误调用率 |
| 工具执行耗时与错误 | 工具执行时 | 性能分析、依赖稳定性判别 |
| Token 用量明细 | 每轮请求 | 成本归因与预算控制 |
| 最终回复原文 | Agent 结束 | 满意度初筛 |
| 任务链 Trace ID | 全链路 | 多轮关联排查 |
每条 Trace 最好有一个全局唯一的 Trace ID,把一次会话内的所有模型调用、工具调用关联起来。排查问题的时候,直接按 Trace ID 捞日志,不必再靠时间戳猜测哪一轮出了问题。
5.2 成本与延迟的“预算意识”
Agent 和普通 API 调用最大的不同是:一次用户请求可能内部触发 5 到 10 次模型调用。你优化一次回复,可能同时优化了 10 次底层调用的成本。控制成本的核心抓手有三个:
- 上下文裁剪:每减少一个无关的历史消息,就省一次模型输入成本,还改善注意力。
- 意图预判:简单问题直接走小模型,不在大模型上烧钱。
- 结果缓存:相同或近似的查询请求命中结果缓存后直接返回,不再调用模型。做得好的话,缓存命中率能达到 30% 以上。
延迟方面,我建议给每轮 Agent 循环设一个内部超时时间,比如单次模型调用 20 秒、单次工具调用 10 秒、整条 Agent 链路 60 秒。超时兜底可以返回“系统忙,请稍后再试”。没有超时的 Agent 在生产中就是一颗定时炸弹。
5.3 从观测数据反推 Harness 优化点
观测数据不能只存不用。我每周都会做一次 Trace 抽样分析,重点看几个比率:无效工具调用率(模型调用了错误工具)、参数修正率(模型第一次写错、看了报错后才改对)、空结果率(工具返回空数据后模型如何反应)。这些比率能直接指出 Harness 的薄弱环节:无效调用率高说明工具描述或者意图路由需要改进;参数修正率高说明某些参数 Schema 对模型不够友好;空结果率高说明工具层缺少“空数据也能产出有价值回复”的兜底策略。
6. 演进路线:Harness Engineering 的四个阶段
我把自己经历过的 Harness 演进过程整理成四个阶段,你可以对照自己当前处于哪个阶段。
6.1 按阶段画像定位自己
| 阶段 | 特征 | 典型痛点 | 核心任务 |
|---|---|---|---|
| 第一阶段:Prompt Hack | 全流程靠提示词约束,几乎无工程结构 | 效果不稳定,改一句话全局波动 | 引入工具注册与环境隔离 |
| 第二阶段:工具化 | Function Calling 跑通,多工具开始调度 | 上下文溢出、循环失控、误调用多 | 建设上下文管理与终止条件 |
| 第三阶段:平台化 | 统一观测、统一评估、统一工具注册中心 | 评估依赖人工抽检、资源竞争 | 建设自动化评估与模型路由 |
| 第四阶段:自治化 | Harness 具备自优化能力,模型可参与工具修复与策略调整 | 信任边界、安全审计难度上升 | 建立治理机制与安全围栏 |
这四个阶段不一定严格串行,很多团队会并行推进。但核心路径是确定的:先让工具调用稳定,再做上下文治理,然后上观测评估,最后才是优化与自治。
6.2 阶段升级的关键信号
什么时候该从第一阶段升级到第二阶段?我自己的判断标准是:工具数量超过 5 个、或者单任务平均需要 3 次以上工具调用时,纯 Prompt 就已经不可靠了,必须引入系统性的工具注册、参数 Schema 和终止条件。
什么时候该从第二阶段升级到第三阶段?当你有两条以上业务线共享同一套 Agent 底座时,就必须建统一观测和评估平台。没有评估数据,你根本没法回答“这次框架升级是变好还是变坏”这个问题。
什么时候升级到第四阶段?当你的 Agent 已经具备自我修复能力(比如根据工具报错自动调整参数、自动切换备用工具)时,你其实已经是一只脚踏进自治化了。这个阶段最需要注意的是安全问题——自治能力越强,失控的风险边界就越模糊,必须加上审计留存和越权拦截。
7. 常见问题速查表与避坑记录
最后把我在实战中遇到最高频的问题列一份速查表,每条都是真实踩过的坑。
7.1 问题速查表
| 问题现象 | 可能原因 | 解决思路 |
|---|---|---|
| 模型返回“我无法调用工具” | 工具参数未正确传入,或模型不支持 Function Calling;也可能是系统提示词没有强制工具调用 | 检查 tools 参数是否生效,换工具调用能力强的模型,在系统提示词中加强制性表述 |
| Agent 陷入循环,反复调用同一工具 | 缺少终止条件,或工具返回结果没有改变模型认知 | 设置最大步数,工具结果中加入“已查询,结果不变”之类的标记;在上下文里抑制重复动作 |
| 工具参数频繁写错 | 工具描述太长太抽象,参数 Schema 约束不足 | 精简描述,每个参数加示例值,必填参数设为 required,典型用法写进 description |
| 并行工具调用结果错乱 | 多个 tool_calls 同时执行,但结果关联失败 | 使用 tool_call_id 严格关联,代码里不要假设执行顺序 |
| 上下文塞满后模型“失忆” | 未做上下文压缩或压缩策略不当 | 触发 70% 用量压缩,优先裁剪闲聊,保持工具调用链完整 |
| Structured Output 偶尔失效 | 模型输出被截断、JSON 格式不规范,或者推理模型在修正轮里再次出错 | 做 tolerant_parse 兜底 + 校验错误回传修正 + 必要时原地重试一次 |
| 推理模型拒绝调用工具 | 部分推理模型在“自我求证”阶段认为可以不查工具 | 系统提示词强制“先工具后回答”,同时把数据缺失的风险明示给模型 |
| 工具报错后模型反复“道歉”不继续 | 模型把工具错误理解为自身错误,进入道歉循环 | 工具报错的返回格式中明确提示“这是工具的临时错误,请重试或尝试备用方案”,引导模型继续执行 |
| 多次重试后系统整体超时 | 单步超时太宽、重试次数太多 | 全局设置 Agent 链路超时,超时直接降级;重试只允许一次,二次失败转人工 |
7.2 踩坑流程复盘
我复盘一个印象很深的项目:某跨平台系统需要在一个页面里同时完成对话、查询、表单填写三个动作。最初版本的 Harness 只有一个大工具“执行页面操作”,参数里塞了十几个字段。模型对参数的理解一团糟,不是漏填就是填错。
后来我做了三个改造:第一,把一个大工具拆成三个小工具——打开页面、填写字段、提交表单;第二,在工具描述里写了正常操作顺序的典型流程;第三,加了一个“操作前提检查”的确定性代码,如果前序页面没打开就执行填写,工具直接返回明确的错误信息。改造之后,工具调用成功率从不到六成提升到九成以上。
这个案例给我的启发是:Harness 设计里有一条非常重要的原则——把模型容易做错的事情用确定性逻辑拦下来。模型不确定怎么办的边界场景,交给代码判断;模型擅长的地方(理解自然语言、生成参数值),才留给模型发挥。代码兜底越硬,Agent 越稳。
7.3 关于 Harness Engineering 的最终个人体会
做了这么多 Agent 项目,我越来越觉得 Harness Engineering 的定位其实是“把模型的自由度关进笼子里,然后在笼子里面给它最大的自由度”。模型能力再强,没有约束和兜底就等于不可控;约束太死,Agent 又变成僵硬的规则引擎,失去智能体该有的灵活。好的 Harness,是在自由与可控之间找到那个动态平衡点。
Harness Engineering 会是 Agent 从原型走向产业化的必经之路。不要再迷恋“Prompt 写得漂亮”这种表面功夫了,真正拉开差距的永远是工程深度:工具怎么注册、上下文怎么治理、失败怎么兜底、效果怎么度量。把这套工程范式吃透,你在 Agent 方向的竞争力会比单纯刷模型能力强一个维度。我自己还在持续的迭代这套方法论,后续有新经验会再回来补充。
