Appearance
项目三:企业智能客服 Multi-Agent 平台
2025.04 - 2025.11 | 亿达信息技术有限公司 | Agent 开发
内部答辩底稿。正文所有效果数字统一写
<待核实>,简历示例值只出现在第六节对照表。
一、30 秒定位
这是一个面向企业客服场景的 Multi-Agent 平台。要解决的不是"答不上话",而是两件更难的事:业务入口分散(售前、订单、物流、售后、投诉散在不同系统和不同坐席手里),以及高风险动作没人管(退款、工单提交这类写操作让模型自己直接调,出错就是真金白银)。我基于 LangGraph 做了"主 Agent 负责意图识别与条件路由 + 领域子 Agent 各管一条业务线"的编排层,把订单、CRM、工单接口封装成带风险分级的标准 Tool,在退款、投诉升级、工单提交三个节点强制人工确认,并把路由、工具调用、审批落成可倒查的审计日志。上线后工具调用成功率、任务完成率、转人工构成都能从日志里回归出来,具体数值 <待核实>。需要说清楚的是:我负责的是编排层、工具层、HITL 与审计分析,不是整个客服系统。
需你本人确认
职级与职责措辞:简历工作经历里写的是"参与 Multi-Agent 智能客服平台核心开发",项目经历里偏"主导"口吻。面试时口径要统一,建议统一成"我负责 Agent 编排层与工具安全层,架构方案由我提出并落地,团队还有 X 人负责前端与业务系统对接"。团队规模、我之外的分工需要你填实。
二、架构与我的位置
| 模块 | 归属 | 我的具体交付 |
|---|---|---|
| LangGraph 主图与五个领域子图 | 我 | State 设计、条件边、澄清与重试分支、循环上限 |
| Tool 层 | 我 | 接口收敛为面向任务的 Tool、Schema、风险分级、幂等、失败矩阵 |
| HITL 与审批状态机 | 我 | interrupt 挂起、恢复入口、超时扫描、审批单表设计 |
| SSE 阶段事件协议 | 我(前端联调) | 服务端事件定义与推送,前端渲染由前端同学做 |
| 审计日志与回归分析 | 我 | 埋点口径、聚合脚本、固定用例集回归 |
| 会话记忆 | 我 | Redis 结构、TTL、滑窗与摘要策略 |
| 订单 / CRM / 工单系统 | 业务系统团队 | 我只消费其 OpenAPI,不改动其内部逻辑 |
| 知识库 RAG 检索服务 | 知识库侧 | 我做接入 + 引用约束 + 拒答,不负责入库与召回调优 |
| 模型网关、GPU 与配额 | 平台组 | 我提需求(并发、超时、模型版本),不负责部署 |
| 组织架构与审批角色主数据 | IAM / 业务方 | 我对接接口,审批人规则由业务方定义 |
三、简历每条 bullet 的展开与追问树
bullet 1:基于 LangGraph 设计"主 Agent + 领域子 Agent"架构,由主 Agent 完成意图识别、任务拆解和条件路由,隔离商品、订单、物流、售后及投诉流程
要讲什么
- 拆分的动机不是"Multi-Agent 时髦",而是单 Agent 挂五条业务线的全部工具时,工具集和 prompt 会互相污染:模型在物流问题上去调退款工具、在售前问题上追问订单号,选错工具的概率随工具数量上升。
- 拆分边界按"工具集 + 数据权限 + 话术规则"三条线是否一致来切:一致的合并,不一致的独立成子图,每个子图的工具数控制在小集合内,系统提示只描述本条线的规则。
- 主 Agent 只做三件事——意图识别、任务拆解、条件路由,它不持有任何业务工具,所以不会被业务细节撑大上下文,也让"为什么走到退款"这个决策点唯一、可审计。
- State 分层:主图只维护意图、用户身份、当前子任务、最终结果;领域中间状态(候选订单、检索证据、待确认参数)留在各自子图,避免全局 State 变成垃圾场。
- 跨域请求("我要退货顺便查下物流")由主 Agent 拆成子任务顺序执行,子图之间不直接通信,通过主图 State 交接结构化字段。
必然被追问
- 为什么不用一个 Agent 挂全部工具? 工具数上升选择准确率下降;不同业务线的 prompt 规则互相冲突;数据权限无法按域收敛;改一条线要回归全部。代价是多一跳路由延迟和一次额外模型调用。
- 为什么不用完全去中心化的 Agent 互相 handoff? 客服要能倒查"这次为什么走到退款",中心化 supervisor 的路由决策点唯一、可记录、可回归;去中心化容易绕圈且难定责。
- 意图识别怎么做的?准确率怎么保证? 规则前置(明确订单号、"退款"等强信号直连)+ LLM 输出受限枚举 + 置信度低走澄清;错分样本回灌成 few-shot 与回归用例。准确率
<待核实>。 - 路由错了会怎样? 分两类:错到只读域最多多问一轮,子图 fallback 回主图重路由;错到敏感域会被 HITL 拦住。策略是"路由不确定就澄清",不硬猜。
- 子 Agent 之间怎么共享上下文? 只传必要结构化字段(用户 ID、订单号、已确认信息、意图),不传完整对话历史。
追到底会问
- 主图和子图的 State 怎么隔离?子图返回什么? 子图有独立 schema,父子之间做输入/输出映射;子图返回结论 + 证据引用 + 是否需要人工,而不是整段推理过程。
- 拆完之后延迟和 token 成本涨多少,怎么控? 路由是一次小模型短输出;澄清尽量一次问全;纯只读查询走确定性节点不走完整 ReAct。实测涨幅
<待核实>。 - 再加两条业务线,你改哪里? 加子图 + 注册意图枚举 + 补回归用例,主图不动。这正是分层拆分的主要收益,也是我判断"该不该拆"的标准之一。
答不上来时的兜底话术
这块我是按"工具集、数据权限、话术规则三者一致才合并"的原则拆的,某条线该不该独立最终是看路由错分类型和回归结果调出来的,具体某个边界我可以把当时的错分样本类型讲一下。
原理补课:Multi-Agent 架构与 Supervisor 边界、LangGraph State 与子图
bullet 2:采用 ReAct + Tool Calling 编排业务链路,将订单、CRM、工单接口封装为标准 Tool;工具调用失败时按错误类型执行重试、降级或转人工
要讲什么
- Tool Calling 的本质是模型只输出"想调什么、参数是什么",真正执行永远在我的代码里,所以安全边界做在执行侧而不是写在 prompt 里。
- 内部接口不是一对一映射成 Tool,而是按"客服会问什么"收敛成面向任务的 Tool(查订单状态、查物流轨迹、创建售后工单),一个 Tool 内部可能串多个下游调用。
- Tool 的描述和 JSON Schema 就是给模型看的说明书:写清适用场景、必填参数从哪来、返回什么;返回体做字段白名单投影和裁剪,不把下游原始大 JSON 灌回上下文。
- ReAct 只用在"需要根据中间结果决定下一步"的链路上;能一步定死的只读查询走确定性节点,不给模型自由度。
- 失败处理不是统一重试三次,而是按错误类型分流:超时/限流/5xx 指数退避重试,参数校验失败回模型修正有限次,业务终态错误(订单不存在、已退款)直接转成结论回答用户,鉴权失败与下游熔断走降级或转人工。
必然被追问
- 一个工具失败了,你怎么判断该重试还是转人工? 错误分类矩阵:可重试(超时、限流、5xx)、可修正(Schema 或参数不存在)、业务终态(不重试,直接答复)、不可恢复(鉴权、熔断、下游不可用)。写操作超时属于"结果未知",必须先查询确认再决定,不能盲目重试。
- ReAct 会不会打转?怎么停? 最大步数上限、同工具同参数重复调用检测、无进展检测(连续 N 步无新证据);触顶后走兜底话术或转人工。上限取值
<待核实>。 - 工具返回的数据量大怎么办? 字段投影 + 截断 + 摘要;列表只给首页与总数;原始返回落日志不落上下文。
- 为什么不用 MCP? 当时工具都在同一服务内、调用方只有这个 Agent,引入 MCP 的收益不足;如果要跨团队复用这些工具,我会包成 MCP Server 暴露。
- 并发上来会怎样? 下游接口有 QPS 上限,Tool 层加并发闸门和限流;连接池复用;单工具超时必须短于 SSE 阶段预算;模型网关侧也要排队与降级。
追到底会问
- 模型给了一个不存在的订单号怎么办? 参数来源约束:关键实体只能来自会话 State 中用户明确提供或系统查得的值,不允许模型自由生成;Tool 内部先做存在性和归属校验(这单是否属于当前用户)。
- 只读工具会不会泄露别人的数据? 每次调用强制携带调用者身份,数据权限在 Tool 内按用户维度过滤,不依赖模型把参数传对。
- 工具超时怎么设? 从用户可等待时间倒推:前端等待上限 → SSE 单阶段预算 → 单工具超时 × 重试次数,保证总和不越界。具体数值
<待核实>。
答不上来时的兜底话术
这条链路上我最在意的是"失败要有确定的去向",所以是先把错误分了类再决定动作;具体某类下游错误码怎么归类,我们是根据线上失败样本逐步补进矩阵的。
原理补课:Tool Calling 协议与失败处理矩阵、Agent 与 ReAct 循环
bullet 3:按风险划分只读 / 敏感工具,使用 Pydantic / JSON Schema 校验入参,为写入类操作增加幂等控制、超时和结构化错误返回
要讲什么
- 工具按副作用分级:只读类(查询)和敏感写类(退款、创建工单、改地址、发券)。分级直接决定三件事——是否必须过 HITL、是否必须带幂等键、审计日志记到什么粒度。
- 入参用 Pydantic 模型定义并导出 JSON Schema 给模型;校验不通过不进业务代码,把逐字段的错误结构化回传给模型让它修正有限次,仍不对就转人工。校验不只是类型和枚举,还包括跨字段业务不变量(退款金额不得超过可退金额、订单状态机允许的动作)。
- 写操作一律要求幂等键,用业务语义构造而不是随机 UUID,这样"用户重复表达同一诉求"能被识别成同一笔;数据库唯一索引兜底。
- 写操作三件套:幂等键 + 超时 + 结构化错误返回。超时归类为"结果未知",走"先查询确认再决定",不直接重试。
- 敏感操作做成两段式:模型最多只能产出一张"申请单"(propose),真正的 execute 由审批通过后的确定性代码执行,模型不在执行路径上。这是整套安全设计里最关键的一刀。
必然被追问
- 幂等键怎么构造的? 稳定业务要素拼接后哈希:租户 + 用户 ID + 业务类型 + 业务主键(订单号/工单号)+ 关键参数(金额)+ 本次审批单 ID。不含时间戳和随机数。落一张幂等记录表加唯一索引,冲突时直接返回首次结果。带审批单 ID 是为了区分"重复提交同一诉求"和"用户确实要发起第二笔退款"。
- 本地幂等和下游怎么配合? 先本地插 pending 记录抢占唯一键,再调下游,把下游返回写回本地;下游支持幂等键时透传同一个键,形成双层保护。
- 模型幻觉出错误参数怎么拦? 四层拦截:Schema 校验 → 参数来源白名单(实体必须来自 State 或查询结果)→ 业务不变量与状态机校验 → HITL 人工确认。任何一层不通过都不执行。
- 为什么不让模型直接调下游接口? 内部接口参数多、语义不面向对话、错误码不可读,且没有权限过滤与幂等约束;封装一层才能把这些补上。
- 校验失败让模型改,会不会死循环? 修正次数有上限,超过转人工;每次只回传具体字段错误而不是整段异常堆栈。
追到底会问
- 事务边界在哪?Agent 里能开事务吗? 不跨 LLM 调用持有数据库事务或连接。写操作在一个短事务内完成本地状态落库,与下游调用之间用"本地状态机 + 补偿",不用分布式事务。
- 两个坐席同时审批同一笔退款怎么办? 审批单唯一,状态流转用条件更新(pending → approved 只能成功一次),必要时行级锁;执行侧再有幂等键兜底。
- 金额上限这类规则放哪? 放服务端确定性代码,同时下游也要校验;绝不能只靠 prompt 或前端。这也是"确定性规则和模型推理解耦"的体现。
答不上来时的兜底话术
我的原则是模型可以决定"要不要做",但"能不能做、做几次"必须由代码判定;幂等键的具体字段组合我可以按当时的业务主键讲一遍。
原理补课:工具安全分级与幂等设计、并发、事务与一致性、Pydantic 校验与依赖注入
bullet 4:在退款、投诉升级和工单提交节点引入 HITL,实现暂停、确认、恢复和超时关闭,并保留路由、工具调用和审批审计日志
要讲什么
- HITL 节点的选择标准是三条同时成立:动作不可逆、影响资金或客户信誉、需要人类判断。只读节点不挂起,否则坐席会被淹没。
- 实现用 LangGraph 的 interrupt + Checkpointer:图执行到审批节点前把状态持久化并中断,通过 SSE 给前端推"待审批"事件;坐席在工作台确认后,用同一个 thread_id 携带审批结果调恢复接口继续执行。
- 挂起态不能只存内存:Checkpoint 落 PostgreSQL,另外单独建审批单表(业务可查、可做看板、可被超时任务扫描),两者用 thread_id 关联。这也是多实例部署能恢复的关键——服务无状态,任意实例按 thread_id 都能续跑。
- 超时关闭由后台扫描任务做:审批单过期 → 状态置 timeout → 用同一个恢复入口走"拒绝/超时"分支,给用户明确结论并留痕。绝不做"超时默认通过"。
- 审计留全链路:谁在什么时间、看到的参数是什么、批还是拒、后续执行结果如何,目标是任何一笔退款都能倒查出完整决策链。
必然被追问
- 挂起态存在哪里?多实例部署怎么恢复? Postgres checkpointer + 审批单表,服务本身无状态;恢复靠 thread_id 从库里读回状态,不依赖会话粘性;前端断线重连后按 thread_id 重新订阅事件流。
- 审批超时怎么处理? 后台 worker 扫过期单 → 走拒绝分支 → 通知用户并记录原因。默认拒绝而不是默认通过,这是风险场景的基本取向。
- 恢复时会不会重复执行前面的节点? 不会,从中断点继续,已完成节点不重跑;执行节点自身还有幂等键做第二层保险。
- 审批人是谁,权限怎么定? 复用组织架构与角色主数据(业务方提供),按金额和类型分级路由到不同角色。我做的是接口对接与状态机,规则由业务方定义。
- 用户在等审批期间又发消息怎么办? 同一 thread 的挂起态优先,新消息进待处理或提示"审批中",不允许开一条并行路径绕过审批。
追到底会问
- 为什么不用自己写任务表 + 轮询,而用 interrupt? 自研也能做,但要自己序列化"图执行到哪、上下文是什么";LangGraph 的 checkpoint 把这件事标准化了。代价是绑定框架、checkpoint 表结构不由我控制、State 里不能放不可序列化对象。
- Checkpoint 会不会膨胀?怎么治? 会,长会话每步一版。做 TTL 清理与归档,State 里只存引用(文档 ID、订单号)不存大文本。
- 如果数据库挂了,挂起的审批怎么办? 审批单是业务数据必须持久化,可用性依赖 DB;DB 不可用时整条写链路熔断为"转人工",宁可不办也不能无审批执行。
- 有没有绕过审批的路径?你怎么证明没有? 执行函数只接受携带有效审批单 ID 的调用,校验在执行侧;可以用审计日志对账——每一笔写操作都必须能匹配到一条已通过的审批单,对不上就是缺陷。
答不上来时的兜底话术
HITL 这块我的判断标准是"挂起态必须是可持久化、可恢复、可超时的业务数据",具体表结构和恢复接口我可以画一下时序。
原理补课:人工兜底、interrupt 与挂起态多实例恢复、Checkpointer 机制、后台任务与超时扫描
bullet 5:接入知识库 RAG、Redis 会话记忆和 SSE 阶段事件;证据不足、路由不确定或多次调用失败时拒答或转人工
要讲什么
- 知识库 RAG 在这个项目里是"被接入的能力":检索服务由知识库侧提供,我做的是把检索结果变成受约束的回答——强制带引用、证据不足就拒答、命中不确定就转人工。这条边界我在面试里会主动讲清楚,不把别人的活算成自己的。
- 会话记忆分三层:Redis 存短期会话状态与最近若干轮;关键业务事实(用户身份、订单号、已确认参数)以结构化字段写进 State,不靠模型从历史里"回忆";超长对话用滑窗 + 摘要压缩。
- SSE 推的是阶段事件而不只是 token 流:意图识别结果、路由到哪个域、正在调什么工具、待人工确认、引用来源、最终结论。客服场景里"看得见它在干什么"直接决定用户愿不愿意等。
- 三类情况主动不答:证据不足(无召回或精排分过低)、路由不确定(置信度低且澄清一次仍不明确)、多次调用失败。拒答不是空手而归,必须给下一步(转人工、自助入口)。
- 拒答与转人工的原因全部枚举化落库,这是后续补知识库、补工具、调阈值的输入,而不是一句"答不了"。
必然被追问
- 怎么判断"证据不足"?阈值怎么定? 组合条件:召回条数、精排最高分与次高分差距、答案能否被引用覆盖。阈值靠标注集在准确率和拒答率之间权衡出来,不是拍的。取值
<待核实>。 - 引用怎么保证不是模型编的? 生成时只允许引用传入候选片段的 ID;生成后做引用校验(ID 是否存在、片段是否真的支持该句),不通过就降级为"给原文片段 + 转人工"。
- Redis 重启数据丢了怎么办? 分清可丢与不可丢:可丢的是缓存态(热点、上下文摘要),不可丢的是审批单、审计日志、checkpoint,这些在 Postgres。Redis 设 TTL 与内存淘汰策略。
- SSE 在网关和多实例下有什么坑? nginx 要关缓冲、要发心跳保活、超时时间要和上游对齐、断线后按 thread_id 续订;SSE 是单向的,审批动作走普通 POST 接口。
- 长对话 token 怎么控? 滑窗 + 摘要 + 结构化字段替代原文,工具返回裁剪,系统提示按域裁剪(子图只带自己那条线的规则)。
追到底会问
- 摘要压缩会不会丢关键信息? 会,所以关键事实不靠摘要,靠结构化 State 字段;摘要只压闲聊和已完结的分支。
- 拒答率上升,业务方不接受怎么办? 把拒答分类再谈:知识库缺内容(补文档)、问法未覆盖(补改写与别名)、确实该转人工(正常)。拿分类数据说话,而不是一味降阈值把幻觉放出来。
- 多轮里用户改了订单号,State 怎么更新? 关键字段更新走显式确认(回读给用户),以用户最后一次明确给出的为准,并在审批单上展示最终参数供人工核对。
答不上来时的兜底话术
拒答策略我是当成产品功能而不是异常处理在做的:什么条件拒、拒了给什么出口、拒答原因怎么统计,这三件事都要落地。具体阈值需要我回去查配置。
原理补课:引用校验、拒答与转人工闭环、SSE 阶段事件协议与生产坑、Redis 会话与 TTL
bullet 6:记录意图路由、工具调用、参数校验、人工确认和转人工原因,按工具成功率、失败类型和任务完成情况进行回归分析
要讲什么
- 埋点按链路节点定义,不是随手打 log:一次会话一条 trace,节点级记录意图与置信度、路由结果、每次工具调用(名称、参数摘要、耗时、错误类型)、参数校验失败项、人工确认结果、转人工原因枚举。
- 参数摘要必须脱敏:手机号、地址、金额做掩码或哈希。日志要能定位问题,但不能变成新的数据泄露面。
- 指标分三层看:工具层(成功率、错误类型分布、P95 耗时)、编排层(路由准确率、平均步数、循环触发率、HITL 触发率与通过率)、业务层(任务完成率、转人工率、人工改写率)。只看端到端指标等于没测。
- 有一套固定用例集做回归:改 prompt、加工具、换模型前后各跑一遍,看指标有没有退步,避免"修好这个坏了那个"。用例集规模
<待核实>。 - 线上和离线形成闭环:线上失败样本回灌评测集,离线指标退步就不发布。
必然被追问
- 工具调用成功率怎么算的?分母是什么? 这个必须先定义清楚:分母是模型发起的调用次数还是任务所需的调用次数?重试算一次还是多次?业务终态拒绝(订单不存在)算不算失败?我的口径
<待核实>,而且建议只读与写操作分开报,两者的风险含义完全不同。 - 任务完成率谁判定? 规则判定(会话内达成目标、无转人工、无人工改写)+ 抽样人工复核;抽样比例与判定规则
<待核实>。 - 转人工率降低说明什么? 单看这个数字没有意义,见第七节——必须同时给漏转率或人工事后纠正率。
- 你怎么发现指标退步的? 固定用例集 + 基线快照,跑批脚本输出对比报告,退步项能定位到具体用例和具体节点。
- 日志量多大,成本怎么控? 分级采样:错误与 HITL 全量,正常会话按比例采样;参数只存摘要;冷数据归档。
追到底会问
- 路由准确率怎么标注? 人工标一批真实会话的正确域,与模型输出比对;歧义样本单列,允许"应当澄清"作为正确答案之一,否则会把合理的澄清判成错误。
- 做过 A/B 吗? 如实回答
<待核实>。如果没做,就说是版本前后对比 + 固定评测集,并主动说明局限:流量结构变化会污染结论,所以我更信离线评测集上的差值。 - 用 LLM 当裁判可信吗? 主观项(答案有用性)可以用,但必须先和人工标注算一致率做校准;关键指标不单靠裁判模型。
答不上来时的兜底话术
我在这块的立场是:拿不出口径的数字我不敢往简历上写,所以我更愿意先讲我们怎么定义指标、怎么发现退步的,具体数值我核对完再给你准确的。
原理补课:分层评测与编排层指标、工具调用审计
四、关键技术决策与备选方案
| 决策点 | 我的选择 | 备选方案 | 为什么这么选 | 代价 |
|---|---|---|---|---|
| 编排框架 | LangGraph 状态图 | LangChain AgentExecutor、自研状态机、CrewAI | 客服需要条件路由 + 可持久化中断 + 断点恢复,AgentExecutor 的黑盒循环拿不到这些;自研要重写 checkpoint | 绑定框架版本,State 必须可序列化,升级有 breaking change 风险 |
| Agent 拓扑 | Supervisor 主 Agent + 领域子图 | 单 Agent 大工具集、去中心化 handoff | 路由决策点唯一便于审计,工具集按域收敛降低误选 | 多一跳模型调用,延迟与 token 上升 |
| 路由实现 | 规则前置 + LLM 受限枚举分类 + 低置信度澄清 | 纯 LLM 自由路由、向量相似度分类、纯规则 | 强信号(订单号、退款关键词)走规则更稳;枚举输出可校验;澄清比猜错便宜 | 规则要维护,枚举扩展要同步改 prompt 与评测集 |
| 敏感操作执行 | 两段式 propose → 审批 → 确定性 execute | 模型直接执行后提供撤销、执行前弹确认框 | 退款不可靠"撤销"补救;把模型踢出执行路径是最强约束 | 链路变长,坐席有审批工作量 |
| HITL 实现 | LangGraph interrupt + Postgres Checkpointer + 独立审批单表 | 自研任务表 + 轮询、同步阻塞等待人工 | 中断态标准化持久化,多实例无状态恢复;审批单表让业务侧可查可看板 | checkpoint 表结构不可控且会膨胀,需要 TTL 与归档 |
| 写操作幂等 | 业务语义幂等键 + 本地唯一索引 + 透传下游 | 依赖下游自身幂等、随机 UUID 幂等键 | 随机键无法识别"重复的同一诉求";下游幂等能力不齐 | 幂等键设计与业务耦合,业务主键变更要跟着改 |
| 失败处理 | 错误类型矩阵(重试 / 修正 / 终态 / 转人工) | 统一重试 N 次后报错 | 写操作超时和"订单不存在"完全不该同样处理 | 矩阵要随下游错误码持续补充 |
| 会话记忆 | Redis 短期状态 + 结构化关键字段 + 滑窗摘要 | 全量历史进 prompt、向量化长期记忆 | 关键事实必须精确不能靠召回;全量历史成本与干扰都高 | 摘要有信息损失,需要靠结构化字段兜住关键项 |
| 传输方式 | SSE 阶段事件 | WebSocket、轮询 | 单向推送足够,实现与网关成本低,天然适配 HTTP 基建 | 单向,审批等反向动作要另开接口;网关缓冲与超时需要配置 |
| 拒答策略 | 显式拒答 + 出口 + 原因枚举落库 | 尽力回答、低分兜底答案 | 客服场景一次错误答复的代价高于一次拒答 | 拒答率是业务方敏感指标,需要用分类数据解释 |
五、故障与取舍
全节需替换
以下是这类项目上线后通常会遇到的问题形态,写成可复述的结构。⚠️ 需替换为你真实遇到的问题,包括真实现象、你当时怎么定位、最后怎么改的。面试官对"你踩过什么坑"的追问最能区分做过和背过。
故障 1:模型编造了业务参数,查到了别人的单 ⚠️ 需替换为你真实遇到的问题
- 现象:用户没提订单号,模型自己"补"了一个格式合法的订单号并调用查询工具,返回了不属于该用户的订单信息。
- 定位:对比会话 trace 里的用户输入与工具入参,发现该字段在用户消息和历史 State 中都不存在,是模型生成的;Schema 校验只管格式合法,管不了来源。
- 处理:加"参数来源白名单"——关键实体只能取自 State 已确认字段或前序工具返回;Tool 内部补归属校验(订单是否属于当前调用者);缺参数时走澄清节点向用户索要,而不是让模型猜。
- 沉淀:把"格式合法 ≠ 来源可信"写进工具开发规范,所有涉及主键的入参必须声明来源。
故障 2:服务重启后挂起的审批全部失联 ⚠️ 需替换为你真实遇到的问题
- 现象:一次发版后,处于"待人工确认"的会话点确认按钮报错,图无法恢复,用户侧一直悬着。
- 定位:checkpointer 用的是内存实现(或挂起态只在进程内缓存),多实例 + 重启后状态不存在;恢复请求还可能被负载均衡打到另一个实例。
- 处理:换成 Postgres checkpointer;审批单独立落库并带过期时间;恢复接口只依赖 thread_id;补一个超时扫描 worker 兜底关闭;发版前检查是否存在挂起态。
- 沉淀:判断标准是"任何一个实例挂掉,流程都必须能在另一个实例上继续",这条后来成了我们评审 Agent 设计的必检项。
故障 3:超时重试导致同一诉求产生了两笔操作 ⚠️ 需替换为你真实遇到的问题
- 现象:下游返回超时,链路自动重试,实际下游第一次已经成功,出现重复工单(或重复退款申请)。
- 定位:重试逻辑对"超时"和"明确失败"一视同仁;幂等键当时用了带时间戳的随机值,两次请求键不同。
- 处理:幂等键改成业务语义构造;写操作超时改走"先查询确认状态再决定";本地幂等表加唯一索引;重试只对确定性失败开放。
- 沉淀:写操作的三种结果是成功、失败、未知,未知必须单独处理——这是这个项目让我印象最深的一条。
故障 4:高峰期长时间无事件,前端连接被网关切断 ⚠️ 需替换为你真实遇到的问题
- 现象:并发上来后,部分会话在"正在处理"状态卡住,前端连接断开,用户重复提问加剧拥塞。
- 定位:模型网关排队导致单节点耗时变长,SSE 长时间无数据被 nginx 按空闲超时断开;同时缺少并发闸门,请求全部压到网关。
- 处理:SSE 加心跳事件;关闭代理缓冲并对齐超时配置;Tool 与模型调用加并发上限与排队,超限快速给出"排队中/稍后重试"而不是干等;前端按 thread_id 断线重连续订。
- 沉淀:流式接口的稳定性一半在协议设计(心跳、阶段事件),一半在容量控制(闸门、超时预算)。
六、数字口径待核实
使用规则
面试中一律先说口径再说数字。以下"简历示例值"是当前简历上的写法,未经核实前不要在面试中说出来;核实后把真实值填进第三列,并准备好证据出处(哪张表、哪个脚本、哪份周报)。
| 简历表述 | 简历示例值 | 真实值 | 该怎么算 | 证据在哪 |
|---|---|---|---|---|
| 工具调用成功率 | 94% | <待核实> | 成功调用数 / 发起调用数。必须先定:重试是否合并计数、业务终态拒绝是否算失败、只读与写是否分开统计 | Tool 调用日志按 tool_name + error_type 聚合 |
| 任务完成率 | 86% | <待核实> | 达成用户目标的会话数 / 有效会话数。需明确"达成"的判定规则与是否排除闲聊会话 | 会话表状态字段 + 抽样人工复核记录 |
| 日均处理会话数 | 约 1,500 次 | <待核实> | 统计周期内会话数 / 天数。需定:会话如何切分(超时多久算新会话)、是否去重测试流量、取哪段时间 | 会话表按天聚合,排除内部账号 |
| 转人工率(上线前) | 35% | <待核实> | 基线来源必须明确:老客服机器人日志还是人工坐席转接记录。口径不同不可对比 | 上线前基线报表;若无基线,简历应改为只写上线后值 |
| 转人工率(上线后) | 18% | <待核实> | 触发转人工的会话数 / 总会话数。建议拆主动转(拒答、低置信、失败兜底)与被动转(用户要求) | 转人工原因枚举字段聚合 |
| 领域子 Agent 数量 | 未写 | <待核实> | 上线时实际独立子图数量(商品、订单、物流、售后、投诉) | 代码中注册的子图清单 |
| Tool 总数与只读/敏感占比 | 未写 | <待核实> | 按注册表统计,标注风险等级 | 工具注册表 |
| HITL 覆盖节点数 / 审批通过率 / 超时率 | 未写 | <待核实> | 审批单表按结果分组:通过、拒绝、超时 | 审批单表 |
| 端到端延迟(P50 / P95) | 未写 | <待核实> | 从用户提问到最终结论;建议同时给首个 SSE 事件延迟 | 链路耗时埋点 |
| 峰值并发 / 实例数 | 未写 | <待核实> | 峰值并发会话数与服务实例数、模型网关配额 | 监控面板、部署配置 |
| 回归用例集规模 | 未写 | <待核实> | 固定用例条数,按业务线分布 | 评测集文件 |
| 项目团队规模与我的模块占比 | 未写 | <待核实> | 总人数、各角色分工、我独立负责的模块 | 你本人回忆,需与简历"参与/主导"措辞一致 |
| 项目周期 | 2025.04 - 2025.11 | <待核实> | 需与 BI 项目(2025.11 起)衔接一致,说明是否有并行期 | 简历时间线自查 |
七、这个项目会被挑战的地方
1. "转人工率大幅下降"——降低到底是好事还是坏事
这是全篇最危险的一个数字,面试官只要懂业务一定会问。
- 质疑逻辑:转人工率下降有两种截然不同的原因。一种是机器人真的把简单问题解决了(好事);另一种是该转的没转——模型硬答、答错、用户放弃,转人工入口变难找(这是事故,且会被投诉与二次来访放大)。单看这个数字无法区分。
- 正确答法:主动把它拆开讲。① 分子要区分主动转(拒答、低置信、失败兜底)和被动转(用户明确要求人工);② 必须配一个反向指标——漏转率或人工事后纠正率、二次来访率、投诉率,用来证明下降不是靠"少转"换的;③ 高风险动作(退款、投诉升级)的人工确认覆盖率不因这个指标下降而下降,HITL 是硬约束不参与优化。
- 可以说的实话:如果当时没有系统统计漏转率,就直说"我们主要靠投诉与二次来访做侧面验证,严格的漏转率统计是这个项目的欠账"。承认欠账比编一个指标安全得多。
- 建议动作:简历上把这条改成"转人工结构优化:被动转人工下降、主动兜底转人工保留",或者补上反向指标,否则这条容易变成失分项。
2. 工具调用成功率的数值本身会被挑刺
- 在写操作场景,如果按"每次调用"算,失败率意味着有相当比例的调用出错,面试官会问"那退款失败的那部分怎么办"。
- 应答方向:分只读与写两组报数;写操作的口径应该是"最终结果正确率(含重试与人工兜底后)"而不是"单次调用成功率";并说明失败的去向(重试、转人工、明确告知用户),没有静默失败。
3. 到底是"参与"还是"主导"
- 简历工作经历写"参与核心开发",项目段落偏"主导"口吻,面试官交叉比对会问。
- 应答方向:给清楚边界——架构方案由我提出并落地、编排层与工具安全层我独立负责、前端与业务系统接口由其他同学负责、知识库检索是复用。主动划边界会加分,含糊会被追到崩。
4. Multi-Agent 是不是过度设计
- 质疑:五条业务线的客服,用一个 Agent + 好一点的工具描述是不是也能做?多一层路由是不是纯粹增加延迟和故障点?
- 应答方向:给判断依据而不是立场——工具数量与误选率的关系、不同业务线 prompt 规则冲突的具体例子、按域收敛数据权限的需求、以及独立回归的工程收益。同时承认代价(延迟、成本、路由错误是新增故障模式),并说明如果业务线少于两三条我不会这么拆。
5. 为什么不用现成的客服 SaaS 或 Dify / Coze 搭
- 应答方向:核心卡点是"写操作 + 审批 + 审计"要深度接内部系统与组织权限,低代码平台在幂等、事务边界、审批状态机、审计留痕这些地方不好改;知识问答部分用平台做没问题,但可执行业务闭环需要自己控代码。不要贬低这些工具,讲边界。
6. 前端出身,Python 后端工程深度够不够
- 一定会被抽查:异步与阻塞(同步 SDK 卡住事件循环)、数据库连接池与事务边界、Redis 数据结构与 TTL、幂等与并发更新、日志与部署。
- 应答方向:不回避出身,用这个项目里踩过的具体问题回答(连接池、超时预算、状态机 CAS),并链到 并发、事务与一致性、FastAPI 进阶、Redis 深入 做补课。
7. 客户数据与合规
- 会问:客户手机号、地址、订单金额进不进模型?日志里存不存?用的是外部 API 还是内网模型?
- 应答方向:最小必要传参、入参与日志脱敏、敏感字段用引用 ID 替代原文、模型网关侧的数据边界由平台组约束。如果当时用的是外部 API,如实说明并讲已做的脱敏措施与遗留风险,别硬说"完全合规"。
8. 意图识别没有算法背景怎么保证
- 应答方向:我不做模型训练,走的是工程手段——规则前置、受限枚举输出、置信度阈值 + 澄清、错分样本回灌 few-shot 与评测集、按业务线拆小分类空间。把"没有算法背景"转成"我用可回归的工程方法控制质量"。
附:面试前 5 分钟速记
- 一句话定位:把客服从"知识问答"做成"可执行、可恢复、可审计"的业务闭环。
- 三个必须答住的硬点:幂等键怎么构造、挂起态存哪里且多实例怎么恢复、模型幻觉参数的四层拦截。
- 一个必须主动拆开的数字:转人工率下降要配反向指标。
- 一个必须主动划的边界:知识库检索是复用别人的能力,我做的是引用约束与拒答。