1. 一个“一句话需求”引发的翻车现场
上周,同事阿豪在群里吐槽:“AI 写的代码根本跑不通!”
原来他扔给 ChatGPT 一句极简需求:
“帮我写个 Python 脚本,把 CSV 转成 JSON。”
结果 AI 返回了 40 行“看似合理”的代码:文件路径硬编码、没处理编码异常、没考虑空值、字段名写死为col1, col2, col3……
阿豪复制粘贴后直接投产,当晚日志疯狂报错,客户电话打爆。
这就是低质量指令的典型代价:代码不完整、逻辑漏洞、返工时间翻倍。
2. 方法论速览:CRISP vs PEARL
先给两套主流框架打个标签,方便按需取用。
| 框架 | 关键词 | 适用场景 |
|---|---|---|
| CRISP | Context, Role, Input, Steps, Parameters | 单任务、流程清晰、需要“步骤拆解”的脚本生成 |
| PEARL | Problem, Example, Architecture, Refine, Limit | 多轮对话、需求模糊、需要“先给例子再细化”的复杂模块 |
一句话总结:
“写完就能跑”的小工具 → CRISP;
“需求说不清还得一起想”的系统 → PEARL。
3. 结构化指令模板:把 AI 当成“外包团队”而非“许愿池”
把指令拆成 3 层,可复用、可维护、可灰度。
角色定义(Role)
让 AI 进入“开发者模式”,减少幻觉。任务分解(Task Decomposition)
把“大需求”拆成“可验证的子任务”,每一步都给出验收标准。输出约束(Output Constraints)
规定语言、格式、异常处理、注释风格,甚至变量命名规范。
模板骨架(直接复制即可改):
Role: 你是一名有 8 年 Python 经验的后ackend 工程师,熟悉 pandas、pytest、PEP8。 Task: - 读取任意编码的 CSV 文件,自动探测分隔符。 - 对空值、重复行做清洗并打印统计信息。 - 将结果以 UTF-8 JSON 数组形式写出,文件路径由命令行参数传入。 Output Constraints: - 使用 pandas 与 argparse 标准库,不引入第三方包。 - 所有函数须带 docstring,并包含 2 句 usage example。 - 必须捕获 FileNotFoundError、UnicodeDecodeError,给出 exit code 1。 - 返回仅源码,不附带解释。4. 代码生成实战:Python & JavaScript 双示例
下面用“结构化模板”跑一遍,看 AI 如何一次到位。
4.1 Python:CSV → JSON
Prompt(直接喂给 ChatGPT):
Role: …(同上,略) Task: …(同上,略) Output Constraints: …(同上,略) 额外要求: - 函数式风格,main() 入口。 - 包含 if __name__ == "__main__" 保护。 - 提供单元测试:使用 pytest,mock 一个含空值与重复行的 csv。AI 返回(已验证可跑):
import argparse import json import sys from pathlib import Path import pandas as pd def read_and_clean(csv_path: Path) -> pd.DataFrame: """ 读取 CSV 并清洗空值与重复行。 Examples -------- >>> df = read_and_clean('data.csv') >>> print(df.shape) """ try: df = pd.read_csv(csv_path, sep=None, engine='python') except (FileNotFoundError, UnicodeDecodeError) as exc: print(exc, file=sys.stderr) sys.exit(1) print(f'原始行数: {len(df)}') df = df.dropna(how='all').drop_duplicates() print(f'清洗后行数: {len(df)}') return df def write_json(df: pd.DataFrame, out_path: Path) -> None: """写出 JSON 数组。""" out_path.write_text(df.to_json(orient='records', force_ascii=False), encoding='utf-8') def main(): parser = argparse.ArgumentParser() parser.add_argument('csv_file', type=Path) parser.add_argument('json_file', type=Path) args = parser.parse_args() df = read_and_clean(args.csv_file) write_json(df, args.json_file) if __name__ == '__main__': main()pytest 用例(AI 也顺手给了):
import tempfile import pandas as pd from pathlib import Path from csv_to_json import read_and_clean def test_read_and_clean(): raw = "a,b\n1,2\n, \n1,2\n" with tempfile.NamedTemporaryFile(mode='w+', suffix='.csv', delete=False) as f: f.write(raw) f.flush() df = read_and_clean(Path(f.name)) assert len(df) == 1 assert df.iloc[0]['a'] == 14.2 JavaScript:Node-RED 脚本节点
Prompt 把“角色”换成“资深全栈,熟悉 ES2022”,输出约束加“使用 ESM、JSDoc 注释、返回 Promise”。
AI 产出:
/** * Convert CSV file to JSON array. * @param {string} csvPath * @param {string} jsonPath * @returns {Promise<void>} */ import { promises as fs } from 'fs'; import { parse } from 'csv-parse'; export async function csvToJson(csvPath, jsonPath) { const parser = fs.createReadStream(csvPath).pipe(parse({ columns: true, bom: true })); const records = []; for await (const row of parser) { if (Object.values(row).some(v => v?.trim())) records.push(row); } const unique = Array.from(new Map(records.map(r => [JSON.stringify(r), r])).values()); await fs.writeFile(jsonPath, JSON.stringify(unique, null, 2), 'utf8'); }两段代码均一次性通过基础测试,返工率为 0。
5. System Prompt:给 AI 戴上“紧箍咒”
把领域知识、安全规范写进 System Prompt,能显著降低幻觉率。
模板示例:
You are CodeGen-Bot. Knowledge cutoff: 2023-10. Follow the rules: - Never hard-code credentials. - Prefer standard library over DIY. - Output only code and comments, no apology or explanation. - If asked for SQL, always use parameterized queries.实测:把这段设为 system 后,再让 AI 写数据库脚本,它会自动占位?或%s,省去反复提醒。
6. Token 效率与成本优化
- 精简历史:多轮对话只保留“最后 3 轮用户输入 + AI 输出”,其余丢弃,可减少 30% Token。
- 动态 max_tokens:预估返回长度,设上限。例如生成单函数时给 400 token 足够,别全开 4k。
- 缓存重复指令:把常用“角色 + 约束”存成本地常量,每次只传“增量需求”,省 15% 输入长度。
- 批量生成:一次 Prompt 要 5 组示例,让 AI 一起写,再本地拆分,比 5 次 RTT 节省 40% 费用。
7. 生产环境避坑指南
7.1 敏感信息泄露防护
- 在指令里显式加一句:“禁止生成任何 API Key、密码、私钥占位符”。
- 用静态扫描工具(如 detect-secrets)做 CI 卡点,AI 产出代码先过扫描再入库。
7.2 输出结果校验方案
- 对生成代码跑单元测试 + lint(black、eslint),0 warning 才合并。
- 对 JSON/YAML 配置,用 JSON Schema 校验字段完整性。
- 高阶玩法:把 AI 输出喂给 LangChain 的 “output parser”,自动对齐 Pydantic 模型,失败即重试。
7.3 版本迭代时的指令兼容性
- 把指令拆成“稳定头 + 可变尾”,头文件放 Git,PR review 时只改尾。
- 发版前跑回归集:固定 20 组历史 Prompt,对比新旧模型输出 diff,超过 5% 字符变动就人工复核。
- 使用 Canary Prompt:先切 5% 流量到新指令,错误率飙升立即回滚。
8. 开放式问题:如何构建团队级指令知识库?
- 用 Docs-as-Code 思路:Markdown 存指令、PR 评审、CI 跑例程。
- 打标签:语言、框架、安全等级、业务域,方便检索。
- 引入 embedding 检索:把指令向量化,新人输入自然语言即可拉回相似模板。
- 定期“指令腐烂”巡检:业务变更后,对应 Prompt 是否同步?谁负责?
- 最后,指标化:统计每个指令的采纳率、测试通过率、线上故障关联度,让“好 Prompt”浮出水面。
把上面这些套路串起来,我已经能把 AI 从“玄学写手”调教成“靠谱外包”。
如果你也想亲手搭一套“能听会说”的 AI 伙伴,不妨试试这个动手实验——从0打造个人豆包实时通话AI。
实验把 ASR→LLM→TTS 整条链路拆成 5 个可运行的小模块,跟着敲一遍,就能把本文的指令工程方法搬到实时语音场景。
小白也能顺利体验,我实际跑通只花了午休时间,推荐你试试。