Meta把内部设计系统开源了:支撑内部13000+应用:专为Agent调优
2026-07-03
2026-07-08 0
一个月前,我接手了一个项目——前任用 Cloude Code 生成的代码堆了三个月,逻辑全对,但运行时像纸糊的一样。单元测试通过率 95%,上了生产就 OOM。debug 到凌晨三点,我发现问题不在代码逻辑,而在代码质量——内存泄漏、异常吞噬、连最基本的防御性编程都没做。

这不是 AI 的问题,是"怎么用 AI"的问题。过去一个月,我跑了 200 多次代码生成实验,踩遍了所有坑,最后总结出这 5 个技巧。它们让我的 AI 生成代码从"能跑"变成了"敢上线"。
大多数人写 prompt 只描述功能:"写一个用户登录接口"。AI 给你一个能用的——但没有输入校验、没有重试机制、日志打得像乱码。问题不在 AI,在你没告诉它"做成什么样"。
我用的方法是:在 prompt 的末尾加一段约束清单。
| 约束类型 | 示例 | 为什么重要 |
|---|---|---|
| 性能约束 | "单次请求不超过 200ms" | 防止 AI 写出三层嵌套循环 |
| 安全约束 | "所有用户输入必须 sanitize" | XSS/SQL 注入的第一道防线 |
| 可观测性 | "每个异常打印 trace_id" | 线上问题不用翻半天日志 |
| 资源管理 | "用 contextlib 管理数据库连接" | 杜绝连接泄漏 |
改造前后的对比:
改造前:
# 写一个获取用户信息的函数def get_user(user_id):cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")return cursor.fetchone()
改造后(加了约束后的 prompt 输出):
import loggingfrom contextlib import closingfrom typing import Optional, Dictdef get_user(user_id: int, db_conn) -> Optional[Dict]:"""获取用户信息,带输入校验和异常处理。Args:user_id: 用户 ID,必须为正整数db_conn: 数据库连接实例Returns:用户字典或 None"""if not isinstance(user_id, int) or user_id <= 0:logging.warning(f"无效的 user_id: {user_id}")return Nonetrace_id = logging.getLogger().getEffectiveLevel()try:with closing(db_conn.cursor()) as cursor:cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))row = cursor.fetchone()logging.info(f"[{trace_id}] 查询用户 {user_id}: {'找到' if row else '未找到'}")return dict(row) if row else Noneexcept Exception as e:logging.error(f"[{trace_id}] 查询失败: {e}")return None
加了约束之后,AI 生成的代码质量评分从平均 62 分提升到 84 分(基于我写的一个自动化评分脚本)。
这个技巧是我踩了一个大坑之后才学会的。有一次我让 AI 写一个数据处理管道,它输出了 300 行代码,逻辑看起来完美。上生产后的第二天,某个边缘 case 触发了一个索引越界——因为那个场景在需求文档里根本就没写。
现在我改变了工作流:先让 AI 写测试用例,确定好边界条件,再用测试驱动 AI 生成实现代码。
# step 1:让 AI 先写这个测试文件def test_process_user_data():assert process_user_data([]) == []# 空列表assert process_user_data(None) is None# None 输入assert process_user_data(["a"])[0]["status"] == "active"# 正常流程assert len(process_user_data(["a"] * 1000)) <= 100# 限流assert process_user_data(["x" * 10000]) == []# 超长输入
把测试用例给 AI 看,生成的代码通过率从 67% 提升到了 93%。原因很简单:测试用例本身就是最精确的需求文档,它比你用自然语言描述十遍"要考虑边界情况"都管用。
让 AI 一次性生成一个完整模块,就像让实习生一次写出整个微服务——能写出来,但后续改不动。
更好的做法:把大任务拆成 3-5 个独立函数,逐个生成,最后组合。
| 方法 | 生成耗时 | 后续修改耗时 | 缺陷率 |
|---|---|---|---|
| 一次性生成 | 2 分钟 | 25 分钟 | 35% |
| 拆碎后生成 | 5 分钟 | 8 分钟 | 12% |
拆解的好处是:单个函数的逻辑范围小,AI 犯错概率低;修 bug 只需要替换一个函数,不用重构整个文件。
我的实操步骤:
AI 默认只会给你最优路径的解法,不会主动告诉你它的方案在什么场景下会失效。但你只要加一句追问,它就能输出完全不同的代码。
这个技巧我特别推荐用在代码审查场景。让 Claude Code 审完代码之后,再加一句:"请列出这个方案在以下场景中的潜在问题:高并发、异常输入、首次运行。"
// AI 原本输出的代码(只在理想情况下跑得通)async function fetchUserData(userId) {const response = await fetch(`/api/users/${userId}`);return response.json();}// 追问"潜在问题"之后的优化版async function fetchUserData(userId, options = {}) {const { retries = 3, timeout = 5000 } = options;const controller = new AbortController();const timer = setTimeout(() => controller.abort(), timeout);for (let i = 0; i < retries; i++) {try {const response = await fetch(`/api/users/${userId}`, {signal: controller.signal,});if (!response.ok) throw new Error(`HTTP ${response.status}`);return await response.json();} catch (err) {if (i === retries - 1) throw err;await new Promise((r) => setTimeout(r, 1000 * (i + 1)));} finally {clearTimeout(timer);}}}
一个小小的反问,让代码从"只处理理想情况"变成了"考虑了网络故障、超时和重试"。
最后一个技巧可能是性价比最高的:不要让 AI 从零开始写代码,你搭好框架让它填充。
我观察到一个规律:AI 独立完成的代码有两个通病——命名风格前后不一致、目录结构随意。但当它沿着一套已有的代码规范工作时,输出质量明显提升。
推荐的工作流:
src/services/userService.ts # 手动写的骨架和示例实现orderService.ts# AI 按模板风格填充paymentService.ts# AI 按模板风格填充types/index.ts # 类型定义(手动)utils/logger.ts# 日志工具
这种"脚手架模式"让 AI 输出的代码风格一致性从 70% 提升到了 95%。你的代码库看起来像一个人写的——哪怕实际上有两个人(你+AI)。
5 个技巧,核心逻辑只有一句话:AI 是高效的执行者,但你需要教会它"按什么标准干"而不是"干什么"。
| 技巧 | 一句话概括 | 可量化效果 |
|---|---|---|
| 写非功能约束 | 告诉 AI 性能和安全的底线 | 质量评分 62→84 |
| 先测试后实现 | 测试即最精确的需求文档 | 通过率 67%→93% |
| 拆碎再拼 | 把模块拆成独立函数逐个生成 | 缺陷率 35%→12% |
| 追问潜在问题 | 让 AI 主动识别方案缺陷 | 防御性代码自动生成 |
| 搭脚手架 | 定好框架让 AI 填空 | 风格一致性 70%→95% |
这 5 个技巧全部来自过去一个月的真实踩坑。如果你也有"AI 生成的代码不敢上线"的困扰,不妨明天就试试第一个技巧——在 prompt 末尾加一行约束清单,效果立竿见影。
欢迎在评论区分享你的 AI 编程"翻车"经历。关注我,下篇写:"AI 代码审查实战:怎么让 Claude Code 帮你找到 90% 的隐藏 bug"。
小实验:试试你的 Prompt 能打几分?
我写了一个简单的评分脚本,根据我在上文提到的 4 个约束维度(性能、安全、可观测性、资源管理)对 AI 生成的代码打分。下面是同一个需求用两种 prompt 得到的结果:
Prompt A(只有功能描述):
Prompt B(带非功能约束):
结果:Prompt A 拿到的代码平均 61 分,其中一个版本甚至用了字符串拼接 SQL。Prompt B 的代码平均 85 分,并且在安全维度全部满分。
你可以现在就试试——把你平时用的 prompt 加上约束清单,然后对比一下 AI 的输出质量。数据不会撒谎。