用四类小任务检验 GPT-6 Astra 的 Python 实战能力

2026-09-04 46 预计阅读时间: 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.

预计阅读时间:11 分钟

让 AI 写一个排序函数并不难,真正有区分度的是那些规模很小、要求却不完全明确的任务。GPT-6 Astra 接受了一组带有 Real Python 风格的“手感测试”:用 Turtle 画一条正在读书的蟒蛇、判断一段 Python 代码的年代、完成一次微小修改,以及处理一个并不存在的函数。

这四类任务分别触碰了生成式编程助手的不同能力:把自然语言转成视觉程序、从语法细节推断版本、在局部约束下修改代码,以及面对错误前提时保持诚实。评价这类模型,不能只看结果是否“像那么回事”,还要看代码能否运行、改动是否克制、解释是否经得起验证。

Turtle 绘图考验的不只是语法

“画一条正在读书的蟒蛇”听起来像一道轻松的创意题,但它同时要求模型处理坐标、图层顺序、颜色、线宽和构图。蛇身、头部、眼睛和书本都可能单独正确,组合后却出现遮挡、比例失衡或主体跑出画布的问题。

这类任务适合检查三个方面:

  • 生成的程序能否直接运行,而不是只提供零散片段;
  • 图形元素是否被拆成可调整的函数;
  • 模型能否把“正在读书”这样的语义落实为明确的视觉关系。

下面是一个可直接运行的简化版本。运行前需要本机 Python 带有 Tk 支持;大多数桌面版 Python 已经包含它。将代码保存为 reading_python.py,执行 python reading_python.py 即可打开绘图窗口。

import turtle

screen = turtle.Screen()
screen.setup(900, 650)
screen.bgcolor("#f5f0e6")
screen.title("A Python Reading a Book")

pen = turtle.Turtle()
pen.hideturtle()
pen.speed(0)
pen.pensize(4)


def filled_shape(points, fill, outline="#263238"):
    pen.color(outline, fill)
    pen.penup()
    pen.goto(points[0])
    pen.pendown()
    pen.begin_fill()
    for point in points[1:]:
        pen.goto(point)
    pen.goto(points[0])
    pen.end_fill()


def dot(x, y, size, color):
    pen.penup()
    pen.goto(x, y)
    pen.dot(size, color)


# Coiled body
pen.color("#2e7d32")
pen.pensize(46)
pen.penup()
pen.goto(-260, -110)
pen.setheading(-15)
pen.pendown()
for radius in (180, 145, 110):
    pen.circle(radius, 235)

# Neck and head
pen.penup()
pen.goto(-70, 40)
pen.setheading(78)
pen.pendown()
pen.forward(145)
pen.dot(105, "#43a047")

# Eyes and glasses
dot(-96, 185, 14, "white")
dot(-55, 190, 14, "white")
dot(-94, 185, 6, "#111111")
dot(-53, 190, 6, "#111111")
pen.color("#37474f")
pen.pensize(3)
for x, y in ((-96, 185), (-55, 190)):
    pen.penup()
    pen.goto(x, y - 16)
    pen.setheading(0)
    pen.pendown()
    pen.circle(16)
pen.penup()
pen.goto(-80, 186)
pen.pendown()
pen.goto(-70, 188)

# Open book in front of the snake
filled_shape(
    [(-185, 35), (-15, 0), (-15, -145), (-205, -105)],
    "#fffdf5",
)
filled_shape(
    [(-15, 0), (170, 45), (190, -95), (-15, -145)],
    "#fffdf5",
)
pen.color("#c62828")
pen.pensize(5)
pen.penup()
pen.goto(-15, 0)
pen.pendown()
pen.goto(-15, -145)

# Printed lines
pen.color("#78909c")
pen.pensize(2)
for y in (-25, -55, -85):
    pen.penup()
    pen.goto(-160, y)
    pen.pendown()
    pen.goto(-45, y - 22)
    pen.penup()
    pen.goto(20, y - 15)
    pen.pendown()
    pen.goto(145, y + 15)

screen.mainloop()

这个例子刻意使用普通函数和坐标列表,没有引入额外依赖。继续测试模型时,可以追加明确约束,例如“不得修改 filled_shape()”“只把书封面改成蓝色”或“让窗口支持按 S 键导出 PostScript”。这样就能从一次性生成,进一步观察它是否会尊重现有结构。

从代码细节判断 Python 的“年份”

所谓判断 Python 的 vintage,并不是只看代码用了 print 还是 print()。可靠的判断应该引用可核实的语言特性,并给出范围而不是武断地猜一个年份。

例如,下面几种线索具有不同的时间边界:

name = "Astra"
print(f"Hello, {name}")                 # f-string: Python 3.6+

if (size := len(name)) > 3:             # := operator: Python 3.8+
    print(size)

items = ["book", "snake"]
match items:                             # structural matching: Python 3.10+
    case [first, *_]:
        print(first)

看到 match 语句,可以合理地说这段代码要求 Python 3.10 或更高版本;但不能仅凭这一点断言代码写于 2021 年,因为开发者可能在多年后仍使用相同语法。好的模型应该区分“最低运行版本”和“实际创作年代”。

还要警惕经过现代化工具改写的代码。ruffpyupgrade 或人工迁移都可能给旧项目加入新语法,因此语法年代只能作为证据之一,还应结合依赖版本、项目元数据和提交历史。

微小修改最能暴露边界意识

让模型“只改一行”往往比让它重写模块更有价值。局部编辑要求它理解现有行为,找到最小变更点,并避免顺手调整格式、命名和无关逻辑。

测试时可以准备一个带测试的微型项目:

# pricing.py
def total_price(unit_price: float, quantity: int) -> float:
    """Return the total price before tax."""
    return unit_price * quantity
# test_pricing.py
from pricing import total_price


def test_total_price():
    assert total_price(19.99, 3) == 59.97

然后只提出一个窄需求:“结果四舍五入到两位小数,不要更改函数签名。”预期修改应接近:

def total_price(unit_price: float, quantity: int) -> float:
    """Return the total price before tax."""
    return round(unit_price * quantity, 2)

可用以下命令验证:

python -m pip install pytest
python -m pytest -q

观察重点不是模型能否想到 round(),而是它是否遵守“不要更改函数签名”,是否避免重写整个文件,以及是否知道浮点金额在真实支付系统中通常应改用 decimal.Decimal。微型题目也需要说明工程边界。

遇到虚构函数时,诚实比补全更重要

“解释 python.magic_reading_snake() 的参数”之类的问题包含一个危险前提:标准库或常见 API 中未必存在这个函数。语言模型容易根据名字编造签名、返回值和版本历史,生成形式完整但无法验证的答案。

更可靠的处理顺序是:

  1. 明确说明无法确认该函数存在;
  2. 询问它来自哪个包、模块或项目;
  3. 建议用运行时检查或官方文档核实;
  4. 如果用户只是希望实现该功能,再提供一个明确标注为自定义实现的方案。

可以用下面的脚本检查一个可导入模块是否公开某个名称。运行时把 MODULE_NAMEFUNCTION_NAME 改成实际值:

import importlib
import inspect

MODULE_NAME = "turtle"
FUNCTION_NAME = "magic_reading_snake"

module = importlib.import_module(MODULE_NAME)
function = getattr(module, FUNCTION_NAME, None)

if function is None:
    print(f"{MODULE_NAME}.{FUNCTION_NAME} does not exist")
elif callable(function):
    print(f"Signature: {inspect.signature(function)}")
    print(inspect.getdoc(function) or "No docstring available")
else:
    print(f"{MODULE_NAME}.{FUNCTION_NAME} exists but is not callable")

这比根据函数名猜测用途更可靠。不过,getattr() 只能检查当前安装的版本,动态生成属性的模块也可能需要额外分析。对于第三方包,还应记录包名和版本,例如运行 python -m pip show <package>

如何把这类测试用于团队选型

一次有趣的 Turtle 绘图不能证明模型适合维护生产代码,但这组任务可以构成成本很低的初筛。团队采用类似方法时,应固定提示词、运行环境和评分标准,并保存模型的原始输出。

建议至少检查以下项目:

  • 可执行性:代码能否在声明的 Python 版本中直接运行;
  • 约束遵循:小改动是否真的保持局部,公开接口是否被意外修改;
  • 版本推理:结论是否引用具体语法,同时承认推断范围;
  • 抗幻觉能力:面对不存在的函数,是否先验证再回答;
  • 维护成本:函数划分、命名和错误处理是否方便后续开发者接手;
  • 验证习惯:模型是否主动给出测试、命令或可复现步骤。

这类“手感测试”的价值不在于排出一个永久有效的模型榜单,而在于把团队日常遇到的模糊需求压缩成可重复的小实验。选择编程助手时,漂亮的首轮答案只是起点;更重要的是它能否在约束、证据和不确定性面前保持稳定。


相关推荐