AI Agent兜底链路设计:从被动转人工到分级优化
2026/9/9 18:15:28 网站建设 项目流程

“AI 处理不了就转人工”,这句话看起来像兜底策略,实际上更像设计上的偷懒。

如果你做过客服机器人、智能助手或者任何带“Agent”字样的系统,一定会遇到类似的灵魂拷问:老板说“AI 搞不定就要能转人工”,产品说“转人工要给用户好体验”,开发说“人工坐席已经开始骂人了,因为机器人天天把烂摊子甩给它们”。

问题出在哪?出在“转人工”这三个字被当成了唯一的兜底方案。AI 一遇到低置信度、多轮歧义、知识缺失,就直接把用户丢给人类。表面上流程闭环了,实际上系统什么都没学会,用户被来回踢皮球,人工成本也没有真正降下来。

这篇文章聊一个更本质的问题:AI Agent 的兜底链路应该如何设计,才能做到“尽量少转人工、转的时候有质量、转完还能反哺 AI”。我会先讲清楚为什么“遇事不决转人工”是反模式,然后从置信度阈值、多级澄清、检索增强、工具调用、坐席交接、反馈闭环几个角度拆解一套可落地的分级兜底方案,并给出完整的 Python 示例代码和排查建议。

如果你正在做智能客服、私域助手、工单系统,或者基于大模型封装企业内部 Agent,这篇文章的核心思路和代码可以直接复用到你的项目里。

1. 这篇文章真正要解决的问题

很多团队做大模型应用时,会把“转人工”当作 AI Agent 的标准配置。流程图大概是这样的:

用户提问 → 意图识别 → 答案生成 → 兜底逻辑 → 转人工

这个流程表面看没有问题,但真正跑起来以后,你会观察到几个典型症状。

第一个症状是转人工率居高不下。模型稍微没把握,系统就触发 human handoff。如果你把日志拉出来看,会发现其中有相当一部分问题根本不难,只是因为提问方式绕了一点、说法不在标准问法里,或者知识库里刚好缺了某个同义词。

第二个症状是人工坐席接到的上下文非常单薄。很多系统转人工时只传一句“用户问了一个问题,我处理不了”,坐席必须重新问一次用户、重新查一遍系统,等于把 AI 本该完成的“信息收集”和“初步诊断”全部推倒重来。

第三个症状是模型永远在原地踏步。转人工之后,没有反馈回流,没有失败样本沉淀,没有知识库补录。明天用户问同样的问题,AI 依然答不上来,依然转人工。系统上线半年,转人工率没有任何变化。

这些症状指向同一个根源:转人工被当成终点,而不是一条需要被持续压缩和优化的兜底路径

从工程上讲,AI Agent 的成熟度不是看它能不能转人工,而是看它在多大比例的场景里可以不转人工,以及不得不转的时候,交接是否高效、是否能带来系统改进。这篇文章要解决的正是这两个问题:怎么设计分级兜底链路来降低转人工率,以及怎么设计带上下文的交接机制来提升转人工质量。

2. 基础概念与核心原理

2.1 什么是 AI Agent 的兜底逻辑

AI Agent 不是一个单一模型,而是一个“感知 → 决策 → 行动 → 反馈”的运行实体。它可能包含大语言模型、意图识别模块、检索模块、多个工具调用、知识库、会话记忆,以及人工坐席系统。

兜底逻辑(Fallback Logic)指的是:当 Agent 在当前链路中无法给出可靠结果时,按照预设策略切换到备用路径的能力

备用路径可以是以下几种:

兜底类型说明成本适用情况
澄清追问让模型主动向用户确认意图意图模糊、信息缺失
检索扩展扩大知识库检索范围或改写问题后重试首次检索未命中
工具调用调用外部 API 或数据库获取动态信息需要实时数据、状态查询
模板引导返回固定引导话术问题确实超出服务边界
人工坐席将会话交给真实客服前序路径全部失败,或用户强烈要求人工

很多系统的错误在于:把最底下那一条“人工坐席”当成默认路径,完全没有尝试上面前四条低成本路径。

2.2 置信度不是一个大模型的自我感觉

要让兜底逻辑可编程,首先得有一个可以判断“我到底行不行”的信号。这个信号通常叫置信度分数(confidence score)。

在经典意图识别模型里,置信度是 Softmax 输出分布中最高类的概率。在基于大语言模型的 Agent 中,置信度可以来自多个维度:

  • 意图分类器输出的概率值
  • LLM 在生成答案时附加的不确定度标记
  • 检索结果与用户问题的相似度分数
  • 模型是否成功调用了工具,以及工具返回是否为空
  • Agent 在 N 次采样中是否得到一致性结果

实际工程里,很少只用单一信号。更常见的做法是把多个信号加权组合成一个 fallback_score:

fallback_score = ( 0.4 * intent_confidence + 0.3 * retrieval_score + 0.3 * response_consistency )

当 fallback_score 低于阈值时,进入兜底链路,而不是直接转人工。这里的关键是:阈值应该基于真实日志调优,而不是拍脑袋

2.3 转人工的三个前置问题

在决定转人工之前,Agent 必须问自己三个问题:

第一个问题是“我理解对了吗”。如果只是意图模糊,那就先澄清,不要急着甩锅。

第二个问题是“我的知识库查够了吗”。如果第一次检索失败,可能是因为同义词、多义表述、问题拆分方式不对。改写检索词、扩大 top-k、做多路召回之后再判断一次,往往能救回不少会话。

第三个问题是“这个任务是不是必须人来完成”。有些任务涉及高权限操作、敏感信息确认、复杂客诉安抚,这些确实需要人工介入。但如果只是查个订单状态、改个备注,Agent 本应通过工具调用自己完成。

转人工应该是这三个问题都认真回答之后的最后一步,而不是第一反应。

3. 环境准备与前置条件

下面进入实操。本文示例采用 Python 编写,核心思路不绑定特定框架。你可以类比迁移到 Spring AI、LangChain4j、RAGFlow 或者其他 Agent 框架中。

建议环境如下:

  • Python 3.9 以上
  • 一个可调用的大模型 API,示例中使用 OpenAI 兼容格式,你也可以替换为国内大模型服务
  • 向量数据库或 Elasticsearch,用于知识检索。示例中为了便于运行,使用内存列表模拟
  • 一个意图识别服务或规则分类器,示例中使用简单关键词加相似度计算代替

依赖安装:

pip install openai numpy

如果你用的是 Spring Boot + Spring AI,依赖对应为:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency>

需要注意的是,本文的代码重点在于“分级兜底链路”的设计,而不是某个具体的模型调用。所以你会看到我把意图识别、检索、工具调用都抽象成了接口。这样无论底层用的是 GPT、文心、通义还是开源模型,骨架逻辑都可以复用。

4. 核心流程拆解:从“直接转人工”到“分级兜底”

4.1 传统的直接转人工流程

传统实现往往写得很简单:

def handle_user_message(message): result = llm.answer(message) if result.low_confidence: return transfer_to_human(message) return result.answer

这段代码的问题一目了然:只要 low_confidence 为真,就转人工。接下来没有任何补救动作。

从日志来看,这种流程下的转人工原因会被笼统归为“AI 处理不了”,但实际上处理不了的原因五花八门:有的是意图没识别出来,有的是知识库里根本没有对应内容,有的是用户问了复合型问题需要拆解,有的是需要查实时数据但 Agent 没有调用工具。没有原因分类,就没有改进方向。

4.2 分级兜底链路的五个层级

改进后的流程分为五层,每一层都尝试用更低成本的方式解决问题,只有前四层全部失败才进入人工坐席。

第一层是澄清。当意图置信度低于高阈值但高于低阈值时,Agent 不直接作答,而是向用户提出一个到两个澄清问题。例如用户说“我要改一下那个”,Agent 应该追问“请问您指的是修改订单地址,还是修改备注信息”。

第二层是检索增强。当澄清后依然无法给出答案,或者检索结果为空时,改写用户问题、扩展同义词、扩大 top-k 召回数量,再做一次检索。这一层非常依赖知识库的索引质量。

第三层是工具调用。如果用户问题涉及实时数据或需要执行具体动作,Agent 应该调用工具。比如查询订单状态、查询库存、创建工单。工具返回成功,就直接回答用户;工具返回失败,则记录失败原因。

第四层是引导与确认。如果问题确实超出当前 Agent 的服务边界,不要假装能答,而是给出可理解的边界说明和替代路径。例如“我这里无法直接办理发票开具,但已为您生成了发票申请工单,您也可以前往官网财务中心处理”。

第五层才是人工坐席。但这里的转人工不是简单甩一个用户消息过去,而是把意图识别结果、检索记录、工具调用记录、Agent 尝试过的方案、用户情绪倾向、建议动作全部打包,同步给坐席系统。

4.3 每条路径都要有记录

分级兜底链路能持续变好的前提是:每一层是否触发、触发后是否成功、最终走向哪一层,都要落到日志里。后续通过这些日志分析转人工原因分布,才能有针对性地补知识、调阈值、改话术。

所以在设计数据结构的时候,一定要把“流程轨迹”作为一等公民。下面代码示例中你会看到兜底结果对象里专门有一个 steps 字段,就是用来记录轨迹的。

5. 完整示例与代码实现

5.1 定义兜底结果结构

文件路径:agent/fallback.py

from dataclasses import dataclass, field from enum import Enum from typing import Any, List, Optional class FallbackLevel(str, Enum): DIRECT_ANSWER = "direct_answer" # 直接回答,无需兜底 CLARIFY = "clarify" # 澄清追问 RETRIEVAL = "retrieval_expand" # 检索扩展 TOOL_CALL = "tool_call" # 工具调用 GUIDANCE = "guided_alternatives" # 引导替代路径 HUMAN_HANDOFF = "human_handoff" # 转人工坐席 @dataclass class AgentStep: """记录 Agent 每一层决策的轨迹。""" level: str action: str detail: Any = None @dataclass class FallbackResult: """Agent 处理用户消息的最终结果。""" level: FallbackLevel reply: str steps: List[AgentStep] = field(default_factory=list) handoff_payload: Optional[dict] = None

这个数据结构的核心价值在于steps字段。无论最终走到哪一层,整个决策链路都被记录下来,便于日志分析和坐席交接。

5.2 实现置信度分层判断

文件路径:agent/scoring.py

def decide_level(confidence: float, clarify_threshold: float = 0.6, answer_threshold: float = 0.85) -> str: """ 根据置信度决定当前应该采用的层级。 - confidence >= answer_threshold: 直接回答 - clarify_threshold <= confidence < answer_threshold: 澄清 - confidence < clarify_threshold: 进入检索扩展或转人工 """ if confidence >= answer_threshold: return "direct" if confidence >= clarify_threshold: return "clarify" return "fallback_retrieval" def combine_confidence(intent_conf: float, retrieval_conf: float, consistency_conf: float) -> float: """ 将多个信号合成最终置信度。 这里的权重需要根据真实日志回归调整。 """ return 0.4 * intent_conf + 0.3 * retrieval_conf + 0.3 * consistency_conf

这里有一个容易被忽视的点:decide_level里的两个阈值不是配置完就一劳永逸的。你需要拿历史会话日志做统计,找到“哪些会话在 0.6 到 0.85 之间”,再人工抽样看这个区间里有多少其实是能答对的。如果答对比例高,可以适当下调answer_threshold到 0.8,让 Agent 更自信一点,减少不必要的澄清。

5.3 实现分级兜底编排器

文件路径:agent/orchestrator.py

import json class IntentService: """模拟意图识别服务,真实项目中可替换为 NLU 模型或 LLM 分类。""" def recognize(self, message: str) -> tuple[str, float]: # 返回 (意图标签, 置信度) # 这里用关键词模拟,真实场景请接入专用模型 if "订单" in message and "查" in message: return "query_order", 0.92 if "退款" in message: return "refund_request", 0.88 if "改" in message and ("地址" in message or "备注" in message): return "modify_order", 0.72 return "unknown", 0.35 class RetrievalService: """模拟知识库检索,真实项目中建议使用向量数据库。""" def __init__(self): self.docs = [ {"id": 1, "title": "退款政策", "content": "用户可在签收后7天内申请退款"}, {"id": 2, "title": "修改订单地址", "content": "订单未发货前可通过人工客服修改地址"}, {"id": 3, "title": "发票开具", "content": "发票开具需在财务中心提交申请"}, ] def search(self, query: str, top_k: int = 1) -> list[dict]: # 简化:用关键词匹配模拟向量检索 matched = [] for doc in self.docs: score = 0.0 for token in query.split(): if token in doc["title"] or token in doc["content"]: score += 0.5 if score > 0: doc_copy = dict(doc) doc_copy["score"] = score matched.append(doc_copy) matched.sort(key=lambda x: x["score"], reverse=True) return matched[:top_k] def expand_query(self, query: str) -> str: # 模拟查询改写:把口语说法转成更贴近知识库的说法 replacements = { "查一下": "查询", "怎么弄": "如何", "修改": "修改", "地址": "地址", } for word, new_word in replacements.items(): query = query.replace(word, new_word) return query class ToolService: """模拟工具调用,用于查询订单状态等动态数据。""" def call(self, tool_name: str, params: dict) -> dict: # 真实场景中这里会调用订单系统、CRM 等 API if tool_name == "query_order_status": return {"success": True, "status": "已发货", "tracking_no": "SF1234567890"} return {"success": False, "error": "unsupported_tool"}

文件路径:agent/fallback_orchestrator.py

from agent.fallback import FallbackResult, AgentStep, FallbackLevel from agent.scoring import decide_level, combine_confidence from agent.orchestrator import IntentService, RetrievalService, ToolService class FallbackOrchestrator: """ 分级兜底编排器。 核心思路: 1. 先判断置信度层级 2. 低置信度先澄清,再检索扩展,再工具调用 3. 所有路径失败才转人工,且带上完整上下文 """ def __init__(self): self.intent_service = IntentService() self.retrieval_service = RetrievalService() self.tool_service = ToolService() self.steps = [] def handle(self, message: str) -> FallbackResult: self.steps = [] intent, intent_conf = self.intent_service.recognize(message) self.steps.append(AgentStep("intent", "recognize", {"intent": intent, "conf": intent_conf})) # 第一层:直接回答 if intent_conf >= 0.85: return FallbackResult( level=FallbackLevel.DIRECT_ANSWER, reply=self._direct_answer(intent), steps=self.steps, ) # 第二层:澄清 if intent_conf >= 0.6: self.steps.append(AgentStep("clarify", "ask_user_confirm", {"intent": intent})) return FallbackResult( level=FallbackLevel.CLARIFY, reply="您是想查询订单状态,还是需要修改订单信息?为了准确处理,请补充一下具体需求。", steps=self.steps, ) # 第三层:检索扩展 + 工具调用 expanded = self.retrieval_service.expand_query(message) docs = self.retrieval_service.search(expanded, top_k=2) self.steps.append(AgentStep("retrieval", "expand_and_search", {"expanded": expanded, "docs_num": len(docs)})) if docs: return FallbackResult( level=FallbackLevel.RETRIEVAL, reply=f"根据知识库内容,为您找到以下信息:{docs[0]['content']}", steps=self.steps, ) if "订单" in message and "查" in message: tool_result = self.tool_service.call("query_order_status", {"user_id": "demo"}) self.steps.append(AgentStep("tool", "query_order_status", tool_result)) if tool_result.get("success"): return FallbackResult( level=FallbackLevel.TOOL_CALL, reply=f"您的订单当前状态为:{tool_result['status']},物流单号是{tool_result['tracking_no']}。", steps=self.steps, ) # 第四层:引导替代路径(不直接转人工) self.steps.append(AgentStep("guidance", "offer_alternative", {"reason": "all_fallback_failed"})) return self._handoff_with_context(message, intent) def _handoff_with_context(self, message: str, intent: str) -> FallbackResult: """转人工时携带完整上下文,而不是只丢一句转人工。""" handoff_payload = { "user_message": message, "intent": intent, "steps": [s.__dict__ for s in self.steps], "suggested_action": "请优先核实订单状态或引导用户前往订单详情页自助查询", "user_sentiment": "unknown", } return FallbackResult( level=FallbackLevel.HUMAN_HANDOFF, reply="好的,这个问题我需要为您转接人工客服。您的会话信息和上下文会同步给坐席,请稍候。", steps=self.steps, handoff_payload=handoff_payload, ) def _direct_answer(self, intent: str) -> str: if intent == "query_order": return "您可以通过订单列表查看最新状态,也可以告诉我订单号,我来帮您查询。" if intent == "refund_request": return "退款需要符合签收后 7 天内的政策,您可以提交退款申请。" return "抱歉,我暂时无法直接处理这个需求,请补充更多信息。"

这段代码演示了最关键的设计变化:handle方法中,Agent 不是一遇到低置信度就跳到最后一步,而是依次尝试澄清、检索扩展、工具调用,最后才转人工。转人工时,handoff_payload里包含了完整的决策轨迹和建议动作,坐席无需让用户重新描述问题。

6. 运行结果与效果验证

为了验证分级兜底的效果,我们写一个简单的测试脚本,模拟几种典型的用户输入。

文件路径:test_demo.py

from agent.fallback_orchestrator import FallbackOrchestrator def main(): bot = FallbackOrchestrator() test_cases = [ "查一下我的订单", "我要退款", "我想改一下那个", "怎么修改订单地址啊", "你们能开发票吗", ] for msg in test_cases: result = bot.handle(msg) print(f"\n用户: {msg}") print(f"层级: {result.level.value}") print(f"回复: {result.reply}") if result.handoff_payload: print(f"坐席交接建议: {result.handoff_payload.get('suggested_action')}") print(f"决策步骤数: {len(result.steps)}") if __name__ == "__main__": main()

运行命令:

python test_demo.py

预期输出如下:

用户: 查一下我的订单 层级: direct_answer 回复: 您可以通过订单列表查看最新状态,也可以告诉我订单号,我来帮您查询。 用户: 我要退款 层级: direct_answer 回复: 退款需要符合签收后 7 天内的政策,您可以提交退款申请。 用户: 我想改一下那个 层级: clarify 回复: 您是想查询订单状态,还是需要修改订单信息?为了准确处理,请补充一下具体需求。 用户: 怎么修改订单地址啊 层级: retrieval_expand 回复: 根据知识库内容,为您找到以下信息:订单未发货前可通过人工客服修改地址。 用户: 你们能开发票吗 层级: human_handoff 回复: 好的,这个问题我需要为您转接人工客服。您的会话信息和上下文会同步给坐席,请稍候。

从输出可以看出几个关键结论:

  • 对于明确的高置信度问题,Agent 直接回答,不打扰用户。
  • 对于模糊表达“我想改一下那个”,Agent 不直接转人工,而是先追问澄清。
  • 对于口语化但知识库能覆盖的问题,通过检索扩展成功回答。
  • 只有真正超出当前知识边界的问题,比如发票开具,才最终转人工。

验证成功的标准很简单:在同样一批测试语料下,分级兜底流程的转人工数量应当明显少于直接转人工流程。你可以把两种实现跑在同一批线上日志上做离线对比,统计转人工率、澄清采纳率、检索命中率三个指标。

如果运行失败,第一步先看打印出的步骤轨迹。steps数组里会清楚记录是意图识别失败、检索未命中还是工具调用异常。找到失败层级后,针对性修复对应模块即可。

7. 常见问题与排查思路

分级兜底链路引入后,会遇到一些新问题。下面这张表格整理了我认为最需要关注的几类场景。

问题现象可能原因排查方式解决方案
转人工率不降反升澄清阈值设置过高,导致大量会话进入澄清流程,用户不耐烦后要求人工统计澄清触发率和用户在澄清后放弃会话的比例调低 clarify_threshold,或优化澄清话术为选择题形式
检索扩展没有救回会话expand_query 改写规则太简单,同义词覆盖不足打印 expanded 结果,人工判断改写质量改用 LLM 做查询改写,或引入词向量召回
工具调用返回失败工具参数缺失、下游系统报错、权限不足查看 tool call 的 detail 字段中的错误信息增加工具参数校验和重试机制,失败时重试一次再转人工
用户反复要求转人工用户对 AI 不信任,或前几轮体验不好分析会话轨迹,看用户在第几轮失去耐心在检测到用户负面情绪时,提前进入人工,不必强行走完所有层级
坐席接到 Handoff 仍需要重新询问handoff_payload 里关键信息缺失对比坐席工单字段和 payload 字段统一设计交接数据结构,包含意图、轨迹、建议动作、用户侧已完成的操作

这里最值得强调的一点:分级兜底不是无限兜底。如果用户已经明确说了“我要人工”,或者用户在三个澄清回合内反复表达烦躁情绪,就不要再用检索和工具路径拖延用户时间。此时应该立刻转人工,并且把“用户主动要求人工”作为一条独立原因记录,不能把它算作 AI 失败。

另一个容易踩坑的地方是阈值调整。不要凭感觉把 answer_threshold 从 0.85 调到 0.9,然后期待转人工率下降。阈值的调整必须基于离线评测集,确保调高后不会出现大量错误回答。建议每次调整阈值后,先在历史日志上做回放对比,再灰度上线。

8. 最佳实践与工程建议

8.1 把“转人工原因”作为一等指标

不要只统计转人工率,要统计转人工原因分布。建议原因枚举至少包括:意图不明、知识缺失、工具失败、用户主动要求、风险操作确认、情感安抚。每个转人工事件都必须带有原因标签,这样每周复盘时,团队才能知道最该优先解决的是知识库覆盖、意图模型,还是工具稳定性。

8.2 转人工坐席交接必须包含“建议动作”

很多系统在交接时只传“用户说了什么”,却没有“Agent 已经尝试过什么”。坐席拿到一个没有上下文的会话,只能重新问一遍。建议在手写交接协议时强制要求以下字段:

  • user_message:用户原始输入
  • intent:Agent 识别出的意图
  • confidence:置信度
  • tried_steps:Agent 已经尝试过的处理路径
  • reason_code:转人工原因枚举
  • suggested_action:给坐席的下一步建议

这样坐席的响应时间会明显缩短,用户体验也会好很多。

8.3 建立失败会话回流机制

每次转人工后,人工坐席应该能够标记“这个问题本可以由 AI 解决”或“知识库缺少 Q”。这些标记要回流到知识库维护流程中。建议每周提取被标记的会话,由运营或算法工程师补充知识条目,并在下一轮评测中验证新知识是否生效。这是整个闭环里最容易被忽略却最有价值的一步。

8.4 安全边界与授权确认

如果 Agent 的工具调用涉及修改数据、退款操作、发送短信等敏感动作,不要只靠置信度判断。建议对高危操作单独设置二次确认,或者要求用户提供额外的身份验证信息。转人工时,也不要无脑把用户隐私数据和完整对话轨迹抛给坐席系统,要根据最小权限原则做字段脱敏和权限校验。

8.5 从工程上预留灰度开关

分级兜底链路不是一个只能整体上线或下线的模块。建议为每一层设计独立开关。例如线上出现检索服务超时,可以临时关闭检索扩展层,直接跳到引导或人工,而不需要回滚整个 Agent 服务。开关配置建议放在配置中心,而不是写死在代码里。

9. 总结与后续学习方向

这篇文章围绕“AI 为什么不能一遇到问题就转人工”展开,核心结论是:转人工不是兜底方案,而是兜底链路中成本最高、最应该最后触发的一层。真正成熟的 AI Agent 应当具备多级兜底能力,按顺序尝试澄清、检索扩展、工具调用、引导替代路径,并且在不得不转人工时,携带完整的决策轨迹和建议动作。

文章中给出的置信度分层、FallbackResult 数据结构、Orchestrator 编排逻辑,以及转人工原因分类,可以直接作为你改造现有客服机器人或 Agent 项目的参考骨架。建议你先拿一个星期历史日志做离线回放,对比直接转人工和分级兜底两种方案在转人工率、人工处理时长两个指标上的差异,再决定是否灰度上线。

后续值得深入的方向包括:基于 LLM 的查询改写、多路召回与重排序、Agent 工具调用的可靠性设计、坐席工单系统的数据打通、以及基于用户反馈的阈值自动调优。如果你在用 Spring AI 或 LangChain4j 做企业级应用,也可以把这套分级兜底思路翻译成对应的 Filter 或 Chain 组件。这里真正的难点不在于代码,而在于你愿不愿意承认:每一次转人工,都是系统在告诉你某个环节还没做好。

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

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

立即咨询