Prompt 工程实战——写好 prompt 的方法论:思维链、少样本示例、从差到好
核心论点:前面的文章全在讲"怎么喂上下文给 AI"——Rules、@ 引用、搜索、Plan 模式。但如果 prompt 本身写得模糊,喂再多上下文也没用。这一篇回到源头:Prompt 本身怎么写。
一个被忽略的事实
整个系列的核心哲学是"AI 编码的瓶颈在项目认知输入"。但这有一个前提:prompt 本身的质量是合格的。
对比:
Prompt A(模糊): 给订单模块加个缓存 Prompt B(清晰): @ …/redis_cache_service.py @ …/routers/order.py 在 order_query() 里加 Redis 缓存: - 查询前先 await cache.get(order_key),命中直接返回 - 未命中查 DB 后 await cache.set(order_key, data, ttl=600) - order_update() 里加 await cache.delete(order_key) 防脏缓存Prompt B 比 A 多了两样东西:上下文(@ 了文件)和具体指令(查哪里、怎么查、ttl 多少、哪里需要清缓存)。同样的需求,prompt 写法不同,结果天差地别。
四类编码 prompt 的实战模式
三段式 prompt(最高频)
[上下文] @ 涉及的文件 [约束] 要遵守的规则 [动作] 要做什么 + 验收标准 示例: @ …/llm_service.py @ …/config.py - 不新建类,扩展现有方法 - 遵循 async/await 规范 给 chat() 加 temperature 参数,默认值从 config 读,透传到 openai 调用。格式:上下文 + 约束 + 动作
为什么三段式比混乱叙述有效:AI 按顺序处理信息。先看上下文(这是项目),再看约束(这是边界),最后看动作(这是任务)。顺序对了,输出质量明显提升。
少样本示例(教 AI 你想要的输出格式)
当你要的是一类重复操作时,给一个例子比描述 10 句更有效:
@ tests/test_conversation_service.py 参考 test_summarize_normal 的写法,给 get_messages() 写测试: # 参考例子 @pytest.mark.asyncio async def test_summarize_normal(mock_llm_response): """正常生成摘要""" service = ConversationService() result = await service.summarize(conversation_id="conv_1") assert result is not None assert len(result) > 0 assert "摘要" in result # 任务 给 get_messages() 写同样风格的测试,覆盖: - 正常获取消息列表 - 空对话返回空列表 - 分页参数的正确性少样本示例的价值:AI 不需要猜"你要的测试长什么样"——你给了一个例子,格式、命名、断言风格都明确了。
思维链(让 AI 展示推理过程)
涉及复杂决策时,要求 AI 先输出推理过程:
@ …/tool_registry.py @ …/mcp_server.py @ …/a2a_routers.py 重构工具调度逻辑。不要直接写代码——先分析: 1. 当前 tool_registry 的调度流程(dispatch 的调用链) 2. MCP Server 和 A2A 分别怎么调用 tool_registry 3. 现有设计的问题在哪里 4. 重构方案(3 个选项 + 推荐) 5. 确认后,按推荐方案实施思维链解决什么问题:复杂任务中,直接要代码 → AI 可能在错误方向上狂奔。先要求推理 → AI 自己理顺了逻辑 → 再写代码,方向正确率大幅提升。
反面约束(告诉 AI “不要这样”)
@ …/core/experiment_service.py 加 experiment 的关闭逻辑。 ❌ 不要: - 新建 ExperimentManager 类 - 直接调 Redis 做状态管理 - 在 router 里加 close 端点 ✅ 要: - 在 experiment_service.py 里加 close() 方法 - 状态用已有的 experiment_store(MySQL) - 关闭后分流一律返回 control 组反面约束比正面约束更有效——因为 AI 的"默认行为"往往是写一个新类、调一个新依赖。"不要"比"要"更精准地拦截了默认行为。
从差到好:三个常见 prompt 的进化
缓存功能
Bad "加个缓存" → AI 自己写 class Cache,内存 dict Good "@ …/redis_cache_service.py 在 order_query() 里加缓存, 用已有的 redis_cache_service,TTL=600" Better "@ …/redis_cache_service.py @ …/routers/order.py 在 order_query() 里加 Redis 缓存: 1. 查前 get(order_key),命中直接返回 2. 未命中查 DB 后 set(order_key, data, ttl=600) 3. order_update() 加 delete(order_key) 防脏缓存 ❌ 不新建 cache 类"进化路径:模糊描述 → 指定组件 → 指定步骤 + 边界处理 + 禁止项
重构
Bad "重构 tool_registry,太乱了" → AI 可能重写整个文件,改动远超预期 Good "重构 tool_registry.py 的 dispatch() 方法: 保持对外接口不变,只重构内部实现。 先输出当前 dispatch() 的问题分析,再出重构方案。" Better "重构 tool_registry.py 的 dispatch() 方法。 约束:保持所有 public 方法签名不变。 步骤: 1. 先列出所有调用 dispatch() 的地方(搜索引用) 2. 分析 dispatch() 当前的问题 3. 出两个方案(轻量重构 vs 深度重构) 4. 确认后实施 ❌ 不改 public 接口签名 ❌ 不改 config 和 router"进化路径:情绪化描述 → 加边界约束 → 加步骤 + 二选一方案 + 禁止项
Bug 修复
Bad "fix the bug" → AI 猜你要修什么 bug,改错地方 Good "format_time() 返回的时间比实际早 8 小时。 看 datetime_utils.py line 42,应该是 UTC 和 CST 的问题。" Better "@ …/datetime_utils.py @ …/tests/test_datetime_utils.py format_time() 返回 UTC+0 而非 UTC+8。用 pytz 修复。 修复后更新 test_format_time_utc8 的期望值。 同时检查项目里还有没有其他用 datetime.utcnow() 的地方。"进化路径:无信息 → 定位问题 → 定位 + 解决方案 + 影响范围 + 测试
什么时候应该用 Ask 而不是直接写 prompt
这篇讲的是 prompt 技巧,但要记住一个原则:方案不确定时,先用 Ask 讨论。
错误做法(在 Craft 里写长 prompt): 给订单模块加个缓存。可以用 Redis 也可以用内存。 如果并发不高就内存,高就 Redis。你看看哪个合适。 → AI 需要自己做决策,结果不确定 正确做法(先用 Ask 讨论): Ask: "订单模块要加缓存,项目里已经有 redis_cache_service。 直接用它会不会太重?有没有更轻量方案?" AI: [分析] 你: "好,用 Redis。在 order_query() 里加。" 然后切 Craft: "@ …/redis_cache_service.py @ …/routers/order.py 在 order_query() 里加 Redis 缓存... [三段式]"原则:如果 prompt 里有"或者"、“你看看”、“你觉得哪个”——说明方案不确定,应该先 Ask。
团队级 prompt 规范:把好 prompt 编码成 Rules
个人 prompt 技巧 → 团队规范的方式:把高频的好 prompt 模式写进 Rules。
# .codebuddy/rules/prompt-template/RULE.mdc ## 新功能开发 使用 `/new-feature` skill 启动标准流程。 ## Bug 修复 Bug 报告必须包含: - 问题现象(预期 vs 实际) - 出错文件 + 行号 - 复现步骤或测试用例 ## 重构 重构请求必须包含: - 约束:哪些接口不能变 - 范围:哪些文件在改动范围内 - 验证方式:用什么测试确认行为不变把 prompt 规范写进 Rules 后,每个团队成员和 AI 交互时都能看到——相当于团队共享了 prompt 最佳实践。
核心要点
- "三段式"是最小的有效 prompt 结构:上下文(@ 文件) + 约束(规则/禁止项) + 动作(步骤 + 验收标准)。一旦习惯这个结构,AI 输出质量稳定提升。
- 少样本示例 > 描述——给一个例子比写十句说明更有效。特别是在测试、文档、重复性操作中。
- 复杂任务用思维链——先让 AI 分析、推理、出方案,确认后再写代码。不要一步到位要代码。
- "反面约束"比"正面约束"拦截力更强——“不要” > “要”。因为 AI 的默认行为是写通用代码,反面约束直接拦截了默认路径。
- 好的 prompt 是三层漏斗的"源动力"——Rules 建立项目认知底线(AI 自动知道有什么/不能做什么)、@ 引用提供精准上下文(每次对话喂什么)、Plan 模式控制流程(什么时候做什么)。但如果 prompt 本身是废的,三层漏斗也救不回来。
