我接手过一套已经跑了三个月的AI客服系统,那段时间最累的不是模型调优,而是每天凌晨三点被人叫醒去看日志。系统里负责处理退款申请的那个AI Agent,在遇到地址模糊、金额对不上、客户语气特别差、外部仓储接口超时这四种情况时,会把这四类工单全部转人工。这四个转人工的兜底环节当时没有名字,我们就统一叫它们“人工回路”。
后来我越来越觉得,只要这些人工回路还在靠人肉翻日志、靠群里艾特、靠值班表来运转,AI员工就永远只是“半自动”。标题里的“把四道人工回路落成四个组件”,说白了就是把那些“人”的动作拆成可配置、可观测、可测试的组件,让AI员工在没人盯着的时候也能被信任。这篇文章就把我这套清单完整写出来,适合正在搭AI Agent、或者已经把AI接进业务但被可靠性问题搞得头疼的人。
1. 先搞清楚:AI员工身上到底有哪几道人工回路
很多团队做AI Agent,一开始都盯着模型的准确率、召回率,但真到了生产环境,最扎心的往往不是模型不行,而是“没人兜底”。一套业务流程里,AI不可能每次都完美走完,于是我们习惯性加一个人工判断节点:不行就让人来。这些节点就是人工回路。
1.1 从一次凌晨三点的工单事故说起
我们当时的场景是:客户提交退款申请,AI Agent自动读取订单、判断退款资格、调用仓储系统确认商品状态,最后发起退款。听起来挺顺,但真实请求千奇百怪。比如客户填的地址是“上次那个地址”,这需要结合历史会话语义理解;比如订单金额和系统记录差一分钱,这需要人工确认是不是有优惠券没算;比如客户情绪激烈,说“再不处理就投诉”,这时候AI直接回话容易捅娄子;再比如仓储接口超时,AI无法确认退货状态,只能干等。
这四个场景,原来的处理方式就是“转人工”。每次转人工,意味着有个值班同事会收到一条消息,然后打开后台、翻上下文、做判断、给结果。刚开始量小还顶得住,后来单量涨起来,每个值班同事同时盯几十个工单,漏掉一个就是一次客诉。我当时看了一个星期的值班记录,发现误操作、漏处理、重复问客户同样问题的情况特别多。这就是人工回路脆弱的直观体现。
1.2 四道回路对应的故障模型
我后来把当时遇到的所有人工介入点归纳成了四类,这四类几乎覆盖了大部分AI Agent的可靠性隐患:
| 回路编号 | 触发场景 | 人工在做什么 | 故障后果 |
|---|---|---|---|
| 回路一 | 输入不完整、含义模糊 | 人工先判断“这单子要不要接” | AI理解错意图,后续全部跑偏 |
| 回路二 | 输出不合规、语气不对 | 人工把AI生成的答复改一遍再发 | 客户收到错误或冒犯性回复 |
| 回路三 | 工具调用失败、依赖超时 | 人工去查日志、重试、补救 | 流程卡死,无法推进 |
| 回路四 | 之前人工修正过的案例被重复纠正 | 人工再次处理相同问题,没有沉淀 | 同样错误反复出现,团队疲于救火 |
每一道回路背后都是一种典型的可靠性工程问题:输入不可控、输出不可信、依赖不可靠、经验不可复用。这四个问题不解决,你的人工介入率永远降不下去,AI Agent也就永远只能是“demo级”。
1.3 为什么靠人肉运维这条路走不通
有人可能会说,转人工就转人工呗,先跑起来再说。但我在实际项目里吃了亏。第一,人的注意力是有限资源,同一个错误发生一百次,人就会疲劳,最后漏掉的那一次可能就造成资损或客诉。第二,人工干预的动作没有标准化,同一个人不同时间、不同人之间处理风格不一样,流程审计根本说不清。第三,人工回路不进入系统数据,意味着你无法用数据衡量“AI到底表现得怎么样”,后续优化没有依据。
所以我把这四道回路当成四个必须“组件化”的工程任务。所谓组件化,不是说写一个公共函数就叫组件,而是要让它具备独立的能力边界、清晰的输入输出协议、可观测的状态、可回滚的降级策略。接下来我一个个拆开讲。
2. 组件一:输入校验器——把人“先看一眼再放行”的动作沉淀成规则
第一道人工回路,通常发生在流程起点。原来人接到工单,第一反应是“这个单子信息够不够?我能不能直接处理?”现在我们要让AI Agent自己做这个判断,而不是傻乎乎往下跑。这个组件我叫它“输入校验器”。
2.1 人工处理时到底在“看”什么
以退款场景为例,人工同事看到一张工单,其实是在做三件小事:第一,检查必填字段是否完整,比如订单号、退款原因、金额、用户ID;第二,判断用户意图是否清晰,比如“我要退钱”和“你们怎么回事”明显不一样;第三,评估风险等级,比如涉及大额退款、黑名单用户,人工会额外谨慎。这些判断如果做成规则,看起来非常简单,但难的是怎么跟大模型能力结合,既不要放过异常,也别把正常请求误杀。
我当时踩了一个坑:一开始把输入校验做成了纯规则校验,字段缺失直接拒单。结果有大量正常用户因为漏填了一个地址就被卡住,客诉飙升。后来才意识到,人看输入是一个“分级处理”的过程,不是“非黑即白”。有的信息缺了,可以引导补充;有的信息模糊,可以结合历史推断;只有真正无法处理的异常才进入人工。这个逻辑必须内嵌到组件里。
2.2 输入校验器组件要具备四个能力
我最终实现的输入校验器,包含四个运行阶段,每个阶段对应一类风险:
- 结构校验:用JSON Schema或者Pydantic模型要求关键字段存在且类型正确。这层解决的是“数据有没有”的问题。
- 语义校验:把用户输入送入一个轻量级分类模型或大模型,判断意图是否清晰、是否在业务白名单内。这层解决的是“能不能做”的问题。
- 上下文校验:检查当前工单是否关联历史会话、订单详情是否已加载。比如客户说“上次买的那个东西”,如果没有上下文快照,就必须触发补充信息的动作。
- 风险分级:根据金额、用户历史、渠道来源计算出风险分,高风险走增强校验或者直接转人工。
第一层是硬性的,直接用代码拦截;后三层是柔性的,需要调用模型。但要注意,柔性判断不能成为性能瓶颈,所以我在工程上会先跑正则和关键词,过滤掉明显正常的请求,只有模糊样本才送模型。
2.3 一个可落地的验证器实现思路
下面的代码片段是我当时验证逻辑的简化版,不是生产代码,但思路很清晰。核心是让校验器返回一个结构化的处理建议,而不是简单的pass/fail:
from pydantic import BaseModel, ValidationError class RefundOrderInput(BaseModel): order_id: str user_id: str amount: float reason: str | None = None def validate_input(raw: dict, history: list | None = None): # 第一层:结构校验 try: parsed = RefundOrderInput(**raw) except ValidationError as e: return {"action": "ask_clarify", "reason": f"missing_fields: {e.errors()}", "new_state": raw} # 第二层:意图白名单 intent = detect_intent(parsed.reason) if intent not in ["refund_request", "order_status", "return_order"]: return {"action": "human_escalate", "reason": f"unclear_intent: {intent}", "new_state": parsed} # 第三层:上下文缺失检测 if history is None or len(history) == 0: return {"action": "ask_clarify", "reason": "missing_context", "new_state": parsed} # 第四层:风险分 risk = compute_risk(parsed.amount, history) if risk > 0.8: return {"action": "human_escalate", "reason": "high_risk", "new_state": parsed} return {"action": "proceed", "reason": "ok", "new_state": parsed}四个动作里,“ask_clarify”会触发一次追问,“human_escalate”会带着完整上下文自动建工单,“proceed”才进入实际业务逻辑。这个设计让我后来在改逻辑时非常省心,因为每个动作都有明确的出口,不会出现校验器把请求卡死的情况。
2.4 落地时最容易踩的坑:校验过严反而伤害体验
这个组件上线半个月,我调整了三次阈值。最大的教训是:你设定的校验规则,本质是在定义“AI员工的权限边界”,如果边界设得太保守,AI就永远像个实习生,什么都不敢干;设得太松,又会出事故。我的经验是把校验器分成强规则和弱提示两级,强规则管数据完整性和合法性,弱提示只负责记录风险,不在当前流程里拦截。这样既能保证安全,又不会让正常用户感受到明显卡顿。
还有一个小技巧:把校验器的决策结果全部打日志,包括“为什么放行”“为什么拦下”。因为后面做复盘、调阈值时,如果没有这些结构化日志,你根本不知道哪个环节误判了。日志就是我们组件的观测基础。
3. 组件二:输出评审器——把人的“我觉得不太好,改一下”变成可执行的检查清单
第二道人工回路,出现在AI生成答复之后。人工原来的动作是:读一遍AI写的回复,不好就改一版再发出去。这个动作在初期救了很多命,但也让交付时间完全取决于人回消息的速度。我们要用“输出评审器”替代掉大部分人工润色和审批。
3.1 人工评审时在掂量什么
客户看到的每一句话,人工都会做三层检查:合规性,比如有没有承诺不该承诺的内容;语气,比如是不是太过僵硬;事实性,比如金额、日期、政策引用跟后台数据对不对得上。这三层检查思路不一样,合规性是红线,语气是体验,事实性是正确性,所以组件不能用一个模型一把梭,必须分层处理。
3.2 评审器的三层结构
我设计的输出评审器分三层:
| 层级 | 实现方式 | 检查内容 | 处理方式 |
|---|---|---|---|
| 规则层 | 正则、敏感词表、模板 | 违禁词、链接、手机号、固定句型 | 违规直接禁发,走改写 |
| 模型层 | LLM-as-Judge | 语气、逻辑连贯性、是否符合指令 | 打分低于阈值则触发重写 |
| 业务层 | 后端API比对 | 金额、订单状态、库存数量、承诺日期 | 不一致则卡住,转人工 |
模型层和业务层要独立跑。因为模型判出来的“不好”很多时候只是风格问题,但业务层比对通常是硬性错误,两回事不能混为一谈。业务层的优先级永远最高,模型打分再高,业务比对不过也不能发出去。
模型层这里我要多说一句,很多人觉得LLM-as-Judge就是问一句“请给这段回复打分”,实际完全不够。我的做法是给每个业务场景写一个评估prompt模板,里面明确写出重点评价维度和一票否决项,并且要求评委模型输出JSON格式的评分明细,不只是总分。后面可以按维度调权重。
{ "dimensions": { "compliance": 0, "tone": 4, "fact_consistency": 3 }, "verdict": "rewrite", "reason": "语气过于生硬,且未使用礼貌用语" }3.3 阈值和自动修正策略怎么定
评审器给出的结果不能只做“通过/不通过”,我最后设了三个出口:直接发送、改写后发送、转人工。规则层的违规项大概率直接触发改写;模型层要看分数区间,比如总分低于60分转人工,60到85分自动调用重构prompt重生成一次,85分以上直接放行;业务层一旦比对失败则无论如何都转人工,不能自动改,因为业务数据的一致性不是模型能判断的。
自动改写的时候要注意避免死循环。我当时加了一个“改写次数上限”,默认两次。如果两次改写后评分还是低于阈值,就直接转人工。这个上限很关键,因为大模型重写可能越改越偏,不能让它无限自嗨。
3.4 一个踩过的坑:LLM-as-Judge也会“审美跑偏”
我们上线后遇到过一种情况:某些客服回复被评委模型连续给低分,但人工看了觉得完全没问题。后来查是因为评委模型在“语气”维度太偏好礼貌词汇,遇到客户本身不讲理的时候,AI如果回得稍微强硬一点就被判低分。解决方案是给评委模型增加业务背景:优先考虑问题是否解决,再考虑语气是否柔和。而且我们每周会抽一批评审结果让人工复核,用这些样本来校准评委模型的prompt。这个动作直到现在还在做,千万不要以为评委模型就是绝对客观的裁判。
另外,评审器会产生大量中间数据,比如原始回复、评分明细、改写后回复、最终动作。这些数据一定要全量入库。后来做AI可靠性的月度分析时,我就是靠这些数据才算出“人工介入率”和“评审通过率”的,否则根本拿不出量化结果。
4. 组件三:异常上报器——把“人肉盯监控”变成事件驱动的工单流转
第三道人工回路发生在AI Agent调用外部工具或交付业务动作的时候。原来系统只要报一个异常,值班同事就得去查日志、重启任务、手动补数据。这套流程在人少时还能忍受,但AI Agent一旦同时处理几百个任务,异常量会指数级增长,人根本盯不过来。我的解法是做“异常上报器”组件。
4.1 工具调用失败不只是超时重试
很多团队一提到异常处理,第一反应就是加try-catch,然后重试。但实际生产里,AI Agent异常的种类很杂,重试只是其中的一个动作。我整理过一份当时的异常清单,核心四类:
- 超时异常:外部API超过10秒没响应,比如仓储系统。
- 限流异常:第三方接口返回429,比如支付网关。
- 参数异常:工具接收到的字段不符合接口定义,比如订单ID带了特殊字符。
- 结果异常:工具正常返回,但结果值与预期矛盾,比如退款金额大于订单总价。
每一类异常的处理策略完全不同。超时的可以适当重试,限流的必须退避,参数异常需要回看输入校验器,结果异常则可能是业务逻辑bug,不能简单重试。
4.2 异常上报器组件的核心能力
我最终的异常上报器没有把异常处理逻辑写死在业务代码里,而是做成一个独立组件,它的职责有三块:捕获、快照、流转。
捕获是指监听所有工具调用的异常事件,并转成统一格式;快照是指在异常发生时,把当时的上下文完整记录下来,包括用户输入、工具入参、返回结果、运行链路ID;流转是指根据异常类型和严重程度,自动决定是重试、降级、还是创建人工工单。
这里我给当时的同学科普过“上下文快照”的价值。人工排查一个AI Agent问题,最怕的就是日志里只有一行“ERROR: timeout”,看不到当时的用户请求,也看不到工具返回了什么。所以异常上报器必须做到:一条异常记录,就能还原整个现场。链路ID贯穿所有环节是关键,没有链路ID,后面根本串不起来。
4.3 组件之间靠什么通信:事件总线而不是函数调用
到这里四个组件已经出现两个了,肯定有人会问:它们之间怎么协作?我的建议是组件之间不要互相调API,而是通过事件总线广播消息。输入校验器发现问题,就发一个“input_validation.failed”事件;输出评审器不通过,就发一个“output_review.rejected”事件;异常上报器捕获到错误,就发一个“tool_execution.error”事件。每个组件只关心自己收到事件后怎么做,不关心事件从哪来。
举个例子,异常上报器捕获到限流异常后,发出事件给“降级策略服务”,如果连续三次限流则触发用户可见提示并转人工工单。这个逻辑如果写在业务代码里,以后每接一个新工具都要改一遍;而放在事件流里,只需要配置对应的事件处理规则就行。这也是我在标题里强调“组件化”的原因,组件通信方式直接决定了整个AI系统复杂度是线性增长还是爆炸式增长。
4.4 一次真实的事故排查过程
上线异常上报器后,我们遇到过仓储接口在促销期间经常超时。以前靠值班同学盯告警群,现在异常上报器会把每一次超时都记录下来,并且自动把连续同一订单号、同一接口的错误聚合成一个“故障事件”发到工单系统。值班同学只需要点击工单链接,就能看到完整的调用链和上下文快照,甚至能看到重试了几次、何时转的人工。
这个改造带来的最大变化不是效率提升多少,而是人终于能“批量地看到问题全貌”,而不是陷在单条日志里。而且因为所有异常都有结构化记录,我月末做可靠性复盘时终于有了可以统计的数据:比如仓储接口的调用成功率从86%涨到94%,人工介入率降了一半。没有组件化之前,这些数字都是拍脑袋估的。
5. 组件四:记忆回放器——把人的“上次不是教过你吗”变成可追溯的闭环
第四道人工回路,也是最隐蔽的一道。很多团队在AI Agent上线后,都经历过同一个错误反复出现的痛苦:人工上周修正过一个退款金额计算问题,下周同类问题又冒出来,等于同一个坑踩了两次。原因很简单——人工修正的过程和结果没有回到系统里。我的方案是做“记忆回放器”,让人工干预的案例真正成为AI员工的长期记忆。
5.1 人工修正过的样本,是最宝贵的训练数据
我见过一些团队一上来就攒数据想微调模型,但微调前的数据清洗、人工标注成本极高。实际上,AI Agent运行过程中人工每一次的点击、每一次改写、每一次“不允许这样处理”的判定,都是天然的高质量标注数据。关键是要把“一次性的人工修正”转化成“可回放的规则和测试用例”。
比如人工受理了一笔因跨行转账延迟导致的退款纠纷,最后判定“客户发起退款后48小时内未到账的,自动标记为高风险并转人工”。这个修正动作如果只是在系统里手动操作了一下,那么AI下次还是不懂。但如果你把它记录下来,形成一条策略规则,再放入回归测试集,之后每次更新模型或prompt的时候都能验证这条规则是否还被遵守,这就是一个完整的闭环。
5.2 记忆回放器组件要做的事情
这个组件有三个核心任务:记录、沉淀、回放。
- 记录:监听所有人工干预事件,把干预前状态、干预后结果、干预理由存下来,形成一个“修正案例库”。
- 沉淀:定期把同类修正案例聚类,提炼成可配置的业务规则,或者生成“典型错误-正确做法”的few-shot样本。
- 回放:每周或每次发版前,拿沉淀出的用例集对整个AI Agent流程做一次批量测试,检测是否还有回归问题。
下面是一个简单的数据结构示例,我用来记录一次人工修正:
{ "case_id": "case_20250612_001", "trigger": "refund_amount_exceeded_order_total", "before": {"ai_action": "auto_approve_refund", "amount": 599.0}, "after": {"ai_action": "human_review", "status": "rejected", "reason": "refund exceeds payable"}, "human_note": "退款金额不能大于订单实付金额,需检查优惠券分摊逻辑", "rules_extracted": ["refund.amount <= order.paid_amount"], "test_id": "test_refund_amount_boundary" }回放器跑的时候,直接把这条case喂给当前流程,看它会不会再犯同样的错。如果犯了,就说明改动破坏了已有逻辑,要么修代码,要么补强prompt。这比每次依赖人工发现回归要靠谱得多。
5.3 如何把修正案例变成回归测试集
光有记录还不够,测试用例的质量决定了回放器的价值。我总结了一套筛选标准:优先回放那些触发过“高成本后果”的案例,比如资损风险、客诉升级;优先回放那些频繁出现的同类型案例,说明模型系统性偏差;还有一些边界案例,比如金额刚好等于阈值、时间刚好卡在截止点。测试集不必很大,刚开始50条就能拦住大部分回归。
回放器的运行方式不需要很复杂。我用的是每天晚上定时跑一批“模拟工单”,把历史真实案例脱敏后重放一遍,比对预期动作和最终动作。如果偏差率超过安全线,就自动冻结当天的模型版本并告警给研发。这其实就是一个微型的持续回归测试系统。
这里有个容易忽略的点:回放器和异常上报器之间也有联动。当回放用例跑出异常时,异常上报器会把失败案例重新打入待人工复核队列。人工确认到底是模型问题还是用例设计问题后,再决定是否更新规则。人工一直在环里,但不再是疲于救火,而是做更高层面的判断。
5.4 闭环之后,人工介入率才真正开始下降
我们当时把记忆回放器跑了一个季度,效果很直观:同一类型的退款问题,从第一周需要人工介入30次,到第三个月基本归零。因为AI已经通过回放机制学会了边界条件。当然,新的问题还是会冒出来,但只要持续记录和回放,介入率的整体曲线是往下走的。尤其值得说的是,回放测试集本身还在不断变大变聪明,这比单纯换一个大模型版本要稳定得多。
6. 四组件串成的可靠性清单:落地顺序和可直接抄的检查项
讲完四个组件,一定有人问:那我到底应该先做哪个?我的答案是不要一上来就四个全做。先找出你业务里最痛的那一道人工回路,然后针对性地做一个组件,跑通了再扩展到其他。我当时就是先做了异常上报器,因为最痛的是凌晨被叫醒;后来才逐步补上输入校验器和输出评审器,最后做的记忆回放器。
6.1 四个组件的依赖关系和部署顺序
从依赖角度看,输入校验器和其他组件的耦合度最低,可以独立上线;异常上报器是所有组件的“观测底座”,建议第二个做,因为它能帮你拿到后续决策所需要的数据;输出评审器依赖输入校验的合法性,适合第三个;记忆回放器依赖前三个组件的日志和事件数据,最后一个做最划算。
原因是:没有输入校验器,异常上报器会收到大量因为输入错误导致的垃圾异常;没有异常上报器的结构化日志,记忆回放器就缺少可靠的案例来源。但四个组件都做完后,它们会形成一个环:输入校验挡掉一批问题,输出评审挡住一批问题,异常上报兜住工具层故障,记忆回放让每一次人工修正都变成未来的自动化能力。环闭合了,AI员工的可靠性才算真正有了保障。
6.2 一份可以直接抄的可靠性工程检查清单
我把每个组件的上线标准列成了一张清单,照着做基本不会漏:
| 组件 | 上线前必须满足的条件 | 关键观测指标 |
|---|---|---|
| 输入校验器 | 每个动作都有明确的出口(proceed/ask_clarify/human_escalate);所有决策有日志 | 误拦截率、澄清率、放行率 |
| 输出评审器 | 三层评审结构齐全;改写次数有上限;业务层硬校验优先 | 评审通过率、改写率、人工二次修改率 |
| 异常上报器 | 异常统一格式;上下文快照完整;事件总线接入所有工具调用 | 异常捕获率、重复异常聚合率、平均定位时长 |
| 记忆回放器 | 人工修正案例100%进入案例库;回放用例可自动执行;偏差超限可告警 | 回归通过率、人工介入趋势、每条case触发的重复次数 |
这张表也回答了一个问题:可靠性工程不只是一个技术动作,更是一组定义清晰、可度量的工程契约。组件化最大的价值就是你终于能用指标来管理AI员工了,而不是天天靠感觉。
6.3 落地时最值得注意的三个实操细节
第一,事件总线不要一上来就引入特别重的消息中间件。我当时直接用了一个发布订阅模式,进程内用回调,跨服务用Redis Stream。够用就好,等到事件量再大再考虑引入专业消息队列,否则组件化本身就会变成一个新的复杂度来源。
第二,上下文快照要控制在合理大小。AI Agent的上下文可能很长,如果异常上报器把全部token都存下来,存储成本会非常吓人。我的做法是存“关键事件摘要”加原始入参出参,不存中间推理过程,只在必要的时候再从日志系统加载完整链路。这样既够排查问题,又不会撑爆存储。
第三,所有组件的配置都必须支持动态调整。输入校验器的风险阈值、输出评审器的评分权重、异常上报器的重试次数、记忆回放器的测试集大小,这些不能靠改代码来调。业务波动时,你经常需要临时把某个阈值调严一点或放宽一点,如果做不到动态配置,组件很快就固化了,反而会变成流程的阻碍。
6.4 我自己的习惯:用一个字段串联所有人工痕迹
最后再分享一个我的习惯。每定义一个组件,我都会在相关事件里保留一个叫human_touch的布尔字段,标记这次流程是否经过了人工干预。输入校验器转人工时置为true,输出评审器转人工时置为true,异常上报器建工单时也置为true。这个字段看着简单,但它让我在几个月后能轻松统计出“这个AI员工每月到底需要多少人工支持”,还能按组件拆解出人工消耗占比。没有这个字段,你的可靠性工程就永远缺少一个最基础的数据源。
这四道回路变成四个组件之后,我最大的感受是:AI员工终于不是靠人盯着的半成品了,它开始在工程体系里有了自己的运行规则、观测数据和持续学习路径。如果你现在也在搭AI Agent,建议先从自己的日志里找出那几道人工回路,别急着上模型,先把兜底组件做扎实。