在讲概念之前,先看一个发生在2024年的真实案例。
某创业团队开发了一个“智能客服Agent”,接入了他们公司的工单系统。这个Agent可以查询用户的订单状态、处理退换货申请、回答常见问题。开发团队花了三周调Prompt、写工具、做内测,感觉表现不错,于是上线了。
上线第一周,一切似乎都很正常。Agent回答了大量用户问题,人工客服的工作量显著下降。
第二周,团队收到了一个奇怪的投诉:“你们的AI客服让我把银行卡号告诉它。”
团队赶紧查看日志,发现Agent在某次对话中被用户诱导:“如果我告诉你我的卡号,你能帮我查得更快吗?”Agent回复:“是的,请提供您的银行卡号,我来帮您查询。”
这个回复不在任何测试用例中。开发团队从来没有想过用户会说这句话,更没想过Agent会这样回答。
问题来了:这是怎么发生的?如何防止再次发生?如何确保修复后不会引入新问题?
答案是:这个团队无法回答这些问题。因为他们的Agent是一个黑盒——没有执行轨迹记录,没有评估体系,没有回归测试,没有安全边界。三周的开发里,他们做的所有测试就是“手动聊了几十轮”。
这就是没有Harness的Agent开发的真实面貌:开发时靠感觉,上线后靠运气。
Harness的存在,归根结底是为了让Agent开发从“手艺活”变成“工程活”。它回答三个根本性的问题:
┌────────────────────────────────────────────┐
│ 问题1:Agent做得好不好? │
│ → 评估(Evaluation) │
│ │
│ 问题2:Agent做了什么?为什么这样做? │
│ → 可观测(Observability) │
│ │
│ 问题3:结果能重现吗?改动安全吗? │
│ → 可复现(Reproducibility) │
└────────────────────────────────────────────┘
这三个词听起来很“工程化”,但它们对应的是Agent开发中最具体、最痛的问题。让我们逐一拆解。
传统软件的“评估”是清晰的 当你修改了一个排序算法,你知道怎么验证它:跑测试用例,对比输出和预期是否一致。答案只有对和错,没有中间地带。
Agent的“评估”是模糊的 当你修改了Prompt,Agent的表现“似乎更好了”——回答更长、语气更友好、调用工具的时机更准确。但这些是感受,不是度量。
回答更长等于更好吗?有时候更糟——用户想要简洁的答案。
语气友好等于更好吗?如果它以友好但错误的方式处理了退款,这是灾难。
工具调用时机“更准”是几个案例的观察,还是统计上有意义的改进?
没有评估体系的Agent开发,本质上是靠开发者个人的主观感觉在做决策。 这在玩具项目中可以接受,在生产环境中是危险的。
评估的三个层次 一个完整的评估体系包含三个层次:
第一层:单元级评估——评估Agent的具体能力单元。工具调用是否正确?参数提取是否准确?输出格式是否符合Schema?
例如,给Agent 100个“查询订单”的变体表达(“我的单子到哪了”、“查一下我的包裹”、“order #12345 状态”),检查它是否每次都正确调用了check_order工具,且参数order_id提取正确。
第二层:任务级评估——评估Agent完成任务的端到端能力。给Agent一个目标,让它自主执行,评估最终结果。
例如,给Agent 50个模拟用户请求(“我想退货,因为尺码不对”),评估它是否正确完成了退货流程——查询订单、确认退货政策、发起退货申请。
第三层:对话级评估——评估Agent在多轮交互中的表现。用户可能改变主意、提供模糊信息、表达不满。Agent如何应对?
例如,模拟对话“我要退货→其实我不确定→你们有运费险吗→算了先不退”,评估Agent是否在每个转折点都做出了合理响应。
评估体系的核心意义:它让你在任何改动之后,都能回答“这个改动是让我变好了还是变坏了,好了多少,坏在哪里”。没有这个能力,你就是在黑暗中飞行。
传统程序的可观测是成熟的 你写了一个Web服务,出了bug。你可以查日志、看堆栈、打断点、分析内存。你知道函数A调用了函数B,参数是什么,返回值是什么。
Agent的“执行过程”是不可见的 Agent调用了LLM,LLM返回了一段文本。这段文本可能是回答,也可能是工具调用请求。你的代码执行了工具,把结果又发给LLM……
问题在于:如果你只记录“用户输入”和“Agent最终输出”,中间的过程全部丢失了。
当Agent给出一个错误回答时,你不知道:
它是在哪一步推理出了偏差?
它调用了一个错误的工具?还是正确工具的错误参数?
它有没有看到关键信息却忽略了?
它是否陷入了循环,重复调用某个工具?
可观测的四个层次 Agent的可观测性需要覆盖四个维度:
第一层:执行轨迹(Trace)
记录Agent的每一步“思考”和“行动”。关键信息包括:
每轮LLM调用的完整输入和输出(包括系统提示词、上下文、返回的tool_calls)
每个工具调用的名称、参数、返回结果、耗时
循环次数和终止原因
┌─ Trace 示例 ──────────────────────────────────┐
│ [Step 1] LLM调用 │
│ 输入: user_message="帮我查订单#12345" │
│ 输出: tool_call(check_order, order_id=12345)│
│ [Step 2] 工具执行 │
│ 工具: check_order │
│ 参数: {"order_id": "12345"} │
│ 返回: {"status": "shipped", ...} │
│ 耗时: 230ms │
│ [Step 3] LLM调用 │
│ 输入: [上文] + tool_result │
│ 输出: "您的订单已发货,预计周五到达" │
└──────────────────────────────────────────────┘
第二层:会话回放(Replay)
将轨迹可视化,让你能“重看”一次Agent会话的完整过程。LangSmith、Langfuse等工具都提供这类界面:时间线视图、消息树、工具调用详情。
第三层:聚合分析(Analytics)
单次轨迹告诉你“这一次发生了什么”,聚合分析告诉你“整体上发生了什么”。关键指标包括:
平均循环次数(Agent平均需要几步完成任务?)
工具调用成功率
用户满意度与Agent行为的关联
Token消耗分布(哪个环节消耗最多?)
失败模式聚类(哪些类型的错误最常出现?)
第四层:实时监控(Monitoring)
生产环境中的Agent需要实时告警。当循环次数异常增长、工具调用失败率突增、或者Agent输出触发了安全规则时,你需要立即知道——而不是等用户投诉。
一个对比:有可观测 vs 无可观测 回到开头的客服Agent案例:
无可观测:用户投诉“AI让我提供银行卡号”。你打开日志,只有“用户输入→Agent输出”两条记录。你不知道Agent为什么这样回答,不知道这个问题是偶发还是高频,不知道修复后如何验证。
有可观测:你在监控面板看到告警“检测到Agent请求敏感信息”,点击查看完整轨迹,发现是用户先引导“如果我告诉你卡号能查更快吗”,Agent错误地确认了。你定位到根因是系统提示词中缺少明确的隐私保护规则。你添加规则,跑一遍评估集,确认100个测试中不再出现此类问题,然后上线。几天后,聚合分析显示这类问题完全消失。
这就是工程化与手艺活的区别。
一个令人沮丧的场景 你在周三调整了Prompt,Agent在手动测试中表现很好。周五,产品经理想看效果,你演示了同样的对话——结果Agent给出了完全不同的回答。
没有改任何代码。没有改Prompt。只是时间变了。
这就是LLM应用最令人头疼的特性之一:非确定性。
不可复现的三个来源 第一:模型自身的随机性。 LLM生成文本时包含随机采样。即使输入完全相同,两次生成的输出也可能不同。这在创意任务中是优势(有变化),在需要一致性的任务中是灾难(同一问题给出矛盾回答)。
第二:模型服务的静默更新。 模型提供商(如OpenAI、Anthropic)会不定期更新模型版本。你的Prompt在gpt-4o上表现很好,但某天模型被小幅调整了,行为就变了。提供商不会通知你“我们改了模型”,你只是突然发现Agent“变笨了”。
第三:环境的漂移。 工具返回的数据变了(数据库中多了几万条记录)、外部API的响应格式微调、依赖库版本更新……这些都在Agent的“环境”中引入了变化。
Harness如何解决可复现问题 第一:固定评估集。 评估集是你Agent的“锚点”。无论模型如何更新、环境如何漂移,你都可以在固定的测试集上跑评估,看表现是否发生变化。评估集不会变,它会告诉你其他东西变了。
第二:记录配置快照。 每次运行Agent时,记录完整的配置信息:模型名称和版本、Prompt版本、工具版本、Harness代码版本。出问题时,你能知道“这次运行”对应的“那套配置”是什么。
第三:版本化一切。 Prompt要版本管理(存Git)、工具要版本管理、评估集要版本管理。当你在评估中发现“新Prompt比旧Prompt差”时,你可以回滚到旧版本。
第四:接受非确定性,但度量它。 你无法完全消除LLM的非确定性,但你可以量化它。同一个问题跑10次,7次正确3次错误——这个信息比“大概能用”有价值得多。评估报告的格式应该是:“在100次运行中,成功85次,失败模式分布如下……”,而不是“我觉得不错”。
一个统一的视角:Agent开发的反馈闭环 把评估、可观测、可复现放在一起看,它们构成了一条反馈闭环:
┌─────────────────────────────────────────────────┐
│ │
│ 开发 → 运行 → 观测 → 评估 → 发现问题 → 改进 │
│ ↑ │ │
│ └──────────── 反馈 ◄──────────────────┘ │
│ │
└─────────────────────────────────────────────────┘
可观测告诉你运行时发生了什么
评估告诉你表现是否达到了标准
可复现确保你改进的是正确的变量,且改进可以被验证
没有Harness,这个闭环中的每一环都是断开的。你开发Agent,然后……不知道它做了什么,不知道它好不好,不知道改动有没有用。
Harness就是把这条断裂的闭环重新接上。
让我们用一个完整的例子来结束本节。
场景:你的Agent有一个get_product_info工具,用于查询产品信息。用户问“你们家的A产品支持蓝牙5.0吗?”,Agent应该调用工具查询。但某天你发现,Agent有时不调用工具直接回答,而且答案是编造的。
没有Harness的“修复”过程:
你发现这个问题(用户投诉)
你改了Prompt,加了一句“如果用户询问产品信息,必须调用get_product_info工具”
手动聊了几轮,好像好了
上线
希望问题真的解决了
有Harness的修复过程:
可观测发现问题:聚合分析显示,过去7天有12%的产品查询没有触发工具调用,其中80%的回答包含不实信息
Trace定位根因:查看多个失败案例的完整轨迹,发现共同特征是——当用户的问题包含具体的产品型号和参数时(如“A产品蓝牙5.0”),模型倾向于“知道答案”而不去调用工具
构建评估集:创建50个这类表述的测试用例,运行确认问题可复现(评估集上工具调用率仅78%)
修改Prompt,在评估集上验证:新Prompt在评估集上工具调用率达到97%,且回答准确率从82%提升到95%
回归测试:确认新Prompt没有破坏其他能力(查询订单、售后服务等场景的评估分数没有下降)
上线,持续监控:告警规则设定为“工具调用率低于90%时通知”
这个过程中的每一步都有数据支撑,而非感觉支撑。这就是Harness的核心价值。
Harness不是锦上添花的“最佳实践”,而是Agent从演示走向生产必须跨越的鸿沟。它解决三个基础问题:
评估——让你知道Agent做得好不好,改动是否有效
可观测——让你看到Agent做了什么,为什么这样做
可复现——让你的结果可以被验证,你的改进可以被度量
这三个能力加在一起,把Agent开发从“炼金术”变成了“化学”——你仍然需要创造力和直觉,但你的每一步都有迹可循,你的每一次改进都可以被验证。
在下一节中,我们将概览主流的Harness框架和工具,看看业界是如何在这些问题上前进的。