让 AI 写出「三个月后还能看懂」的代码——一个可落地的提示词工程实战
让 AI 写出「三个月后还能看懂」的代码——一个可落地的提示词工程实战
你有没有遇到过这种情况:打开三个月前让 AI 帮你写的一段代码,完全不知道它在干什么。变量叫 res2,函数叫 handleStuff,注释一行没有,逻辑全靠猜。
这不是 AI 的问题,是你没告诉它你要什么。
今天这篇文章,我们用一个可以直接跑的 Python 脚本,系统性地解决这个问题——让 AI 生成的代码,从第一行就对人类友好。
问题根源:AI 默认生成「能跑」而不是「能读」
大多数人给 AI 的 prompt 是这样的:
"帮我写一个解析 JWT 的函数"
AI 给出的结果能跑,但:
- 没有类型注解
- 没有边界情况说明
- 异常处理是
except Exception as e: pass - 函数名叫
parse,参数叫t
三个月后你回来看,等于看天书。
解法不是换模型,是换提示词策略。
核心思路:给 AI 一个「代码风格宪法」
我们要做的是在每次请求前,注入一段系统级的编码规范,让模型知道你的期望不只是「能跑」,而是「可维护」。
完整可运行代码
下面这个脚本封装了一个 CodeGen 类,你可以直接集成到自己的工作流里。
# codegen.py
# 依赖: pip install openai
from openai import OpenAI
client = OpenAI(
api_key="你的API密钥",
base_url="https://api2everything.xyz/v1" # 国内直连,无需代理
)
# ===== 核心:代码风格宪法 =====
CODE_CONSTITUTION = """
你是一位注重可维护性的高级工程师。生成代码时必须遵守以下规则:
1. **命名规范**
- 变量/函数名必须是自解释的,禁止使用 res, data, tmp, stuff 等模糊名
- 布尔变量以 is_/has_/can_ 开头
- 常量全大写加下划线
2. **类型注解**(Python)
- 所有函数参数和返回值必须有类型注解
- 复杂类型用 TypedDict 或 dataclass 定义
3. **注释规范**
- 每个函数必须有 docstring,说明:做什么、参数含义、返回值、可能抛出的异常
- 非直觉逻辑必须有行内注释,解释「为什么」而不是「做什么」
4. **错误处理**
- 禁止裸 except,必须捕获具体异常类型
- 错误信息必须包含上下文,方便调试
5. **边界情况**
- 函数开头必须校验关键参数
- 说明函数对 None、空列表、空字符串的处理方式
生成完代码后,附上一段「三个月后的你需要知道的事」,用 2-3 句话解释这段代码最容易踩的坑。
"""
def generate_maintainable_code(
task_description: str,
language: str = "Python",
model: str = "claude-sonnet-4-5"
) -> str:
"""
根据任务描述生成可维护的代码。
Args:
task_description: 自然语言描述的编程任务
language: 目标编程语言,默认 Python
model: 使用的模型,支持 Claude / GPT / Gemini 等 300+ 模型
Returns:
包含代码和维护说明的完整响应字符串
Raises:
openai.APIError: API 调用失败时抛出
"""
response = client.chat.completions.create(
model=model,
messages=[
{
"role": "system",
"content": CODE_CONSTITUTION
},
{
"role": "user",
"content": f"语言:{language}\n\n任务:{task_description}"
}
],
temperature=0.2, # 降低随机性,代码生成用低温度更稳定
)
return response.choices[0].message.content
# ===== 批量生成模式:一次性生成整个模块 =====
def generate_module(tasks: list[str], module_name: str) -> None:
"""
批量生成一个模块的多个函数,统一风格。
Args:
tasks: 任务描述列表,每项对应一个函数
module_name: 输出文件名(不含 .py)
"""
print(f"开始生成模块 {module_name},共 {len(tasks)} 个函数...\n")
all_code_parts: list[str] = []
for i, task in enumerate(tasks, start=1):
print(f"[{i}/{len(tasks)}] 生成中:{task[:50]}...")
code = generate_maintainable_code(task)
all_code_parts.append(f"# === 函数 {i}:{task[:30]} ===\n{code}\n")
output_path = f"{module_name}.py"
with open(output_path, "w", encoding="utf-8") as f:
f.write("\n\n".join(all_code_parts))
print(f"\n✅ 已写入 {output_path}")
if __name__ == "__main__":
# 单个函数示例
result = generate_maintainable_code(
task_description="解析 JWT token,提取 payload,验证过期时间",
language="Python"
)
print(result)
关键细节解释
为什么用 temperature=0.2?
代码生成不需要创意,需要确定性。低温度让模型更倾向于标准写法,减少「聪明但奇怪」的实现。
「三个月后需要知道的事」这个技巧从哪来?
这是逼迫模型做元认知的方式——它生成代码的同时,必须思考这段代码的脆弱点在哪。实践下来,这部分内容往往比注释本身更有价值。
为什么用这个 base_url?
我用的是无量 API,国内直连,不需要代理,支持 Claude、GPT-4o、Gemini、DeepSeek 等 300+ 模型,而且价格比官方便宜 60% 以上。claude-sonnet-4-5 这类需要付费订阅才能用的模型,在这里按 token 付费,日常学习和小项目非常划算。注册还送 ¥1 余额,可以先试试效果。
实际效果对比
同样的任务「解析 JWT」,普通 prompt 给出的结果:
def parse(t):
parts = t.split('.')
return json.loads(base64.decode(parts[1]))
用上面这套 prompt 工程之后:
def decode_jwt_payload(token: str) -> dict[str, Any]:
"""
解码 JWT token 的 payload 部分,不做签名验证。
Args:
token: 标准格式的 JWT 字符串(header.payload.signature)
Returns:
解码后的 payload 字典
Raises:
ValueError: token 格式不正确(不含两个 '.')
jwt.ExpiredSignatureError: token 已过期
"""
...
差距一目了然。三个月后你回来,第一个你看不懂;第二个你直接知道该怎么用、会出什么问题。
延伸:把这套规范加到你的编辑器里
如果你用 Cursor 或 VS Code + Continue,可以把 CODE_CONSTITUTION 的内容直接放进项目根目录的 .cursorrules 或 AGENTS.md 文件。这样所有 AI 辅助写代码的场景都会自动应用这套规范,不用每次手动注入。
代码已经给到了,逻辑也说清楚了。如果你在实际运行中遇到问题,或者想聊某个具体场景下的 prompt 策略,评论区见。
觉得有用的话点个赞,下次更新「如何让 AI 给遗留代码自动补文档」。
🔗 文中用到的 API 服务:无量 API — 国内直连 300+ 模型,注册送 ¥1,余额永久有效