--- name: systematic-debugging description: 当用户要求诊断或修复错误、测试失败、异常行为或性能退化时使用;永久修复前先建立可重复的问题验证路径,无法立即复现时建立线上证据采集路径。 --- # 系统化调试 用证据定位根因,但让调查深度与问题复杂度匹配。简单问题快速验证;复杂问题逐步缩小;无法立即复现的线上问题先补齐可观测性。 ## 先确认授权范围 - **只诊断**:输出根因、证据与建议,不实施永久修复。 - **诊断并修复**:确认根因后实施修复并验证。 - 用户受影响的线上事故可以先采取可逆措施恢复服务。回滚、关闭功能开关、降级或隔离流量属于**临时缓解**,不是根因修复;恢复后继续诊断。 ## 1. 明确问题 从已有上下文确认: - 实际发生了什么,预期是什么? - 在什么环境、输入和条件下出现? - 用户观察到的准确症状是什么? - 已有哪些错误信息、日志、截图、性能数据或复现步骤? 信息充分时直接调查,不为走流程重复提问。证据不足且答案会改变调查方向时,再向用户确认。 ## 2. 建立证据路径 ### 可以立即复现 永久修复前,先建立一条**可重复的问题验证路径**。它可以是测试、命令、接口请求、浏览器操作或其他可执行步骤,但应当: - 捕获用户报告的真实症状,而不是附近的另一个错误; - 能重复运行,并明确判断问题是否仍然存在; - 尽可能稳定、快速,并可由代理独立执行; - 记录实际运行结果,不把“理论上能复现”当作证据。 初始路径不必是最小复现。先获得可靠信号,再按需收紧。 ### 无法立即复现 低频、环境相关或只在线上出现的问题,改为建立**证据采集路径**: 1. 记录现象、影响范围、已知条件和已经排除的原因。 2. 明确当前要区分的假设,以及什么信号能支持或否定它们。 3. 在最有区分力的位置增加结构化日志、指标、链路信息、监控或报警。 4. 说明观察窗口、后续检查方式和收到证据后的下一步。 此时明确写出“根因尚未确认”。不要为了继续流程而猜测根因。 ## 3. 按证据选择诊断方法 下面是工具箱,不是固定检查清单。选择成本最低、最能区分当前假设的方法: - **阅读现有证据**:完整阅读错误、调用栈、相关日志和性能数据。 - **检查近期变化**:查看相关提交、依赖、配置和环境差异。 - **针对性临时日志**:只记录能区分假设的数据流和组件边界,使用统一可搜索标识。 - **断点或交互式调试**:直接观察运行时状态,避免用大量日志间接猜测。 - **Git 二分定位**:已知正常和异常版本时,用 `git bisect` 定位首次引入问题的提交。 - **差异对比**:让相同输入经过正常版本与异常版本,比较输出、状态或性能。 - **请求或事件重放**:保存真实输入,在隔离环境中重放问题路径。 - **性能诊断**:先建立基线,再使用性能分析、时间测量或查询计划定位退化。 - **最小复现**:完整场景过慢、不稳定或变量过多时,逐步删除无关条件。 临时日志、监控和报警不得记录密钥、令牌、个人信息或完整敏感载荷。报警应对应可执行动作,避免形成长期噪声。 ## 4. 形成并验证根因假设 - 假设必须能够被证据推翻,并说明它预测会观察到什么。 - 优先验证最能区分多个可能原因的信号。 - 一次只改变一个关键变量;失败后根据新证据更新判断,不叠加未经验证的修复。 - 沿错误数据和调用关系追到最初产生异常的位置,区分症状、直接原因与根因。 - 多次尝试持续暴露不同位置的共享状态或耦合时,暂停补丁式尝试,与用户讨论是否属于架构问题;不使用固定次数代替判断。 ## 5. 修复与验证 仅在用户授权修复且根因已经确认后执行;进入永久修复实现时调用 `test-driven-development` 判断证据寿命,选择当前证据以及是否需要永久保护: 1. 只有永久保护门槛成立且存在能够覆盖真实问题的正确测试接缝时,才把问题固化为失败测试。 2. 不满足永久保护门槛或没有正确接缝时,记录这一限制,使用可重复的问题验证路径,不添加无法捕获真实问题的浅层测试。 3. 修复已经确认的根因,不混入无关重构。 4. 重新运行最初的问题验证路径,确认用户报告的原始症状消失。 5. 运行受影响范围的回归检查。 6. 删除临时日志、脚本和诊断代码;确有长期价值的观测项应明确保留理由。 ## 输出 按任务实际范围简洁报告: ```markdown ## 现象 ## 问题验证路径或证据采集路径 ## 根因与证据 ## 修复或建议方案 ## 验证结果 ## 剩余风险 ``` 只诊断时省略“验证结果”中的修复验证,不把建议方案描述为已经完成的修改。