接着上一篇 《别把 LLM 当裸机跑》 的话题,这次想聊一个更具体的话题:Prompt 工程

我做 LLM 应用一年多,最大的体会是——很多人以为某个任务"模型搞不定",其实是 Prompt 写歪了

同一个任务,同一个模型,Prompt 写法不同,输出质量能差好几个量级。这篇笔记把我踩过的坑整理一下,希望对正在做 LLM 应用的同行有点参考。

代码示例都用 Python + OpenAI SDK,但思路适用于所有主流大模型 API。


坑一:把所有约束塞进 system prompt

刚入门时我喜欢这样写:

system_prompt = """
你是一个专业的代码审查助手。
请遵循以下规则:
1. 检查变量命名是否符合 PEP8 规范
2. 检查是否有未使用的 import
3. 检查是否有 SQL 注入风险
4. 检查异常处理是否完善
5. 检查日志输出是否合理
6. 检查注释是否清晰
7. 检查测试覆盖率
8. 输出格式必须是 JSON
9. 每个问题要标注严重程度
10. ...(还有 15 条)
"""

然后兴致勃勃地运行,发现:

模型只遵循了前 3 条规则,后面的全部被无视了

后来读了一些研究才知道,LLM 对 prompt 中信息位置的敏感度差异极大。这是所谓的 "Lost in the Middle" 现象——模型对开头和结尾的内容关注度最高,中间的内容很容易被"遗忘"

正确做法

把核心约束放在 prompt 的开头和结尾,重要的事情说两遍

system_prompt = """
[核心任务] 进行 Python 代码审查,输出 JSON 格式结果。

[审查维度]
- 安全性: SQL 注入、XSS、敏感信息泄露
- 规范性: PEP8、命名约定、import 顺序
- 健壮性: 异常处理、边界条件、空值判断
- 可读性: 注释、变量命名、函数职责单一

[输出格式]
{
  "issues": [
    {"type": "security", "severity": "high", "line": 12, "message": "..."}
  ]
}

[再次强调] 必须输出合法 JSON,不要包含任何解释性文本。
"""

把约束结构化分组,把最关键的"输出格式"在开头和结尾各强调一次。这一步改完之后,我的 Prompt 遵循度从 50% 提到了 90%+。


坑二:用"否定句"约束模型

一个特别隐蔽的坑:LLM 对否定句的处理远不如肯定句

我曾经写过这样的 prompt:

prompt = """
请总结以下文章内容,不要超过 100 字,不要使用专业术语,不要包含个人观点。
"""

结果模型给我返回了:

  • 一段 250 字的总结
  • 满篇专业术语
  • 夹杂大量"我认为""值得注意的是"等主观表达

为什么?

因为 LLM 本质上是"概率续写","不要 X"这种指令在训练数据里出现得相对少,模型更容易抓住"X"本身然后继续生成。就像你跟一个人说"不要想白熊",他脑子里第一时间出现的就是白熊

正确做法:把所有否定句改成肯定句。

prompt = """
请总结以下文章内容,要求:
- 总字数控制在 100 字以内
- 使用通俗易懂的日常用语
- 客观陈述事实,不加评价
"""

把"不要使用专业术语"改成"使用通俗易懂的日常用语",模型的遵循度立刻提升。这是个非常小的细节,但对输出质量影响巨大


坑三:让模型"自由发挥"

新手做 LLM 应用时还有一个常见错误:对输出格式不做约束

prompt = "请帮我分析这段代码的性能瓶颈"

你以为模型会给你一段精炼的分析。

实际上模型可能给你:

  • 第一次:4 段散文,没有结构
  • 第二次:分点列表,但条目数随机
  • 第三次:先来段"非常好的问题!"开头,然后混合各种格式

这种输出基本无法做下游的程序化处理

正确做法:用 结构化输出 + few-shot 示例 来约束。

prompt = """
分析以下代码的性能瓶颈,严格按照下面的格式输出:

## 瓶颈点 1
- 位置: [文件:行号]
- 类型: [I/O / CPU / 内存 / 网络]
- 严重程度: [高/中/低]
- 优化建议: [具体方案]

## 瓶颈点 2
...

示例输出:
## 瓶颈点 1
- 位置: main.py:42
- 类型: I/O
- 严重程度: 高
- 优化建议: 改用批量查询替代循环单次查询

[待分析代码]
{code}
"""

加上示例输出这一步是核心。LLM 是"模仿型选手",你给它一个具体例子,它的输出格式遵循度会跳一个台阶。


坑四:忽略 temperature 的副作用

很多人调 LLM 只用默认参数。但 temperature 这一个参数,对输出影响极大。

简单理解:

  • temperature = 0:模型每次都选概率最高的 token → 输出确定、保守、重复性高
  • temperature = 1:模型按概率分布随机采样 → 输出多样、有创意、不稳定
  • temperature = 2:模型大量采样低概率 token → 输出经常崩坏、出现胡言乱语

我踩过的坑是:做严肃任务时 temperature 拉太高

比如让模型生成 SQL,我设了 temperature=0.8,结果同一个查询需求,模型有时返回正确 SQL,有时返回带语法错误的 SQL,有时甚至开始"创造"我数据库里不存在的字段名

经验法则

任务类型 推荐 temperature
代码生成、SQL 生成 0 - 0.2
信息提取、分类 0 - 0.3
总结、改写 0.3 - 0.6
创意写作、故事生成 0.7 - 1.0
头脑风暴 1.0+

严肃任务 temperature 调低,创意任务调高。这条规则简单粗暴但极其有效。


坑五:不给模型"思考空间"

最后一个想分享的,是 Chain-of-Thought(思维链) 在工程实践中的应用。

我曾经让模型做一个复杂的数学推理任务,prompt 是:

prompt = "如果一个商品打 8 折后再打 9 折,相当于打几折?直接告诉我答案。"

模型经常给错答案(比如答 17 折、7 折、85 折),错误率高得离谱。

后来我改成:

prompt = """
如果一个商品打 8 折后再打 9 折,相当于打几折?

请按以下步骤推理:
1. 假设原价为 100
2. 第一次打 8 折后的价格是?
3. 第二次打 9 折后的价格是?
4. 最终价格相对原价是几折?

最后给出答案。
"""

错误率立刻降到接近 0。

原因是:LLM 没有"心算"能力。它的每一次输出 token 本质上都是基于前面 token 的概率推理。不给它"中间推理过程"的输出空间,它就只能直接猜结果——猜对了是运气,猜错了是常态。

经验法则:复杂推理任务,一定要让模型 "step by step" 输出推理过程,再得出最终答案。哪怕你只需要最终答案,也要保留推理过程的输出——因为这个过程本身能显著提高准确率。


写在最后

Prompt 工程在很多人眼里像"玄学",但实际上它有自己的工程规律:

  • 位置敏感:核心约束放头尾
  • 正向表达:肯定句优于否定句
  • 结构化:明确输出格式 + few-shot
  • 参数匹配任务:temperature 别瞎调
  • 给思考空间:让模型 step by step

这些规律每一条都不复杂,但叠加起来对输出质量的影响是数量级的。

下次写 prompt 之前,可以拿这个清单过一遍。如果你也踩过其他 Prompt 的坑,欢迎评论区交流。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐