设计题 02:多智能体垂类客服
权重:★★★ 形式:45 分钟系统设计轮
素材来源:Own — HKJC Race Bot 的 Agentic Workflow 编排、QueWI 的意图识别与模型路由
相关知识点:04-agent-architecture/(multi-agent / tool-use / context-engineering)、05-agent-evaluation/agent-eval.md、06-agent-infra/gateway-routing.md、02-post-training/sft.md
1. 题干#
「我们有个客户,想做一个客服机器人。他们的业务领域很大 —— 产品说明、政策条款、常见问题,还有一堆内部业务数据。用户问什么的都有:有闲聊的,有问政策的,也有很复杂的 —— 比如『帮我把过去三个季度这个品类的退款情况按地区拉一下』。你来做,怎么设计?」
注意这个题干有多模糊:没说复杂请求占多少、没说要不要查数据库、没说答错的代价、没说用户是内部员工还是外部公众、知识库谁维护也没提。这是刻意的 —— 面试官要看的是你什么时候发现信息不足。
2. 第一步:澄清(这一轮最重要的动作)#
绝对不要听完就开始画多智能体架构。开场第一句应该是:
「在动手之前,我想先确认几件事 —— 因为这几个答案会直接决定要不要编排、以及编排到什么程度。」
必问清单(按对方案的影响排序)#
| # | 问题 | 为什么它会改变方案 |
|---|---|---|
| 1 | 复杂请求占多少比例? | 这是最关键的。如果 90% 是 FAQ 和闲聊、只有 10% 是复杂分析,正常路径应该是单 agent + 检索工具,复杂分支作为特例处理;反过来如果 60% 是复杂分析,架构的重心完全不同。不问这一条就画多智能体,是直接减分 |
| 2 | 复杂请求要不要查结构化数据? | 要 → 内部含一条 Text2SQL 子流水线(见设计题 03),它天然是一个可独立评测、独立替换的子系统;只要查文档 → 就是设计题 01 的 RAG,不需要多智能体 |
| 3 | 答错的代价是什么? | 涉及金额、政策、合规 → 必须强制引用来源、低置信拒答、可转人工;纯闲聊答错无所谓 → 可以放开生成。这条决定系统的「保守程度」 |
| 4 | 知识库谁维护? | 客户自己维护 → 需要后台工具 + 更新流程 + 灰度;我们维护 → 是持续的交付负担。决定要不要做管理界面,也决定更新链路的责任边界 |
| 5 | 用户是内部员工还是外部公众? | 外部公众 → 合规要求(香港场景要看 PDPO)、成本、防滥用、内容安全都上一个台阶;内部工具 → 权限体系是主要问题 |
| 6 | 要不要转人工? | 客服场景通常必须有人工出口。决定降级路径的最后一跳是什么 |
| 7 | 多少用户、多少并发? | 决定成本量级、要不要自建推理、要不要缓存 |
| 8 | 多轮吗?会话要记多久? | 客服基本是多轮 → 需要会话状态管理、指代消解 |
面试技巧:不要机械地把 8 个问题念完。先问 1、2、3 —— 这三个决定架构骨架,拿到答案再问下一层。追问本身也是考点。
3. 参考架构#
假设澄清后得到:复杂分析约占两成、需要查结构化数据、面向外部公众、答错代价高、需要转人工。
┌─ 在线请求(多轮,带 session) ──────────────────────────┐
│ 用户输入 │
│ ↓ ① 输入安全检测(越狱 / 有害 / 注入 / PII) │
│ ↓ ② 话题分类 + 意图识别(小模型 → 标签 + 置信度) │
│ ↓ ③ 路由(Router) │
│ ├─ 闲聊 / 简单 FAQ → 直接生成(小模型,轻量) │
│ ├─ 知识问答 → RAG 子流水线(设计题 01) │
│ ├─ 数据问答 → Text2SQL 子流水线(设计题 03) │
│ └─ 越界 / 高风险 → 拒答 + 引导人工 │
│ ↓ ④ 子流程执行(带超时、重试、降级) │
│ ↓ ⑤ 结果后处理 + 输出安全校验(引用、口径、格式) │
│ 回复 │
└───────────────────────────────────────────────────────┘
↓ 旁路(每一跳都写)
┌─ 会话状态 · 链路追踪 · 失败 case 归档 ─────────────────┐
└───────────────────────────────────────────────────────┘画图时要讲的三个点(这是把架构和「背组件」区分开的地方):
- 这是一个 workflow(编排),不是 multi-agent(多智能体)。区别很关键:编排的控制流是固定、可预测的(分类 → 路由 → 分支子流水线),每一个分支的输入输出契约是明确的;多智能体是让模型自己决定调用哪个 agent、agent 之间互相 handoff。这个场景的请求类型是可分类的有限集合,用编排就够了 —— 而且可控、可评测、可调试。主动说出这个区分,是本题最大的得分点。
- ② 必须是显式阶段,不能塞进 prompt。安全与话题分类要输出一个标签 + 置信度的确定性结果,而不是让主模型「自己注意」。理由见 4.3。
- ④ 的每一跳都要有超时和兜底。编排式系统最大的风险是错误复合 —— 路由判错了,后面的子流程再正确也白搭,而且下游不知道自己拿到的输入是错的。
4. 关键决策与权衡#
4.1 核心问题:什么时候该上多智能体,什么时候单 agent + 工具就够#
这是本题的中心考点,千万不要默认「客服 = 多智能体」。
先讲单 agent + 工具什么时候够用:
「一个模型 + 一组工具定义 + 一个工具调用循环。如果工具只有 3–5 个、领域集中、任务短,这就是最优解 —— 加编排只会增加延迟和失败面。」
判据:工具集有没有大到模型选不准。工具选择准确率随工具数量上升而下降。工具少的时候,单 agent 不但够用,而且明显更好。
再说多智能体/子流水线在什么条件下才划算:
- 工具集不重叠且都很大 —— 知识库检索工具十几个 + 数据查询工具十几个,全塞进一个 agent,模型选错工具的概率会显著上升。按工具集切开,每个子系统只面对自己的工具,选择空间立刻变小。这是最常见的正当理由。
- 上下文需求冲突 —— RAG 要注入大量检索到的原文(噪声多),Text2SQL 要干净的 schema 加 few-shot 范例(噪声敏感)。混在一个上下文里会互相污染。
- 子任务可独立评测、独立替换 —— 这是最大的工程收益:意图识别错了就只修意图识别,Text2SQL 模块可以单独训练、单独评测,不用动整个系统。
- 需要不同模型档位 —— 闲聊走小模型,SQL 生成走微调过的模型。
然后必须主动说代价(这比说好处更能建立可信度):
- 错误复合:n 步串联,各步准确率 p,端到端大致是 p 的 n 次方;更糟的是路由判错时下游无从察觉。
- 成本:每个子系统都有自己的 system prompt、工具定义、历史,这些是重复的常驻开销,多分支系统的 token 消耗比单次调用高一个数量级是常见现象。⚠️ 补一句正确口径:不要抛无出处的印象倍数,但有出处的已发表数字可以引 —— 例如 LongHorizon-Harness 的 Manage–Execute–Audit 换来 WeaveBench 51.8%→80.7%,代价是总 token 2.3 倍、输出 token 3.6 倍,而 Terminal-Bench 上 token 反而减少 24%。「代价随任务类型差异极大」这个判断本身,比任何一个倍数都值钱。
- 调试:单 agent 的轨迹是一条线,编排的轨迹是一棵树 —— 失败点可能在任意节点。没有链路追踪就不该上编排。
要在面试里明确说出的结论:
「所以这个场景我要做的是一个编排器 + 若干可独立评测的分支,不是一群 agent 互相聊天。而且如果澄清下来发现 90% 的请求其实是同一类 FAQ,我会先只做『单 agent + 检索工具』,把编排留到真的撞上瓶颈再加 —— 先做最简单的能跑通的方案。」
4.2 路由怎么实现#
- 用一个小而快的模型做分类(QueWI 的经验)。原因和意图识别 SFT 的四条理由一样:它是分类任务不是生成任务、在关键路径上、调用量大、需要贴合业务意图体系。路由本身必须便宜 —— 如果为了决定走哪条路先调了个大模型,那就本末倒置。
- 误判的代价是不对称的:把复杂请求误判成简单 → 直接给出低质量回答,用户可感知;把简单请求误判成复杂 → 只是多花算力和时间。所以阈值要偏保守(宁可升配)。
- 低置信不要硬走分支:低置信时应该澄清追问或升级到更贵的路径,而不是赌一把。
4.3 安全与话题分类必须是显式的流水线阶段#
不能只在 system prompt 里写一句「不要回答 XX」。 三个理由:
- 可被绕过 —— prompt 层的约束是软约束,越狱一变就失效;独立分类器是硬闸门。
- 不可评测 —— 你没法给「一句 prompt 约束」建评测集,也就无法回答「该拦的拦住了多少、误拦了多少」。独立阶段可以单独建集、单独调阈值。
- 不可监控 —— 独立阶段能记录拦截率和分布,上线后能看出攻击模式的变化。
输出要结构化:分类结果是 标签 + 置信度,不是一句自然语言。这样下游路由是确定性的,而且每个标签都能单独建评测集。
边界类请求要在这一层识别:预测性、投资建议、医疗法律意见这类,应该在话题分类阶段就走安全分支。呼应 Race Bot 里的原则 —— 系统做的是信息查询和统计,不做预测性建议。展示「知道什么不该做」。
4.4 错误传播与兜底#
- 级联错误的真正危险:子流程的输出摘要丢了关键信息、或者用错了实体,下游 agent 在缺失/错误信息下继续工作,而它不知道自己缺信息 —— 这比直接报错危险得多。
- 每一跳都要有:置信度 + 超时 + 结果合理性检查(比如 SQL 返回空集、检索最高分过低,都是信号)。
- 兜底要有明确顺序:重试 → 降级到更简单的路径(数据问答失败就退化成「我查到这些相关文档」)→ 澄清追问 → 转人工。
- 「不知道」优于瞎猜。客服场景里,一句编造的正确答案比一句「我没查到,帮你转人工」伤害大得多。
4.5 明确不做什么#
- 不做 agent 自由对话(AutoGen 式多 agent 群聊)。⚠️ 理由要改:此前写的「控制流不可预测」站不住 —— AutoGen 的发言者是由中心化的
GroupChatManager统一裁决的,它的控制流其实比 handoff 网络更可预测,遇到懂 AutoGen 的面试官一句话就被顶回来。真正成立的理由是三条:① 对这个场景没有能力增益 —— 所有参与者看的是同一份对话记录,没有引入单 Agent 拿不到的新信息(见04-agent-architecture/multi-agent.md的判据层);② 共享同一份对话记录会污染上下文 —— 每个角色的噪声互相稀释,正好抵消我们要的「上下文隔离」;③ 延迟与成本高,而这个场景的收益覆盖不了。 - 不做一个巨型 prompt 里塞所有工具。工具选择准确率会崩。
- 不做「全自动、无人工出口」。客服场景必须有转人工。
- 不做自建推理,除非并发量真的撑得起来(见第 5 节)。
5. 容量与成本直觉#
面试官常问「这大概多少钱、延迟多少」。不要求精算,但要有量级感觉:
- 成本决定项不是检索,是「每条请求走几次模型调用、每次注入多少上下文」。
- 简单请求应该只花一次小模型调用 —— 这正是路由省下来的钱。如果闲聊也走完整编排,路由的意义就没了。
- 复杂请求是多阶段流水线:每次可能 3–5 次模型调用加一次 SQL 执行,单位成本比闲聊高一个量级。所以占比是关键:
- 复杂请求占 5% → 总成本影响可控,不用专门优化;
- 占 50% → 必须专门做缓存、并行化、结果截断,甚至考虑自建推理。
- 延迟:多阶段流水线天然慢。优化手段是并行化相互独立的步骤、缓存高频问题(客服场景的问题重复度其实很高)、用小模型做分类和抽取。用户体验上要给「正在查询」的反馈,而不是让用户面对空白等待。
- 要不要自建推理:取决于 QPS。中等规模的客服系统直接用 API 更划算;自建 vLLM 要有足够并发才回本,这是
06-agent-infra/latency-cost.md里的核心判断。说出「这个规模下自建不划算」比说「我用 vLLM」更能体现工程判断。
6. 面试官会怎么往下挖#
第一层:澄清与动机#
- Q:你会先问我什么? ← 见第 2 节,这是开场题。先问复杂请求占比。
- Q:为什么这里是编排而不是多智能体? ← 见 4.1。要说清「固定控制流 vs 模型自决」的区别。
- Q:为什么不用一个大模型一个 prompt 搞定? ← 请求类型差异太大:工具描述冗长、容易选错工具、且无法对单步做评测和优化。
第二层:技术细节#
- Q:路由判错了怎么办?错误会怎么传播? ← 代价不对称(4.2)+ 级联风险(4.4)。
- Q:安全分类为什么是独立阶段,而不是 system prompt 里写一句? ← 见 4.3 的三个理由。
- Q:简单请求和复杂请求走同一条路径吗?为什么不分? ← 成本与延迟;路由的意义就在于分流。
- Q:多轮对话的状态怎么管理?指代怎么消解? ← 会话状态存储、指代需要把历史实体带进当前轮。
- Q:用户的问题横跨两个分支怎么办(既问政策又要数据)? ← 这题很难。诚实答法:当前路由是单标签的,会选一个主分支;正确做法是引入子问题拆分与结果合并,属于已知局限。
第三层:工程与生产#
- Q:怎么知道系统上线后有没有变差? ← 固定的回归评测集 + 分桶评测(按分支分别看,整体指标好可能掩盖某一分支的退化)+ 线上失败回流。
- Q:怎么排查线上某一条错误回答? ← 链路追踪,每一跳的输入输出都要留。编排系统没有这个就查不动。
- Q:成本怎么控制? ← 路由分流、上下文预算、缓存高频问题、retry 次数上限。
- Q:客户的知识库更新了怎么办? ← 增量索引 + 失效机制(见设计题 01);同时要能回答「这是哪个版本的政策」。
- Q:子流程超时或上游模型挂了,系统怎么表现? ← 降级链路 + 明确的用户提示,不能让用户对着转圈等待。
第四层:反思与边界#
- Q:这个方案什么时候会不够用? ← 跨分支的复合问题、需要多步规划的任务、强实时性要求。
- Q:客户说「一次都不能答错」,你怎么回? ← 诚实说做不到 100%,然后把方案改成「强制引用 + 高置信才作答 + 低置信转人工」,并告知这会让自动回答的比例下降 —— 把用可用性换准确性的选择权交回客户。
- Q:什么条件下你才会真的上多智能体? ← 工具集大到单个 agent 选不准、上下文需求冲突、子任务需要独立评测/并行/不同权限。不要为了用而用。
- Q:这个项目里最容易被低估的工作量是什么? ← 知识库治理(内容质量、更新责任)和安全评测集的构建,不是模型。
7. 自测#
1. 什么情况下该上多智能体,什么情况下单 agent + 工具就够?给出判据。
答案要点
判据的核心是工具集是否大到模型选不准,以及子任务是否需要隔离。单 agent + 工具够用的条件:工具少(大致个位数)、领域集中、任务短 —— 此时加编排只增加延迟和失败面。多智能体/子流水线划算的条件:工具集不重叠且都很大、上下文需求冲突(检索噪声 vs 干净 schema)、子任务需要独立评测与替换、需要不同模型档位或不同权限。结论应是「先做单 agent,撞上具体瓶颈再拆」,而不是先设计多智能体再找理由。
2. 安全与话题分类为什么必须是显式流水线阶段,而不是 system prompt 里的一句约束?说出两个具体理由。
答案要点
① 可绕过性 —— prompt 层是软约束,越狱一变就失效;独立分类器是硬闸门。② 不可评测 —— 一句 prompt 没法建评测集,因此无法回答「该拦的拦住了多少、误拦了多少」;独立阶段可以单独建集、单独调阈值、单独监控拦截率分布。③ 不可监控 —— 独立阶段能记录拦截率与攻击模式的变化。输出还应当是结构化的「标签 + 置信度」,而不是自然语言,这样下游路由才是确定性的。
3. 路由把复杂请求误判成了简单请求,会发生什么?阈值应该偏向哪一边?
答案要点
后果是直接产生低质量回答且用户可感知,伤害信任。误判代价不对称:复杂→简单是「答错」,简单→复杂只是「多花钱多花时间」。因此阈值应偏保守,宁可升配。同时用置信度阈值兜底:低置信时不硬走分支,而是澄清追问或升级到更贵的路径,并把误判 case 记录回流。
4. 编排式系统最危险的错误传播形式是什么?设计三层兜底。
答案要点
最危险的不是某一步报错,而是下游拿到了错误或缺失的输入却无从察觉 —— 例如子流程的摘要丢了关键实体,下一个环节在错误信息上继续工作。三层兜底:① 重试(带错误信息回注,限次数);② 降级到更简单的路径(数据问答失败退化为文档检索);③ 澄清追问或转人工。每一跳都要有置信度、超时和结果合理性检查(空结果、超低分都是信号)。原则是「不知道」优于瞎猜。
5. 换条件:客户澄清后说「其实 80% 的请求都是同一类 FAQ,复杂分析很少见」,你的架构怎么改?
答案要点
砍掉编排的大部分:退回到单 agent + RAG 检索工具的主路径,把复杂分析作为兜底的次要分支,甚至可以第一版先不做。这不是能力退化,而是判断必要性 —— 编排的价值在于「有多条差异很大的路径」,路径其实很集中时,编排只是凭空增加延迟、失败面和维护成本。要点是识别出「复杂度要由需求驱动,不是由架构美感驱动」,并说明什么条件下会再加回编排(复杂请求占比上升、工具集扩张到选不准)。