M3.1-Flash-Preview 生成的代码总跑不起来 / 是提示写得太松吗?

文章导读
M3.1-Flash-Preview 生成的代码总跑不起来,多数情况下不是它完全不会写,而是提示写得太松:只说了要做什么,没说输入长什么样、输出要什么结构、空值和异常怎么处理、用什么命令验证。建议先把判断方向固定成一步:拿最近一次失败的提示和生成结果,把报错定位到具体行,再从那一行倒推缺失的约束,补进提示后重新生成并立刻运行。如果重写后仍然报同一处错误,再考虑换实现语言、拆分任务或缩小函数职责,而
📋 目录
  1. Ⅰ 把跑不起来的代码和原始提示并排放在一起
  2. Ⅱ 把需求拆成输入、输出、边界三类约束
  3. Ⅲ 在提示里补一段可运行示例
  4. Ⅳ 重新生成后立刻运行并记录差异
  5. Ⅴ 把有效约束固化成可复用模板
A A

M3.1-Flash-Preview 生成的代码总跑不起来,多数情况下不是它完全不会写,而是提示写得太松:只说了要做什么,没说输入长什么样、输出要什么结构、空值和异常怎么处理、用什么命令验证。建议先把判断方向固定成一步:拿最近一次失败的提示和生成结果,把报错定位到具体行,再从那一行倒推缺失的约束,补进提示后重新生成并立刻运行。如果重写后仍然报同一处错误,再考虑换实现语言、拆分任务或缩小函数职责,而不是继续反复点“重新生成”。

适用场景:同一个需求连续多次生成都跑不起来,且报错集中在输入解析、类型转换或边界处理。操作动作:记录原始提示、生成代码、报错行,把输入格式、期望输出、空值与异常规则写成可检查条件,连同示例函数签名一起放回提示。验证方式:重新生成后用同一条命令运行,逐条对比实际输出与期望输出。风险边界:约束越具体,模型越可能只针对示例写死,所以示例要覆盖不止一种输入,不要把示例当成唯一契约。

把跑不起来的代码和原始提示并排放在一起

这一步的目的不是评价模型,而是判断问题出在需求缺失还是实现出错。建议用文本文件记录三样东西:原始提示原文、生成代码、完整报错(包含错误类型和行号)。三样放在同一屏里对照,能直接看出提示里没写的东西是否正好对应报错位置。

例如原始提示:

写一个 Python 函数,读取 CSV 文件,统计每个用户的订单金额总和,返回字典。

生成代码只保留关键部分:

def sum_orders(path):
    result = {}
    for line in open(path):
        user, amount = line.split(',')
        result[user] += amount
    return result

运行后报错:

M3.1-Flash-Preview 生成的代码总跑不起来 / 是提示写得太松吗?
ValueError: not enough values to unpack (expected 2, got 1)

对照记录可以写成这样:

  • 报错行:第 3 行 user, amount = line.split(',')。提示里没写 CSV 是否有表头、空行怎么处理,表头行按逗号拆分后字段数不匹配就会在这里炸。
  • 潜在第二处错误:第 4 行 result[user] += amount。某个 user 第一次出现时 key 不存在,触发 KeyError,提示里没要求默认值。
  • 潜在第三处错误:amount 是字符串,直接相加会做拼接或在后续运算时抛 TypeError,提示里没规定数值类型。

如果这几处问题都来自提示没写清楚,而不是模型不能在 Python 里实现求和,那么方向就是补约束,而不是换模型。反过来说,如果报错是语法错误或调用了环境里不存在的库,先确认运行环境里有没有这个库、版本是否匹配,再决定要不要改写提示。

把需求拆成输入、输出、边界三类约束

提示里要出现能被检查的具体条件,至少覆盖输入格式、期望输出、空值与异常输入。下面这段可以直接拼在需求描述后面,替换其中的字段名和类型。

输入约束:
- 文件为 UTF-8 编码的 CSV,第一行是表头,列为 user_id,amount
- amount 为十进制数字字符串,可能带小数
- 文件末尾可能有一个空行

输出约束:
- 返回 dict,key 为 str 类型的 user_id,value 为 float 类型的金额合计
- 不对结果排序

边界约束:
- 空文件或只有表头时,返回空 dict,不抛异常
- 某一行字段数不为 2 时,跳过该行
- amount 无法转成 float 时,跳过该行
- 同一 user_id 出现多次时金额相加

这样做的作用是让模型在写代码前先看到判断条件,生成的实现通常会把解析、类型转换、默认值处理分开写。需要结合环境确认的一点是,跳过异常行还是抛出异常,取决于业务侧更希望看到脏数据还是拿到完整结果,提示里要明确二选一,不要写“合理处理”“尽量健壮”这类无法检查的要求。

M3.1-Flash-Preview 生成的代码总跑不起来 / 是提示写得太松吗?

在提示里补一段可运行示例

形容词对生成代码没有约束力,“健壮的、规范的、优雅的”都不能被验证。用示例代替形容词更有效:给出函数签名、调用方式、期望打印结果,让模型照着对齐接口和风格。

请实现函数签名:
def sum_orders(path: str) -> dict:
    ...

调用方式:
print(sum_orders('orders.csv'))

orders.csv 内容:
user_id,amount
u1,10.5
u2,5
u1,20

期望打印结果:
{'u1': 30.5, 'u2': 5.0}

要求:不打印除返回值之外的调试信息;如果文件不存在,抛出 FileNotFoundError。

这段示例同时解决了几个模糊点:返回的是字典而不是列表;金额是 float;重复 user_id 相加;输出格式固定。把示例和上一节的边界约束一起放进提示,模型就不太可能只在示例这一种输入上写通,而会顺带处理表头和空行。

重新生成后立刻运行并记录差异

重新生成之后不要先读代码,先跑。运行命令建议固定成可复现的一条,例如把上面的示例文件保存为 orders.csv 后执行:

python -c "from sum_orders import sum_orders; print(sum_orders('orders.csv'))"

实际输出与期望输出的差异,按三类记录:

M3.1-Flash-Preview 生成的代码总跑不起来 / 是提示写得太松吗?
  1. 类型差异:打印出来是 {'u1': '30.5', 'u2': '5'},说明金额还是字符串,提示里的类型约束没生效,重写时要把“value 为 float”再强调一次,或直接要求转换后再累加。
  2. 异常差异:遇到空行时直接抛 ValueError,说明“跳过字段数不为 2 的行”没有被实现。
  3. 行为差异:文件不存在时抛出别的异常或返回空字典,和示例里要求的 FileNotFoundError 不一致。

如果这次运行只剩最后一类差异,通常说明提示方向已经对了,继续在当前提示上补一两条边界,而不是整段推倒重写。还要补一组最小测试片段,避免只验证成功路径:

def test_empty():
    open('empty.csv', 'w').write('user_id,amount\n')
    assert sum_orders('empty.csv') == {}

def test_bad_row():
    open('bad.csv', 'w').write('user_id,amount\nu1,1\nbroken\n')
    assert sum_orders('bad.csv') == {'u1': 1.0}

运行方式可以是 python -m pytest -q,也可以直接手动调用并打印结果。关键是把实际输出贴回三样对照记录里,而不是凭印象判断“好像能跑了”。

把有效约束固化成可复用模板

一次调通之后,把提示改成带占位符的模板,下次同类任务直接替换。模板结构可以固定为五段:任务一句话、输入约束、输出约束、边界约束、示例与运行方式。

【任务】
用 {语言} 实现 {函数名},只做 {单一职责}。

【输入】
- 类型/格式:{输入类型}
- 字段或参数:{字段列表}
- 编码或依赖版本:{编码或依赖}

【输出】
- 类型:{返回类型}
- 结构示例:{输出样例}

【边界】
- 空输入:{行为}
- 非法输入:{跳过或抛错}
- 重复数据:{合并规则}

【示例】
def {函数名}({参数}) -> {返回类型}: ...
调用:{调用代码}
期望输出:{期望打印结果}
运行命令:{命令}

使用时的检查点:每次替换占位符后,确认示例里的输入能覆盖至少两种分支,比如一条正常记录加一条脏数据;确认边界约束是二选一的明确动作,不出现“尽量”“合理”;确认运行命令能在当前环境直接复制执行;生成后先跑最小测试,再读代码。这样固化的不是某一次生成的代码,而是一组可被检查的条件,模型换代或换版本时依然可以复用。