核心论点:能上生产的 Agent harness(指套在 LLM 外面、把工程约束"编织"进运行时的那层骨架),不是 LangChain 文档里那个"think → act → observe"的单循环,而是路由层 + 多策略执行器 + 生产守卫的三层结构。把延迟、韧性、安全、可观测性直接编进运行时本身,而不是等出事后再打补丁。


一、教科书里的 Agent 循环,为什么不够

所有 Agent 入门文章都会画同一张图:LLM 产出想法 → 选工具 → 执行 → 观察结果 → 再思考……直到给出最终答案。ReAct 范式干净、优雅,但它偷偷假设了四件事:

  1. LLM 永远在线、且调用免费(可用性与成本两件事);
  2. 工具总是成功返回;
  3. 用户输入是干净的;
  4. 没人需要盯着它。

生产环境把这四条全破了:LLM 有速率限制和偶发超时,且每 token 都要计费;远程工具会限流、返回空、部分成功;用户输入带 typo、情绪甚至攻击;合规还要求"高风险动作必须人确认"。

所以 harness 真正要解决的,不是"怎么跑循环",而是循环之外的工程问题:请求进来前怎么净化、循环怎么设上限、出错怎么兜底、谁在盯着。这就是本文要拆的"生产级 harness"。

二、Harness 的三层结构:路由层 + 执行器 + 守卫

第一篇从分层视角讲了"系统由哪些层组成",本篇换一个切面:把运行时单独拎出来,看一次请求在 harness 内部实际经过了哪些闸门。先看全貌——Shop-Agent 的 harness 不是单一 loop,而是三段:

生产守卫(外包一层):输入安全过滤 · 输出安全过滤 · 人在回路 · 全链路可观测

按意图分发

按意图分发

按意图分发

按意图分发

用户请求

路由层 · 入口
归一化 / Token 截断 / 情绪 / 意图识别

ReAct 执行器
自由循环

固定步骤执行器
Plan-Execute / RAG 兜底 / 固定四步

直接分发
简单查询

纠纷协调器
专用 · 分布式锁

注:图上把 Plan-Execute 与 RAG 兜底合并为一类——它们走的是同一套固定步骤执行器。纠纷协调器带分布式锁、不跑通用循环,属于特化路径,不计入"多策略"三选一。

第一个反直觉结论:harness = 路由层 + 多策略执行器,而不是一个万能循环。路由层负责"该用哪个执行器",每个执行器负责"在自己的循环里把事做成"。把这两层分开,守卫才能被复用,而不是在每个执行器里重写一遍。

顺带区分两个"三":导语说的"三层"是纵向的处理阶段(路由层 / 执行器 / 守卫),而"多策略三选一"是横向的执行器分工(ReAct / 固定步骤 / 直接分发),两者不是同一个三。

三、路由层:harness 的第一道闸门

路由层是 harness 的入口,它本身不跑 LLM 循环,而是把生产约束前置到循环之外。逐一看它立下的几道闸门:

  • 同义词归一化(规则 + 本地模型,零 LLM 成本):轻度清洗,失败就回退原文本,绝不阻塞流程。
  • Token 预算截断:用 tokenizer 精确估算(中文 ≈ 1.5 token/字),超限就重建不可变(frozen)的请求对象。这避免了一个超长输入把后续整条链路拖垮。
  • 情绪检测级联(规则 <1ms + 本地模型 ~30ms):本地模型优先,保持延迟可控。
  • 舆情风险 → 立即升级:检测到紧急情况直接短路整条管线,返回"已升级高级专员",连意图识别都不做。这是 fail-closed(出问题时默认拒绝而非放行)的教科书示例。
  • 意图识别 → 路由分发:命中远程调用走参数抽取 + 门控;复杂意图走 ReAct;简单意图走直接分发;纠纷类走协调器。
  • 纠纷协调前的分布式锁:锁的 key 由"会话号 + 订单号"拼接,TTL 5 分钟。防止接口重试或消息队列"至少一次"投递导致的重复触发——这是 harness 给"幂等"上的第一道锁。
  • 输出内容安全过滤:规则引擎,零 LLM 成本。
  • 全链路 trace + A/B 注入:整条管线共享一个 handler,实验分组在出口注入。

论点:这些守卫前置到路由层,意味着无论请求最终落到哪个执行器,净化、截断、情绪、安全、可观测都已经发生。这正是"守卫是 harness 一等公民"的体现(下文「守卫不是补丁」一节收口成表)。

四、执行器一:ReAct 循环(递归上限即护栏)

ReAct 执行器(图编排框架驱动)是自由循环执行器。它做对了几件生产化的事:

  • 工具选择前置:按意图过滤 + embedding 重排(把文本转成向量、用相似度匹配),只把相关工具喂给 LLM,而不是几百个全量 Function Calling(把工具描述全塞进 prompt 让模型自己挑)(呼应《软预过滤工具选择方案》)。
  • 输入安全过滤:规则引擎拦截,不进循环。
  • 图状态存档(checkpointer):状态存档器把执行到一半的图状态存下来,是人在回路 interrupt() 的必需品。
  • 递归上限 = 基础步数 × 2 + 2:基础步数设为 5 → 上限 12。这是 harness 给"循环"装的断路器——把教科书里可能无限转圈的 ReAct,变成有限状态机。没有它,一个钻牛角尖的 Agent 会一直烧 token。(这个值在图默认配置与每次调用的配置里双重设定,防止漏配。)
  • 人在回路:当退款申请这类工具被调用,置待审批标志,把图状态按会话级标识存下,返回等待确认。后续人工审批后,用同一标识 resume 恢复,而不是从头重跑。
  • 推理链抽取:从图的消息里抽出最终答案 + 中间步骤(think→act→observe 的痕迹),作为可审计的推理链。

关键论点:递归上限是循环的断路器,状态存档器是循环的暂停键。这两样东西,才是 ReAct 从"demo 玩具"变成"生产组件"的分水岭。

五、执行器二:Plan-and-Execute 固定步骤

固定步骤执行器是第二个执行器,但它不跑自由循环,而是固定四步:

  1. 理解 / 改写查询:并检测"元描述"陷阱(如"问题类型:流程咨询"),命中就回退原始问题,避免改写丢失意图。
  2. 安全审查:门控不通过就生成降级回复直接返回。
  3. 并行检索:向量检索 + 图查询并行,且复用路由层预计算的 embedding,省掉一次 embedding API 调用。
  4. 生成 + 质量评估:打"质量分"与"是否解决"标志,并上报 Prometheus 指标。

为什么需要第二个执行器?因为不是所有任务都该跑自由 ReAct。知识问答(即 RAG 兜底)是确定性步骤流,用固定四步比自由循环更可控、更便宜、更易观测。harness 的"多策略"本质,是按任务复杂度选执行器:简单查询走直接分发,多步推理走 ReAct,知识问答走固定步骤。这就是前面那张分发图的真正含义。

六、守卫不是补丁,是 harness 的一等公民

把前面散落的守卫收口成一张表,能看清 harness 的设计哲学——守卫分层、前置、复用,而不是事后打补丁:

守卫点 机制 失败语义
输入归一化 规则 / 本地模型 回退原文本,不阻塞
Token 截断 tokenizer 精确估算 重建请求,防拖垮链路
情绪 / 舆情 级联检测 + 升级 短路管线(fail-closed)
意图路由 意图识别 + 复杂度门控 选对执行器
工具选择 意图过滤 + embedding 重排 降维候选集
输入 / 输出安全 规则引擎(零 LLM 成本) 拦截 / 过滤
幂等 分布式锁(TTL 5 分钟) 跳过重复触发
人在回路 状态存档 + interrupt 暂停等待人工
可观测 全链路 trace + 指标 全链路 trace + 指标

这张表也回答了开篇的问题:为什么教科书循环不够?因为守卫必须前置且分层,否则每个执行器都要各自重写一遍安全、截断、可观测——那才是真正的维护噩梦。

七、Harness 与外围设施的关系

此外,多工具部分成功、跨服务上下文同步等失败模式不在本文范围,见《AI Agent 分布式系统》系列的《工具调用部分成功》《分布式上下文存储与同步》两篇。

八、要点

  • harness ≠ 单一 ReAct 循环,而是路由层 + 多策略执行器 + 生产守卫的三层结构。
  • 路由层把生产约束前置到循环之外;执行器按任务复杂度分工(直接分发 / ReAct / 固定步骤)。
  • 递归上限是循环的断路器,状态存档器是循环的暂停键——这两样是 ReAct 生产化的分水岭。
  • 守卫是 harness 的一等公民:分层、前置、复用,而不是每个执行器各写一遍。
  • harness 与 LLM 网关、监控 Agent 是配套的;网关管"出得去",监控管"看得见"。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐