代码语言
知识点思维导图
61 个知识节点
生产工程(16) - 附录:问题排查清单
这份清单用于定位首个异常阶段,不用于把所有检查项无差别执行一遍。 开始前先固定一个能稳定复现的输入、请求 ID、版本、环境和时间窗口。 每次只改变一个主要变量;没有原失败样本的回放结果,就不能宣布修复完成。
一、先保存故障现场
1.1 请求身份
- 保存客户端 request ID 和服务端 Trace ID。
- 记录用户、租户、权限角色和会话 ID,敏感值只保存脱敏摘要。
- 记录请求开始时间、首字时间、完成时间和客户端超时点。
- 记录应用提交、配置版本、Prompt 版本、模型标识和知识库快照。
1.2 输入与输出
- 保存脱敏后的原始输入,不只保存改写后的 Prompt。
- 保存最终消息序列及每部分 Token 数。
- 保存模型原始响应、结束原因、错误码和响应头。
- 保存检索候选、工具提议、参数校验和外部调用结果。
1.3 先做边界判断
- 单个用户失败还是同租户失败?
- 单个模型失败还是所有模型失败?
- 单类文档失败还是所有查询失败?
- 新版本首次出现还是旧版本也可复现?
- 故障正在扩大时先停止扩量,保留上一稳定版本的回滚入口。
二、模型没有返回结果
2.1 先定位在哪一层断开
- 浏览器没有发出请求:检查表单校验、事件绑定和客户端异常。
- 网关没有收到请求:检查 URL、DNS、代理、CORS 和网络超时。
- 应用没有调用模型:检查鉴权、限流、队列和输入校验。
- 模型返回错误:按状态码处理,不把所有错误统一改成重试。
- 模型成功但前端无内容:检查流式事件解析、缓冲和完成事件。
2.2 应保存的证据
- 浏览器 Network 中的请求状态、响应头和响应体。
- 应用日志中的上游请求 ID、模型名和耗时分段。
- 模型服务错误码,例如认证失败、配额、限流或上下文超限。
- 流式事件序号、事件类型、结束原因和最后成功块。
2.3 禁止的修复方式
- 不把认证失败加入重试循环。
- 不在日志中打印 API Key 来验证配置。
- 不用无限延长超时掩盖队列拥塞。
- 不把错误响应替换成空字符串后返回 HTTP 200。
三、回答很慢
3.1 分段而不是只看总耗时
- 客户端到网关耗时。
- 鉴权、限流和队列等待时间。
- 检索、重排和权限过滤时间。
- Prompt 组装与 Token 统计时间。
- Prefill 到首 Token 的 TTFT。
- Decode 阶段的 TPOT 与输出 Token 数。
3.2 用现象判断候选根因
| 现象 | 优先检查 | 不应先做 |
|---|---|---|
| TTFT 高、TPOT 正常 | 输入过长、排队、Prefill、冷启动 | 盲目缩短输出 |
| TTFT 正常、TPOT 高 | 批次、硬件、并发、解码参数 | 只优化检索 |
| 检索耗时高 | 查询数量、索引、过滤、重排候选数 | 增大模型超时 |
| 高峰期才慢 | 队列、连接池、并发上限、限流 | 用平均值证明正常 |
| 客户端慢、服务端快 | 代理缓冲、网络、渲染频率 | 更换模型 |
3.3 恢复判定
- 用同一请求集比较 P50、P95 和 P99,不只看单次成功。
- 同时比较质量、错误率、吞吐和成本,避免以错误回答换速度。
- 冷启动与稳态分别测量,说明样本量和并发模型。
四、上下文超限或输出被截断
4.1 预算拆解
- 分别统计系统消息、历史、检索材料、工具 Schema 和用户输入 Token。
- 为输出预留明确预算,不能把整个窗口都分配给输入。
- 确认 tokenizer 与实际模型匹配。
- 保存被删除、摘要或截断的消息 ID。
4.2 判断截断发生位置
- 客户端是否限制输入字符数。
- 后端是否裁剪历史或检索片段。
- SDK 是否设置过小的最大输出 Token。
- 模型结束原因是否为长度限制。
- 流式连接是否在结束事件前断开。
4.3 修复验收
- 正常输入、刚好到边界和超过边界三组样本都有明确结果。
- 超限请求应在可解释位置拒绝或压缩,不静默丢失关键约束。
- 被压缩内容的引用关系仍能回到原文。
五、RAG 没有召回正确资料
5.1 按管线定位
- 解析:原文是否成功提取,表格、图片和标题是否丢失?
- 切分:答案所需事实是否被拆散,chunk 是否保留文档位置?
- 索引:目标 chunk 是否进入当前集合,向量模型和维度是否一致?
- 查询:原查询和改写查询是否保留编号、主体与时间条件?
- 召回:正确 chunk 是否进入 topK,关键词与向量两路各自结果是什么?
- 过滤:metadata 或权限过滤是否误删正确候选?
- 重排:正确候选是否在 rerank 后掉出上下文?
5.2 必须保存
- 文档 ID、版本、chunk ID 和原文位置。
- 原查询、改写查询、各路候选及原始分数。
- 过滤前后候选、过滤表达式和用户权限。
- 重排前后顺序、模型版本和最终送入 Prompt 的片段。
5.3 恢复判定
- 固定标注集上的 Recall@K 和 NDCG 达到基线。
- 编号、专有名词、同义表达和无答案问题分别通过。
- 权限测试证明无越权召回,不能只验证相关性。
六、召回正确但回答错误
6.1 区分生成阶段问题
- 正确证据是否真的进入最终 Prompt,而不是只出现在检索日志。
- Prompt 是否要求证据不足时拒答。
- 多份证据冲突时是否声明版本和冲突,而不是任意选择。
- 引用 ID 是否在模板渲染和模型输出解析中保持稳定。
- 后处理是否错误删除限定条件或拼接了其他会话内容。
6.2 反例回放
- 提供支持答案的证据样本。
- 提供没有答案的证据样本。
- 提供两份相互冲突的证据样本。
- 提供用户问题含错误前提的样本。
- 检查回答、拒答、引用和不确定性表达是否分别符合契约。
七、工具调用失败或产生错误副作用
7.1 执行前检查
- 工具名称来自白名单,不能由模型拼接 URL 或命令直接执行。
- 参数先通过 Schema,再通过业务权限和资源范围校验。
- 写操作使用幂等键,重试不会重复扣款、发信或创建记录。
- 高风险操作需要确认或审批,模型不能替用户同意。
- 工具超时、最大步骤和总预算都有硬上限。
7.2 失败分层
| 阶段 | 典型失败 | 首个证据 |
|---|---|---|
| 模型提议 | 工具名错误、字段缺失 | 原始 tool call |
| Schema 校验 | 类型、枚举、必填项错误 | 校验错误路径 |
| 授权 | 用户无资源权限 | 主体、资源、拒绝原因 |
| 执行 | 超时、依赖失败、业务冲突 | 工具 Trace 和状态码 |
| 回传 | 结果过大、序列化失败 | 原始结果与截断记录 |
| 重试 | 重复副作用 | 幂等键与数据库约束 |
7.3 事故处置
- 先关闭产生副作用的入口,不继续自动重试。
- 查询幂等记录和最终业务状态,不能从模型文本推断是否成功。
- 需要补偿时记录补偿动作与原事务关联。
- 修复后重放同一重复请求和超时请求。
八、结构化输出解析失败
8.1 定位顺序
- 保存模型原始响应,禁止只记录解析异常。
- 确认实际是否启用了目标 Schema 或结构化输出能力。
- 区分 JSON 语法错误、Schema 错误和业务规则错误。
- 检查流式拼接是否漏块、重复块或提前解析。
- 检查修复器是否悄悄改变金额、ID、日期等业务值。
8.2 验收样本
- 合法最小对象。
- 缺少必填字段。
- 枚举值不合法。
- 数字越界或字符串过长。
- 多余字段与嵌套层级错误。
- 模型拒答或安全拦截而非业务对象。
九、串话、记忆错误或数据泄漏
9.1 检查数据范围
- 会话查询是否同时限定用户、租户和会话 ID。
- 缓存 Key 是否包含模型、Prompt、权限和知识版本。
- Memory 写入是否记录来源、范围、过期和删除策略。
- 检索过滤是否在召回阶段执行,而不是生成后再遮盖。
- 日志、Trace 和评测数据是否完成脱敏。
9.2 立即停止条件
- 出现跨用户、跨租户或跨权限数据时立即停用相关缓存或记忆入口。
- 保留访问日志和版本,不通过清缓存销毁根因证据。
- 按受影响范围轮换密钥、撤销访问并启动安全响应流程。
十、重试、降级与恢复失控
10.1 重试检查
- 只有瞬时且可重试的错误进入重试策略。
- 使用有上限的指数退避与随机抖动。
- 认证、参数和权限错误不重试。
- 写操作在重试前确认幂等与超时后的真实状态。
10.2 降级检查
- 备用模型满足所需上下文、工具或结构化输出能力。
- 缓存回答绑定权限和知识版本。
- 规则回答或人工接管有明确用户提示。
- 主链路恢复后有探测和回切条件,避免永久停留在降级状态。
十一、前端状态错误
11.1 流式交互
- loading、streaming、done、error 和 cancelled 是互斥且可解释的状态。
- 用户取消会传递到服务端,而不是只隐藏界面。
- 中途失败保留已接收内容并明确标记未完成。
- 重试创建新请求 ID,不把两次事件流拼到同一回答。
- 引用与正文使用稳定 ID 关联,不按数组位置猜测。
11.2 浏览器验收
- 慢首字时有进行中状态,布局不跳动。
- 4xx 与 5xx 展示不同的可操作信息。
- 键盘、移动端和窄屏下仍能取消、重试和查看引用。
- 控制台无未处理 Promise、重复 key 和 hydration 错误。
十二、发布前回归记录
| 字段 | 必须记录的内容 |
|---|---|
| 问题样本 | 能稳定触发故障的最小输入和前置状态 |
| 根因位置 | 第一个偏离预期的组件、字段或状态迁移 |
| 基线版本 | 代码、配置、模型、Prompt、索引和数据快照 |
| 候选变更 | 只包含当前根因对应的最小修改 |
| 正常路径 | 原有成功样本没有退化 |
| 边界路径 | 长度、并发、权限、空值和容量边界 |
| 失败路径 | 原失败样本不再出现且错误可解释 |
| 运行指标 | 错误率、延迟、吞吐、质量和成本 |
| 停止条件 | 触发回滚或停止扩量的明确阈值 |
| 未覆盖风险 | 尚未验证的模型、租户、数据或外部依赖 |
十三、总结
- 先保留证据:请求、版本、输入、中间状态和原始输出缺一项,根因链就可能断裂。
- 按阶段定位:模型、检索、工具、存储和前端分别有不同证据,不能都归因于“模型不稳定”。
- 验证异常路径:成功一次只证明主路径曾经可用,不能证明重试、权限和恢复正确。
- 控制影响范围:数据泄漏、重复副作用和错误自动化必须先停入口,再分析和回放。
- 完成标准:同一失败样本在固定版本和环境下通过,且正常路径与关键指标没有退化。