用 AI Agent 调试 Python:从复现失败测试到验证修复

2026-08-17 34 预计阅读时间: 1 分钟
来源: realpython.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

调试 Python 代码时,AI Agent 的价值不在于“猜一个可能的答案”,而在于协助完成一条可验证的闭环:先用失败测试稳定复现问题,再定位根因、修改代码,最后重新运行测试确认修复没有引入回归。这个过程把自然语言分析和工程证据连接起来,也让调试结果更容易复查。

先把 bug 变成失败测试

一个可靠的调试任务应该从可重复的失败开始。下面的示例假设我们正在实现一个计算购物车总价的函数,要求折扣只应用于商品小计,不影响运费。

将以下内容保存为 test_cart.py,安装 pytest 后运行测试:

from decimal import Decimal


def calculate_total(items, shipping, discount_rate):
    subtotal = sum(Decimal(str(item["price"])) * item["quantity"] for item in items)
    discount = subtotal * Decimal(str(discount_rate))
    return subtotal + Decimal(str(shipping)) - discount


def test_discount_does_not_reduce_shipping():
    items = [{"price": "100.00", "quantity": 1}]

    assert calculate_total(items, "10.00", "0.10") == Decimal("100.00")

运行命令:

python -m pip install pytest
pytest -q

测试会失败,因为 discount_rate 的含义没有明确:当前实现把 0.10 当成了“减去 10% 的小计”,但断言期待的结果是 100 + 10 - 10 = 100。如果实际业务规则是“折扣金额由外部传入”,则函数接口本身就需要重新设计;如果 discount_rate 表示比例,当前实现的计算结果应为 100.00,这个测试反而是正确的。

这正是 AI Agent 参与调试时必须澄清的地方:测试失败本身不等于代码错误,断言、接口契约和业务规则需要一起检查。

给 Agent 的调试上下文

不要只把一段报错信息丢给 Agent。可以提供以下信息:

  • 如何运行测试,以及完整的失败输出。
  • 相关源文件和测试文件。
  • 预期行为与实际行为。
  • 不应改变的公共接口或兼容性要求。
  • 允许修改的范围。

例如,可以这样组织提示词:

请调试这个 Python 项目。

目标:修复购物车总价计算错误,同时保持 calculate_total 的函数签名不变。
现象:pytest -q 失败,test_discount_does_not_reduce_shipping 期望 Decimal("100.00"),实际得到 Decimal("100.00") 或其他值时,请先通过运行测试确认,不要凭猜测修改代码。
要求:
1. 先阅读实现和测试,复现失败。
2. 说明失败是测试断言错误、实现错误,还是输入契约不清晰。
3. 给出最小修改方案。
4. 修改后运行全部测试,并报告测试命令和结果。
5. 不要删除失败测试来让测试通过。

这类提示词把 Agent 的任务限定为“调查、修改、验证”,而不是让它直接生成一段未经运行的修复代码。

用证据定位根因

AI Agent 适合帮助整理调用链、提出假设和生成补充测试,但每个假设都应该通过命令验证。一个实用的调试循环如下:

# 查看项目中的 Python 文件和测试
rg --files -g '*.py'

# 先运行相关测试,缩小反馈范围
python -m pytest -q test_cart.py

# 查看完整失败信息
python -m pytest -vv test_cart.py

# 修复后运行整个测试集
python -m pytest -q

如果规则是折扣比例,测试可以改成更明确的形式:

from decimal import Decimal


def test_discount_rate_applies_to_subtotal_only():
    items = [{"price": "100.00", "quantity": 1}]

    assert calculate_total(items, "10.00", "0.10") == Decimal("100.00")

如果原实现已经得到这个结果,Agent 不应该为了“修复”而改动代码。更合理的结论是:当前示例没有复现实现缺陷,应该继续寻找真实失败输入,或者修正对业务规则的描述。

调试时尤其要警惕几种看似有效但不可靠的行为:只修改测试断言、捕获异常后静默返回、删除边界用例、把固定值写死,以及只运行单个测试而跳过整个测试集。这些操作可能让局部测试变绿,却没有证明问题真正解决。

验证修复,而不是验证猜测

修复完成后,至少需要验证三件事:原始失败用例通过、相关边界用例通过、完整测试集没有回归。可以增加空购物车、多数量商品和零折扣等测试:

from decimal import Decimal


def test_empty_cart_only_charges_shipping():
    assert calculate_total([], "10.00", "0") == Decimal("10.00")


def test_multiple_items_are_discounted_before_shipping():
    items = [
        {"price": "12.50", "quantity": 2},
        {"price": "5.00", "quantity": 1},
    ]

    # 小计 30,折扣 3,运费 4,总价 31
    assert calculate_total(items, "4.00", "0.10") == Decimal("31.00")

如果 Agent 提议重构金额计算,还应检查 Decimal 的使用方式、字符串输入转换和负数输入处理。金额问题不能依赖二进制浮点数的近似结果;而输入校验是否需要加入,则取决于现有接口契约,不应在没有依据时扩大修改范围。

一份可执行的检查清单

把 AI Agent 用在 Python 调试中时,可以按这条顺序工作:

  1. 用一个明确的失败测试描述 bug。
  2. 让 Agent 运行测试,而不是只阅读错误文本。
  3. 区分测试错误、业务规则不清和实现缺陷。
  4. 用最小修改修复根因,保留公共接口和现有行为。
  5. 增加能覆盖边界条件的测试。
  6. 运行相关测试和完整测试集。
  7. 检查 diff,确认没有删除测试或引入无关改动。

AI Agent 可以缩短搜索和试错时间,但“测试通过”仍然只是证据的一部分。真正可信的修复需要同时满足可复现、可解释、可验证三个条件。


相关推荐