name: debug-with-file description: 通过文档记录探索、理解演进和分析辅助纠正的交互式假设驱动调试。 argument-hint: “BUG="<bug描述或错误信息>"”
Codex Debug-With-File 提示
概述
增强的证据驱动调试,带文档记录探索过程。记录理解演进,整合洞察,并使用分析来纠正误解。
核心工作流:探索 → 记录 → 日志 → 分析 → 纠正理解 → 修复 → 验证
相对于 /prompts:debug 的关键增强:
- understanding.md:探索和学习的时间线
- 分析辅助纠正:验证和纠正假设
- 整合:简化被证明错误的理解以避免杂乱
- 学习保留:保留学到的内容,即使是失败的尝试
目标 Bug
$BUG
执行过程
会话检测:
├─ 检查是否存在此bug的调试会话
├─ 存在 + understanding.md 存在 → 继续模式
└─ 未找到 → 探索模式
探索模式:
├─ 在代码库中定位错误源
├─ 在 understanding.md 中记录初始理解
├─ 生成可测试假设并进行分析验证
├─ 添加 NDJSON 日志插桩
└─ 输出:假设列表 + 等待用户复现
分析模式:
├─ 解析 debug.log,验证每个假设
├─ 使用分析评估假设并纠正理解
├─ 更新 understanding.md:
│ ├─ 新证据
│ ├─ 纠正的误解(删除线 + 更正)
│ └─ 整合当前理解
└─ 决策:
├─ 确认 → 修复根因
├─ 不明确 → 添加更多日志,迭代
└─ 全部拒绝 → 辅助新假设
修复与清理:
├─ 基于确认的假设应用修复
├─ 用户验证
├─ 记录最终理解和经验教训
├─ 移除调试插桩
└─ 如果未修复 → 返回分析模式
实现细节
会话设置与模式检测
步骤 0:确定项目根目录
检测项目根目录,确保 .workflow/ 产物位置正确:
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
优先通过 git 获取仓库根目录;非 git 项目回退到 pwd 取当前绝对路径。
存储为 {projectRoot},后续所有 .workflow/ 路径必须以此为前缀。
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
const projectRoot = bash('git rev-parse --show-toplevel 2>/dev/null || pwd').trim()
const bugSlug = "$BUG".toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 30)
const dateStr = getUtc8ISOString().substring(0, 10)
const sessionId = `DBG-${bugSlug}-${dateStr}`
const sessionFolder = `${projectRoot}/.workflow/.debug/${sessionId}`
const debugLogPath = `${sessionFolder}/debug.log`
const understandingPath = `${sessionFolder}/understanding.md`
const hypothesesPath = `${sessionFolder}/hypotheses.json`
// 自动检测模式
const sessionExists = fs.existsSync(sessionFolder)
const hasUnderstanding = sessionExists && fs.existsSync(understandingPath)
const logHasContent = sessionExists && fs.existsSync(debugLogPath) && fs.statSync(debugLogPath).size > 0
const mode = logHasContent ? 'analyze' : (hasUnderstanding ? 'continue' : 'explore')
if (!sessionExists) {
bash(`mkdir -p ${sessionFolder}`)
}
探索模式
步骤 1.1:定位错误源
// 从bug描述中提取关键词
const keywords = extractErrorKeywords("$BUG")
// 搜索代码库以找到错误位置
const searchResults = []
for (const keyword of keywords) {
const results = Grep({ pattern: keyword, path: ".", output_mode: "content", "-C": 3 })
searchResults.push({ keyword, results })
}
// 识别受影响文件和函数
const affectedLocations = analyzeSearchResults(searchResults)
步骤 1.2:记录初始理解
创建 understanding.md:
# 理解文档
**会话 ID**:${sessionId}
**Bug 描述**:$BUG
**开始时间**:${getUtc8ISOString()}
---
## 探索时间线
### 迭代 1 - 初始探索(${timestamp})
#### 当前理解
基于bug描述和初始代码搜索:
- 错误模式:${errorPattern}
- 影响区域:${affectedLocations.map(l => l.file).join(', ')}
- 初始假设:${initialThoughts}
#### 代码搜索证据
${searchResults.map(r => `
**关键词:"${r.keyword}"**
- 找到位置:${r.results.files.join(', ')}
- 关键发现:${r.insights}
`).join('
')}
#### 下一步
- 生成可测试假设
- 添加插桩
- 等待复现
---
## 当前整合理解
${initialConsolidatedUnderstanding}
步骤 1.3:生成假设
分析bug并生成3-5个可测试假设:
// 基于错误模式生成假设
const HYPOTHESIS_PATTERNS = {
"not found|missing|undefined|未找到": "data_mismatch",
"0|empty|zero|registered": "logic_error",
"timeout|connection|sync": "integration_issue",
"type|format|parse": "type_mismatch"
}
function generateHypotheses(bugDescription, affectedLocations) {
// 基于错误分析生成针对性假设
// 每个假设包括:
// - id: H1, H2, ...
// - description: 可能出错的地方
// - testable_condition: 要记录的内容
// - logging_point: 添加插桩的位置
// - evidence_criteria: 确认/拒绝的条件
return hypotheses
}
保存到 hypotheses.json:
{
"iteration": 1,
"timestamp": "2025-01-21T10:00:00+08:00",
"hypotheses": [
{
"id": "H1",
"description": "数据结构不匹配 - 预期键不存在",
"testable_condition": "检查字典中目标键是否存在",
"logging_point": "file.py:func:42",
"evidence_criteria": {
"confirm": "数据显示缺失键",
"reject": "键存在且值有效"
},
"likelihood": 1,
"status": "pending"
}
]
}
步骤 1.4:添加 NDJSON 插桩
对于每个假设,在指定位置添加日志:
Python 模板:
# region debug [H{n}]
try:
import json, time
_dbg = {
"sid": "{sessionId}",
"hid": "H{n}",
"loc": "{file}:{line}",
"msg": "{testable_condition}",
"data": {
# 在此处捕获相关值
},
"ts": int(time.time() * 1000)
}
with open(r"{debugLogPath}", "a", encoding="utf-8") as _f:
_f.write(json.dumps(_dbg, ensure_ascii=False) + "
")
except: pass
# endregion
JavaScript/TypeScript 模板:
// region debug [H{n}]
try {
require('fs').appendFileSync("{debugLogPath}", JSON.stringify({
sid: "{sessionId}",
hid: "H{n}",
loc: "{file}:{line}",
msg: "{testable_condition}",
data: { /* 捕获相关值 */ },
ts: Date.now()
}) + "
");
} catch(_) {}
// endregion
步骤 1.5:输出给用户
## 生成的假设
基于错误 "$BUG",生成 {n} 个假设:
{hypotheses.map(h => `
### ${h.id}: ${h.description}
- 日志位置:${h.logging_point}
- 测试内容:${h.testable_condition}
- 确认证据:${h.evidence_criteria.confirm}
- 拒绝证据:${h.evidence_criteria.reject}
`).join('')}
**调试日志**:${debugLogPath}
**下一步**:运行复现步骤,然后返回进行分析。
分析模式
步骤 2.1:解析调试日志
// 解析 NDJSON 日志
const entries = Read(debugLogPath).split('
')
.filter(l => l.trim())
.map(l => JSON.parse(l))
// 按假设分组
const byHypothesis = groupBy(entries, 'hid')
// 验证每个假设
for (const [hid, logs] of Object.entries(byHypothesis)) {
const hypothesis = hypotheses.find(h => h.id === hid)
const latestLog = logs[logs.length - 1]
// 检查证据是否确认或拒绝假设
const verdict = evaluateEvidence(hypothesis, latestLog.data)
// 返回:'confirmed' | 'rejected' | 'inconclusive'
}
步骤 2.2:分析证据并纠正理解
审查调试日志并评估每个假设:
- 解析所有日志条目
- 按假设 ID 分组
- 比较证据与预期条件
- 确定裁决:确认 | 拒绝 | 不明确
- 识别先前理解中的错误假设
- 生成更正
步骤 2.3:更新理解与更正
在 understanding.md 中追加新迭代:
### 迭代 ${n} - 证据分析(${timestamp})
#### 日志分析结果
${results.map(r => `
**${r.id}**:${r.verdict.toUpperCase()}
- 证据:${JSON.stringify(r.evidence)}
- 推理:${r.reason}
`).join('
')}
#### 纠正的理解
先前识别和纠正的误解:
${corrections.map(c => `
- ~~${c.wrong}~~ → ${c.corrected}
- 错误原因:${c.reason}
- 证据:${c.evidence}
`).join('
')}
#### 新洞察
${newInsights.join('
- ')}
${confirmedHypothesis ? `
#### 识别根因
**${confirmedHypothesis.id}**:${confirmedHypothesis.description}
支持此结论的证据:
${confirmedHypothesis.supportingEvidence}
` : `
#### 下一步
${nextSteps}
`}
---
## 当前整合理解(已更新)
${consolidatedUnderstanding}
步骤 2.4:更新 hypotheses.json
{
"iteration": 2,
"timestamp": "2025-01-21T10:15:00+08:00",
"hypotheses": [
{
"id": "H1",
"status": "rejected",
"verdict_reason": "证据显示键存在且值有效",
"evidence": {...}
},
{
"id": "H2",
"status": "confirmed",
"verdict_reason": "日志数据确认时序问题",
"evidence": {...}
}
],
"corrections": [
{
"wrong_assumption": "...",
"corrected_to": "...",
"reason": "..."
}
]
}
修复与验证
步骤 3.1:应用修复
基于确认的假设,在受影响文件中实施修复。
步骤 3.2:记录解决方案
在 understanding.md 中追加:
### 迭代 ${n} - 解决方案(${timestamp})
#### 应用的修复
- 修改的文件:${modifiedFiles.join(', ')}
- 修复描述:${fixDescription}
- 解决的根因:${rootCause}
#### 验证结果
${verificationResults}
#### 经验教训
从此调试会话中学到的:
1. ${lesson1}
2. ${lesson2}
3. ${lesson3}
#### 未来关键洞察
- ${insight1}
- ${insight2}
步骤 3.3:清理
通过搜索区域标记移除调试插桩:
const instrumentedFiles = Grep({
pattern: "# region debug|// region debug",
output_mode: "files_with_matches"
})
for (const file of instrumentedFiles) {
// 移除区域标记之间的内容
removeDebugRegions(file)
}
会话文件夹结构
{projectRoot}/.workflow/.debug/DBG-{slug}-{date}/
├── debug.log # NDJSON 日志(执行证据)
├── understanding.md # 探索时间线 + 整合理解
└── hypotheses.json # 假设历史与裁决
理解文档模板
# 理解文档
**会话 ID**:DBG-xxx-2025-01-21
**Bug 描述**:[原始描述]
**开始时间**:2025-01-21T10:00:00+08:00
---
## 探索时间线
### 迭代 1 - 初始探索(2025-01-21 10:00)
#### 当前理解
...
#### 代码搜索证据
...
#### 生成的假设
...
### 迭代 2 - 证据分析(2025-01-21 10:15)
#### 日志分析结果
...
#### 纠正的理解
- ~~[错误]~~ → [更正]
#### 分析结果
...
---
## 当前整合理解
### 已知信息
- [有效理解点]
### 被证伪的
- ~~[证伪的假设]~~
### 当前调查重点
[当前焦点]
### 剩余问题
- [未解问题]
调试日志格式(NDJSON)
每行是一个 JSON 对象:
{"sid":"DBG-xxx-2025-01-21","hid":"H1","loc":"file.py:func:42","msg":"检查字典键","data":{"keys":["a","b"],"target":"c","found":false},"ts":1734567890123}
| 字段 | 描述 |
|---|---|
sid |
会话 ID |
hid |
假设 ID(H1, H2, …) |
loc |
代码位置 |
msg |
测试内容 |
data |
捕获的值 |
ts |
时间戳(毫秒) |
迭代流程
首次调用(BUG="error"):
├─ 会话不存在 → 探索模式
├─ 提取错误关键词,搜索代码库
├─ 在 understanding.md 中记录初始理解
├─ 生成假设
├─ 添加日志插桩
└─ 等待用户复现
复现后(BUG="error"):
├─ 会话存在 + debug.log 有内容 → 分析模式
├─ 解析日志,评估假设
├─ 更新 understanding.md:
│ ├─ 证据分析结果
│ ├─ 纠正的误解(删除线)
│ ├─ 新洞察
│ └─ 更新的整合理解
├─ 更新 hypotheses.json 与裁决
└─ 决策:
├─ 确认 → 修复 → 记录解决方案
├─ 不明确 → 添加日志,记录下一步
└─ 全部拒绝 → 辅助新假设
输出:
├─ {projectRoot}/.workflow/.debug/DBG-{slug}-{date}/debug.log
├─ {projectRoot}/.workflow/.debug/DBG-{slug}-{date}/understanding.md(演进文档)
└─ {projectRoot}/.workflow/.debug/DBG-{slug}-{date}/hypotheses.json(历史)
错误处理
| 情况 | 行动 |
|---|---|
| 空的 debug.log | 验证复现是否触发了代码路径 |
| 所有假设被拒绝 | 基于证伪的假设生成新假设 |
| 修复无效 | 记录失败修复尝试,基于精炼理解迭代 |
| >5 次迭代 | 审查整合理解,以完整上下文升级 |
| 理解过长 | 积极整合,将旧迭代归档到单独文件 |
整合规则
更新“当前整合理解”时:
- 简化证伪项:移至“被证伪的”并单行摘要
- 保留有效洞察:将确认发现提升至“已知信息”
- 避免重复:不在整合部分重复时间线细节
- 关注当前状态:当前所知,而非过程
- 保留关键更正:保留重要错误→正确转换以用于学习
差(杂乱):
## 当前整合理解
在迭代1我们以为X,但在迭代2我们发现Y,然后在迭代3...
还有我们检查A找到B,然后检查C...
好(整合):
## 当前整合理解
### 已知信息
- 错误在运行时更新时发生,而非初始化
- 配置值为None(非缺失键)
### 被证伪的
- ~~初始化错误~~(时序证据)
- ~~缺失键假设~~(键存在)
### 当前调查重点
为什么配置值在更新时为None?
关键特性
| 特性 | 描述 |
|---|---|
| NDJSON 日志 | 结构化调试日志与假设跟踪 |
| 假设生成 | 分析辅助的假设创建 |
| 探索文档记录 | understanding.md 带时间线 |
| 理解演进 | 时间线 + 更正跟踪 |
| 错误纠正 | 删除线 + 错误假设推理 |
| 整合学习 | 当前理解部分 |
| 假设历史 | hypotheses.json 带裁决 |
| 分析验证 | 在关键决策点 |
适用场景
最适合:
- 需要多轮调查的复杂bug
- 调试过程学习有价值
- 团队需要理解调试原理
- bug可能复发,文档有助于预防
现在为bug执行 debug-with-file 工作流:$BUG