1. 从一场分享聊起:Kymo 的 Harness 引擎到底在解决什么问题
在云栖那场分享里,Kymo 团队把 Harness 引擎和 MCP 审计方案放在一起讲,这个组合本身就很有意思。我听完之后第一反应是:这不就是在给智能体装“行车记录仪”加“方向盘”吗?Harness 负责让智能体跑得稳、跑得可控,MCP 审计负责记录它到底跑了哪些路、做了哪些动作。两者配合起来,才构成一个能真正落地到生产环境的智能体运行底座。
先说 Harness 这个词。在智能体语境下,Harness 不是某个具体框架的名字,而是一类工程实践的统称——它指的是包裹在模型或智能体外面的那层“驾驭装置”。你可以把它理解成马具:马本身力气大、跑得快,但如果没有缰绳、鞍具和嚼子,你根本没法让它按你的意图走。Harness 引擎干的就是这件事,它把智能体的推理、工具调用、上下文管理、错误恢复、权限控制这些环节串起来,形成一个可观测、可干预、可回滚的执行链路。
那 MCP 审计又是什么?MCP 是 Model Context Protocol 的缩写,它定义了一套标准化的接口,让智能体能够以统一的方式去调用外部工具、读取资源、获取提示模板。而 MCP 审计,就是在 MCP 这层协议上做行为记录和合规检查。每一次工具调用、每一次资源读取、每一次提示注入,都会被审计模块捕获,形成结构化日志。这样一来,当智能体做出一个意外动作时,你能追溯到它是被哪条上下文触发的、调用了哪个工具、传了什么参数、返回了什么结果。
这两件事放在一起,解决的是同一个核心痛点:智能体从“能跑”到“敢用”之间的鸿沟。很多团队搭智能体,demo 阶段很惊艳,一上生产就各种翻车——要么是工具调用失控,要么是上下文污染导致行为漂移,要么是出了问题根本查不到原因。Harness 引擎负责在运行时施加约束,MCP 审计负责在事后提供证据链,一个管事前事中,一个管事后,形成闭环。
适合谁来参考这套东西?我认为有三类人最值得花时间研究:第一类是正在做智能体平台架构的工程师,你需要知道执行层该怎么设计才能既灵活又安全;第二类是做 AI 应用落地的技术负责人,你要评估智能体能不能进生产、怎么进;第三类是对智能体行为审计有合规要求的团队,比如金融、医疗、企业服务这些领域,审计不是可选项而是必选项。哪怕你暂时不打算自己造轮子,理解这套思路也能帮你在选型时看清哪些平台是真有工程底子,哪些只是套了个壳。
2. Harness 引擎的核心设计思路拆解
2.1 为什么需要一层独立的 Harness 而不是直接调模型
很多人一开始做智能体,就是写个循环:把用户输入拼进 prompt,调模型,解析输出,如果输出里有工具调用就执行,把结果再拼回去,继续调模型。这个循环跑通不难,难的是让它稳定跑一万次不出事。直接调模型的问题在于,模型本身是无状态的,它不知道上一次调用发生了什么,也不知道当前这个工具调用会不会越权,更不知道如果工具返回了异常该怎么优雅降级。这些逻辑如果全塞在业务代码里,很快就会变成一团乱麻。
Harness 引擎的价值就在于把这层逻辑抽出来,做成一个独立的执行层。它不关心你用的是哪个模型,也不关心你调的是哪个工具,它只关心一件事:如何让一次智能体执行过程变得可定义、可观测、可控制。具体来说,Harness 通常包含这几个核心模块:执行循环管理器、上下文窗口管理器、工具调用代理、错误恢复策略、权限与配额控制、以及执行轨迹记录。
我自己的体会是,有没有这层 Harness,决定了你的智能体是“玩具”还是“产品”。玩具可以容忍偶尔抽风,产品不行。Harness 引擎让你能够在执行层面做很多细粒度的控制,比如限制单次会话最多调用多少次工具、限制某个工具只能被特定角色的智能体调用、当模型输出格式不符合预期时自动重试而不是直接崩溃。这些控制如果散落在业务代码里,维护成本极高,抽出来之后才能复用和演进。
2.2 Harness 与 Agent 的区别:别把马具和马混为一谈
热词里有个问题问“harness 和 agent 区别”,这个问题其实很关键。Agent 是那个“会思考、会决策、会行动”的主体,它包含模型、提示词、工具集、记忆机制这些要素。而 Harness 是包裹在 Agent 外面的执行框架,它不参与决策,只负责让决策过程变得可控。打个比方,Agent 是司机,Harness 是方向盘、刹车、仪表盘和后视镜。司机决定去哪,但方向盘和刹车决定了这辆车能不能安全到达。
在实际工程中,这个区分很重要。因为很多人会把 Harness 的职责和 Agent 的职责混在一起,结果就是 Agent 的提示词里塞了一堆执行控制的逻辑,比如“如果你调用工具失败超过三次就停止”,这种指令模型不一定能可靠执行,而且每次都要消耗 token。更好的做法是把这些控制逻辑放在 Harness 层,用代码而不是提示词来实现。代码是确定性的,提示词是概率性的,能用代码保证的事情不要交给模型。
Kymo 分享里提到的 Harness 引擎,我理解它的定位就是这样一个执行层。它可能不绑定特定的 Agent 框架,而是提供一套通用的执行原语,让不同的 Agent 实现都能接入。这种设计的好处是解耦:Agent 可以换,模型可以换,工具可以换,但 Harness 提供的执行保障是稳定的。对于平台型产品来说,这种分层设计几乎是必然选择。
2.3 执行循环里的关键控制点
一个典型的 Harness 执行循环,大致会经过这几个阶段:接收输入、构建上下文、调用模型、解析输出、判断是否需要工具调用、执行工具、处理工具结果、判断是否继续循环、最终输出。每个阶段都有可以施加控制的地方。
在构建上下文阶段,Harness 需要决定哪些历史消息保留、哪些丢弃、哪些压缩。上下文窗口是有限资源,如果无脑全塞进去,很快就会超限,而且会引入噪声。常见的策略包括滑动窗口、摘要压缩、关键信息提取等。我实测下来,滑动窗口加定期摘要的组合比较稳,既能保留近期细节,又能维持长期记忆。
在解析输出阶段,Harness 需要处理模型输出格式不稳定的问题。即使你要求模型输出 JSON,它也可能给你带 markdown 代码块、带额外解释文字、或者字段缺失。Harness 需要有一套容错解析机制,比如先尝试直接解析,失败后尝试提取代码块,再失败后尝试用正则修复,最后才报错。这个重试链条的设计直接决定了智能体的鲁棒性。
在工具调用阶段,Harness 需要做权限检查、参数校验、超时控制、重试策略、结果截断。工具调用是智能体最容易出问题的环节,因为外部工具的行为不可控。一个 HTTP 请求可能超时,一个数据库查询可能返回巨量数据,一个文件操作可能没有权限。Harness 要在这些环节做好防护,避免单个工具故障导致整个执行链路崩溃。
在循环控制阶段,Harness 需要设置最大迭代次数、最大 token 消耗、最大执行时长等硬性限制。没有这些限制,智能体可能陷入死循环,不断调用工具却永远不输出最终答案。我见过最夸张的案例是一个智能体因为工具返回格式不符合预期,反复重试了上百次,烧掉了大量 token。有了 Harness 层的硬限制,这种情况就能被及时掐断。
3. MCP 审计方案的技术细节与落地要点
3.1 MCP 协议为什么适合做审计切入点
MCP 的设计初衷是标准化智能体与外部世界的交互方式。在 MCP 出现之前,每个智能体框架都有自己的工具调用格式,有的用 JSON schema,有的用函数签名,有的用自然语言描述。这种碎片化导致工具难以复用,也让审计变得困难,因为每个框架的调用记录格式都不一样。
MCP 把这层交互标准化之后,审计就有了统一的切入点。无论底层是哪个模型、哪个框架,只要工具调用走的是 MCP 协议,审计模块就能以一致的方式捕获调用信息。这就像给所有车辆统一了 OBD 接口,不管什么品牌的车,插上诊断仪都能读到标准化的运行数据。
MCP 的核心原语包括 Tools、Resources、Prompts 这几类。Tools 是可调用的函数,Resources 是可读取的数据源,Prompts 是可复用的提示模板。审计方案需要覆盖这三类原语的访问记录。特别是 Tools 调用,因为它涉及实际的动作执行,是审计的重中之重。每一次工具调用,审计模块应该记录:调用时间、调用方标识、工具名称、输入参数、返回结果、执行耗时、是否成功、错误信息(如果有)。
这些记录不仅是事后追查的依据,也是实时监控的数据源。你可以基于审计日志做实时告警,比如某个工具在短时间内被高频调用、某个参数值超出了正常范围、某个智能体尝试访问未授权的资源。这些异常行为如果能被及时发现,就能在造成实际影响之前被阻断。
3.2 审计日志的结构化设计
审计日志最忌讳的是记成一锅粥。如果只是把每次调用的原始 JSON 丢进日志文件,事后排查时你会非常痛苦。好的审计日志应该是结构化的、可查询的、有关联关系的。
我建议的日志结构至少包含这几个维度:会话维度(session_id、conversation_id)、执行维度(trace_id、span_id、parent_span_id)、主体维度(agent_id、user_id、tenant_id)、动作维度(tool_name、action_type、resource_uri)、结果维度(status、error_code、duration_ms)、内容维度(input_payload、output_payload、payload_hash)。
其中 trace_id 和 span_id 的设计参考了分布式追踪的思路。一次智能体执行可能包含多轮模型调用和多次工具调用,它们之间是有层级关系的。通过 trace_id 把一次完整执行串起来,通过 span_id 标识每个子步骤,通过 parent_span_id 建立调用树,这样你就能还原出完整的执行路径。当出现问题时,你可以沿着调用树逐层下钻,快速定位是哪个环节出了偏差。
payload_hash 的作用是去重和完整性校验。工具调用的输入输出可能很大,全量存储成本高。可以先存 hash,需要时再根据 hash 去对象存储里取原始内容。同时 hash 也能用来校验日志是否被篡改,满足合规审计的要求。
3.3 审计数据的采集方式与性能考量
审计数据的采集方式直接影响对主流程的性能影响。最粗暴的方式是同步写日志,每次工具调用都等日志落盘再继续。这种方式最可靠但性能最差,在高频调用场景下会成为瓶颈。更好的方式是异步采集,工具调用完成后把审计事件推入消息队列,由独立的消费者写入存储。这样主流程不受影响,但需要处理消息丢失和顺序问题。
还有一种方式是旁路采集,通过 MCP 网关代理所有工具调用,网关在转发请求的同时记录审计信息。这种方式对智能体透明,不需要修改智能体代码,但会引入额外的网络跳转。如果网关本身做了高可用和低延迟优化,这个开销是可以接受的。Kymo 的方案我推测可能采用了网关代理加异步落盘的组合,因为这样既能保证采集的完整性,又能控制性能损耗。
性能考量方面,有几个参数需要重点关注:采样率、批量大小、刷盘间隔。采样率决定了记录多少比例的调用,对于高频低风险的调用可以适当降采样,对于高风险操作则应该全量记录。批量大小和刷盘间隔影响写入效率和数据丢失窗口,需要根据业务对审计实时性的要求来权衡。如果要求秒级可查,刷盘间隔就不能太长;如果能容忍分钟级延迟,就可以用更大的批量来提升吞吐。
注意:审计日志本身也可能包含敏感信息,比如工具调用的参数里可能有用户隐私数据。在设计审计方案时,必须考虑日志的脱敏和访问控制。不是所有能看日志的人都能看原始 payload,需要做字段级权限控制。
4. 把 Harness 和 MCP 审计串起来:一个可落地的执行链路
4.1 整体架构分层
把 Harness 引擎和 MCP 审计放在一起看,一个完整的智能体执行链路大致分为四层:接入层、编排层、执行层、审计层。接入层负责接收用户请求、做身份认证和限流;编排层负责决定用哪个智能体、加载哪些工具、初始化什么上下文;执行层就是 Harness 引擎所在的位置,负责驱动整个执行循环;审计层横切所有层,采集各层的审计事件。
这个分层的好处是职责清晰。接入层不关心智能体怎么执行,编排层不关心工具怎么调用,执行层不关心日志怎么存储。每层可以独立演进和替换。比如你想换一个模型供应商,只需要改执行层里模型调用的适配器;你想换审计存储,只需要改审计层的写入实现。这种解耦对于长期维护至关重要。
在实际部署时,执行层和审计层可以部署在同一个进程内,也可以拆成独立服务。如果追求低延迟和简单部署,同进程内通过内存队列传递审计事件就够了。如果追求高可用和独立扩展,就把审计层拆出来,通过消息队列解耦。我个人的建议是初期同进程,等审计量大了再拆,避免过早引入分布式复杂度。
4.2 一次完整执行的审计轨迹示例
假设用户向智能体提问:“帮我查一下上个月的销售数据,并生成一份摘要报告。”这个请求会触发一系列动作。首先,编排层加载销售分析智能体,该智能体配置了数据库查询工具和报告生成工具。然后 Harness 引擎开始执行循环。
第一轮,模型判断需要调用数据库查询工具,Harness 检查权限通过后,通过 MCP 客户端发起工具调用。审计层记录一条事件:tool_call,tool_name=query_sales_db,input={month: “last_month”},status=success,duration=230ms。工具返回数据后,Harness 把结果拼回上下文,进入第二轮。
第二轮,模型判断数据已足够,调用报告生成工具。审计层再记录一条事件:tool_call,tool_name=generate_report,input={data_hash: “abc123”},status=success,duration=1500ms。报告生成后,模型输出最终答案,Harness 判断循环结束,返回结果。审计层记录一条事件:execution_complete,total_tool_calls=2,total_duration=2100ms,status=success。
这条审计轨迹看起来简单,但它包含了完整的信息链。如果报告内容有问题,你可以回溯到是查询的数据不对,还是报告生成的参数不对。如果查询超时了,你能看到是数据库响应慢还是网络问题。如果智能体调用了不该调用的工具,审计日志会明确记录这次越权尝试。这就是审计的价值:让每一次执行都有据可查。
4.3 权限控制与审计的联动
审计不只是被动记录,它还可以和权限控制联动,形成主动防御。具体做法是:在执行工具调用之前,Harness 先向审计模块查询该智能体对该工具的调用历史,如果发现异常模式,比如短时间内高频调用、调用参数超出正常范围、调用了从未调用过的敏感工具,就可以触发额外的审批流程或直接阻断。
这种联动需要审计模块提供实时查询能力,而不只是事后查询。实现上可以用流式处理引擎,对审计事件做实时聚合和规则匹配。规则可以很简单,比如“同一智能体对同一工具的一分钟调用次数超过 100 次则告警”,也可以很复杂,比如“调用参数中的用户 ID 不属于当前会话的授权用户列表则阻断”。规则越复杂,误报和漏报的平衡就越难把握,需要根据实际业务场景调优。
我踩过的一个坑是:初期规则设得太严,导致正常的高频调用被误阻断,影响了业务。后来改成先告警观察一段时间,收集足够的基线数据后再逐步收紧规则。这个渐进式的策略比较稳妥,不建议一上来就开阻断模式。
5. 实操中常见的坑与排查技巧
5.1 Harness 执行循环卡死或无限重试
这是最常见的问题之一。表现是智能体一直不返回最终答案,日志里看到工具调用在反复执行。根本原因通常是模型输出格式不符合 Harness 的解析预期,导致 Harness 认为工具调用失败,于是重试,但重试时上下文没有变化,模型还是输出同样的格式,形成死循环。
排查思路:先看审计日志里同一 trace_id 下的工具调用次数,如果某个工具被调用了异常多次,基本可以确定是循环问题。然后检查模型原始输出,看是不是格式问题。常见格式问题包括:模型把 JSON 包在 markdown 代码块里、模型输出了多个 JSON 对象、模型在 JSON 前后加了自然语言解释。
解决方法:在 Harness 的解析层增加容错处理,先尝试提取代码块内容,再尝试用括号匹配提取 JSON,再尝试用宽松的 JSON 解析器。同时设置最大重试次数,超过后强制中断并返回错误,而不是无限重试。另外可以在提示词里强化格式要求,但不要完全依赖提示词,代码层的容错才是根本保障。
5.2 MCP 工具调用超时但审计日志缺失
有时候工具调用明明超时了,但审计日志里找不到对应记录。这种情况通常是审计采集的时机不对。如果审计事件是在工具调用成功返回后才记录,那么超时的调用就不会被记录。正确的做法是在工具调用发起前就记录一条“调用开始”事件,调用结束后再记录一条“调用结束”事件,通过 trace_id 关联。这样即使调用超时,你也能看到它开始了但没结束。
另一个可能原因是审计事件在异步队列里丢失了。如果消息队列没有做持久化,进程崩溃时队列里的消息就丢了。解决方法是开启消息队列的持久化,并设置合理的确认机制。对于审计这种不能丢的数据,宁可牺牲一点性能也要保证可靠性。
5.3 审计日志量过大导致存储成本失控
智能体高频调用工具时,审计日志量会快速增长。如果不做控制,存储成本会很快超出预算。常见的优化手段包括:对低风险工具调用做采样记录、对 payload 做压缩存储、对历史日志做分级存储(近期热数据存 SSD,远期冷数据存对象存储)、对日志做定期归档和清理。
但要注意,采样不能一刀切。对于涉及资金、权限、敏感数据的工具调用,必须全量记录。可以给每个工具打上风险等级标签,根据等级决定采样策略。高风险全量,中风险按比例采样,低风险只记录聚合统计。这样既控制了成本,又保住了关键审计能力。
5.4 智能体行为漂移但审计日志看不出原因
有时候智能体的行为会逐渐偏离预期,但审计日志里每次调用看起来都正常。这种情况往往是上下文管理出了问题。随着对话轮次增加,上下文里积累了大量历史信息,其中可能包含过时的、矛盾的、甚至被污染的内容。模型在这些噪声的影响下,行为逐渐漂移。
排查这种问题,需要在审计日志里额外记录每次模型调用时的上下文摘要,比如上下文里包含多少条消息、总 token 数、最近几条消息的内容哈希。这样当行为漂移发生时,你可以对比不同轮次的上下文差异,找到是哪些内容导致了漂移。解决方法是优化上下文管理策略,定期清理无关历史,对关键信息做摘要而不是全量保留。
| 常见问题 | 典型表现 | 排查切入点 | 解决方向 |
|---|---|---|---|
| 执行循环卡死 | 工具反复调用不返回 | 同 trace_id 下调用次数 | 解析容错加最大重试限制 |
| 审计日志缺失 | 超时调用无记录 | 审计事件采集时机 | 调用前后双事件加队列持久化 |
| 存储成本失控 | 日志量快速增长 | 各工具调用频次与风险等级 | 分级采样加冷热分离存储 |
| 行为漂移 | 输出逐渐偏离预期 | 上下文摘要与 token 变化 | 优化上下文清理与摘要策略 |
6. 关于智能体审计的一些延伸思考
智能体行为审计这个概念,现在越来越被重视。2026 年 OWASP 发布的智能体应用 Top 10 风险里,好几个都跟审计直接相关,比如智能体权限滥用、工具调用失控、上下文注入攻击。审计不只是合规要求,它其实是智能体安全体系的基础设施。没有审计,你连发生了什么都不知道,更谈不上防护。
我在实际项目里的体会是,审计方案的设计要趁早。很多团队是等出了问题才想起来加审计,这时候往往已经积累了大量技术债,补起来很痛苦。如果一开始就把审计作为执行链路的一等公民来设计,后面会省很多事。具体来说,在定义工具接口的时候就把审计字段考虑进去,在执行循环里预留审计钩子,在存储选型时把审计数据的特性纳入考量。
另外一个值得关注的方向是审计数据的智能化分析。现在大部分审计还是人工查日志,效率低且依赖经验。如果能用模型对审计日志做异常检测和根因分析,就能大幅提升排查效率。比如训练一个模型来识别正常的调用模式,当出现偏离时自动告警并给出可能的原因。这个方向目前还在早期,但我觉得很有潜力。
最后分享一个小技巧:在审计日志里给每次执行打一个“可复现标记”。具体做法是记录执行时的模型版本、提示词版本、工具版本、上下文快照哈希。这样当你想复现一次有问题的执行时,可以用相同的条件重新跑一遍,看看问题是否稳定复现。这对于调试智能体行为问题非常有用,因为智能体的行为受太多因素影响,没有可复现性就很难定位根因。