客服 AI 应用工程 2026:意图路由、澄清与转人工
把大模型接进客服系统,难点不在模型,而在于把一段自然语言对话翻译成可路由、可补全、可交接、可计费的工单状态机。本文给出一套从意图分层到 outcome 结算的完整落地方法。
约 54 分钟阅读16,029 字1 次阅读博主

把大模型接进客服系统,难点不在模型,而在于把一段自然语言对话翻译成可路由、可补全、可交接、可计费的工单状态机。本文给出一套从意图分层到 outcome 结算的完整落地方法。

导语:把大模型接进客服系统,难点不在模型,而在于把一段自然语言对话翻译成可路由、可补全、可交接、可计费的工单状态机——本文给出一套从意图分层到 outcome 结算的完整落地方法。
客服是 Agent 落地中最被低估、也最难被做好的一类应用。它不像代码助手那样有自动测试可以当反馈信号,也不像搜索问答那样有"答得对不对"的二元判据;它的输入是千奇百怪的自然语言,输出是一连串可能改钱、改库存、改用户权益的动作,而最终的成功判据——"客户的问题被解决了"——本身必须由业务方先定义清楚,再由工程系统去测量和结算。
本文不谈 Agent 内核原理,也不重复"框架怎么选"这类话题。聚焦的是一个具体问题:如何把客服 Agent 从"演示能聊"推到"生产能算账"。全文围绕五个可工程化的对象展开——意图路由、槽位与澄清、拒答与转人工、结果计费、语音通道——并给出会话状态机设计、工具契约、评估口径与上线路线。
Anthropic 在其工程博客《Building effective agents》(2024 年 12 月 19 日发布,文首已加注"自 2024 年 12 月以来相关工具生态已有变化")的附录一里,把客服列为两个最具前景的 Agent 落地领域之一,并给出了四条理由:客服交互天然遵循对话流,同时需要访问外部信息与执行动作;工具可以把客户数据、订单历史和知识库文章拉进来;退单、更新工单这类动作可以被程序化处理;而成功可以用用户定义的 "resolution" 清晰度量。
这四条理由恰好定义了客服 Agent 的骨架,也解释了为什么它比看起来难:
其一,输入侧的方差极大。 同一句"我的订单还没到",可能是物流延迟、可能是地址填错、可能是想改地址、也可能是根本没付款只是在下单页看到"处理中"。意图识别错一次,后面全部动作都错。
其二,状态是隐式的。 客服对话的真实状态不在上下文里,而在一张工单上:客户是谁、订单是哪一单、已经尝试过什么、哪一步需要人批、哪一步可以回滚。把这些藏在 prompt 里会导致状态无法持久化、无法交接、无法审计。
其三,"成功"必须先定义。 这不是技术问题而是业务契约问题。Intercom 在 2026 年 9 月 23 日更新的《Fin AI Agent outcomes》文档里,把这个契约写得非常具体:一次会话最多只计一次 outcome,类型包括 Resolution(最后一次 AI 答复之后客户不再请求帮助,0.99 美元)、Procedure handoff(Fin 成功执行一个被配置为最终交接给人或工作流的 Procedure,0.99 美元)、Disqualification(判定潜客不符合资格并据此淘汰,0.99 美元)、Qualification(把潜客匹配到资格条件并据此路由,9.99 美元)、以及 Self-serve routing(自助式路由,按 0.99 美元的较低费率计)。这意味着工程实现必须把"结果"变成可写事件、可判定条件,而不是靠人看对话录像。
其四,错误代价不对称。 答错一句可以道歉,多退一笔钱要人工去追。所以客服 Agent 的护栏密度天然高于其他类型。
在写任何 prompt 之前,先定义数据模型。客服 Agent 的最小完整状态至少包含六个对象:
| 对象 | 含义 | 常见取值举例 | 谁来决定 |
|---|---|---|---|
| intent 意图 | 客户要解决哪一类事 | 物流查询 / 退款 / 改地址 / 咨询 | 路由器 |
| slot 槽位 | 完成该意图所需的具体参数 | order_id / 新地址 / 退款原因 | 对话填充 |
| action 动作 | 对外部系统产生的写入 | 发起退款 / 更新地址 / 建工单 | Agent + 工具 |
| policy 策略 | 该动作的前置条件与审批要求 | 金额上限、是否需要人批 | 业务配置 |
| handoff 交接 | 把会话移交给人或工作流 | 携带结构化上下文 | Agent 显式调用 |
| outcome 结算 | 本次会话最终计什么 | resolution / handoff / disqualification | 业务规则 + 事件 |
一次客服会话因此可以显式地分成六个阶段:识别 → 补全 → 执行 → 交接 → 收尾 → 结算。把这六个阶段固定下来之后,几乎所有的工程问题就都有地方可以挂载:意图错了看识别阶段,槽位卡住看补全阶段,误操作看执行阶段与策略配置,"AI 明明解决了但没计费"看结算阶段。
这里最容易被跳过的是"收尾"和"结算"两阶段的分离。用户在界面上看到"问题已解决"和系统在账上记一笔 outcome,是两件不同的事。前者可以由模型判断,后者必须由确定性代码根据事件日志判断——因为计费是要跟客户对账的,不能让模型说了算。
Anthropic 定义的 routing 工作流是:"路由对输入进行分类,并把它导向专门的后续任务。这一工作流允许关注点分离,并构建更专门的 prompt。如果没有这一工作流,针对一类输入做的优化往往会损害其他输入的表现。"它给出的客服示例非常直白:把不同类型的客服提问(一般性咨询、退款申请、技术支持)导向各自不同的下游流程、prompt 和工具。
这条原则值得逐字咀嚼。"针对一类输入做的优化会损害其他输入"——这是把 30 类意图塞进一个 prompt、挂 40 个工具的写法必然会踩到的坑:意图一多,工具描述彼此干扰、上下文被稀释、每类意图的专属规则互相污染,最后表现为"简单问题答得还行,复杂问题一上手就乱"。路由的本质不是分类,是上下文隔离。
推荐的实现是三层:
第一层,传统分类器或小模型。 高频、边界清晰的意图(订单状态查询、物流催问)用轻量模型或规则先分流。这一层的价值是延迟和成本:客服是高频链路,绝大多数轮次根本不需要旗舰模型。Anthropic 在同一篇文章里给的成本路由建议是——把简单/常见问题路由到 Haiku 4.5 这类更小更省成本的模型,把困难/不寻常的问题路由到 Sonnet 4.5 这类更强模型。
第二层,LLM 分类。 边界模糊、需要理解上下文的意图("上次那个问题还没解决"实际指向哪个工单)交给大模型做带解释的分类,并且要求输出置信度。
第三层,兜底。 分类置信度低于阈值时,不猜测,而是走澄清或直接转人工。"我不知道"必须是一个合法的路由结果,而且要是一个被显式建模、可以被评估的分支,而不是让模型在低置信度时自由发挥。
路由的工程化产物应该是一张表,而不是一段 prompt:
route(intent_confidence):
if confidence >= HIGH:
bind_intent_tools(intent) # 工具白名单
bind_prompt(intent) # 专属 prompt
bind_budget(intent) # token / 调用次数 / 金额上限
enter(slot_filling)
elif confidence >= MEDIUM:
ask_clarification(max_questions=1)
else:
handoff(reason="intent_unclear")
注意这里每个意图绑定了三样东西:工具白名单、专属 prompt、预算上限。缺任何一样,路由就退化成"换个说法问模型"。工具白名单保证意图与能力边界一致(退款意图里不应该出现"查询物流"工具);专属 prompt 保证优化不会互相污染;预算上限让高成本意图(退款、换货)有天然的收敛点。
澄清是客服 Agent 里最被低估的机制,它的工程含义远比"再问一句"复杂。
先看一个直接来自计费文档的细节。Intercom 的文档明确写着:如果 Fin 提出了澄清问题而客户没有回应,会话会在不活跃超时后自动关闭;由于 Fin 的最后一条消息是问题而不是答案,因此不会记录 resolution 状态,也不构成可计费 outcome。换句话说,一次澄清提问在收入语义上等于把这次会话押在了"客户会回答"上。这解释了为什么澄清不能随便问——每问一次,都在消耗这次会话的期望价值。
在工程上,澄清应该被设计成一次有成本的状态转移,而不是一次随口的提问。几条实操规则:
第一,必填槽位要区分类型。 有些槽位是绝对必填(退款必须知道订单号),有些是条件必填(只有"换地址"才需要新地址),有些是可选(备注)。把三者混为一谈会导致过度提问。
第二,禁止默认值。 客服场景里"猜"一个参数的代价远高于多问一句——猜错订单号就是给错误的人退款。
第三,每轮最多问一个问题。 一次抛三个问题,客户大概率只回答第一个,剩下的答案与问题错位,槽位状态直接污染。
第四,同一槽位最多追问一次。 客户没给或者给不了,就走替代路径(转人工、用订单列表让客户点选),而不是陷入追问循环。
第五,沉默必须有定义。 客户不回答不是"还在想",而是一个明确的终止信号。这条在计费口径上已经被 Intercom 写死了,工程上要照做:澄清超时应当关闭会话,且不计 outcome。
槽位填充的状态可以很简单:
slots = {order_id: None, refund_reason: None, confirmed: False}
# 每轮:从用户输入抽取候选槽位 → 校验 → 若缺必填则生成一条澄清问题并 return
# 若全部就绪则 confirmed = True,进入执行阶段
关键设计取舍是:槽位校验必须是确定性代码,不能交给模型判断"信息够不够"。模型可以负责抽取槽位,但不能负责声明抽取正确。把"够不够"写成 schema 上的必填字段加一段 Python 校验,是可测试的;让模型自己判断则不可测试。
客服会话的出口有且只有三种:完成(resolution)、交接(handoff)、拒答(disqualification)。三者的工程实现完全不同。
交接的实现有成熟的参考实现。 OpenAI Agents SDK 的 handoffs 文档写得很清楚:handoff 允许一个 agent 把任务委派给另一个 agent,"这对不同 agent 各自专精不同领域的场景特别有用——例如一个客服应用里,可能有分别专门处理订单状态、退款、FAQ 等任务的 agent"。关键实现细节是:handoff 在 LLM 看来就是一个 tool。如果有一个名叫 Refund Agent 的 agent 需要被交接,对应的 tool 名字就是 transfer_to_refund_agent。
handoff() 函数可以覆盖的字段包括:tool_name_override(默认由 Handoff.default_tool_name() 解析为 transfer_to_<agent_name>)、tool_description_override、on_handoff(回调,接收 agent context,可选接收 LLM 生成的输入,输入由 input_type 决定)、input_type(handoff tool-call 参数的 schema)、is_enabled(布尔或返回布尔的函数,允许运行时动态启停某个交接),以及 nest_handoff_history。文档还明确了一条设计原则:handoff() 总是把控制权交给你指定的那个 agent;如果有多个可能目的地,就为每个目的地注册一个 handoff,让模型自己选;只有当你自己写的交接代码必须在调用时决定返回哪个 agent 时,才使用自定义 Handoff。
这套 API 背后的工程直觉,对客服系统是可以直接迁移的:
transfer_to_refund_agent 比 route_intent_2 好得多——工具名本身就是给模型的路由提示。on_handoff 在交接瞬间拉数据。 文档说这个回调"在你知道交接被调用时启动一些数据拉取正合适"。客服场景里这正是人类坐席最想做的事:不要让客户再把订单号、已尝试动作、报错信息重复一遍。交接时一次性把工单摘要、历史尝试、客户等级、风险标记塞进上下文,人类接手时看到的是一个完整案件,而不是一句"转人工了"。input_type 定义交接契约。 交接不是"喊一声",而是一份结构化的移交单:发生了什么、已收集到哪些槽位、为什么升级、下一步建议。Anthropic 在同一篇文章里强调 agent 执行中必须从环境获得 "ground truth"(工具调用结果、代码执行结果)来评估进展,并可以设置停止条件——移交单本质就是把这些 ground truth 固化成交接契约。人工审批门与交接是两件事。 OpenAI Agents SDK 另有一套 human-in-the-loop 机制,用于在敏感工具调用前暂停等待人批准或拒绝:工具通过 needs_approval=True 声明总是需要审批,或提供一个异步函数按每次调用决定是否需要审批。该回调接收 run context、已解析的工具参数和 tool call ID。文档给出了一条极重要的失败安全规则:当 SDK 无法安全检查参数时,可调用式审批规则一律 fail closed——参数缺失、为空、只含空白、是畸形 JSON、是合法 JSON 但不是对象(例如 null 或数组)、或包含 NaN / Infinity / -Infinity 这类非标准常量时,回调不会被调用,该次调用转为需要人工审批。Runner 与 Realtime 的工具调用行为一致。
同页还说明了审批面的作用域:审批是 run 级别的,不限于当前顶层 agent——无论工具属于当前 agent、通过 handoff 到达的 agent,还是嵌套的 Agent.as_tool() 执行,嵌套场景下中断仍浮现在外层 run 上,由外层 RunState 批准或拒绝后恢复原始顶层 run。要让被暂停的运行跨越进程重启而恢复,靠的是 RunState 序列化。
LangChain 侧的 LangGraph interrupt() 提供了另一种实现,并给出了一组对客服场景同样适用的工程铁律。文档列出的规则是:不要用 try/except 包住 interrupt 调用;不要在一个节点内重排 interrupt 调用;不要在 interrupt 调用中返回复杂值;interrupt 之前触发的副作用必须是幂等的。 最后一条在客服系统里尤其致命——如果"已发起退款"这个副作用在 interrupt 之前执行,而审批在两分钟后被拒绝,那么重放时必须识别出退款已发起过并跳过,否则会退两次款。
文档还专门警告了一个陷阱:不要在单个节点里写 while True 加 interrupt() 的循环。因为节点在每次恢复时都会从头重跑,循环里多次调用 interrupt 会导致每次恢复重放此前所有迭代——第一次恢复重放 1 轮,第二次重放 2 轮,指数级重复执行循环体内的代码。正确模式是把待提问的问题存进 state(如 pending_question),在节点里恰好调用一次 interrupt(),如果答案不合法就返回更新后的 pending_question 让下次调用重新提问,并用 add_conditional_edges 路由回该节点直到收集到合法值。
审批与拒绝的写法是 Command(resume=True) 批准、Command(resume=False) 拒绝,interrupt() 的返回值即恢复时传入的载荷。
把这些机制对齐到客服场景,能推导出几条可执行的工程指标:交接上下文完整率(移交单中必填字段的填充比例)、人类重复询问率(人类接手后问了客户已经在对话里说过的问题的比例)、交接后一次解决率、以及审批误操作率。第一条直接决定人工成本,第二条是绝大多数 AI 客服系统"看起来聪明但实际上很烦"的技术根因。
计费口径是一套现成的评估定义,这是客服场景相对于其他 Agent 应用的独特优势——业务方已经把"成功"写成了可判定的规则,我们要做的是把它翻译成工程断言。
先把 Intercom 的口径完整列出,因为它定义了 outcome 的边界条件:
文档里还有一条对工程实现极具约束力的规则:如果一次会话被视为已解决(无论 confirmed 还是 assumed),但客户之后回到同一会话继续寻求协助——即使跨越了计费周期——该 resolution 会被扣除且不计费。 这意味着 outcome 不是终态,而是可撤销的判定。工程上必须保留"客户在 T 时刻之后又回到本会话"的事件流,用于回滚计费。
另外两个操作性的细节:Fin 在所有套餐中可用,但不使用不计费,可以设置使用提醒和硬性上限;以及"resolution 只在 Fin 实际给出答案时才计数,如果只是回应一句问候,不算答案也不算 resolution"。
把这套口径翻译成工程断言,得到三个层次的评估体系:
任务层指标(单轮可判):意图路由准确率、槽位抽取精确率/召回率、澄清问题的必要率(在必填槽位已可从上下文推导时是否仍然发问)、动作选择正确率、护栏拦截的误报/漏报率。
会话层指标(跨轮可判):首次接触解决率、转人工率与转人工原因分布、澄清轮次分布、平均每会话 LLM 调用次数与 token 成本、重复求助率(同一个会话内客户重复问同一件事的比例)。
业务层指标(跨会话可判):每 outcome 成本、每坐席时(人工处理时长 × 人工单价与自动解决时长 × 成本的对标)、outcome 被回滚的比例。
开源评估工具的现状(2026-10-26 实时拉取 GitHub API):promptfoo 26451★(MIT,2026-10-26 有推送)、langfuse 36516★(NOASSERTION 许可证,TypeScript,2026-10-26 推送)、confident-ai/deepeval 19111★(Apache-2.0)、explodinggradients/ragas 16152★(MIT,最后推送 2026-02-24)、guardrails-ai/guardrails 7559★(Apache-2.0)。做 PII 脱敏可以用 microsoft/presidio(11515★,MIT,2026-10-26 推送)。
一个实践建议:断言优先于模型评判。 凡是能用确定性规则判定的(转人工率、重复求助率、outcome 回滚率、每次会话调用次数),一律用规则判定;只有"回答是否切题且有据"这种没有硬判据的维度才交给 LLM 评判。把两类指标混在一起用模型判,既贵又不可复现。ragas 16152★ 的最后推送时间是 2026-02-24,近八个月没有更新,用它做 RAG 场景评估时要注意维护节奏;而 deepeval 与 promptfoo 都是当日仍在推送的活跃项目。
文字客服跑通之后,语音几乎是必答题,但语音不是"把 TTS 和 STT 接上"这么简单,它引入了文字渠道不存在的三个问题。
第一个问题是轮次判定(turn detection)。 LiveKit Agents 文档把这件事讲得最细:轮次检测就是判断用户何时开始和结束"轮次",从而让 agent 知道何时开始听、何时开始响应。大多数轮次检测依赖 VAD(voice activity detection)检测用户输入中的静音,agent 对 VAD 数据应用启发式规则做短语端点检测(phrase endpointing)来确定一句话或一个想法的结束。LiveKit 提供三种模式:Turn detector model(对多数 agent 推荐且是默认,从语音含义和声学属性两方面预测轮次结束,叠加在 VAD 之上)、VAD only(需要最低延迟或 turn detector model 未覆盖的语言时使用)、STT endpointing(已经在用自带轮次检测的 STT 时使用,例如 AssemblyAI 或 Deepgram Flux)。
第二个问题是打断(interruption)。 用户在 agent 说话过程中插话,agent 必须能及时让出控制权——但要区分"真打断"和"附和"(backchanneling,比如"嗯""对")。LiveKit 提供的 adaptive interruption handling 就是干这个的。此外还有 uninterruptible speech(不可打断段落,用于必须完整播报的关键信息,例如合规声明)、user turn limit(用户轮次上限,防止无限循环)以及 endpointing delay(可设 min_delay 与 max_delay,Python 侧还支持依据会话停顿统计做动态端点)。
第三个问题是多步流程中的回退。 LiveKit 的 Task 与 TaskGroup 模型是很好的参考:Task 是聚焦、可复用的单元,完成目标后返回类型化结果,接管会话直到目标达成;TaskGroup 执行有序的任务序列,同时允许用户回到之前的步骤做修正——组内所有任务共享会话上下文,组结束时把摘要结果交还给启动它的 agent。文档提到 task factory 在任务被重新访问时可以被重新初始化,task 的 id 与描述会作为标识符传给 LLM,让 LLM 在需要回到前一步时知道那个任务的目的和上下文。文档同时给出了用异常跳过剩余任务的模式(在回调里抛出自定义异常并在 await task group 处捕获),并强调 return_exceptions 默认为 false。
这套"允许回退到前一步"的能力,正是客服场景里最实用的特性之一:客户说"不对,我说的是另一个订单",agent 需要能退回槽位填充阶段重新填 order_id,而不是从头重来。
电话接入层面,Twilio 的 Conversation Relay 提供了一条相对直接的路径:通过 TwiML 的 <ConversationRelay> 名词建立会话,例如
const response = new VoiceResponse();
const connect = response.connect({ action: 'https://myhttpserver.com/connect_action' });
connect.conversationRelay({
url: 'wss://mywebsocketserver.com/websocket',
welcomeGreeting: 'Hi! Ask me anything!'
});
LiveKit 则提供了另一条路径,其 Agents 文档说明 agent 可以通过 LiveKit 的 SIP 集成呼出和接听电话,用户从电话接入而不必打开前端应用;其语音管线既支持由多个专用模型组成的 STT-LLM-TTS 管线,也支持具备直接语音到语音能力的 realtime 模型。
语音渠道还有一条容易被忽略的客服铁律:语音里不能发链接。 文字渠道常见的"请点击这个链接查看物流"在电话里是无效的,方案必须改写——要么口述关键信息,要么通过短信补发链接,要么改成"我帮您改到xx地址,您确认吗"这种确认式对话。这条约束会反过来影响工具设计:语音场景下的工具应当返回可直接朗读的短文本,而不是长 URL。
工具契约就是业务边界。 Anthropic 在附录二专门讲了对工具做 prompt engineering:工具定义与规格应该得到和整体 prompt 同等的注意力;常见做法是给模型足够的 token 去"想清楚再写",保持格式贴近互联网文本中自然出现的形式,避免出现"保持对数千行代码的准确计数"或"对写出的代码做字符串转义"这类格式开销。它给出的例子极具体:写 diff 需要在写新代码之前就知道 chunk header 里有多少行会变;在 JSON 里写代码(相比 markdown)需要额外转义换行和引号。
它还记录了一条真实教训:SWE-bench 的 agent 工具优化花的时间比整体 prompt 更多。原因是模型在使用相对路径的工具时会犯错(agent 移出根目录之后),修法是把工具改成始终要求绝对路径,模型随后就再也没出过错。这就是 poka-yoke——通过改变参数设计让犯错变难。客服场景的对应物非常直接:查订单的工具如果接受自由文本订单号,模型就会自己编;改成只接受从候选列表中选择的枚举 id,编造就从"可能"变成"不可能"。
还有一条文档反复强调的准则:把工具描述当成给团队里初级开发者写一份优秀 docstring。这在工具数量多的时候尤其重要——相似的工具(查物流 vs 查订单状态)必须靠描述区分开。
会话与持久化。 OpenAI Agents SDK 的 sessions 文档给出了一个干净的默认行为:当启用会话记忆时,每次 run 之前 runner 会自动取出该会话的对话历史并前置到输入条目;每次 run 之后,本次产生的所有新条目(用户输入、助手回复、工具调用等)自动存入会话;后续使用同一会话的 run 会包含完整对话历史,从而免去了手动调用 .to_input_list() 和自行管理会话状态。文档同时提供了控制历史与新输入如何合并、限制取回历史长度,以及内置实现清单——OpenAI Conversations API sessions、OpenAI Responses compaction sessions、SQLite(及异步版)、Redis、SQLAlchemy、Dapr、MongoDB、Advanced SQLite、Encrypted sessions,以及 Session ID 命名规范。
客服场景里有两个特殊需求值得强调。其一是限制取回历史长度:长期会话如果全量塞进上下文,成本和延迟都会失控,"最近 N 轮 + 摘要 + 结构化槽位状态"的组合比"全历史"更稳。其二是纠错能力:文档提到内存操作中的 pop_item 用于 corrections——客户说"我刚才说的不对"时,能从会话里撤回那条错误陈述并重新填槽,这比让模型在长上下文里"自己记住别用那条"要可靠得多。
LangGraph 侧的对应物是 checkpointer 与 thread_id:文档把 thread_id 称为你的持久化游标,复用它会恢复同一个 checkpoint,换新值则开启一个空状态的新线程;interrupt() 触发时,LangGraph 通过持久化层保存图状态并无限期等待,直到你用 Command 重新调用图来恢复。
护栏。 OpenAI Agents SDK 提供三类护栏位置——输入护栏、输出护栏、工具护栏,外加 tripwires(当某个条件被触发时直接抛出异常终止运行)。客服场景的护栏清单至少包括:金额上限与动作白名单(哪些意图可以触发退款、退款金额上限)、PII 脱敏(presidio 11515★)、拒绝执行法律/医疗/投资建议、以及跨境数据合规。护栏的位置选择有讲究:输入护栏防提示注入与越权请求,工具护栏防的是"模型被诱导调用了不该调用的工具",输出护栏防的是"回答里出现了不该出现的信息(内部价格、其他客户数据)"。
开源底座的现状(均为 2026-10-26 实时拉取 GitHub API):工单与收件箱侧有 chatwoot/chatwoot(38330★,Ruby,2026-10-26 推送)与 zammad/zammad(6031★,AGPL-3.0,Ruby);LLM 应用层有 langgenius/dify(159589★,Python,2026-10-26 推送)、vercel/ai(27521★,TypeScript,2026-10-26 推送)、n8n-io/n8n(208635★,TypeScript,2026-10-26 推送)、microsoft/autogen(61572★,CC-BY-4.0)、openai/openai-agents-python(30296★,MIT,2026-10-22 推送)、google/adk-python(22012★,Apache-2.0)、langchain-ai/langchain(148486★,MIT,2026-10-26 推送)、langchain-ai/langgraph(43925★,MIT,2026-10-26 推送)、microsoft/semantic-kernel(28697★,MIT,C#)、BerriAI/litellm(62064★)、anthropics/anthropic-cookbook(53789★,MIT)、anthropics/anthropic-sdk-python(4008★,Apache-2.0)、openai/openai-python(31955★,MIT);工具与 Agent 运行时侧有 livekit/agents(14939★,Apache-2.0,2026-10-26 推送)、baptisteArno/typebot.io(10580★,TypeScript)、browser-use/browser-use(119181★,MIT)、Skyvern-AI/skyvern(23278★,AGPL-3.0)、ComposioHQ/composio(30759★,MIT,TypeScript)、microsoft/BotFramework(284★,已归档,2020-01-08 最后推送);检索与记忆侧有 infiniflow/ragflow(92895★,Apache-2.0,Go)、milvus-io/milvus(46486★,Go)、qdrant/qdrant(35258★,Rust)、chroma-core/chroma(29583★,Rust)、pgvector/pgvector(23483★,C)、weaviate/weaviate(16915★,Go)、lancedb/lancedb(11776★,Apache-2.0,Rust)、mem0ai/mem0(67837★,MIT)、letta-ai/letta(25260★)、topoteretes/cognee(32770★,Apache-2.0)、deepset-ai/haystack(26847★,Apache-2.0,2026-10-26 推送)。
方法论上有一个值得写进正文的重要提醒:star 数高不代表项目活跃,路径 200 也不代表它是权威仓库。 本次实测中,Chainlit/chainlit 有 12515★ 但仓库已被标记 archived(最后推送 2026-09-18);microsoft/BotFramework 仅 284★ 且已归档、2020 年后无推送;microsoft/copilot-studio-agents 只有 13★ 且 2024-12-26 后无推送——这三个都返回 HTTP 200,但都不该被当作"活跃的官方方案"引用。另有若干路径直接 404:Dify-ai/dify、typebot-io/typebot、dust-tt/dust、salesforce/Agentforce、weavel-ai/guardrails、unitaryai/dspy,其中 Dify 与 Typebot 的真实路径分别是 langgenius/dify(159589★)和 baptisteArno/typebot.io(10580★),用搜索 API 按仓库名 + 星标排序才能定位。凡是没有实时拉取到确认状态的仓库,本文一律不引用。
路线建议分三阶段,每阶段的验收标准不同。
第一阶段:只读知识问答。此时不接任何写动作,唯一目标是验证意图路由与检索的准确率,并同时把 outcome 定义写进代码——在还没有写权限的时候就把结算口径定下来,是最容易被跳过但最不该被跳过的一步。验收看意图路由准确率与幻觉率。
第二阶段:加入可逆的写动作。优先选择"可逆 + 低金额 + 高频"的写动作(下单备注修改、预约改期、催单工单创建),所有真正改变资金或权益的动作仍走人工审批。此阶段重点建立护栏与审批闭环,验收看护栏误报率、审批通过时延、审批拒绝后的回滚正确性(尤其要验证幂等性)。
第三阶段:加入转人工与按结果计费。上线 handoff 机制与 outcome 结算,验收看首次接触解决率、转人工率、每 outcome 成本、以及 outcome 回滚比例。
八个常见陷阱:
客服 Agent 的工程难点,可以被压缩成一句话:让一段不确定的自然语言,稳定地落到一次可审计、可回滚、可计费的动作上。
本文给出的路径是:用意图路由做上下文隔离,每个意图绑定专属 prompt、工具白名单与预算上限;用槽位与澄清做缺失信息的状态化处理,把"问什么""问几次""沉默怎么办"全部写死;用拒答与转人工构建三条合法出口,交接必须携带结构化上下文,审批必须 fail closed 且幂等可重放;用 outcome 计费反向定义成功,把评估拆成任务层、会话层、业务层三档并让断言优先;用语音通道的轮次检测、打断区分与任务回退补上文字渠道缺失的交互能力。
Anthropic 在那篇工程博客结尾给出的三条原则,放在客服这个具体场景里依然成立且更加具体:保持 Agent 设计的简单性;优先保证透明度——显式展示 Agent 的规划步骤(对客服而言,这意味着把"我接下来要做什么"讲给客户听);以及认真打磨 Agent-Computer 接口,做充分的工具文档与测试。客服场景还会加上第四条:把业务契约前置——先定义什么叫解决、什么算交接、什么该计费,再开始写代码。
<ConversationRelay> TwiML 名词). https://www.twilio.com/docs/voice/conversationrelayConversation
0 条