AI Prompt工程:混乱不够用了之后

让 AI「写个 Python 脚本处理 CSV」,第一次只做清洗,第二次加了异常处理却把核心逻辑改了,第三次要格式化输出,它又把前面重构一轮。同一句人话,隔一天结果对不上,多轮对话改复杂任务成本更高——五步法经常要七八轮才摸清楚边界。

我后来才意识到:写代码会模块化、会版本管理,给 AI 下指令却每次从零试探。这篇记怎么把 prompt 当成可迭代工程来管。

背景:为什么需要 Prompt 工程

最初的问题很简单:我让 AI “帮我写个 Python 脚本处理 CSV 文件”,它每次生成的代码都不一样。

第一次要求数据清洗,它只给了基础代码;第二次加了异常处理,结果把核心逻辑改了;第三次想让输出格式化,它又把前面的重构了一轮。最头疼的是,同样的一句话,今天能跑通,明天就报错——模型本身的随机性加上我表述的细微差异,让整个过程充满不确定性。

我也试过"多轮对话逐步调整"的办法,但很快就发现这个方法在复杂任务上成本太高。五个步骤的任务,通常需要七八轮对话才能摸清楚模型的"脾气"边界;如果是十步以上的任务,基本等于从头写一遍。

再往后我开始思考:为什么自己写代码时能模块化、能复用、能迭代,到了给 AI 下指令时就变成了每次从头试探?

答案其实是:我从来没有把 prompt 当作代码来写。

需求:到底要解决什么

从工程角度看,我需要解决三个具体问题:

  1. 稳定性:同样的需求在不同时间调用时,结果要保持一致。这一点在自动化场景里尤其重要——你不能让每次部署都产出不同版本。

  2. 可复用性:遇到类似问题时,不应该每次都重新试探。应该能基于已有的 prompt 模板快速适配,而不是每次从零开始。

  3. 可迭代性:当 prompt 效果不满足时,应该能定位问题、局部调整、验证效果,而不是推翻重来。

简单说就是:我要把 prompt 从"一次性对话"变成"可维护的工程产物"。

实现:结构化 Prompt 设计框架

经过一段时间的尝试,我沉淀了一个基本框架。它不是什么"最佳实践",只是我自己觉得好用的结构。

核心结构

一个完整的 prompt 通常包含七个部分:

## 角色
你是一个 [具体角色],擅长 [具体技能]。

## 背景
当前任务的背景是 [真实场景描述]。

## 目标
你需要完成 [明确的目标]。

## 限制
- 限制条件 1
- 限制条件 2
- 限制条件 3

## 输入
[实际数据或问题描述]

## 输出格式
[具体的输出格式要求]

## 示例
输入: [示例输入]
输出: [示例输出]

这个结构看着有点重,但它的价值在于每个部分都有明确目的:角色定义了能力边界,背景提供了上下文,目标锁定了期望结果,限制防止了跑偏,输出格式保证了可用性,示例则降低了理解成本。

角色定义:不是所有 AI 都是万能的

我发现一个很有意思的现象:同样的任务,换个角色定义,结果差异会很大。

比如"帮我优化这段代码"这个需求:

  • 如果角色是"资深 Python 工程师",它会从性能、可读性、维护性三个维度优化,可能会引入新的库。
  • 如果角色是"代码审查专家",它会侧重于安全性、边界条件处理、异常处理。
  • 如果角色是"教学助手",它会加上详细的注释和解释,方便新人理解。

角色名花不花哨无所谓,得把模型该用的视角写清楚

## 角色
你是一个专注于性能优化的 Python 后端工程师,擅长识别瓶颈、重构热点代码、降低复杂度。
你熟悉 asyncio、并发编程和常见的性能分析工具,但不建议为了优化牺牲可读性。

这样的角色定义比单纯的"Python 专家"更精确,因为它限定了"专注性能"和"不牺牲可读性"两个边界。

目标拆分:从模糊到具体

最大的变化发生在目标设定上。我以前的目标通常是模糊的:

  • “帮我写个脚本”
  • “优化这段代码”
  • “解释一下这个概念”

现在我会把目标拆解成可验证的小目标:

## 目标
基于输入的 CSV 文件,完成以下任务:
1. 读取数据并验证字段完整性
2. 清洗异常值(空值、负数、超出范围的数值)
3. 计算每个用户的消费总额和平均消费
4. 按消费总额降序排序
5. 输出清洗后的数据和统计结果

拆解的好处在于:每一步都可以独立验证,整体进度可以追踪,问题可以快速定位。

限制条件:告诉模型"不要做什么"

限制条件是我后来才发现真正有用的部分。最开始我只会告诉模型"要做什么",不会说"不要做什么",结果经常收到意料之外的输出。

比如处理文本数据时,如果只说"提取关键信息",模型可能会:

  • 删掉上下文中的有用细节
  • 改变原意的表述
  • 增加自己推断的内容

加了限制条件后:

## 限制
- 只提取明确提及的信息,不要推断或添加内容
- 保持原文的表述风格和语序
- 如果某个字段在输入中不存在,输出 "N/A" 而非猜测
- 代码中不要使用需要额外安装的库,只使用 Python 标准库
- 处理异常时要给出明确的错误信息,而不是静默失败

这样的限制条件直接降低了模型的"发挥空间",反而提升了结果的可预期性。

输出格式:让结果直接可用

输出格式是我踩坑最多的地方。刚开始我只关注"内容对不对",没在意"好不好用",结果每次拿到结果都要手动调整格式。

现在我会明确指定输出格式,特别是对于代码类任务:

## 输出格式
以 Markdown 代码块形式输出 Python 脚本,包含以下部分:
1. 文件头部注释,说明脚本用途、依赖、使用方式
2. 导入语句
3. 常量定义
4. 主函数
5. if __name__ == '__main__' 调用

代码中每个函数都要有清晰的文档字符串(docstring),说明参数、返回值和异常情况。

对于数据处理任务,输出格式更加关键:

## 输出格式
输出两个 Markdown 表格:
1. 清洗后的数据:列名保持不变,每行代表一个用户的完整信息
2. 统计结果:包含用户ID、消费总额、平均消费三列,按消费总额降序排序

表格上方用一句话说明表的内容,下方标注数据量。

这样的输出格式设计让结果可以直接用于下游处理,不需要额外的转换成本。

踩坑:这些地方最容易出问题

实践过程中我踩了不少坑,这里记录几个最常见的。

问题一:prompt 越写越长,效果反而变差

刚开始为了追求"精确",我把 prompt 写得非常详细,结果发现模型反而更容易跑偏。后来才明白:信息量不等于信息质量,关键信息被淹没在无关细节里。

现在我的原则是:每个部分只保留最必要的信息,去掉那些"可能有帮助"的补充说明。比如角色定义里,我不会列出所有相关技术栈,只会写"当前任务会用到的核心技能"。

问题二:一次性要求太多步骤

最开始我习惯在一个 prompt 里塞满所有步骤,以为这样能一次拿到完整结果。现实是:步骤越多,模型越容易在中途丢掉细节,越往后的部分质量越差。

现在的做法是:把复杂任务拆成多个 prompt,每个 prompt 专注一个具体步骤。比如数据处理任务会拆成"数据验证"、“数据清洗”、“数据计算”、“结果格式化"四个独立调用。

graph LR A[原始数据] --> B[数据验证] B --> C[数据清洗] C --> D[数据计算] D --> E[结果格式化] E --> F[最终输出] style A fill:#e1f5fe style F fill:#c8e6c9

这样做的好处是:每个步骤可以独立验证和调试,整体流程更可控。

问题三:过度依赖示例

我有一段时间非常迷信"few-shot learning”,每个 prompt 都会加上三五个示例。后来发现这带来了两个问题:

  1. 示例编写成本高,每次调整 prompt 都要重新验证示例的准确性
  2. 示例太多反而会限制模型的创造力,导致结果过于机械

现在的原则是:只有在模型对任务理解有偏差时才加示例,而且通常一个就够了。更多时候,清晰的描述比示例更有效。

问题四:忽略模型的上下文窗口

最开始我写 prompt 时没有考虑 token 限制,结果经常遇到"截断"问题:输出到一半突然断了,或者模型为了控制长度直接压缩了关键信息。

现在的习惯是:

  • 每个 prompt 控制在 500-800 token 左右
  • 复杂任务拆分成多次调用,而不是一次性塞满上下文
  • 输出部分明确限制长度,避免模型"发散"

结果:这套方法的实际效果

用了三个月左右,这套方法带来的变化挺明显的。

效率提升

最常见的重复性任务,现在基本都有对应的 prompt 模板。比如代码审查、文档撰写、数据清洗,都不用每次从零开始。模板复用率大约在 70% 左右,剩下的 30% 是针对特定场景的定制。

一个原来需要 7-8 轮对话才能完成的任务,现在通常 2-3 轮就能搞定。第一轮给出结构化 prompt,第二轮针对细节调整,第三轮验证结果。整体时间大概减少了 60%。

质量稳定

最明显的变化是结果的可预期性。同样的需求,使用相同的模板,输出结果的风格和质量基本一致。这一点在自动化场景里尤其重要——你不会希望每次部署生成的代码都有不同的风格。

代码类任务的可用率从原来的 60% 左右提升到了 85% 以上。剩下的 15% 通常是一些边界情况或者模型能力限制,这种情况下人工介入反而更高效。

可迭代性

现在遇到 prompt 效果不好的情况,我基本能快速定位问题:是角色定义不准?还是目标拆分有问题?或者是限制条件没写对?定位清楚后,局部调整就能解决,不需要推翻重来。

最近我在优化一个文档生成任务的 prompt,发现输出内容总是不够聚焦。加了"每个段落只讲一个核心观点,段落之间用过渡句衔接"这个限制后,效果明显好了不少。整个调试过程只用了两轮尝试。

边界:这套方法也不是万能的

坦白说,这套方法也有它的局限性。

对于非常简单的一问一答任务,结构化 prompt 反而是"杀鸡用牛刀"。有时候就是需要快速查个事实、要个建议,这时候模板化的框架只会增加成本。

对于高度创造性的任务,比如写小说、设计游戏玩法,过度结构化反而会限制发挥。这种情况下,我更倾向于用"轻量框架 + 多轮迭代"的方式,先把方向理清楚,再让模型自由发挥。

还有些任务模型能力本身就不够,prompt 写到头也救不了,只能换模型、换方法,或者把预期降下来。

后续:还在继续折腾

Prompt 工程这个领域变化很快,我现在的理解也只是当前阶段的产物。最近开始关注几个新方向:

一个是动态 prompt 生成——根据任务复杂度自动调整 prompt 的结构和长度,简单任务用轻量框架,复杂任务用完整框架。

另一个是prompt 版本管理——把 prompt 当作代码一样做版本控制,记录每次调整的原因和效果,形成可追溯的优化历史。

还有一个是效果评估——建立自动化的评估机制,用标准化的测试集来验证 prompt 的效果,而不是每次都靠人工判断。

这些方向还在摸索中,等有了一些结果再单独写篇文章分享。

结语

这三个月折腾下来,我手里多了一套能复用、能迭代的 prompt 写法,离"完美 prompt"还远。

核心就一条:把 prompt 当工程产物管——有结构、有边界、能验证、能改。跟写代码是同一种习惯。

框架还会随模型和任务变,但态度得先变:别把它当一次性聊天,当维护成本算进去。

如果你也在 prompt 上反复踩坑,希望这篇能少浪费你几轮对话。够用就行,不必追求模板完美。

版权声明: 本文首发于 指尖魔法屋-AI Prompt工程:混乱不够用了之后https://blog.thinkmoon.cn/post/356-ai-prompt-engineering-chaos-structure-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!