AI Agent 的灵魂对话:Prompt Engineering 系统提示词设计的艺术与工程

写在前面

如果你读过本系列之前的 ReAct 模式Tool UseMemory 记忆系统RAG 检索增强 等文章,你会发现一个共同点——所有这些能力的”开关”,都藏在 Prompt 里

ReAct 的思考链靠 Prompt 驱动,Tool Use 的工具描述靠 Prompt 传递,Memory 的上下文靠 Prompt 拼接,RAG 的检索结果靠 Prompt 注入。Prompt 就像 Agent 的灵魂,写得好,Agent 聪明得像人;写得差,Agent 蠢得像块石头。

今天这篇,我们聊聊 Prompt Engineering——不是那种”请你帮我写个 Prompt”的入门科普,而是从工程视角出发:System Prompt 的底层原理是什么?为什么有些 Prompt 写法效果好?在 Java 生态中,Spring AI 和 LangChain4j 分别怎么管理 Prompt?企业级场景下怎么组织多层提示词架构?

一、Prompt 的本质:你和模型之间的”合约”

1.1 先搞清楚一个认知误区

很多人以为 Prompt 就是”给模型写的一段话”。这个理解没错,但太浅了。

Prompt 本质上是你和模型之间的一份合约。你在这份合约里规定了模型的角色、行为边界、输出格式、思考方式。模型拿到这份合约后,会在它的概率空间里找到一个最符合合约描述的”人格切片”。

这就解释了为什么”你是一个有 10 年经验的 Java 架构师”和”回答以下问题”会让同一个模型给出完全不同质量的答案——不是模型变聪明了,而是你激活了不同的参数子空间。

1.2 System Prompt vs User Prompt:两种不同的”信号”

在 Chat API 中,消息分为三种角色:

1
2
3
4
5
┌─────────────────────────────────────────────────────┐
│ System Prompt → "你是谁,怎么做事"(底层指令) │
│ User Prompt → "用户想问什么"(具体任务) │
│ Assistant Prompt → "模型之前说了什么"(对话历史) │
└─────────────────────────────────────────────────────┘

System Prompt 之所以特殊,是因为它在 Attention 计算中通常被赋予更高的权重。虽然 OpenAI 等厂商没有公开具体的权重机制,但从实验结果来看,System Prompt 的指令对模型行为的约束力远强于同等长度的 User Prompt。

用一个类比:User Prompt 像是”今天我想吃什么”,System Prompt 像是”我是一个素食主义者”。前者改变一次决策,后者改变所有决策。

1.3 Token 经济学:为什么 Prompt 长度很重要

每个 Prompt 都要消耗 Token,而 Token 意味着钱和延迟。理解 Token 经济学是工程化 Prompt 设计的基础:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌───────────────────────────────────────────────────────┐
│ Prompt 长度的三个代价 │
│ │
│ 💰 成本:每千 Token 都要花钱 │
│ - GPT-4o System Prompt 2000 Token ≈ ¥0.04/次 │
│ - 100 个并发用户 × 10 次/天 = ¥40/天 │
│ │
│ ⏱️ 延迟:Prompt 趱长,首 Token 延迟越高 │
│ - 1000 Token → ~200ms │
│ - 4000 Token → ~500ms │
│ - 16000 Token → ~1500ms │
│ │
│ 🧠 注意力稀释:信息越多,模型越容易"走神" │
│ - Lost in the Middle 现象:中间信息容易被忽略 │
│ - 关键指令应放在开头或结尾 │
└───────────────────────────────────────────────────────┘

“Lost in the Middle” 是 2023 年斯坦福的一项研究发现:当上下文很长时,模型对开头和结尾的信息注意力最强,对中间的信息注意力最弱。这意味着——

你的 System Prompt 如果很长,关键指令一定要放在最前面或最后面。

二、System Prompt 设计的五层架构

一个好的 System Prompt 不是随手写的几句话,而是有结构的。我把它总结为五层架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌─────────────────────────────────────────────────────────┐
│ 第 1 层:角色定义 │
│ "你是一个企业级 Java 架构师助手" │
├─────────────────────────────────────────────────────────┤
│ 第 2 层:能力边界 │
│ "你擅长 Spring Boot、微服务、数据库设计" │
│ "你不会提供投资建议或医疗诊断" │
├─────────────────────────────────────────────────────────┤
│ 第 3 行为规范 │
│ "回答先给结论,再展开解释" │
│ "代码示例用 Java 21,Spring Boot 3.x" │
│ "不确定的事情明确说不确定" │
├─────────────────────────────────────────────────────────┤
│ 第 4 层:输出格式 │
│ "用 Markdown 格式输出" │
│ "代码块标注语言" │
│ "长回答分小节" │
├─────────────────────────────────────────────────────────┤
│ 第 5 层:动态注入 │
│ "当前用户角色:{role}" │
│ "检索到的相关文档:{context}" │
│ "可用工具列表:{tools}" │
└─────────────────────────────────────────────────────────┘

为什么要分层? 因为每一层的更新频率不同:

层级 更新频率 典型场景
角色定义 几乎不变 产品定型后就固定
能力边界 偶尔调整 新增能力或合规要求变化
行为规范 随迭代优化 发现模型回复质量问题时调整
输出格式 按场景切换 给用户的 vs 给系统的格式不同
动态注入 每次请求 用户信息、检索结果、工具列表

分层设计让你不需要每次都重写整个 Prompt,只需要替换变化的部分。

三、核心技巧:从原理到实践

3.1 Chain-of-Thought(CoT):让模型”想出来”

CoT 是最经典的 Prompt 技巧。核心思想很简单:让模型先想再说

原理:Transformer 的每一层都是对上一层表示的”精炼”。当你要求模型”一步步思考”时,你在给模型更多的计算步骤来处理问题——相当于从 12 层 Transformer 的思考,变成了”12 层 × N 步”的思考。

1
2
3
4
5
6
7
8
9
10
11
12
❌ 普通 Prompt:
Q: 一个商店有 23 个苹果,卖了 7 个,又进了 12 个,还剩多少?
A: 28

✅ CoT Prompt:
Q: 一个商店有 23 个苹果,卖了 7 个,又进了 12 个,还剩多少?
请一步步思考。
A:
- 初始:23 个
- 卖了 7 个:23 - 7 = 16 个
- 又进了 12 个:16 + 12 = 28 个
- 答案:28 个

对于 Agent 场景,CoT 的价值更大。还记得 ReAct 模式 中的 Thought-Action-Observation 循环吗?ReAct 本质上就是 CoT 的工程化实现——模型在执行工具调用前,先用自然语言描述自己的推理过程。

3.2 Few-shot:用例子教模型”格式”

Few-shot 比”请用以下格式输出”有效 10 倍。原因很直观:模型通过示例学格式,比通过描述学格式快得多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
System Prompt:
你是一个代码审查助手。请按以下示例的格式输出审查结果。

示例输入:
public void process(String name) {
String sql = "SELECT * FROM users WHERE name = '" + name + "'";
db.execute(sql);
}

示例输出:
🔴 严重:SQL 注入漏洞
- 位置:process() 方法第 2 行
- 问题:直接拼接用户输入构造 SQL
- 修复:使用 PreparedStatement 参数化查询
- 影响:攻击者可执行任意 SQL

请审查以下代码:
{code}

关键要点

  • 示例要有代表性,覆盖你期望的输出风格
  • 示例要有多样性,包括简单和复杂的 case
  • 示例数量通常 2-3 个就够,太多会浪费 Token

3.3 自我一致性(Self-Consistency):多数投票

这是 2022 年 Google 提出的技术,核心思想是:同一个问题问模型多次,取多数票

1
2
3
4
5
6
7
8
9
温度 = 0.7 时:

第 1 次回答:答案是 A
第 2 次回答:答案是 A
第 3 次回答:答案是 B
第 4 次回答:答案是 A
第 5 次回答:答案是 A

多数票 → A(4/5)

在 Agent 场景中,这可以用于关键决策节点——比如让 Agent 对”是否需要调用工具”做多次判断,减少误触发。

3.4 结构化 Prompt:用 XML/JSON 约束输出

还记得 Spring AI 结构化输出 那篇文章吗?Prompt 层面的结构化约束是另一种思路——直接在 Prompt 中告诉模型”你只能输出以下格式”:

1
2
3
4
5
6
7
8
9
10
11
12
13
System Prompt:
分析用户的问题,输出以下 JSON 格式:

{
"intent": "分类意图",
"confidence": 0.0-1.0,
"entities": [
{"type": "实体类型", "value": "实体值"}
],
"response_strategy": "direct|search|clarify"
}

只输出 JSON,不要输出其他内容。

为什么结构化输出在 Prompt 层面很重要?

因为 Agent 的下游逻辑需要解析模型输出。如果模型返回自然语言,你需要再写一层解析逻辑;如果模型直接返回 JSON,你可以直接 JSON.parse(),省掉一层 NLU。

结构化输出 = Prompt 层面的 Schema 约束 + 生成层面的 Grammar 约束。两者配合才能实现可靠的结构化输出。

四、Prompt 与 Agent 组件的交互

Prompt 不是孤立存在的。在 Agent 架构中,Prompt 是连接各个组件的”总线”。

4.1 Prompt + Memory

当你为 Agent 添加 Memory 记忆系统 时,记忆是以 Prompt 的形式注入的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
System Prompt:
你是一个个人助手。

[长期记忆]
- 用户是 Java 开发者,偏好 Spring Boot
- 用户在北京,时区 UTC+8
- 用户不喜欢冗长的回答

[短期记忆 - 最近对话]
用户:帮我写个排序算法
助手:好的,这是冒泡排序...
用户:有没有更快的?
助手:快速排序更适合...

[当前问题]
用户:{new_message}

这里有个关键的工程问题:记忆注入的位置和格式。

研究表明,记忆放在 System Prompt 的中间偏后位置效果最好——既不会覆盖角色定义(开头),也不会被当前问题挤掉注意力(末尾)。

4.2 Prompt + RAG

RAG 场景 中,检索到的文档需要注入 Prompt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
System Prompt:
基于以下参考资料回答用户问题。
如果参考资料不足以回答,请明确说明。
不要编造参考资料中没有的信息。

---

参考资料:
[1] 文档标题:Spring Boot 自动配置原理
内容:Spring Boot 的自动配置基于 @EnableAutoConfiguration...

[2] 文档标题:Spring Boot Starter 机制
内容:Starter 是一组依赖的集合...

---

用户问题:{question}

RAG Prompt 的三个陷阱

  1. 信息过载:塞太多检索结果,反而让模型”迷路”。通常 Top 3-5 条结果足够。
  2. 来源冲突:不同文档说法矛盾时,Prompt 要给模型”裁判规则”(如优先信源)。
  3. 幻觉转移:模型可能忽略参考资料,直接用自身知识回答。需要强约束:”只基于参考资料回答”。

4.3 Prompt + Tool Use

Tool Use 场景 中,工具的描述本身就是 Prompt 的一部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
System Prompt:
你可以使用以下工具:

## search_knowledge_base
描述:搜索企业知识库
参数:
- query (string, 必填): 搜索关键词
- top_k (int, 可选): 返回结果数量,默认 5
使用场景:当用户询问公司内部知识时使用

## send_email
描述:发送邮件
参数:
- to (string, 必填): 收件人邮箱
- subject (string, 必填): 邮件主题
- body (string, 必填): 邮件正文
使用场景:当用户要求发送邮件时使用

---
请根据用户的问题,判断是否需要调用工具。
如果需要,输出工具调用的 JSON 格式。
如果不需要,直接回答用户问题。

工具描述的质量直接影响调用准确率。 一个常见的坑是工具描述太简略——搜索知识库 这五个字的信息量远不如上面那段带参数说明和使用场景的描述。

五、Java 生态实战:Spring AI 与 LangChain4j

5.1 Spring AI 的 Prompt 模板引擎

Spring AI 提供了 PromptTemplate 类,基于 ST4(StringTemplate 4)模板引擎:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.stereotype.Service;

@Service
public class AgentPromptService {

// 系统提示词模板
private static final String SYSTEM_PROMPT = """
你是一个 {role}。

## 能力
{capabilities}

## 行为规范
- 回答先给结论,再展开解释
- 代码示例使用 {language} {version}
- 不确定的事情明确说"我不确定"

## 输出格式
{output_format}
""";

// RAG 上下文注入模板
private static final String RAG_PROMPT = """
基于以下参考资料回答用户问题。
如果参考资料不足,说明信息不完整。

---
参考资料:
{context}
---

用户问题:{question}
""";

/**
* 构建完整的 System Prompt
*/
public Prompt buildSystemPrompt(String role, String capabilities,
String language, String version,
String outputFormat) {
PromptTemplate template = new PromptTemplate(SYSTEM_PROMPT);

return new Prompt(
List.of(template.createMessage(
Map.of(
"role", role,
"capabilities", capabilities,
"language", language,
"version", version,
"output_format", outputFormat
),
org.springframework.ai.chat.model.ChatModelMessage.SYSTEM
))
);
}

/**
* 构建带 RAG 上下文的 Prompt
*/
public Prompt buildRagPrompt(String question, List<String> references) {
// 将检索结果格式化为带编号的引用
String formattedContext = IntStream.range(0, references.size())
.mapToObj(i -> "[%d] %s".formatted(i + 1, references.get(i)))
.collect(Collectors.joining("\n\n"));

PromptTemplate template = new PromptTemplate(RAG_PROMPT);
return new Prompt(template.create(
Map.of("context", formattedContext, "question", question)
));
}
}

**Spring AI Prompt 的核心设计思路是”模板化 + 结构化”**。PromptTemplate 把 Prompt 当作带变量的模板,运行时填充变量。这比字符串拼接优雅得多,也更安全(避免注入攻击)。

5.2 LangChain4j 的 SystemMessage 构建

LangChain4j 的 API 风格更函数式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.service.TokenStream;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.ToolExecutionResultMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.Result;

import java.util.List;
import java.util.Map;

// 1. 定义助手接口(声明式 System Prompt)
public interface CodeReviewAssistant {

@SystemMessage("""
你是一个高级 Java 代码审查专家。

## 审查维度
1. 安全性:SQL 注入、XSS、权限绕过
2. 性能:N+1 查询、内存泄漏、锁竞争
3. 可维护性:命名、抽象、单一职责
4. 健壮性:异常处理、空指针、边界条件

## 输出格式
对每个问题输出:
- 严重等级:🔴 严重 / 🟡 警告 / 🔵 建议
- 问题描述
- 修复建议(附代码)

## 约束
- 只关注 Java/Spring Boot 代码
- 忽略代码风格问题(交给 Checkstyle)
""")
String review(@UserMessage String code);
}

// 2. 使用 AiServices 构建助手
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o")
.temperature(0.3) // 代码审查用低温度,减少随机性
.build();

CodeReviewAssistant assistant = AiServices.create(
CodeReviewAssistant.class, model
);

// 3. 调用
String review = assistant.review("""
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
String sql = "SELECT * FROM users WHERE id = " + id;
return jdbcTemplate.queryForObject(sql, User.class);
}
""");

System.out.println(review);

LangChain4j 的 @SystemMessage 注解方式有一个巨大优势:System Prompt 和业务代码紧耦合,重构时不会遗漏。Spring AI 的模板方式则更灵活,适合 Prompt 需要动态组合的场景。

5.3 两种框架的 Prompt 管理对比

维度 Spring AI LangChain4j
Prompt 定义 PromptTemplate + 字符串模板 @SystemMessage 注解
变量替换 Map<String, Object> 填充 @V 注解 + 参数绑定
多轮对话 手动管理 List<Message> ChatMemory 自动管理
工具描述 @Tool 注解 + FunctionCallback @Tool 注解 + ToolSpecification
灵活度 高(模板可外部化到文件/数据库) 中(注解编译期确定)
类型安全 低(Map 传参) 高(接口强类型)
适用场景 Prompt 频繁变化、需要 A/B 测试 Prompt 稳定、追求代码可维护性

我的建议:两者可以混用。System Prompt 用 Spring AI 的模板引擎管理(方便热更新),业务接口用 LangChain4j 的注解方式(类型安全)。

六、企业级多层 Prompt 架构

在真实的企业场景中,Prompt 不是一段文字,而是一个分层的系统

6.1 三层 Prompt 架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌───────────────────────────────────────────────────────────┐
│ Layer 1:基础层(Base Prompt) │
│ ├── 角色定义、合规约束、输出格式 │
│ ├── 存储位置:代码库 / 配置中心 │
│ └── 更新频率:月级 │
├───────────────────────────────────────────────────────────┤
│ Layer 2:场景层(Scenario Prompt) │
│ ├── 客服场景 / 数据分析场景 / 代码审查场景 │
│ ├── 存储位置:Prompt 管理平台 │
│ └── 更新频率:周级 │
├───────────────────────────────────────────────────────────┤
│ Layer 3:动态层(Dynamic Context) │
│ ├── RAG 检索结果、用户画像、对话历史 │
│ ├── 存储位置:内存(运行时拼接) │
│ └── 更新频率:每次请求 │
└───────────────────────────────────────────────────────────┘

6.2 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class PromptOrchestrator {

private final PromptRepository promptRepository;
private final UserProfileService userProfileService;
private final RagService ragService;

/**
* 组装完整的 Prompt
*/
public Prompt assemble(String userId, String scenario,
String userMessage) {
List<ChatMessage> messages = new ArrayList<>();

// Layer 1: 基础层 — 从配置加载
String basePrompt = loadBasePrompt();
messages.add(new SystemMessage(basePrompt));

// Layer 2: 场景层 — 从 Prompt 管理平台加载
String scenarioPrompt = promptRepository.findByScenario(scenario);
messages.add(new SystemMessage(scenarioPrompt));

// Layer 3: 动态层 — 运行时拼接
UserProfile profile = userProfileService.getProfile(userId);
List<Document> docs = ragService.retrieve(userMessage, 5);

String dynamicContext = buildDynamicContext(profile, docs);
messages.add(new SystemMessage(dynamicContext));

// 用户消息
messages.add(new UserMessage(userMessage));

return new Prompt(messages);
}

/**
* 构建动态上下文
*/
private String buildDynamicContext(UserProfile profile,
List<Document> docs) {
StringBuilder sb = new StringBuilder();
sb.append("## 用户信息\n");
sb.append("- 角色:").append(profile.getRole()).append("\n");
sb.append("- 偏好语言:").append(profile.getPreferredLang()).append("\n");
sb.append("- 历史交互次数:").append(profile.getInteractionCount()).append("\n\n");

if (!docs.isEmpty()) {
sb.append("## 参考资料\n");
for (int i = 0; i < docs.size(); i++) {
sb.append("[").append(i + 1).append("] ");
sb.append(docs.get(i).getTitle()).append("\n");
sb.append(docs.get(i).getContent()).append("\n\n");
}
}

return sb.toString();
}
}

6.3 Prompt 版本管理

在生产环境中,Prompt 需要像代码一样做版本管理:

1
2
3
4
5
6
7
8
9
10
CREATE TABLE prompt_templates (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
scenario VARCHAR(50) NOT NULL, -- 场景标识
version INT NOT NULL, -- 版本号
content TEXT NOT NULL, -- Prompt 内容
is_active BOOLEAN DEFAULT FALSE, -- 是否激活
metrics JSON, -- A/B 测试指标
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE KEY uk_scenario_version (scenario, version)
);

这样做有三个好处:

  1. A/B 测试:同一场景部署两个版本,对比效果
  2. 快速回滚:新 Prompt 效果差,一键切回上一版
  3. 效果追踪:记录每个版本的满意度、准确率等指标

七、常见陷阱与最佳实践

7.1 五个致命陷阱

陷阱 1:指令矛盾

1
2
3
❌ 你是一个友好的助手。回答要简洁。
...
对每个问题提供详细、全面的解释,不要遗漏任何细节。

模型收到矛盾指令后,行为会变得不可预测——有时简洁,有时冗长,完全看运气。

陷阱 2:否定指令的滥用

1
2
3
❌ 不要输出代码
❌ 不要提到 Java
❌ 不要太长

模型对否定指令的遵循率远低于肯定指令。原因是模型的训练数据中,”不要做 X”的样本远少于”做 Y”的样本。

更好的写法:

1
2
3
✅ 用纯文字描述方案,不包含代码块
✅ 使用 Python 作为示例语言
✅ 控制在 200 字以内

陷阱 3:角色定义过于宽泛

1
❌ 你是一个全栈开发专家

“全栈”太宽泛,模型无法聚焦。改为:

1
2
3
✅ 你是一个专注于 Spring Boot 后端 + Vue 3 前端的全栈开发者
擅长领域:REST API 设计、数据库优化、前端状态管理
技术栈:Java 21, Spring Boot 3.x, Vue 3, TypeScript, PostgreSQL

陷阱 4:没有给”退路”

1
❌ 回答用户的所有问题

模型遇到超出能力范围的问题会编造答案。加一句”退路”指令:

1
2
✅ 如果你不确定答案,明确说"这个问题我不确定,建议查阅官方文档"
如果问题超出你的知识范围,建议用户咨询相关专家

陷阱 5:Prompt 过长导致性能下降

Prompt 超过 4000 Token 后,模型的指令遵循率开始下降。如果你的 Prompt 太长,考虑:

  • 精简冗余描述
  • 将不常用指令移到动态层
  • 使用 Prompt 压缩技术(如摘要替代原文)

7.2 最佳实践清单

1
2
3
4
5
6
7
8
9
10
✅ 指令用肯定句,不用否定句
✅ 关键指令放在开头或结尾(利用注意力分布)
✅ 用分隔符区分指令和内容(如 --- 或 XML 标签)
✅ 提供 2-3 个 Few-shot 示例
✅ 指定输出格式(Markdown / JSON / XML)
✅ 给模型"退路"(不确定时怎么说)
✅ 控制 System Prompt 在 1000-3000 Token 以内
✅ 做 A/B 测试,用数据驱动 Prompt 优化
✅ 版本管理 Prompt,支持快速回滚
✅ 用低温度(0.1-0.3)处理确定性任务,高温度(0.7-1.0)处理创意任务

八、扩展思考:Prompt Engineering 的边界在哪?

8.1 Prompt 不是万能的

再好的 Prompt 也解决不了这些问题:

  • 模型本身的能力天花板:GPT-3.5 不可能通过 Prompt 变成 GPT-4
  • 需要精确计算的场景:数学计算、日期推算,模型容易出错
  • 实时信息:模型不知道今天的天气和股价
  • 长文本的一致性:超过模型上下文窗口的内容,Prompt 无法弥补

这些问题的解决方案不是更好的 Prompt,而是更好的架构——用工具调用解决计算问题,用 RAG 解决知识问题,用 Memory 解决上下文问题。

8.2 未来的方向

  1. Prompt 自动生成:让 AI 帮你写 Prompt(DSPy 框架已经在做这件事)
  2. Prompt 优化器:自动 A/B 测试,用遗传算法搜索最优 Prompt
  3. 多模态 Prompt:图文混合的 Prompt 设计(图片 + 文字指令)
  4. Prompt-as-Code:Prompt 纳入 CI/CD 流水线,自动化测试和部署

总结

Prompt Engineering 不是”玄学”,而是一门工程学科。它的核心原则可以用三句话概括:

  1. 清晰胜过聪明:模型不需要你的文学才华,它需要你的精确指令
  2. 结构胜过长度:一个 500 Token 的结构化 Prompt,效果远好于 3000 Token 的散文
  3. 迭代胜过完美:没有一稿就完美的 Prompt,持续测试和优化才是正道

回到我们 AI Agent 系列的脉络:ReAct 给了 Agent 思考能力,Tool Use 给了 Agent 动手能力,Memory 给了 Agent 记忆能力,RAG 给了 Agent 知识检索能力,Planning 给了 Agent 规划能力,结构化输出 让 Agent 能”说人话”。

而 Prompt Engineering,是让这些能力协调运转的粘合剂。

好的 Prompt 不是让模型更聪明,而是让模型的聪明用对地方。