1. 这道题到底在考什么
面试 Agent 工程师,尤其是工单场景,面试官扔出一道设计题,表面上看是让你画架构图、列技术栈,实际上是在做一次高密度的能力扫描。我面过不少人,也被人面过,这道题几乎成了区分“会调 API”和“真能做 Agent 系统”的分水岭。
工单 Agent 这个场景选得特别刁钻。它不像闲聊机器人那样可以糊弄,也不像纯 RAG 问答那样有标准答案可背。工单意味着有明确的输入(用户报障描述)、有状态流转(待处理、处理中、已解决)、有工具调用(查知识库、查历史工单、派单、改状态)、有兜底策略(搞不定要转人工)。面试官想看的是,你能不能在一个有约束、有反馈、有失败路径的真实业务里,把 Agent 的骨架搭起来。
我拿到的题目大意是:设计一个工单处理 Agent,用户提交问题描述后,Agent 要能理解问题、检索相关知识、判断是否需要更多信息、决定是否自动解决或转派,并且整个过程要可观测、可干预。关键词里 RAG、Agent 架构、工具调用、并发、安全全冒出来了,这基本就是当前 Agent 工程师面试的标配考察面。
这篇文章我打算把这道题拆透。不是给你一份标准答案去背,而是把每个设计决策背后的“为什么”讲清楚,让你在面试时能自己推导出合理方案,而不是硬套模板。适合正在准备 Agent 方向面试的人,也适合已经在做 Agent 项目但想系统梳理思路的开发者。读完之后,你至少能明白面试官在每个追问背后想听什么,以及哪些坑是必须提前想到的。
2. 整体架构怎么搭才不虚
2.1 为什么是“编排层 + 能力层 + 状态层”三层结构
很多人一上来就说“我用 LangChain 搭一个 Agent”,这话在面试里基本等于没说。面试官想听的是分层逻辑。工单 Agent 我习惯拆成三层:编排层负责决策和流程控制,能力层负责具体工具和检索,状态层负责工单生命周期和上下文持久化。
这么分的原因很实际。编排层是大脑,它决定下一步干什么,但它不应该关心知识库是向量检索还是关键词检索,也不应该关心工单状态存在 MySQL 还是 Redis。能力层是手脚,每个工具只做一件事,输入输出明确。状态层是记忆,工单不是一次性问答,它可能跨小时、跨天,甚至跨多个处理人,状态必须外置,不能塞在对话历史里。
我见过有人把工单状态直接拼在 prompt 里传给模型,短期能跑,一旦工单多了、状态复杂了,prompt 膨胀得没法看,而且模型很容易改错状态字段。状态外置之后,Agent 每次只拿当前需要的状态片段,决策完再通过工具去改状态,职责清晰,也方便做审计。
提示:面试时如果面试官问“为什么不用一个大的 Agent 全包了”,你就从可观测性和可干预性两个角度回答。分层之后每一层的输入输出都能打日志,出问题能定位到是决策错了还是工具返回错了,这在工单这种要求可追溯的场景里是硬需求。
2.2 编排层选 ReAct 还是 Plan-and-Execute
这是面试里高频追问的点。ReAct 是边想边做,每一步根据上一步结果决定下一步;Plan-and-Execute 是先出完整计划再逐步执行。工单场景我倾向于 ReAct 为主,局部用固定流程兜底。
原因在于工单的输入太不确定。用户可能说“打印机坏了”,也可能说“昨天还好好的今天开机没反应,灯闪红色”,还可能贴一段错误码。你没法预先规划出一个通用计划。ReAct 的循环——观察、思考、行动——天然适配这种探索式处理。但纯 ReAct 有个问题,它可能陷入循环,比如反复查同一个知识库查不到还一直查。
所以我的做法是:ReAct 循环加最大步数限制,同时给几个高频场景配固定子流程。比如“查工单状态”这种明确意图,直接走固定流程,不浪费模型调用。混合策略在面试里是个加分项,说明你既懂灵活性也懂成本控制。
2.3 状态层为什么不能只靠对话历史
对话历史是有长度限制的,而且模型对长上下文的中间部分注意力会衰减。工单场景里,用户三小时前说的“我试过重启了”这种关键信息,如果埋在几十轮对话里,模型很可能漏掉。状态层要做的是把关键信息结构化提取出来,比如设备型号、故障现象、已尝试操作、当前处理阶段,存成字段,每次决策时按需注入。
我一般用一张工单主表加一张事件流水表。主表存当前快照,流水表存每次状态变更和 Agent 决策记录。这样既能快速拿到当前状态,又能回溯整个处理过程。面试官如果追问“怎么防止 Agent 改错状态”,答案就是状态变更必须走工具调用,工具内部做校验,比如不能从“已解决”直接跳到“待处理”,必须有重新打开的显式操作。
3. RAG 在工单场景里怎么用才不翻车
3.1 知识库检索的粒度选择
工单场景的 RAG 和通用问答的 RAG 有个本质区别:工单要的是可执行的解决步骤,不是一段解释性文字。所以检索粒度不能是整篇文档,也不能是单句,最好是“问题-解决方案”对,或者操作步骤块。
我试过按段落切分,效果一般,因为一段里可能混着原因说明和操作步骤,检索出来模型还得自己挑。后来改成按语义块切,每个块是一个完整的处理动作,比如“重置打印机网络设置:1. 长按 Wi-Fi 按钮 5 秒 2. 指示灯闪烁后松开 3. 在设备列表里重新连接”。这种块检索出来直接能用,模型不需要二次加工。
切分策略上,固定长度切分在工单场景基本不可取,因为会切断操作步骤。我一般用基于标题和列表结构的切分,再配合重叠窗口。重叠窗口的作用是防止一个步骤被切到两个块里,检索时只召回一半导致操作不完整。
3.2 检索召回不理想时的兜底链路
面试官很爱问“如果知识库检索不到怎么办”。这不是一个技术问题,是一个产品思维问题。我的回答通常是三级兜底:第一级,放宽检索条件,比如降低相似度阈值、换关键词检索;第二级,检索历史相似工单,看人工是怎么处理的;第三级,信息不足就主动向用户追问,而不是硬答。
这里有个细节很多人忽略:追问也是有策略的。不能问“你能详细描述一下吗”这种开放式问题,用户会烦。要问封闭式或选择式问题,比如“设备指示灯是什么颜色?红色、蓝色还是不亮?”这样用户回答成本低,Agent 也能快速收敛。
注意:RAG 检索不到时,绝对不能让模型自由发挥编答案。工单场景编错了是要出事的,比如让用户去拆机,结果还在保修期内,这就麻烦了。检索不到就明确说“我需要更多信息”或者“这个问题我转给人工处理”,比瞎答强一百倍。
3.3 知识库更新与版本管理
工单知识库不是静态的。产品迭代、流程变更、新故障出现,知识库都得更新。面试里如果聊到这块,说明你在想生产环境的事,不是 demo 思维。
我的做法是知识库分版本,每个知识块带生效时间和失效时间。检索时只召回当前生效的块。同时保留旧版本用于历史工单回溯,因为三个月前的工单可能是按旧流程处理的,审计时需要能看到当时的知识依据。更新流程上,新知识先进入待审核区,人工确认后发布,避免错误知识直接进生产库。
4. 工具调用与并发处理
4.1 工具设计的原则:少而精还是多而全
工单 Agent 的工具集我倾向于少而精。常见的有:查知识库、查历史工单、查工单状态、更新工单状态、创建派单、请求人工介入。就这几个,不要搞几十个工具。
原因有两个。一是工具太多,模型选择困难,容易选错。二是每个工具都要写描述、定义参数、处理异常,维护成本高。我见过有人把每个数据库操作都包成一个工具,结果模型在“查用户信息”和“查设备信息”之间反复横跳,效率极低。
工具描述要写得像给新人看的操作手册,说清楚什么时候用、输入是什么、返回什么。比如“查历史工单”的描述不能只写“查询历史工单”,要写“当当前知识库无法解决问题时,用此工具检索相似的历史工单,输入是问题描述关键词,返回最多五条相似工单的摘要和处理结果”。
4.2 并发场景下 Agent 怎么扛
热词里有个“ai agent 怎么扛并发”,这确实是生产环境的痛点。工单系统可能同时进来几百个请求,每个请求都要跑 Agent 循环,还要调模型、查向量库、查数据库。我的思路是分层削峰。
接入层用队列缓冲,请求进来先入队,Worker 按能力消费。Agent 循环本身是 IO 密集型的,模型调用和检索都是网络请求,所以用异步框架能显著提升单机吞吐。状态层用连接池,数据库和 Redis 都要配合理的池大小,避免 Agent 多了把数据库连接打满。
模型调用这块,如果用的是外部 API,要加限流和重试。重试要有退避策略,不能失败了一直猛冲。如果并发量特别大,可以考虑把一些简单意图的请求路由到小模型或规则引擎,不全都走大模型。面试时能聊到这些,说明你考虑过真实流量,不是只跑过单条测试。
4.3 工具调用的失败处理
工具调用失败是常态,不是异常。网络超时、数据库连接失败、知识库返回空,都得有处理策略。我的原则是:可重试的失败自动重试,不可重试的失败降级,降级不了的转人工。
比如查知识库超时,重试两次还不行,就跳过检索,直接基于已有信息决策,同时记录一条降级日志。更新工单状态失败,这个不能跳过,必须重试到成功或者告警,因为状态不一致会导致后续处理混乱。转人工是一个兜底工具,任何时候 Agent 觉得自己搞不定,都可以调它。
提示:面试时如果被问到“Agent 调工具调错了怎么办”,你可以说工具内部做参数校验,比如更新状态时校验状态流转是否合法,派单时校验工单是否存在。校验不通过就返回明确错误,Agent 根据错误信息决定下一步,而不是让错误静默发生。
5. 面试现场怎么讲这道题
5.1 从需求澄清开始,别急着画架构
面试官抛出题目后,很多人直接开始说“我会用 LangChain 加向量数据库”。这个开头就输了。正确的做法是先澄清需求:工单来源是什么?是用户直接提交还是客服代提交?工单类型有哪些?是技术故障还是业务咨询?自动解决率的目标是多少?有没有人工兜底?
这些问题不是废话,它们直接决定架构。如果工单类型单一,可能不需要复杂的意图识别;如果自动解决率要求不高,可以更保守地转人工;如果有严格 SLA,状态流转的设计就要更谨慎。面试官看你主动澄清需求,会认为你有实际项目经验,知道需求不清就动手是灾难。
5.2 讲清楚取舍,而不是堆技术名词
面试里最忌讳的是把知道的框架全列一遍。LangChain、LlamaIndex、AutoGPT、向量库、图数据库全说上,面试官只会觉得你没有判断力。正确的讲法是:我考虑过 A 和 B,选 A 是因为在这个场景下 A 的某个特性更匹配,B 虽然某方面更强但会带来什么代价。
比如向量库选型,你可以说“我考虑过专用向量库和 pgvector,选 pgvector 是因为工单数据本身就在 Postgres 里,用 pgvector 可以少维护一个组件,虽然专用向量库在超大规模下性能更好,但工单知识库的量级用 pgvector 完全够”。这种回答展示的是工程判断力,比列一堆名词强得多。
5.3 主动暴露风险和边界
面试官最后往往会问“这个方案有什么问题”。这时候不要硬撑说没问题,要主动说风险。比如“ReAct 循环在复杂工单上可能步数过多,导致响应慢,我的缓解措施是设最大步数和超时,超时后转人工”。再比如“知识库覆盖不足时自动解决率会下降,需要持续运营知识库”。
主动暴露风险不是减分,是加分。它说明你做过真实系统,知道没有银弹。面试官要的不是一个完美方案,而是一个知道边界在哪、有应对策略的方案。
6. 常见追问与应对思路
6.1 “你怎么评估这个 Agent 好不好”
评估分两层。离线评估用历史工单做回放,看 Agent 的决策和人工处理是否一致,一致率是一个指标。在线评估看自动解决率、平均处理时长、转人工率、用户满意度。但工单场景有个特殊点,自动解决不等于正确解决,用户可能问题没解决但懒得再报,所以要有回访机制或者后续工单关联分析。
我一般会强调“解决”的定义要明确。是工单状态变成已解决就算,还是用户确认才算,还是七天内没有同类问题复现才算。定义不同,指标差很多。面试时把这个说清楚,面试官会觉得你懂业务。
6.2 “Agent 决策错了怎么回滚”
工单状态变更要设计成可回滚的。每次变更记录前一个状态和变更原因,回滚就是反向操作加一条回滚记录。但有些操作不可逆,比如已经派单给工程师了,回滚不是撤销派单,而是重新分配或取消。所以工具设计时就要区分可逆操作和不可逆操作,不可逆操作要加二次确认或者权限控制。
对话层面,如果 Agent 给用户回了错误信息,没法撤回,但可以追加更正消息。所以重要信息发送前要过一道校验,比如涉及操作步骤的回复,检查一下是否和知识库一致,不一致就不发。
6.3 “多轮对话里用户改需求怎么办”
工单场景里用户改需求很常见,一开始说“打印机坏了”,聊着聊着说“其实我是想换一台新的”。这时候 Agent 要能识别意图漂移,重新走意图识别流程,而不是在原来的故障排查路径上继续。实现上可以在每轮对话后做一次意图置信度检查,低于阈值就重新分类。
状态层要记录意图变更历史,因为可能涉及工单类型变更,比如从故障工单变成采购咨询工单,处理流程完全不同。这种变更要通知相关人员,不能悄悄改了。
7. 我踩过的坑和实操心得
第一个坑是过度依赖模型做状态判断。早期我让模型从对话历史里自己推断工单当前状态,结果模型经常把“已解决”和“已关闭”搞混,导致统计报表全乱。后来改成状态必须显式存储和显式变更,模型只能通过工具读状态,不能自己推断,问题就没了。
第二个坑是知识库检索的相似度阈值设得太高。一开始设 0.8,结果很多能解决的问题因为检索不到相似块而转人工。后来降到 0.65 并配合重排序,自动解决率上来了,但误召回也多了。最终的平衡点是动态阈值,根据问题类型调整,故障类问题阈值高一点,咨询类低一点。
第三个坑是忽略工具调用的幂等性。有一次 Agent 重试更新工单状态,结果因为网络抖动,第一次调用其实成功了但响应超时,重试又更新了一次,状态流水里出现两条相同记录。后来所有写操作都加幂等键,用工单 ID 加操作类型加时间戳做唯一约束,重复调用直接返回已有结果。
提示:如果你正在准备面试,建议自己动手写一个最小可用的工单 Agent,哪怕只支持查知识库和更新状态两个工具。跑通一遍之后,上面这些坑你至少会踩到两三个,面试时讲出来就是真实经验,比背答案有说服力得多。
最后分享一个我在实际项目里验证有效的做法:把 Agent 的每次决策都记成结构化日志,包含输入状态、候选动作、最终动作、工具返回、耗时。这个日志在排查问题时极其有用,而且积累多了之后可以做决策模式分析,找出 Agent 容易出错的场景,针对性优化。面试时提到这个,面试官通常会追问细节,因为这说明你真正运营过 Agent 系统,不是只做过 demo。