AI 工程师的 Prompt 工程:不是玄学,是工程实践
- 约 28 分钟读完 - 全文 11138 字AI 工程师的 Prompt 工程:不是玄学,是工程实践
很多人觉得 Prompt Engineering 就是"怎么跟 AI 说话",甚至有人把它当成玄学。但在工程实践中,Prompt 本质上是在设计人与大模型之间的接口协议,是 LLM 应用的核心代码之一,需要版本管理、回归测试、性能评估。这篇文章结合两个真实项目——AI 视频生成管线(方糖猫 / GeekCast Engine)和一套我开发的 AI 结对编程 Prompt 规则库(keframework-aidev-promptkit)——分享沉淀下来的 Prompt 工程方法。不罗列模板,只讲可落地、可评估、可迭代的系统能力。
一、Prompt 是接口,不是提示语
很多团队把 Prompt 写在代码的某个字符串里,或者放在在线编辑器的临时文本框里调试。这种方式在小原型阶段没问题,但一旦进入生产环境,就会暴露出三个问题:
- 不可追溯:某个版本上线后效果变差,你不知道是哪一句提示被改了。
- 不可回归:更新模型或调整业务逻辑后,旧用例是否还成立?没人说得清。
- 不可协作:产品、运营、工程师各自改一版,最后没人能说出"正确版本"是什么。
所以在 AI 应用里,Prompt 的地位等同于传统代码:
| 传统代码 | Prompt |
|---|---|
| 需要版本控制 | 需要版本控制 |
| 需要测试 | 需要回归测试 |
| 需要 Code Review | 需要效果 Review |
| 会引入 Bug | 会引入幻觉、格式错误 |
| 有架构分层 | 也有分层(系统规则 / 模式规则 / 领域规范) |
| 有 CI/CD | 有评测集 + 回归流水线 |
更进一步,可以把 Prompt 看作一个函数签名:
f(context, instruction, constraints, examples) → output
context:模型需要知道的背景信息instruction:明确要做什么constraints:输出格式、长度、风格、禁止事项examples:少量示例,帮助模型快速对齐预期
设计 Prompt 时,首先考虑的不是"这句话够不够自然",而是输入是否完整、输出是否可解析、边界是否可控。当你开始用接口设计的思路写 Prompt,很多所谓"玄学"就会消失。
我们的做法:每个 Prompt 都是一个独立文件,纳入 Git 管理,有版本历史、有变更日志(CHANGELOG)、有配套评测。
下面先看一个完整的真实样本。
二、真实样本解剖:一个 AI 开发的 Prompt 规则库
keframework-aidev-promptkit 是一套给 AI 结对编程工具(Cline / RooCode / Cursor / Windsurf)使用的 Prompt 规则库。它的目标不是"让 AI 聊天更聪明",而是让 AI 像一个严格遵守工程规范的高级开发一样工作:读需求、做澄清、出方案、拆计划、写代码、跑测试、留文档,全流程可追溯。
它的目录结构本身就是一套 Prompt 架构:
keframework-aidev-promptkit/
├── prompt_rules/ # 规则源文件(Single Source of Truth)
│ ├── common/ # 所有模式都加载的通用规则
│ │ ├── common_general_rules.md # 输出语言、状态标记等"宪法"
│ │ └── common_memory.md # Memory Bank 机制
│ ├── plan_architect/ # PLAN/架构模式专用规则
│ │ └── plan_architect_planning.md
│ ├── act_code/ # ACT/编码模式专用规则
│ │ └── act_code_implement.md
│ └── spec/ # 技术规范(Java 后端、Vue、数据库、API…)
├── ai_work/spec/ # 规范在项目内的落盘位置(只读引用)
├── docs/ # 配置指南、开发全流程指南、Review 指南
└── CHANGELOG.md # Prompt 资产自身的变更日志
用一张图看清它的分层:
graph TD
subgraph 规则分层["Prompt 规则分层(prompt_rules/)"]
C["common/<br/>通用规则 + Memory Bank<br/>alwaysApply: true"]
P["plan_architect/<br/>规划模式规则"]
A["act_code/<br/>实现模式规则"]
S["spec/<br/>技术规范(只读上下文)"]
end
subgraph 工具适配["工具适配层(复制分发)"]
ROO[".roo/rules<br/>.roo/rules-code<br/>.roo/rules-architect"]
CLINE[".clinerules/ACT<br/>.clinerules/PLAN"]
CURSOR[".cursor/rules/"]
end
subgraph 项目内上下文["项目内上下文(ai_work/)"]
MEM["Memory Bank<br/>project_brief / task_plan<br/>active_context / learnings"]
SPEC2["ai_work/spec/<br/>技术规范副本(全模式只读)"]
end
C --> ROO & CLINE & CURSOR
P --> ROO & CLINE & CURSOR
A --> ROO & CLINE & CURSOR
S --> SPEC2
C -.定义机制.-> MEM
这个结构里藏着几个关键设计决策,下面逐一拆解。
2.1 决策一:按"加载时机"分层,而不是按主题堆砌
规则分三类的依据是何时生效:
common/:永远生效(规则文件头部带 YAML frontmatter:alwaysApply: true)plan_architect/:只在 PLAN/架构模式生效act_code/:只在 ACT/编码模式生效spec/:不注入 System Prompt,而是落盘为项目文件,由规则要求 AI 按需读取、全程只读
这和软件架构里的分层同理:全局常量、按请求注入的拦截器、按需加载的配置。如果把所有规则塞进一个巨大的 System Prompt,AI 在长会话中会逐渐"遗忘"靠后的指令——规则分层本质是注意力预算管理。
2.2 决策二:规则源文件与工具解耦
同一套规则通过脚本复制到不同工具的约定目录(.roo/、.clinerules/、.cursor/rules/),工具各自加载。这保证:
- 规则只有一份源文件,改一处全工具生效
- 工具升级或更换时规则资产不丢失
- 可以针对某个工具做薄薄的适配层,而不动核心规则
2.3 决策三:Prompt 资产自己有 CHANGELOG
这个仓库维护了 CHANGELOG.md / CHANGELOG_cn.md,记录类似这样的条目:
加强规划与实现阶段文档衔接:
plan_architect_planning.md明确规划输出需结构化、无歧义,直接作为实现输入,且实现必须严格遵循,任何偏离需回溯并更新规划。
注意这条日志的写法:不是"优化了提示词",而是像 API 变更一样描述行为契约的变化。这就是"Prompt 是代码"在资产管理层面的落地。
三、上下文工程:比提示词本身更重要
大模型的能力边界,很大程度上由上下文决定。同样的模型,给不同的上下文,表现可能天差地别。上下文工程至少包含四件事:会话间的记忆延续、相关性管理、知识缺口补足、超长任务的分段策略。
3.1 Memory Bank:解决会话间记忆清零
AI Coding 工具的根本限制是会话之间记忆清零,单次会话上下文有限。promptkit 的解法是 Memory Bank:一组结构化 Markdown 文件,作为 AI 的唯一事实来源(sole context source)。
graph TD
PB["project_brief.md<br/>项目范围与目标(事实源头)"] --> PR["design/product_requirements.md<br/>PRD:产品需求"]
PR --> AR["spec/architecture_spec.md<br/>系统架构、组件关系"]
AR --> TC["spec/technical_spec.md<br/>技术栈与约束"]
TC --> TP["task/task_plan.md<br/>任务 backlog 与进度"]
TP --> AC["task/active_context.md<br/>当前焦点、最近变更、下一步"]
AC --> LE["task/learnings.md<br/>错误/修复/模式 学习日志"]
读写权限按模式划分——这是最容易被忽视的设计:
| 文件 | PLAN 模式 | ACT 模式 |
|---|---|---|
project_brief.md |
可编辑 | 只读 |
design/(PRD、实现设计) |
可编辑 | 只读 |
spec/(架构、技术规范) |
全模式只读 | 全模式只读 |
task/task_plan.md |
可编辑 | 可编辑 |
task/active_context.md |
可编辑 | 可编辑 |
task/learnings.md |
可编辑 | 可编辑 |
为什么要这样设计?因为没有一个写代码的 Agent 会自觉地不去改需求文档。如果 ACT 模式可以改 spec/,AI 遇到"规范和代码冲突"时往往会悄悄改规范来迁就代码——这在工程上是灾难。用 Prompt 规则把权限写死,等于给 AI 上了文件系统级别的 ACL。
规则还定义了人类可触发的显式命令:read memory bank / rmb(会话开始恢复全部上下文)、update memory bank / umb(里程碑完成后落盘进度)。这把"上下文管理"从 AI 的隐式行为变成了人和 AI 共享的显式协议。
3.2 相关性优先于信息量
很多人误以为上下文越长越好,于是把整个文档、整段对话历史都塞进去。实际上,无关信息会稀释注意力,降低关键细节的召回概率。 尤其是在长上下文窗口下,模型对中间位置的信息敏感度会下降。
在 RAG 系统里,我们会对检索结果做重排序,只保留最相关的片段;在 Agent 任务中,我们会维护一个精简的"工作记忆",定期丢弃已经完成、不再影响后续决策的中间结果。Memory Bank 的七个文件刻意保持"简洁而完备",也是同一个道理。
3.3 用 RAG 补足预训练知识的缺口
大模型的训练数据有截止日期,且不会包含你的私有文档、最新产品资料、内部知识库。直接问模型"我们公司上个月上线了哪些功能",它要么胡说,要么拒绝回答。
我们在短视频生成平台里搭建了基于 ChromaDB 的本地素材库:把品牌素材、历史优质脚本、风格指南等向量化,生成任务触发时先做语义检索,再把检索结果注入 Prompt。这样模型不是在"回忆",而是在"依据材料创作"。
3.4 长文本要分段:模型负责局部,应用层负责全局
当任务超出单次 Token 上限,或者单次生成难以保证一致性时,不要硬塞。GeekCast Engine 处理长视频口播稿时,采用了"分段生成 + 本地组装"的策略:
- 按语义把口播稿切分成若干段
- 每段独立调用 LLM 生成视觉元素规划
- 在应用层做冲突检测、风格统一和最终组装
这个思路和分布式系统里的 MapReduce 很像:模型负责局部计算,应用层负责全局协调。
四、工作流即 Prompt:PLAN / ACT 双模式
promptkit 最核心的思想是:不指望 AI 自由发挥,而是把软件工程流程编码进 Prompt。PLAN 和 ACT 两个模式各有一段专属规则,规则里直接画出了执行流程。
4.1 PLAN 模式流程
flowchart TD
Start([开始]) --> Read[读取全部 Memory Bank 核心文件]
Read --> Check{上下文完整?}
Check -->|否| Create[补齐缺失文件/计划]
Create --> Clarify
Check -->|是| Clarify["<CLARIFICATION><br/>反复澄清,消除所有歧义"]
Clarify --> Reason["<STEP BY STEP REASONING><br/>分解问题、多方案权衡"]
Reason --> Present["<REASONING PRESENTATION><br/>呈现计划:假设、取舍、步骤"]
Present --> Verify{人确认计划?}
Verify -->|否| Clarify
Verify -->|是| Update[更新 Memory Bank<br/>落盘结构化计划]
4.2 ACT 模式流程
flowchart TD
Start([开始]) --> Read[读取 Memory Bank<br/>spec/ 与 design/ 只读]
Read --> Analyze["<ANALYZE CODE><br/>依赖分析 + 端到端流程分析"]
Analyze --> Plan["<PLAN CODE><br/>结构化提案,等待确认"]
Plan --> Sim["<SIMULATION ANALYSIS><br/>Dry run 推演副作用"]
Sim --> Valid{模拟通过?}
Valid -->|否| Fix[修复并重新模拟]
Fix --> Sim
Valid -->|是| Impl["<MAKE CHANGES><br/>单逻辑变更,增量提交"]
Impl --> Test["<TESTING><br/>单元测试 + 回归测试"]
Test --> Update[更新 active_context<br/>与 learnings]
4.3 XML 标签作为"行为锚点"
注意规则里大量使用 <CLARIFICATION>、<SIMULATION ANALYSIS>、<NO BREAKAGE ASSERTION> 这类自定义 XML 标签。这不是装饰,而是一种经过验证的 Prompt 技巧:
- 标签把"阶段"显式化,AI 输出时会自报当前处于哪个阶段,方便人审查 AI 是否跳步
- 标签给 LLM 提供了清晰的注意力锚点,比自然语言段落里的祈使句更不容易被忽略
- 标签名形成词汇表后,人可以缩写指令:“先做
<ANALYZE CODE>再动手”,沟通成本骤降
举两个有代表性的片段(译注,原文为英文):
<CLARIFICATION>
- 永远主动追问澄清和细节。
- 识别所有不明确的需求,逐一追问。
- 对所有假设提问,消除全部歧义。
- 提出我没想到的方案,预判我的需求。
- 只有百分之百清晰后,才进入方案阶段。
</CLARIFICATION><NO BREAKAGE ASSERTION>
提出变更后,自己运行测试并确认通过。
不要依赖用户来做这件事,并且要确信不会破坏用户现有代码。
</NO BREAKAGE ASSERTION>可以看到,这些规则写的不是"提示",而是带强制语气的行为规范——和给新员工发的《开发规范》没有区别。
五、规划到实现的交接协议
Prompt 工程里最难的不是"让 AI 生成好内容",而是让 AI 的上一轮输出成为下一轮可严格执行的输入。promptkit 对此定义了一套交接协议(Handoff Protocol)。
5.1 结构化计划输出
PLAN 模式的产出必须是 YAML 或 Markdown 表格,每个 phase/step 有固定字段:
id: P3-S2
name: Implement login endpoint
description: Add POST /login endpoint for user authentication
source_requirement: PRD-REQ-12
entry_conditions: [P2 completed, API spec approved]
exit_conditions: [Unit tests pass, Docs updated, Code reviewed]
responsible: AI
test_cases: [test_P3_S2_login]
status: planned
requirement_version: v1.2
change_log:
- {date: 2024-06-01, author: AI, change: 'Initial creation'}5.2 全链路可追溯
graph LR
PRD["PRD-REQ-12<br/>需求条目"] --> STEP["P3-S2<br/>计划步骤"]
STEP --> CODE["user_login_P3_S2.java<br/>实现代码"]
STEP --> TEST["test_P3_S2_login.java<br/>测试代码"]
STEP --> COMMIT["feat(P3-S2): ...<br/>提交信息"]
STEP --> LOG["change_log<br/>变更记录"]
规则强制:
- 每个 step 必须引用至少一个 PRD 需求 ID;每条需求必须被至少一个 step 覆盖
- 代码文件、测试文件、commit message 全部携带 step ID
- 实现阶段发现计划有问题,必须暂停并回溯更新计划,不允许擅自偏离
- 每个 phase 的 exit 条件包含"单元测试通过、覆盖率 ≥ 90%",而不是把测试堆到最后
这套东西眼熟吗?它就是把传统项目管理里的**需求追踪矩阵(RTM)**搬进了 Prompt。AI 输出的结构化程度,决定了它在下一阶段的可控性。
六、从单次问答到 Agent 编排
当你让 AI 做一个复杂任务时,单次 Prompt 往往不够。真正难的不是让模型"回答",而是让它按照正确的路径完成任务,并在出错时恢复。
6.1 ReAct:让模型"想一步、做一步"
ReAct(Reasoning + Acting)是我们用得最多的模式。它的核心不是一次性生成最终答案,而是让模型在每一步都输出:
- Thought:当前怎么想
- Action:下一步要调用什么工具
- Observation:工具返回了什么结果
flowchart LR
T["Thought<br/>当前怎么想"] --> A["Action<br/>调用什么工具"]
A --> O["Observation<br/>工具返回结果"]
O --> D{任务完成?}
D -->|否| T
D -->|是| F["Final Answer<br/>输出最终结果"]
比如一个短视频生成任务,Agent 的规划可能是:
- 读取用户输入的主题和风格要求
- 检索素材库,找到匹配的背景音乐和视觉素材
- 生成脚本初稿
- 检查脚本长度是否符合平台要求
- 如果不符合,进行压缩或扩展
- 输出最终脚本并进入渲染队列
每一步都有明确的输入输出和异常处理路径。这比一个"请帮我生成视频"的大而全 Prompt 可靠得多。
6.2 异常恢复与降级策略
真实生产环境里,模型调用可能失败、工具返回可能异常、生成的 JSON 可能解析失败。我们在 Agent 层设计了:
- 重试机制:对临时性错误进行指数退避重试
- 降级策略:如果主模型调用失败,切换到备用模型或简化流程
- 边界控制:当模型输出偏离预期时,通过约束模板和校验规则及时拦截
这些不是 Prompt 本身能解决的,但好的 Prompt 设计会为这些机制留出接口——比如让模型以固定 JSON 格式输出,就是为了后续程序化处理。
七、控制幻觉与讨好倾向
大模型有两个常见毛病:一是胡说八道还一本正经(幻觉),二是倾向于说你想听的(讨好倾向)。作为工程师,不能指望用户每次都火眼金睛,必须在系统层做防控。
7.1 要求依据,而不是要求答案
当你让模型做判断时,不要只问"对不对",而要问"为什么对"、“依据是什么”。在 RAG 场景里,我们会让模型引用它使用的素材片段;在代码评审场景里,我们会让模型指出具体行号和修改理由。
一个实用技巧是:让模型先列出置信度,再给出结论。 低置信度的输出可以直接进入人工复核队列。
7.2 用中性提问对抗诱导
避免在 Prompt 里夹带倾向性表述。比如不要问"这个方案是不是很好",而要问"这个方案的优缺点是什么,适用场景和潜在风险分别是什么"。
在涉及评分、排序、比较的任务里,提前定义清晰的评分标准,并让模型逐项说明得分理由。这比一个总体分数更有信息量,也更容易发现偏差。
7.3 多模型交叉验证
对于关键决策,可以让不同模型分别评估,再对结果做一致性检查。这个方法成本高,但在高风险场景(如医疗、金融、安全审核)里值得考虑。
八、多模态提示:文本只是入口
在短视频生成和口播剪辑项目里,我们大量接触了图像、音频、视频与文本的协同。多模态提示有几个值得注意的工程经验。
8.1 图像理解的"整体-细节"偏差
AI 读图时往往先把握整体构图,对局部细节容易遗漏。如果任务依赖细节(比如识别小字、检测图标),可以:
- 裁剪放大关键区域后单独输入
- 提供多张不同角度或不同尺度的图片
- 在 Prompt 中明确指定"请重点描述左上角的文字"
8.2 图像生成的提示词工程
扩散模型对文本描述非常敏感。直接写"一只猫在草地上",结果可能平平无奇。更好的做法是用一个文本模型先把需求扩写成结构化描述:
- 主体:什么猫、姿态、表情
- 场景:草地类型、光线、天气、时间
- 风格:写实、插画、赛博朋克、宫崎骏动画
- 镜头:特写、中景、鸟瞰、景深效果
也可以上传参考图,让模型先描述参考图的风格,再把描述作为提示词用于生成。
8.3 视频生成需要"时间维度"的上下文
相比单张图片,视频多了一个时间轴。生成视频脚本或分镜时,Prompt 里要包含:
- 每个镜头的起止时间
- 画面过渡方式
- 音频与画面的对齐点
- 字幕出现和消失的节拍
我们在方糖猫里把这些问题模板化,让 Agent 分步骤输出分镜表、配音稿、字幕轴,再交给 Remotion + FFmpeg 渲染流水线执行。
九、另一个视角:生成管线里的 Prompt 迭代
如果说 promptkit 展示的是"规范驱动"的 Prompt 工程,那么 GeekCast Engine 的视觉规划 Prompt 展示的是"数据驱动"的迭代路径。两者互补。
9.1 V1:基础版
请为以下口播文案规划视觉元素。
文案:{script}
可选元素:TitleCard, BRoll, QuoteCard, CodeBlock, ListCard, TalkingHead
请输出 JSON 数组。
问题:LLM 输出解释性文字;JSON 格式不稳定;对每种元素的用途理解不一致。
9.2 V2:结构化版
你是一名专业的口播视频剪辑师。请根据文案为每个句子规划视觉元素。
可用元素及定义:
- TitleCard: 章节开头或核心观点强调
- BRoll: 补充说明画面
- QuoteCard: 名言、数据引用
- CodeBlock: 代码展示
- ListCard: 多要点展示
- TalkingHead: 保持说话人画面
文案:{script}
请输出 JSON 数组,每个元素包含 sentence_index, element_type, reason, suggested_content。
不要输出任何解释性文字。
改进:明确角色、定义每个元素、明确输出格式。
仍有问题:复杂文案处理不好;长文案超出 Token 限制。
9.3 V3:分段 + Schema 约束版
你是一名专业的口播视频剪辑师。请根据文案为每个句子规划视觉元素。
[元素定义...]
请输出严格符合以下 JSON Schema 的数组:
{schema}
注意:
1. 不要输出任何解释性文字
2. 每句文案只选择一种最合适的视觉元素
3. 如果句子包含代码或技术术语,优先使用 CodeBlock
4. 如果句子引用名言或数据,优先使用 QuoteCard
文案:{script}
改进:加入 JSON Schema、增加选择规则、配合后端 Pydantic 校验。
9.4 迭代路径总结
flowchart LR
V1["V1 基础版<br/>格式不稳定"] -->|问题驱动| V2["V2 结构化版<br/>角色+定义+格式"]
V2 -->|评测驱动| V3["V3 Schema 约束版<br/>规则+后端校验"]
V3 -->|失败样本回流| EVAL[评测集扩充]
EVAL --> V4["下一版本..."]
三次迭代的共同规律:每一版都是先在生产/评测中暴露问题,再有针对性地加约束——而不是一开始就写一个"完美"的长 Prompt。这和 promptkit 用 CHANGELOG 记录行为契约变更,是同一个方法论的两面。
十、Prompt 版本管理与加载
10.1 文件组织
prompts/
├── visual_plan/
│ ├── v1.md
│ ├── v2.md
│ └── v3.md
├── storyboard/
│ ├── v1.md
│ └── v2.md
├── query_rewrite/
│ └── v1.md
└── README.md
每个 Prompt 文件头部包含:版本号、适用模型、使用场景、输入变量说明、输出格式要求、变更记录。
10.2 加载与渲染
import os
class PromptManager:
def __init__(self, base_path="prompts"):
self.base_path = base_path
def load(self, name: str, version: str) -> str:
path = os.path.join(self.base_path, name, f"{version}.md")
with open(path, "r", encoding="utf-8") as f:
return f.read()
def render(self, name: str, version: str, variables: dict) -> str:
template = self.load(name, version)
return template.format(**variables)10.3 常用设计模式速查
| 模式 | 适用场景 | 要点 |
|---|---|---|
| 角色 + 任务 + 格式 | 结构化输出 | 最简单,80% 场景够用 |
| Chain-of-Thought | 需要推理的复杂任务 | 显式列出思考步骤 |
| Few-shot | 格式复杂或需要风格 | 示例控制在 2-3 个 |
| 动态 Few-shot | 有素材库可检索 | 从 RAG 召回相似示例拼入 Prompt |
| ReAct | 需要工具调用的 Agent 任务 | Thought/Action/Observation 循环 |
| 模式化规则注入 | AI Coding 场景 | 按 PLAN/ACT 等模式加载不同规则(见第四节) |
动态 Few-shot 的实现:
def build_dynamic_prompt(query: str, examples: list[str]) -> str:
prompt = "以下是几个类似场景的处理示例:\n\n"
for i, ex in enumerate(examples, 1):
prompt += f"示例 {i}:\n{ex}\n\n"
prompt += f"现在请处理:\n{query}"
return prompt十一、评估与回归:没有评测集就没有迭代资格
提示工程最难的部分不是写出第一版 Prompt,而是持续知道它在变差,并及时修复。
11.1 评测数据集
收集一批代表性用例,覆盖正常输入、边界输入、异常输入:
[
{
"input": "大家好,今天讲 AI 视频生成...",
"expected": [
{"sentence_index": 0, "element_type": "TitleCard"},
{"sentence_index": 2, "element_type": "CodeBlock"}
]
}
]11.2 分任务定义可量化的指标
不同任务的关注点不同:
| 任务类型 | 核心指标 |
|---|---|
| 通用生成任务 | 格式合规率、语义准确率、字段完整率、Token 消耗、平均延迟 |
| RAG 任务 | 召回率、准确率、回答相关性 |
| Agent 任务 | 任务完成率、平均步数、异常恢复率 |
除了技术指标,还要跟踪业务指标。我们在短视频生成平台里跟踪:渲染成功率、用户二次编辑率、单视频平均 Token 成本。这些指标会反过来指导 Prompt 优化方向。
11.3 回归测试脚本
def run_prompt_regression(prompt_version: str, test_cases: list):
results = []
for case in test_cases:
output = llm_call(case["input"], prompt_version)
parsed = parse_output(output)
results.append({
"case_id": case["id"],
"format_valid": is_valid_format(parsed),
"semantic_score": compare_with_expected(parsed, case["expected"]),
"token_count": count_tokens(output),
"latency": measure_latency()
})
return summarize(results)11.4 合并门禁
每次修改 Prompt 前:
- 复制当前版本为新版本
- 在评测集上跑回归测试
- 对比新版本和旧版本的指标
- 只有指标不下降才合并
这套流程和代码的 CI 门禁完全同构。promptkit 的 CHANGELOG + 这里的回归脚本,一个管"规则资产",一个管"生成资产",合起来才是完整的 Prompt 版本管理。
十二、成本控制:Prompt 也是成本中心
长 Prompt 和高轮次调用都会直接转化为模型费用。优化 Prompt 不只是为了效果更好,也是为了更便宜。
12.1 模型路由
不是所有任务都需要最强的模型:
| 任务 | 模型 | 原因 |
|---|---|---|
| 简单格式提取 | DeepSeek-V3 / GPT-3.5 | 便宜、够快 |
| 复杂创意规划 | GPT-4 / Claude 3.5 | 质量高 |
| 代码相关任务 | Claude 3.5+ | 代码能力强 |
promptkit 的 README 里也有同样的分层建议:讨论需求用带搜索的 Chat 工具,规划设计用分析能力强的模型,编码用代码能力强的模型。按阶段选模型,而不是一个模型打全场。
12.2 Prompt 压缩
- 删除冗余说明
- 用更短的变量名
- Few-shot 示例控制在 2-3 个
- 长文案先分段,再分别处理
12.3 缓存
def cached_llm_call(query: str, prompt_version: str):
key = hash(f"{prompt_version}:{query}")
cached = redis.get(key)
if cached:
return cached
result = llm_call(query, prompt_version)
redis.setex(key, 3600, result)
return result两个注意点:缓存 key 里必须带 prompt_version——Prompt 变了,缓存就必须失效;同样的思路也适用于其他生成产物,比如我们按文案 hash 缓存 TTS 结果,避免重复合成。
十三、踩过的坑
13.1 Prompt 里塞了太多信息
早期一个 Prompt 要同时做意图分析、视觉规划、素材推荐,结果哪一项都做得不好。
解决:拆成多个专门 Prompt,每个只负责一个任务。promptkit 把 PLAN 和 ACT 拆成两套规则文件,是同一件事。
13.2 过度依赖 LLM 做判断
有些规则明确的判断(比如句子长度、是否包含代码关键字),完全可以用代码做,没必要让 LLM 判断。
解决:规则用代码,创意用 LLM。
13.3 没有记录失败案例
线上遇到解析失败的 Prompt 输出,没有系统收集,导致同样的问题反复出现。
解决:建立失败样本库,定期补充到评测集中。promptkit 的 learnings.md 是同一个思想在 AI Coding 场景的落地——让 AI 把自己犯过的错写下来,下次会话先读。
13.4 忽视不同模型的差异
同一个 Prompt 在 DeepSeek 上表现好,在 GPT-4 上可能出问题。
解决:为不同模型维护微调后的 Prompt 版本;评测集要覆盖所有生产用模型。
13.5 让 AI 自己改规范
AI 遇到"规范与实现冲突"时,倾向于悄悄改规范迁就实现。
解决:把规范目录在规则里声明为全模式只读(promptkit 的 ai_work/spec/ 就是这么做的),规范的变更只能由人发起。
13.6 规划与实现脱节
AI 在 PLAN 模式出了漂亮的方案,到了 ACT 模式就自由发挥,交付物和计划对不上。
解决:用交接协议强制——实现必须引用计划中的 step ID,发现计划不可行必须暂停回溯,不允许擅自偏离(见第五节)。
十四、Prompt 工程的核心原则
- 把 Prompt 当接口设计:输入完整、输出可解析、边界可控,像设计函数签名一样设计 Prompt
- 把 Prompt 当代码管理:版本控制、CHANGELOG、测试、Review 缺一不可
- 按加载时机分层:全局规则 / 模式规则 / 只读规范,分开管理注意力预算
- 上下文要显式化:Memory Bank 这类结构化上下文文件,比依赖会话记忆可靠得多
- 相关性优先于信息量:无关上下文会稀释注意力,检索结果要重排序,工作记忆要定期清理
- 流程编码进 Prompt:不要指望 AI 自觉遵守工程流程,把流程画成它必须执行的步骤
- 复杂任务编排成步骤:用 ReAct 等模式拆解任务、设计异常恢复,而不是一个大 Prompt 包打天下
- 要求依据,而非答案:让模型给置信度、引用素材、指出行号,低置信度进人工队列
- AI 之间的交接要有协议:结构化输出 + ID 追溯 + 暂停回溯机制
- 简单任务优先用代码:不要让 LLM 做规则能做的事
- 输出必须可校验:Schema + 后端校验是底线
- 用数据驱动优化:评测集、技术指标 + 业务指标、回归门禁
- 收集失败样本:失败案例是最值钱的评测集增量
十五、总结
Prompt Engineering 不是玄学,也不是简单的"提示词技巧"。它至少是三层东西的组合:
graph TD
L3["工程管理层<br/>版本控制 / CHANGELOG / 评测回归 / 成本路由"]
L2["系统设计层<br/>规则分层 / Memory Bank / 双模式工作流 / 交接协议 / Agent 编排"]
L1["文本技巧层<br/>角色设定 / CoT / Few-shot / Schema 约束"]
L3 --> L2 --> L1
大多数人讨论的"Prompt 技巧"只在最底层打转;真正把 LLM 应用做稳定的团队,都在上两层下功夫:
- 系统设计层:Prompt 决定 Agent 能做什么、不能做什么,读写权限、模式切换、交接协议、异常恢复都是架构决策
- 工程管理层:Prompt 是需要版本、测试、评估、变更日志管理的资产,也是直接的成本中心
方糖猫的视觉规划 Prompt 从 V1 到 V3 提升的是单点输出质量;promptkit 用一套规则库约束的是整个 AI 开发流程的行为。两者路径不同,结论一致:Prompt 工程的天花板不在"会不会写提示词",而在"有没有把它当工程做"。
所以,不要花太多时间寻找"万能 Prompt"。更值钱的能力是:把业务问题拆解成模型能稳定执行的子任务,再用工程化的方法把它变成可交付、可维护的系统。
如果你也在做 LLM 应用开发或 AI Coding 落地,欢迎交流 Prompt 版本管理、规则分层和回归测试的经验。