AI Agent转人工机制设计实战:从降级策略到上下文工单
2026/9/10 19:34:03 网站建设 项目流程

这次我们聊一个 AI Agent 项目里最容易被低估的设计:转人工机制。很多团队把“转人工”当成保险丝,模型答不上来就转人工,用户连续追问两次就转人工,工具调用报错也转人工。最后做出来的不是一个 AI Agent,而是一个“人工客服中转站”。这轮实战记录把问题拆开讲:AI 为什么不能一遇到问题就转人工,转人工的触发条件应该怎么设计,以及转人工之后信息怎么交接才能不丢上下文。

先说结论:转人工不是兜底方案,转人工是最后一道防线。如果 Agent 的第一反应是转人工,那说明意图识别、知识检索、工具调用和话术兜底这几层都没有发挥作用。转人工每触发一次,就相当于把一次本该由系统消化的成本转嫁到人工团队身上。短期看问题解决了,长期看模型没有因为“解决不了的问题”发生任何改变,转人工率会一直居高不下。

这篇内容面向正在做 AI 客服、AI 助手、内部知识问答这类 Agent 项目的同学。你会看到:给 Agent 设计一套从重试到澄清再到转人工的分级降级策略,如何用置信度决定是否触达人工,转人工前如何把上下文打包成工单,以及转人工率这个指标怎么压测和优化。核心代码用 Python 伪代码写,可以直接按你的项目结构改。

1. 为什么说“一遇到问题就转人工”是反面实践

1.1 转人工的隐性成本

很多项目组把转人工率当作一个“安全指标”:只要转人工了,就默认 AI 没有乱答,至少没闯祸。但转人工的成本并不是“用户被转走”那一瞬间才产生的。用户被转走后需要重新描述问题,人工客服需要重新阅读上下文,如果在转人工时 AI 又没有提供足够的对话摘要,用户会明显感受到服务的断裂感。等待人工接管的几分钟里,用户可能已经失去耐心。

更要命的是,转人工率过高会直接掩盖 Agent 的能力缺陷。设想一个企业内部知识问答 Agent,上线第一周转人工率 15%。如果团队把“转人工”当成正常的兜底路径,那这个 15% 会被一直保留下去。没有人会去分析这 15% 到底是什么问题、分布在哪些意图、知识库里缺了什么文档。时间一长,Agent 能自动处理的问题比例不会增长,人工团队的工作量也不会下降,这个项目的价值就无法体现。

从成本模型上看,转人工的代价可以拆成三部分:一是人工处理的人力成本,二是用户等待和重复描述带来的体验损耗,三是问题没有被系统自动吸收带来的长期能力缺失。前两点是显性成本,第三点才是转人工率过高的真正风险。Agent 系统如果没有机制从“解决不了的问题”中学习,那它永远停留在原地,只能做简单问题分流。

1.2 什么时候才应该转人工

反过来说,转人工当然不能完全取消。有些场景是 AI 不该碰的:涉及退款、账号安全、法律条款解释、医疗建议、情绪激烈投诉,这些场景即使模型有 90% 的置信度,也应该走人工审核。这里的原则是“风险优先于效率”:宁可多转一个,不能漏转一个。

另外,用户明确要求“转人工”“叫客服”“我要投诉”时,Agent 不应该反复挽留。这时候最好的体验是马上转,并且在转人工前把已经收集到的信息一并交给人工,让用户不需要再重复一遍。这个点非常关键,因为很多实现里“转人工”就是把会话切换到另一个队列,上下文却断了。

所以正确的思路不是“能不能不转人工”,而是“在什么条件下允许 AI 继续自救,在什么条件下必须转人工”。把这两种情况做成显式规则,用测试数据持续迭代。

2. AI Agent 自救层级:把转人工推到最后

转人工之前,Agent 至少应该有五级自救手段。每一级都是独立的处理逻辑,上一级失败才进入下一级。这样设计的好处是每级都可以单独测试,不会出现“一失败就跳到转人工”的黑箱行为。

2.1 第一层:重试与容错

第一层解决的是“偶发故障”。LLM 接口超时、工具 API 返回 500、JSON 解析失败,这些都不代表问题本身解决不了,很可能是网络抖动或服务临时不可用。此时直接转人工,等于把一个临时故障放大了成一次人工工单。

建议在 Agent 的工具调用层做统一的失败重试机制。核心原则是:区分“可重试错误”和“不可重试错误”。超时、5xx、限流属于可重试;参数错误、鉴权失败、业务规则校验失败属于不可重试。不要把两类错误混在一起处理。

# 工具调用重试逻辑,简化版 import time from tenacity import retry, stop_after_attempt, wait_exponential RETRYABLE_STATUS = {500, 502, 503, 504} @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10)) def call_order_api(order_id: str) -> dict: resp = http_client.post("/api/order/detail", json={"order_id": order_id}) if resp.status_code in RETRYABLE_STATUS: raise RuntimeError(f"temporary error: {resp.status_code}") if resp.status_code != 200: raise ValueError(f"business error: {resp.status_code} {resp.text}") return resp.json()

这个例子说明一个关键点:工具调用的重试要在 Agent 框架层做,而不是在每个业务工具里重复写。重试两到三次仍然失败,才开始进入下一级自救,而不是转人工。

2.2 第二层:澄清与反问

很多“回答不了”的问题,其实是用户没把问题说清楚。比如用户只问“这个怎么弄”,不加对象、不加上下文。Agent 这时候直接转人工,等于把一个“信息不足”的问题甩给了人工。

澄清策略要注意两点。第一,澄清要给出可选项,不要开放式提问。开放式提问会让用户觉得你在敷衍,而给出选项能帮助用户更快确认意图。第二,澄清必须有次数上限。如果澄清了两轮用户仍然无法表达清楚,那就不该继续追问,而应该进入后面的检索或转人工判断,避免无限循环。

例如,用户问“怎么退款”,Agent 应该先判断当前会话有没有订单上下文。没有上下文时,回复:“您是想退哪一笔订单?可以给我订单号,或者告诉我您在哪个页面看到的入口。”这个追问本身不是转人工,而是把问题信息补全。

2.3 第三层:知识库检索与多路召回

澄清之后,Agent 需要检索知识库。但很多项目的检索只有一路:把用户问题向量化,到向量库做相似度检索,top5 没有相关结果就直接转人工。这种做法太粗糙。

更稳妥的是多路召回。除了向量检索,还要做关键词检索、同义词改写检索、文档标题检索。有时候向量检索召回不到,是因为问题里的关键词和文档里的用词不一致。比如用户问“怎么开发票”,文档里写的是“发票申请流程”,向量相似度可能不够高,但关键词检索能命中。

多路召回之后再做重排,把各路结果合并、去重、打分。如果重排后仍然没有超过阈值的答案,这时候才认为“知识库真的没有覆盖这个问题”。这一层做完,还没有进入转人工,因为 Agent 还可以尝试工具调用,或者给出替代性建议。

2.4 第四层:工具调用与外部系统查询

知识库没答案,不代表系统无法解决问题。很多业务问题需要查询订单系统、库存系统、CRM 系统才能回答。Agent 在这个层级要通过工具调用获取结构化数据,再结合知识库内容生成回答。

工具调用的失败模式需要细分。最常见的问题是“工具本身正常,但数据不存在”。比如用户问“我的订单到哪了”,订单系统返回“订单号不存在”。这不是工具故障,而是用户给的信息有问题。此时 Agent 的错误处理应该引导用户核对订单号,而不是转人工。

判断工具结果时要注意:工具返回空结果”和“工具调用异常”是两个完全不同的状态。前者说明系统内确实没有这个数据,后者说明系统暂时不可用。不要把两者都塞进同一个异常分支里。

2.5 第五层:让步式回答与替代方案

如果知识库和工具都拿不到确切答案,Agent 不要直接说“不知道”。更好的做法是给出替代方案或近似答案,同时标明不确定性。

例如用户问“我们公司能不能报销这个项目费用”,知识库里没有这一条具体说明。Agent 可以回复:“目前知识库里没有找到该项目费用的明确说明。从现有政策看,类似项目通常需要三级审批。建议您查看知识库文档《费用报销细则》第 4.2 节,或者直接联系财务同事确认。”这段话虽然没有完全解决用户问题,但给了用户下一步动作,比一句“不知道”有价值得多,也可以降低不必要的转人工频次。

3. 转人工的判断核心:置信度与边界规则

3.1 置信度从哪来

转人工不能靠“猜”,需要把判断逻辑显式化。常见的置信度信号可以分成三类:意图识别的置信度、检索结果的相关度得分、工具调用失败的类型和次数。

意图识别置信度来自分类模型或 LLM 结构化输出。可以让 LLM 在输出意图时同时输出一个 0 到 1 的 confidence 字段。这个值不是精确概率,但可以作为决策参考。关键是每次判断后要有日志,后续用线下数据校准阈值。

检索相关度得分需要设置一个下限。低于下限时,即使 LLM 强行生成了答案,答案也可能是在“编”。这一层要结合模型校准来判断:宁可让模型说“没有找到资料”,也不要让它顺着用户的话生成一个没有依据的答案。

工具调用失败次数是另一个重要信号。如果一个 Agent 在单轮对话里连续失败 3 次,继续让它自愈的意义已经不大。它可能遇到了配置错误、权限不足或外部系统持续故障,这些都不是“多问一遍”能解决的。

3.2 用规则函数控制转人工

把上面的信号整合成一个判断函数,业务人员可以直接改阈值,测试人员可以批量跑测试数据。

def should_escalate(conv_state: dict) -> bool: """ 判断当前对话是否需要转人工。 返回 True 表示转人工,False 表示 Agent 继续自救。 """ # 1. 用户明确要求人工,直接转 if conv_state.get("user_request_human"): return True # 2. 高危业务意图,无条件转人工 danger_intents = {"refund", "complaint", "legal", "medical", "account_security"} if conv_state.get("intent") in danger_intents: return True # 3. 自救次数已经超过上限 if conv_state.get("retry_count", 0) >= 3: return True # 4. 置信度低,并且问题有一定敏感度 confidence = conv_state.get("confidence", 0.0) sensitivity = conv_state.get("sensitivity", 0.0) if confidence < 0.4 and sensitivity > 0.6: return True return False

这个函数的逻辑顺序很重要。先判断硬性规则,再判断软性置信度。硬性规则是不允许通过调低置信度阈值来绕过的,比如高危意图和用户主动要求人工。顺序反过来的话,可能出现“用户都要求转人工了,系统还因为置信度不够高而继续自救”的荒唐局面。

3.3 让 LLM 输出结构化置信度

实际工程中,可以通过约束 LLM 输出 JSON 来获得 confidence 字段。下面是一个简化示例:

def predict_intent_with_confidence(dialogue: list[dict]) -> dict: prompt = ( "根据用户最近的对话内容,判断用户的核心意图。\n" "输出 JSON:{\"intent\": \"意图名称\", \"confidence\": 0-1的小数, " "\"need_clarify\": true/false, \"sensitivity\": 0-1的小数}\n" "sensitivity 表示问题涉及资金、法律、医疗、账号安全等敏感程度,越高越敏感。" ) resp = llm.chat( messages=[ {"role": "system", "content": prompt}, {"role": "user", "content": format_dialogue(dialogue)}, ], response_format={"type": "json_object"}, ) return json.loads(resp.content)

有一点要强调:LLM 输出的 confidence 不是真正的模型概率,它只是模型对自己的自我评估。这个值会受 prompt 影响,也可能存在过度自信。所以不能把 confidence 当成唯一判断依据,必须和规则、外部工具结果组合使用。上线后要定期抽取样本,人工标注“当时该不该转人工”,再去校准阈值,而不是一次性定死。

4. 转人工工单设计:不丢上下文,不重复描述

转人工最伤体验的不是“转走了”,而是“用户需要重新说一遍”。要避免这个问题,Agent 在转人工前必须生成一份结构化的上下文摘要,和会话一起提交给人工客服工作台。

4.1 工单应该包含哪些内容

一份合格的转人工工单至少要有六个部分:用户基本信息和意图、对话摘要、Agent 已尝试的路径、工具调用结果、敏感标记、建议下一步动作。

对话摘要是给人工客服快速阅读的,不要直接把原始聊天记录全量贴过去。Agent 已尝试的路径可以让客服知道用户已经被问过什么、查过什么,避免重复询问。工具调用结果里面如果有订单号、报错信息这类结构化数据,也要直接写进去。

{ "ticket_id": "TK20250117001", "user_id": "u_123456", "intent": "order_status", "summary": "用户询问订单 20250112_088 的物流状态,Agent 在订单系统中查到订单已发货,但物流接口两次请求超时。", "agent_tried": [ {"step": "retry", "result": "failed_2_times"}, {"step": "tool_call", "tool": "order_api", "result": "success"}, {"step": "tool_call", "tool": "logistics_api", "result": "timeout"} ], "structured_data": { "order_id": "20250112_088", "status": "shipped" }, "sensitive_flags": ["high_value_order"], "suggested_next_action": "查询物流接口异常原因,联系仓库确认包裹当前位置" }

这样人工客服一上来就能看到问题全貌,可以直接进入处理,而不是花两分钟读聊天记录。

4.2 转人工后的反馈闭环

转人工本身不应该是一个终点。人工客服处理完问题后,系统应该记录:这个问题最终是如何解决的、参考了哪份文档、调用了哪个系统。这些信息是知识库补充和 Agent 能力优化的关键素材。

如果人工解决了问题但知识库中没有对应内容,可以考虑把该问题的标准答案沉淀进知识库;如果人工发现是 Agent 误判了用户意图,那要回去优化意图识别逻辑。转人工率不是越低越好,更合理的指标是“转人工后的人工无效处理率”:如果人工接手后发现问题其实很常规,说明 Agent 转得太早了。

5. 状态机与主循环实现:把整个流程串起来

到此为止,各层自救和转人工判断都是分散的逻辑。要把它们组织成一个可运行的 Agent 主循环,建议引入简单的状态机。状态包括接收输入、澄清、检索、工具调用、生成回复、转人工六个状态。

在实际项目中,不需要引入复杂的状态机框架,用枚举加条件分支就能实现。关键是每个状态都有明确的进入条件和退出条件,方便排查问题。

from enum import Enum class AgentState(str, Enum): COLLECT_INPUT = "collect_input" CLARIFY = "clarify" RETRIEVE = "retrieve" TOOL_CALL = "tool_call" RESPOND = "respond" ESCALATE = "escalate" def agent_loop(conv_state: dict) -> dict: """ 简易 Agent 主循环。省略了持久化、日志、鉴权等细节。 """ state = AgentState.COLLECT_INPUT while True: if state == AgentState.COLLECT_INPUT: # 接收用户消息,进入意图识别 user_msg = receive_user_message(conv_state) conv_state["last_user_msg"] = user_msg intent_info = predict_intent_with_confidence(conv_state) conv_state.update(intent_info) if should_escalate(conv_state): state = AgentState.ESCALATE elif intent_info.get("need_clarify"): state = AgentState.CLARIFY else: state = AgentState.RETRIEVE elif state == AgentState.CLARIFY: clarity_count = conv_state.get("clarity_count", 0) if clarity_count >= 2: state = AgentState.ESCALATE else: ask_clarify_question(conv_state) conv_state["clarity_count"] = clarity_count + 1 state = AgentState.COLLECT_INPUT elif state == AgentState.RETRIEVE: docs = multi_recall(conv_state["last_user_msg"]) if docs: conv_state["retrieved_docs"] = docs state = AgentState.TOOL_CALL else: # 知识库没有命中,尝试工具调用 state = AgentState.TOOL_CALL elif state == AgentState.TOOL_CALL: tool_result = run_tool_with_retry(conv_state) conv_state["tool_result"] = tool_result if tool_result.get("exhausted_retry"): state = AgentState.ESCALATE else: state = AgentState.RESPOND elif state == AgentState.RESPOND: answer = generate_answer(conv_state) send_user_message(conv_state["user_id"], answer) if should_escalate_after_response(conv_state): state = AgentState.ESCALATE else: state = AgentState.COLLECT_INPUT elif state == AgentState.ESCALATE: ticket = build_escalation_ticket(conv_state) handoff_to_human(ticket) return conv_state

这类实现的优点是调试起来非常直观。任何一个 Agent 回答异常,只要看一眼当前状态是停在哪个分支,就能快速定位问题是出在检索、工具调用还是置信度判断。比“遇到问题就转人工”的黑盒方案好排查得多。

6. 转人工率的压测与指标观察

6.1 准备测试集

转人工机制上线后,不能只看线上真实流量,还要准备一套离线测试集做回归验证。测试集要覆盖五类样本:普通问题、模糊问题、边缘问题、情绪化问题、高危敏感问题。

普通问题用来验证基础解决率没有退化。模糊问题用来验证澄清机制是否有效,比如用户只说“这个怎么弄”而没有指代对象。边缘问题是指知识库里有相关内容但检索容易漏掉的场景。情绪化问题和高危敏感问题用来验证转人工的硬性规则是否触发,这类样本必须保证绝对安全。

每个样本除了输入对话,还要标注期望结果。期望结果可以是“AI 直接解决”“AI 澄清后解决”“转人工”“AI 给出替代建议”四类。标注的时候可以多人交叉评审,尽量避免把标准定得太主观。

6.2 核心指标组合

单看转人工率这一个指标没有意义,它必须和解决率、澄清次数、人工处理结果一起看。

转人工率衡量的是“多少对话最终被移交给了人工”。如果这个值突然升高,要先看是不是意图识别出现了漂移。解决率衡量的是“Agent 能独立解决的问题比例”。澄清次数太频繁会让用户烦躁,所以澄清超过三次的会话占比也要监控。

还有一个容易被忽视的指标:人工客服收到工单后的“无效工单率”。如果转人工工单里大量属于常规问题,说明 Agent 的自救层级没有正常生效,模型大概率在“偷懒转人工”。

6.3 调参方法

调整转人工策略时,每次只改一个变量。比如先固定危险意图清单,然后调整 confidence 阈值,跑一遍离线测试集。记录转人工率和解决率的变化曲线。

如果 confidence 阈值从 0.5 降到 0.3,转人工率下降,同时解决率也没有明显下降,说明原来的阈值过于保守。但如果解决率也随之下降,说明 Agent 在低置信度场景下不具备足够能力,这时候不应该继续降阈值,而应该补知识库或优化检索。

7. 常见问题与排查方法

问题现象可能原因排查方式解决方案
转人工率突然升高意图识别漂移,或新上线功能改变了对话分布对比近三天意图分布和转人工日志重新校准意图分类,补充新功能上下文
用户被反复转人工转人工后没有反馈闭环,知识库未更新检查工单回流流程是否生效建立人工处理后的知识沉淀机制
转人工工单缺少上下文构建工单时未收集工具调用结果查看工单构建函数,确认是否传入了 conv_state 全量字段在 build_escalation_ticket 中补全关键字段
Agent 遇到临时故障直接转人工重试机制未生效或超时时间过短查看工具调用日志中的错误码增加按错误码分类的重试策略
澄清问题导致用户流失澄清轮次太多或提问太开放分析澄清后用户是否继续输入限制最多两轮澄清,问题改成选择题
高危意图没有触发转人工意图识别结果不包含 danger_intents 中定义的词查看该会话的 intent 字段补全意图别名映射,增加同义表达

8. 最佳实践与项目落地建议

转人工机制不是一次性能做完的,建议按下面的节奏分阶段落地。

第一阶段只做硬性规则:用户要求人工立即转接,高危意图无条件转人工。这个阶段不需要做置信度判断,先把安全底线守住。

第二阶段加入置信度判断和自救层级:重试、澄清、多路召回、工具调用逐步接入。每接入一个层级,跑一遍离线测试集,确认转人工率和解决率的变化。

第三阶段做转人工后的反馈闭环:人工工单处理结果回流到知识库和意图识别模型。这一步是长期降低转人工率的关键。只有让系统从人工处理中学习,自动化能力才会持续提升,而不是停留在固定的规则阈值上。

还要特别注意合规边界。涉及真实用户的退款、账号、投诉等信息时,转人工前要做好数据脱敏和权限管控。如果 Agent 处理的是医疗、法律、金融建议,系统必须明确标注“AI 生成内容仅供参考,最终以人工审核为准”。这类场景宁可多转人工,也不能为了指标好看而放宽安全规则。

9. 总结与下一步

这一期从“AI 为什么不能一遇到问题就转人工”入手,把 Agent 的降级链路完整过了一遍。核心就三件事:第一,给 Agent 配上重试、澄清、知识库检索、工具调用这四级自救手段,把转人工推到第五级;第二,把转人工的触发条件变成显式规则,高危意图和用户明确要求是硬性条件,置信度阈值是可调参数;第三,转人工不是甩锅,要把上下文摘要、尝试路径、结构化数据打包成工单,再把人工处理结果回流到系统。

如果你现在正在做 AI 客服或企业助手类 Agent,可以从最小的转人工规则开始,不要一上来就追求复杂的置信度模型。先记录每次转人工的会话日志,跑一个月之后做一次人工分析,你会发现大部分转人工样本都集中在几个固定原因上。把这些问题先解决,比调模型参数更有效。下一期可以聊一聊这些转人工日志如何做自动化归因,把人工处理结果变成 Agent 持续进化的数据燃料。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询