先把报错栈和最小复现整理齐——DeepSeek-Coder 定位代码问题前要给的输入

文章导读
把报错原文整段丢给模型,通常只会换回一段泛泛的异常解释。真正影响定位质量的是三份输入:一段标好关键帧的报错栈、一份能独立跑起来的最小复现、以及输入数据 / 期望结果 / 实际结果这三样对照信息。这三样齐了,模型才可能指出具体哪一行、哪个变量、哪种边界出了问题;缺哪一样,回答就容易退回“检查空值”“注意类型”这类通用说法。
📋 目录
  1. A 从运行日志里截出报错栈,标出第一处属于自己代码的帧
  2. B 把复现缩到最小,去掉无关依赖和无关分支
  3. C 整理输入数据、期望结果、实际结果三样东西
  4. D 把三样拼成一次提问,观察模型给的是定位说明还是直接改写
  5. E 按定位方向回到代码里逐条验证
A A

把报错原文整段丢给模型,通常只会换回一段泛泛的异常解释。真正影响定位质量的是三份输入:一段标好关键帧的报错栈、一份能独立跑起来的最小复现、以及输入数据 / 期望结果 / 实际结果这三样对照信息。这三样齐了,模型才可能指出具体哪一行、哪个变量、哪种边界出了问题;缺哪一样,回答就容易退回“检查空值”“注意类型”这类通用说法。

先做输入准备再提问,适用场景是本地能跑起来、能拿到完整日志的调试问题。操作动作:从日志里截出报错栈并标出属于自己代码的帧,把调用路径裁到最小可复现,再写清输入、期望、实际三项。验证方式:把模型给的定位方向逐条落到日志或断点上确认。风险边界:模型只能基于你给的片段推断,片段里的路径、行号、变量名一旦被删改,它的定位就失去依据;涉及不可见的运行时状态时,仍需自己回代码里核对。

从运行日志里截出报错栈,标出第一处属于自己代码的帧

日志里往往混着框架的中间帧,直接全贴会稀释信号。先找两个位置:从栈底往上找第一个文件路径落在自己仓库目录下的帧,那里通常是异常真正抛出的位置;从栈顶往下找第一个自己的帧,那里是这次调用的入口。判断依据很具体——路径是否在自己的源码目录、模块名是否属于本项目、是否落在 site-packages、node_modules、标准库或第三方 SDK 路径下。

下面是一段常见的 Python 报错栈原文,异常发生在自己代码里,但栈中夹着框架帧:

Traceback (most recent call last):
  File "/srv/app/api/order_view.py", line 42, in create_order
    total = calc_total(payload['items'])
  File "/srv/app/services/price.py", line 17, in calc_total
    return sum(i['price'] * i['qty'] for i in items)
  File "/usr/local/lib/python3.11/site-packages/.../middleware.py", line 88, in __call__
    response = self.get_response(request)
TypeError: unsupported operand type(s) for *: 'str' and 'int'

提问时保留 order_view.py 第 42 行和 price.py 第 17 行这两帧就够,中间的框架帧可以压成一句“此处经过框架中间件,与本问题无关”。同时把异常类型那一行原样带上,它是模型判断类型问题的直接线索。如果日志被截断,只留了最后一行异常而丢了栈,可以先调高日志级别或捕获时打印完整 traceback,再回来整理。

把复现缩到最小,去掉无关依赖和无关分支

复现路径越长,模型越容易猜错方向。裁剪的目标是让一段十几行、不依赖数据库和网络的代码就能触发同一个异常。裁剪前后把调用路径写出来对比,能直观看出哪些环节其实没参与出错。

先把报错栈和最小复现整理齐——DeepSeek-Coder 定位代码问题前要给的输入
  • 裁剪前:HTTP 请求 → 路由 → 中间件鉴权 → 读取数据库 → 组装 items → calc_total → 抛错
  • 裁剪后:直接构造 items 列表 → calc_total → 抛错

最小复现脚本可以写成这样,用固定输入替代真实数据:

items = [{'price': '12.50', 'qty': 2}]
total = calc_total(items)
print(total)

判断复现是否够小的方法:把不相关的 import、数据库连接、配置读取逐个注释掉,异常仍然出现,说明这些确实无关;一旦注释后异常消失,就说明该环节是必需上下文,应当保留并写进提问里。最小输入要一并给出,比如上面这条 items 里 price 是字符串——这往往就是异常的直接来源。

整理输入数据、期望结果、实际结果三样东西

这三样决定模型判断的是逻辑问题还是边界条件问题。书写格式建议固定成三段,避免把它混在大段叙述里:

输入数据:items = [{'price': '12.50', 'qty': 2}]
期望结果:total 为数值 25.00,类型为数值类型
实际结果:抛出 TypeError: unsupported operand type(s) for *: 'str' and 'int'

填写示例里要注意几点:输入数据写实际值而不是“用户传过来的数据”,期望结果写具体值和类型而不是“应该正常”,实际结果照抄异常或打印输出而不是转述。如果实际结果是错误的值而不是异常,就把打印出来的原值贴上去。三样之间能对齐,模型才有可能指出是 price 的类型在传入前没有转换,而不是笼统地说“检查数据类型”。

先把报错栈和最小复现整理齐——DeepSeek-Coder 定位代码问题前要给的输入

把三样拼成一次提问,观察模型给的是定位说明还是直接改写

提问模板可以按下面这个骨架组织,把材料放进去、再补一句自己的初步判断:

环境:Python 3.11,项目内函数 calc_total(路径 services/price.py)
报错栈关键帧:price.py 第 17 行,TypeError: str 与 int 相乘
最小复现:items = [{'price': '12.50', 'qty': 2}] 调用 calc_total 即复现
输入数据 / 期望结果 / 实际结果:见上
我已排除:数据库与网络无关,注释后仍复现
请指出出错点在哪一行,以及是哪一步把类型带错的,先不要重写代码。

回答拿到手后先分两类看。解释性回答会指出具体行号、说明变量在哪一步变成字符串、给出验证思路,这类可以直接拿去做下一步;改写性回答会直接贴一段新函数体,却不解释原代码为什么错,这类必须先回到原代码确认改动点是否真的对应异常,否则容易引入未经验证的逻辑。判断点可以概括为一句:如果回答里能对应上你给的输入值、行号和异常类型,它算定位说明;如果通篇是新代码而没引用你的材料,就当草稿处理。

按定位方向回到代码里逐条验证

模型给的推断终究是推断,需要落到可运行的检查上。可以按下面的顺序走:

  1. 在模型指出的那一行之前加一行打印或日志,把参与运算的变量值和类型打出来,确认是不是它说的那种类型。
  2. 如果打了日志但仍不确定,就在该行下断点,单步进入被调用函数,确认值是在哪一层被改变的。
  3. 把模型提到的边界情况手动构造一次,例如把 price 改成数值类型再跑一遍,看异常是否消失、结果是否符合期望。
  4. 确认原因后先做最小改动,只改被证实有问题的那一处,改完用同一份最小复现重跑,再回原始调用路径跑一次。
  5. 如果验证结果与模型的推断不符,就带着新的日志输出重新组织一次提问,而不是直接采纳未验证的改法。

验证过程中保留每次的运行输出,它能同时充当“实际结果”的更新材料。需要结合具体运行环境确认的地方——比如依赖版本差异导致的行为不同——建议先在本地复现确认,再考虑是否调整线上代码。