验证闭环
AI 写 PuXian 最大的风险不是写不出来,是「写出来了、看起来对、其实没跑过」。这一章给一条固定流程:每一步都有可验证的产出,走完之后你才可以说「完成」。
闭环:七步
1. 摸清现场(不许臆测)
先读三样东西:目标文件的现有代码、它的调用方、以及 px --version。别人的代码风格、已有的公共库、当前的编译器版本,任何一项猜错都会让后面的工作作废。
✓ px --version # 0.2.382 ✓ ls /data/work/<项目>/ # 有什么公共库可复用 ✓ head -40 <同类文件> # 命名与错误处理惯例
2. 先写 5 行验证假设
任何「我不确定这个 API 是不是这样」的点,单独写 5 行跑一次。不要把它塞进 200 行的实现里再一起调试 —— 那时候一个错误假设会伪装成 5 个 bug。
def main(): print(json_stringify(file_stat("/tmp"))) print(str(contains("abc", ".."))) print(str(contains("abc", "..") == 0))
file_stat 返回什么字段、contains 返回什么类型、== 0 是否成立。40 秒做完,比读源码 20 分钟可靠。3. 写最小可运行版本
先让主路径跑通(成功分支),错误分支暂时留 TODO。不要一开始就把 6 个端点一起写 —— 一旦公共库有错,6 个文件同时挂,报错信息还会指向公共库,定位成本翻倍。
4. 逐个编译,不要批量
✗ 一次改 6 个文件然后一起 px build ✓ 改 1 个 → px lint → px build → 再改下一个
理由很实在:2026-11-05 那天,公共库里一个 from 保留字同时让 3 个文件编译失败,而报错指向的是公共库第 478 行 —— 如果分批编译,第一次就会停在真正的病灶上。
5. 跑分支矩阵
错误分支必须真的发请求触发,不能「读着觉得对」。一个接口至少要有这几条用例:
| 用例 | 期望 | 为什么必须有 |
|---|---|---|
| 正常输入 | 2xx + 正确体 | 基线 |
| 空体 / 缺字段 | 400 + 明确文案 | 前端第一次联调就会这么传 |
| 坏 JSON | 400,不是 500 | 最容易被 json_parse 打成 500 |
| 跨站 Origin | 403 | curl 不带 Origin 会假绿 |
| 未登录 | 401 | 鉴权链是否真的接上 |
| 重复请求 / 冷却中 | 429 或幂等成功 | 限流与幂等 |
6. 编译轨跑一遍
px run 通过 ≠ px build 通过,也 ≠ 产物行为一致。至少对热路径(接口、循环、IO)用产物跑一次同样的用例,并对比耗时。
7. 留回滚
部署前先备份,部署后立刻验证,失败就退回。这是纪律不是建议:
cp 目标 /path/backup-$(date +%Y%m%d-%H%M)
cp 新产物 /path/target.new && mv -f /path/target.new /path/target # 运行中直接 cp 会 ETXTBSY
systemctl restart <服务>
验证三条关键请求,任一失败 → 恢复备份 + 重启cp 覆盖**正在运行**的二进制会失败(Text file busy)。用「复制到 .new → mv 覆盖」的原子替换;mv 换的是目录项,运行中的进程仍持旧 inode,不受影响。AI 的六种失败模式
| 模式 | 长什么样 | 对策 |
|---|---|---|
| 幻觉 API | 写出 str.trim_left()、dict.get()、file.read_all() | 只用手册里出现过的函数;不确定就 5 行试验 |
| 语言迁移 | 写出 try/catch、f-string、0 == False 假设 | 先读「AI 专用」前三章,把 Python 直觉显式覆盖掉 |
| 不验证就交付 | 「已实现,逻辑正确」但一行未跑 | 交付前必须贴出真实运行输出,没有输出就不算完成 |
| 过度自信的排障 | 「问题一定在 X」然后大改 X | 先用一条打印/一次请求证伪,再动手 |
| 批量修改 | 一次改 6 个文件,编译挂了不知道谁的问题 | 一次一个文件,一改一编译 |
| 忽略执行轨 | 拿 px run 的 6 秒当性能结论 | 性能数据必须标注执行轨;关键路径用产物测 |
对抗幻觉的两个动作
① 用清单核对,不用记忆。标准库只有 27 个内置模块,生态包在 registry/,需要 pxpkg add 才有。import mysql 能用,是因为项目里装了 mysql@0.2.0;在没装的项目里写它就是错。
pxpkg init && pxpkg add mysql@0.2.0 && pxpkg install # 引入包 ls /usr/share/puxian/stdlib # 内置标准库 ls /usr/share/puxian/registry | head # 生态包
② 让错误说话。拿不准的写法,直接写出来编译一次,E2001 / R1001 / R1008 会立刻告诉你答案。编译器是最便宜的信息源,比在脑子里推演便宜一个数量级。
什么时候可以停下来
满足这四条才叫完成:
- 主路径与错误路径都有真实请求记录(不是推理);
px build通过,产物跑过同样用例;- 有回滚方案,且备份文件确实存在;
- 知道这次改动影响谁(哪些站点/服务/定时任务会用到它)。