首页/面试题库/故障排查篇
面试题库 · 第 08 章

故障排查篇

故障排查题是面试官的"终极武器":给一个现象,看你有没有系统性的排查方法论而不是瞎猜。答题模板统一为:现象 → 定位(数据归因)→ 根因 → 修复 → 预防。这四题同时是真实生产事故的高发区——把它们当"入职后的第一周预…

约 17 分钟6,796 字0 个代码示例

故障排查题是面试官的"终极武器":给一个现象,看你有没有系统性的排查方法论而不是瞎猜。答题模板统一为:现象 → 定位(数据归因)→ 根因 → 修复 → 预防。这四题同时是真实生产事故的高发区——把它们当"入职后的第一周预演"来准备。


Q01 · Agent 上线两周后开始"卡死":成本一晚上翻了十倍

难度:★★★★ | 频率:高 | 对应课件:agent核心/08、15

面试官:线上事故:你的 DeepResearch Agent 平时每任务平均 7 轮,昨天开始出现任务跑满 30 轮轮次上限,token 账单翻了十倍,用户反馈"研究半天不出结果"。你接手排查,怎么走?

第 1 层追问:第一步看什么?

先说你的排查动作顺序。

参考回答:不猜先看轨迹。取 10 个触发轮次上限的失败任务的完整事件轨迹(没轨迹日志的话,先别排查——把"补日志"记进事故报告的改进项)。看的顺序:一,轮次分布:是所有任务都变多(系统性退化),还是 10% 任务拖到 30 轮(尾部恶化)——均值和分布要一起看,这次是后者。二,轨迹里逐轮看工具调用序列:把每个任务的工具调用 (函数名 + 参数哈希) 按序画出来,立刻看到两种模式——一部分在"鬼打墙"(同参数反复 web_search),一部分在"打乒乓"(read_webpage 在两个 URL 间横跳)。三,和两周前的正常轨迹做 diff:问自己"变的到底是什么"。

第 2 层追问:根因定位

轨迹看到循环模式了,为什么两周后才爆发?

参考回答:循环本身一直存在(概率行为偶发),两周内必有变量把它从偶发放大成高发。按"最近改了什么"排查变更:一查提示词——git log 发现上周加了句"务必给出详尽答案":指令冲突——"详尽"和原有的"最多 N 轮"互相拉扯,模型宁可持续收集也不敢收敛,"承认失败换方向"的出口被堵死了一半。二查外部依赖——搜索 API 返回格式悄悄变了(结果列表里多了空摘要字段),模型对"信息不足"的判断变了。三查流量分布——新涌入的某类问题(模糊的长尾问题)天然难收敛。根因通常是叠加的:提示词变更是主因、问题分布是放大器。定位手段是控制变量回放:拿同一批问题分别跑新旧提示词(时间旅行/checkpoint 复现的用武之地),复现率差异一测便知。

第 3 层追问:修复与止血

当晚要止血,你做什么?根治呢?

参考回答:止血(当晚):回滚提示词变更(最可疑变量先撤)+ 临时收紧闸门(轮次上限 30→15,token 预算减半)——先保成本和体验,再谈功能。根治(三天内):一,提示词加"出口":恢复并强化"连续两次搜索不满意就更换关键词或直接基于已有信息作答"——给模型合法的放弃路径。二,重复检测闸门从"检测"升级为"检测 + 纠偏":中断时注入纠偏提示再给一次机会,而不是直接杀。三,工具返回值加引导:搜索空结果时返回"未找到,建议尝试 XXX"而不是空字符串。四,限流兜底:给同类问题加全局并发闸,防单类故障拖垮成本。

第 4 层追问:怎么防再发?

这类事故的长期预防?

参考回答:三道防线。一,指标前移:把"平均轮次"和"轮次上限触发率"做成告警(阈值:触发率 > 5% 告警)——这次事故其实有两天的缓慢爬升期,有指标就能在账单爆炸前发现。二,变更门禁:提示词变更纳入评测流程——提示词也是代码,上线前跑固定测试集对比轮次分布和成功率,防"改一句崩一片"。三,混沌演练:定期注入"搜索 API 返回异常"的故障看 Agent 鲁棒性。故障排查的产出从来不只是修复,是把这次事故变成下次的免疫力。

考察意图与踩坑点

  • 考察意图:完整考察排查方法论——看数据先于猜原因、找变量先于查代码、止血先于根治。背会答案不如掌握这个顺序。
  • 踩坑点:第一步就"看看代码有没有 bug"(没有数据支撑的排查是抽奖);只归因到"模型变笨了"就停(那是现象不是根因);修复完没有预防层(下次同样死法)。
  • 一句话总结:轨迹定位模式 → 变更 diff 找变量 → 回滚止血 + 出口根治 → 轮次触发率进告警——排查是流程不是直觉。

Q02 · 知识库更新后,问答正确率雪崩

难度:★★★★ | 频率:高 | 对应课件:LangChain指南/06-08、agent核心/15

面试官:周五你们往知识库导入了 2000 篇新文档,周一用户反馈"答非所问"暴增。你的 RAG 上周评测还是 92% 命中率。排查思路?

第 1 层追问:先分诊

第一个动作是什么?

参考回答:先分诊:是"检索坏"还是"生成坏"。抽 20 条用户投诉的"答非所问"案例,人工核对:每条去查检索日志,命中了正确文档吗(课程的分段归因法)。分诊结果决定方向——如果命中了但答案错 → 生成层问题(去看材料排序、提示词);没命中 → 检索层问题,这次大概率是后者。同时查一个廉价的高信号指标:检索为空率(score_threshold 过滤后什么都不剩的比例)——如果从 3% 涨到 40%,问题直指新数据。

第 2 层追问:入库侧排查

新文档怎么把检索弄坏的?

参考回答:按入库管线逆序查四环。一查切割:抽查新文档切块的形态——格式变了(新文档是带表格的 PDF,按纯文本切的,表格被腰斩、语义稀碎),这解释了"块命中了但内容读不通"。二查嵌入:新语料嵌入时是否走了和存量不同的模型或参数(有人升级了嵌入模型版本只重嵌了新文档——新旧向量不在同一个空间,相似度全部失真,这解释了"检索为空率"暴涨——混合空间里距离全乱了)。三查数据分布:2000 篇新文档是不是同质内容(某产品线文档占了大头)——top-k 被同主题块霸占,老问题的正确答案被挤出窗口。四查 score_threshold 的分数基准漂移:新文档的相似度分布整体偏低,固定阈值变成了"误伤过滤器"。

第 3 层追问:修复

确认嵌入模型不一致是根因,怎么修?

参考回答:对齐嵌入空间是唯一的正解:全量库用同一个模型版本重新嵌入(增量补嵌救不了——空间不一致是全局问题)。执行要点:一,分批 + 限流 + 断点续跑(十万块的量级,课程里的批量嵌入工程);二,双写验证:重嵌期间新旧索引并行,抽测试集在两边跑对比,新索引命中率达标再切流量;三,顺带把流程补上:嵌入模型版本写进索引 metadata,入库脚本加"版本一致性"断言(嵌入前查当前库版本号,不匹配直接拒绝入库并告警)——把这次的教训变成下次的闸门。

第 4 层追问:更深的教训

这类事故暴露了什么系统性缺失?

参考回答:两个缺失。一,入库质量门禁:新数据入库前没有"样本嵌入抽检"——抽 100 块新数据跑固定问题集,命中率不达标就不放行。数据管道也需要 CI,不只是代码需要。二,监控缺了分布维度:只监控了"整体正确率",没监控分文档来源的命中率——新文档的命中率周五当天就崩了,但被存量数据的均值掩盖了三天。分维度(数据来源/问题类型/用户群)的正确率监控是这次要补的基建。RAG 的"静默退化"特性(不报错、只变笨)决定了:没有分段归因 + 分维监控的 RAG,等于没有监控。

考察意图与踩坑点

  • 考察意图:考察 RAG 运维的成熟度——入库管线也是生产系统,版本一致性、质量门禁、分维监控是运维思维的三件套。
  • 踩坑点:直接调 prompt 碰运气;分诊跳过(检索和生成的问题用同一个方子治);不知道新旧嵌入混库这个坑(真实事故里最常见的根因之一)。
  • 一句话总结:先分段归因分诊 → 逆管线排查四环 → 嵌入版本对齐要全量重嵌 → 入库门禁 + 分维监控补基建。

Q03 · 上线后幻觉率上升:模型说得越来越"自信"了

难度:★★★ | 频率:中 | 对应课件:agent核心/06、15、LangChain指南/08

面试官:你们的客服问答系统,上线初期抽检幻觉率 3%,一个月后人工抽检发现涨到了 12%,而且都是"一本正经引用不存在的条款"这种。怎么回事?

第 1 层追问:现象解读

"引用不存在的条款"这个细节说明什么?

参考回答:这个细节直接缩小了排查面。"一本正经 + 编造引用"说明生成行为正常、材料里有诱因——模型在检索到相似但不含答案的块时,被 helpful 倾向驱动着"补全"了不存在的条款(幻觉机制见 LLM 原理篇 Q04)。重点排查两个方向:一,拒答机制是否失效——上线初期"库里没有就直说"的拒答在后期是不是变少了(拒答率下降 = 幻觉率上升的镜像);二,检索质量是否退化——"相似但不相关"的块是不是变多了。先查拒答率指标:如果它从 15% 掉到 2%,说明模型从"老实说不知道"退化成了"硬编"。

第 2 层追问:为什么行为会漂移?

模型和提示词都没人动过,行为怎么就漂了?

参考回答:行为漂移的常见根因是上下文里的"榜样"变了。逐层查:一,对话历史里被污染——多轮会话的历史里,早期版本的模型自己编过一次条款(当时是低概率事故),这条编造内容留在上下文里,成了后续轮次的"事实榜样"——模型看到"上文说过有这个条款",后续轮次就会自信引用它:幻觉在会话内自我强化。二,few-shot 样例污染——提示词里的示例被运营改过,示例本身就含"编造引用"的坏榜样。三,流量分布迁移——新增的问题类型(知识库覆盖外的长尾问题)天然高幻觉率,12% 是加权后的假象——分问题类型看幻觉率,如果老问题类型稳定在 3%、新类型 40%,那不是退化是分布变了。

第 3 层追问:修复方案

确认是"会话内自我强化",怎么治?

参考回答:四味药。一,引用硬校验(治本):生成层强制结构化输出带条款引用 id,校验器核对每条引用真实存在于知识库——引用不存在直接打回重试或转拒答。这是把"说依据"从软约束变成硬闸,幻觉率的下限由此锁定。二,历史消毒:多轮会话中,进入上下文的 assistant 历史消息先过一遍引用校验,编造过的内容替换成"(该条回答未能核实)"——切断榜样污染。三,拒答提示词强化 + 负例 few-shot:示例里明确放"库里没有 → 直说没有"的范例,教模型"放弃也是好答案"。四,监控补位:幻觉抽检改成分层抽样(按问题类型分层),拒答率进仪表盘——这两个数是幻觉的一体两面,必须一起盯。

第 4 层追问:更深一层

为什么不干脆"全靠校验",提示词不管了?

参考回答:因为硬闸和软闸是配合关系不是替代关系。校验的代价:每条输出多一次校验开销,打回重试烧 token 且加延迟——如果模型 90% 的输出是好的,全量硬校验是资源浪费。所以正确的架构是漏斗:提示词(软闸)把幻觉率从 40% 压到 5% 的量级 → 校验(硬闸)拦掉剩下的 5% → 人工抽检盯漏网的。三层各司其职:软闸管成本、硬闸管底线、抽检管演化。面试里能讲出"软硬配合 + 分层漏斗",就是安全工程思维的信号。

考察意图与踩坑点

  • 考察意图:幻觉治理是 AI 应用运维的核心议题,考察点在"细节驱动的排查面收窄"(引用不存在的条款 → 检索诱因 + 拒答机制失效)和软硬闸的架构思维。
  • 踩坑点:把幻觉率上升归结为"模型变笨了"就停止思考;没意识到会话内自我强化这个机制;只会堆提示词不知道校验兜底。
  • 一句话总结:细节收窄排查面 → 查拒答率的镜像变化 → 引用硬校验锁下限 + 历史消毒断榜样 → 软硬闸漏斗配合。

Q04 · LangGraph 状态诡异故障两连:字段被"吃"了 + 节点跑了两次

难度:★★★ | 频率:中 | 对应课件:langgraph框架指南/03、05、07

面试官:两个 LangGraph 线上怪事。第一个:Send 扇出的 5 个调研节点,最后 findings 里只剩 1 个结果。第二个:图里有个"汇总节点"明明该跑一次,日志显示执行了两次,报告生成了两份。分别怎么回事?

第 1 层追问:findings 丢失

5 路结果剩 1 路,先说诊断。

参考回答:教科书级的 reducer 缺失。诊断路径:看报错(如果 InvalidUpdateError 直接实锤)或看最终状态(findings 值像被覆盖过——5 路写入只剩"最后结算"那一路的值)。根因:findings 字段没挂追加 reducer,走了默认的覆盖语义——5 个并行节点各写各的补丁,结算时后面的覆盖前面的,结果取决于结算顺序,不确定性就是这么来的。修复一行:findings: Annotated[list, operator.add](或 add_messages 类追加语义)——Send 的铁律:被扇出节点写入的字段必须有 reducer,因为 Send 就是为多路并发写而生。课程里的原话场景,面试官考的就是这句铁律。

第 2 层追问:汇总节点跑了两次

第二个故障呢?

参考回答:汇合重复触发——LangGraph 篇 Q03 那个陷阱的现场版。机制:A、B 两个并行分支都指向汇总节点 C,如果 A 和 B 不在同一个超步完成(A 先完成),边触发时 C 被调度了一次;B 完成后 C 又被触发一次。同超步内到达的边会被 barrier 合并,跨超步到达的边各自触发——这就是"执行两次"的来源。修复三选一:一,哨兵字段——C 开头检查"已执行过"标记,已执行直接 return 空补丁(幂等);二,改图结构——让 A、B 汇到一个中间节点再走条件边到 C,人为制造同步点;三,条件边守卫——进入 C 的边上加条件"所有分支都完成才放行"。最稳的是一 + 三组合。

第 3 层追问:为什么这类 bug 上线才爆?

开发时怎么没发现?

参考回答:因为并发时序在测试环境里是"运气好"的。开发时数据量小、分支快,A、B 几乎总在同一超步完成,barrier 顺路挡掉了问题;上线后真实延迟抖动(某个调研分支网络慢半秒),跨超步到达立刻出现。这是并发 bug 的通性:时序依赖的 bug 在低负载下隐形。预防两手:一,压测注入延迟抖动——测试时给分支人为加随机延迟(0-500ms),逼出时序问题;二,stream 轨迹断言——在集成测试里断言"汇总节点在单次运行中恰好执行 1 次",执行次数进 CI 检查——超步序列断言是 LangGraph 项目该有的回归测试形态。

第 4 层追问:通用心法

从这两个故障里提炼一条通用教训?

参考回答:LangGraph 的诡异行为 90% 源于"对执行模型的理解偏差",而不是框架 bug。遇到怪现象的标准三步:一,stream() 看真实的超步序列和 updates——别猜图怎么跑的,看引擎实际怎么跑的(多数时候和你脑中的图不一样);二,get_state() 查通道值和 next——状态和"下一步是谁"直接核对;三,对照语义规则自检——补丁语义、reducer 语义、超步可见性、跨超步触发,四个规则对照哪个被违反了。课程的方法论原话:先在纸上写预期超步序列,再跑 stream 对照——这个习惯能把这类"诡异"消灭在提交之前。

考察意图与踩坑点

  • 考察意图:给有 LangGraph 经验的候选人的收官题——两个故障都是课程明讲的经典陷阱,答出即证明"学过且消化了";答不出说明 LangChain/LangGraph 部分需要回去补课(对应课件标注都在)。
  • 踩坑点:把 reducer 缺失说成"框架 bug"(是语义误用);说不出"跨超步触发"就解释不了执行两次;开发环境没复现就认为"无法预防"(缺时序意识)。
  • 一句话总结:findings 被吃 = 没挂 reducer;节点跑两次 = 跨超步边各自触发;解法是 stream 看真实执行 + 超步序列进回归测试。

本篇速记卡

题 一句话核心
Q01 成本爆炸 看轨迹先于猜原因;变更 diff 找变量;回滚止血 + 给模型"出口"根治
Q02 RAG 雪崩 分段归因分诊 → 逆管线四环 → 嵌入版本对齐全量重嵌 → 入库要门禁
Q03 幻觉上升 拒答率是镜像指标;会话内自我强化要消毒历史;软硬闸漏斗配合
Q04 LangGraph 怪象 前者缺 reducer、后者跨超步触发;stream 看真实执行,序列断言进 CI