大模型 Prompt 工程:从基础控制到推理、工具与自动优化
Prompt 工程并不只是寻找一句“更好用的提示词”,而是通过组织指令、上下文、示例和外部工具,让模型更稳定地理解任务并生成可用结果。随着任务复杂度提高,单次提示往往会逐步演变为包含推理、检索、工具调用、结果校验和持续优化的完整工作流。
本文从 Prompt 的基础结构出发,依次介绍示例提示、推理增强、搜索与纠错、工具工作流以及自动优化方法。重点不只是展示这些方法“怎么写”,也会说明它们解决什么问题、如何工作,以及在实际应用中的限制与取舍。
一、Prompt 基础结构与控制方法
本节从 Prompt 的基本组成出发,依次介绍消息角色与对话状态、指令清晰化、结构化 Prompt 以及 Zero-shot、One-shot 和 Few-shot 示例提示。重点说明如何区分应用规则、用户输入和历史消息,管理模型当前能够看到的上下文,明确任务与约束,组织输入输出结构,并通过示例补充任务边界。
1. 消息角色与对话状态
消息结构
在对话 API 中,Prompt 通常被组织为一组按顺序排列的消息,而不是一段不区分来源的长文本。这样设计可以把应用规则、用户任务和模型回复分开表示,便于模型识别信息来源、处理指令优先级,并在多轮对话中延续上下文。
一条消息通常包含两类核心信息:
role:说明消息由谁提供,以及它在对话中的作用。content:消息的具体内容,可以是文本,也可以包含接口支持的图片、文件等输入。
多条消息按照先后顺序共同构成当前请求的上下文。
消息角色
角色解决的是“谁在说话、指令优先级如何划分”。以核验时的 OpenAI Responses API 文档 为例,常见消息角色包括以下三种;其他接口或模型支持的角色及其语义可能不同:
- developer:由应用开发者提供的规则、业务逻辑和长期约束,优先级高于用户消息。
- user:终端用户提出的任务、问题和输入数据。
- assistant:模型生成的回复,也可以成为后续轮次的上下文。
对话状态
对话状态解决的是“下一轮能看到哪些历史信息”。常见状态管理方式有三种:
- 应用侧手动维护:保存历史消息,并在下一次请求时选择需要的内容重新发送。
- 通过上一响应继续:在支持的接口中传入
previous_response_id,将多次响应串成同一条会话链。 - 使用持久化会话对象:通过 Conversations API 等机制,在跨会话、设备或任务时复用状态。
应用侧手动维护示例
下面的示例展示了应用侧如何将不同角色的历史消息按顺序组成下一次请求的上下文:
[
{
"role": "developer",
"content": "你是一名数学助教。回答简洁,并说明关键计算。"
},
{
"role": "user",
"content": "请问 12 × 8 等于多少?"
},
{
"role": "assistant",
"content": "12 × 8 = 96。"
},
{
"role": "user",
"content": "那再加上 4 呢?"
}
]2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2. 指令清晰化
在使用大模型时,一个很容易被忽略的问题是:提示词本身是否表达清晰。
很多时候,模型回答不符合预期,并不完全是能力问题,也可能是 Prompt 没有把任务、输入和输出要求描述清楚。清晰的指令应让模型能够判断:要完成什么、依据什么信息、需要遵守哪些约束,以及结果应如何呈现。
例如,不太清晰的提示:
帮我分析一下这条用户反馈。模型可能无法确定需要完成哪一种任务,例如:
- 概括反馈内容
- 判断用户情绪
- 识别产品问题
- 提出回复或改进建议
改写时,可以明确角色、任务步骤、判断范围和输出要求:
你是一名产品运营人员。请分析下面的用户反馈:
1. 用一句话概括核心问题;
2. 判断用户情绪:正面、中性或负面;
3. 给出最多两条可执行的改进建议。
仅依据反馈内容分析,不补充未提供的事实。
用户反馈:
“更新后应用经常闪退,联系客服三天也没人回复。”2
3
4
5
6
7
8
9
10
编写清晰指令时,可以优先检查以下内容:
- 明确任务目标:使用具体动词说明要总结、分类、提取、改写,还是生成内容。
- 提供必要上下文并划分输入边界:说明角色、背景、目标读者和业务规则,同时区分指令与待处理数据。
- 规定输出要求:明确格式、字段、长度、语言、语气以及必须覆盖的信息。
- 按顺序拆分复杂任务:当执行顺序或完整性很重要时,使用编号列出步骤。
- 用示例和评估消除歧义:提供具有代表性的输入输出示例,并使用多组真实样本验证效果。
应优先描述模型“需要做什么”,而不是只罗列“不能做什么”。安全、合规和数据边界等必要约束仍需明确写出。
衍生阅读及参考:
3. 结构化 Prompt(Structured Prompting)
结构化 Prompt 是指使用明确的段落、标题或标签组织任务说明、上下文、输入数据、约束条件和输出要求。它并不是一种固定模板,而是通过清晰的层次和边界,帮助模型区分不同类型的信息。
结构化输入
常见的组织方式包括 Markdown 标题与列表、XML 标签以及其他明确的分隔符。它们主要用于:
- 区分指令、上下文和待处理数据;
- 表达内容之间的层级关系;
- 方便程序动态拼接、复用和维护 Prompt。
例如,可以将翻译任务组织为以下结构:
# 任务
将给定中文文本翻译成英文。
# 输入
人工智能正在改变软件开发的方式,提高了开发效率,也带来了新的挑战。
# 翻译要求
1. 保持原意准确;
2. 语言自然流畅;
3. 不添加原文中不存在的信息。
# 输出格式
仅返回一个 JSON 对象,并包含以下字段:
- source_text:原始中文文本;
- translated_text:英文翻译结果。2
3
4
5
6
7
8
9
10
11
12
13
14
15
期望输出如下:
{
"source_text": "人工智能正在改变软件开发的方式,提高了开发效率,也带来了新的挑战。",
"translated_text": "Artificial intelligence is changing the way software is developed, improving efficiency while also introducing new challenges."
}2
3
4
结构化输出
仅在 Prompt 中声明 JSON 格式和字段要求,通常只能提高输出格式的一致性。模型仍可能生成无效 JSON,或者遗漏、增加不符合要求的字段。
因此,在需要由程序稳定解析结果的生产场景中,应优先使用模型 API 提供的 Schema 约束能力,例如 OpenAI 的 Structured Outputs。
从解码过程看,可以这样理解 Structured Outputs:模型会通过 logits 为下一步可能生成的 token 打分,系统再根据 JSON Schema 动态屏蔽不符合当前结构的 token,让模型只能从合法选项中继续生成。当所用模型支持指定的 JSON Schema 子集,并且响应正常完成、没有发生安全拒答、内容过滤或输出截断时,生成结果能够符合指定的字段和格式。
不过,Structured Outputs 只约束正常生成结果的结构。应用仍需处理拒答、输出截断和接口错误,并对字段内容的事实准确性与业务逻辑另行校验。
如果所用接口不支持 Schema 约束,则仍需在应用侧进行解析校验,并配合错误处理和必要的重试。
结构化 Prompt 负责组织输入信息,Structured Outputs 负责约束输出结构;两者相关,但不是同一层面的机制。
衍生阅读及参考:
- Message formatting with Markdown and XML
- Structure prompts with XML tags
- Structured model outputs
- Structured Outputs 的约束机制:Constrained decoding
4. 示例提示(Zero-shot / One-shot / Few-shot)
当任务的标签含义、输入输出关系或格式要求仅靠文字难以说明清楚时,可以在 Prompt 中加入示例,让模型参考示例处理新的输入。Zero-shot、One-shot 和 Few-shot 的区别,主要在于 Prompt 中提供了多少个示例。
这些方式都发生在推理阶段,不会进行梯度更新,也不会修改模型参数。模型只是根据当前上下文中的任务说明和示例生成结果,这类能力通常称为 in-context learning(上下文学习)。
Zero-shot(零样本)
Prompt 中不提供输入输出示例,只给出任务说明、待处理内容和必要约束。
请判断下面这句话的情绪是“正面”还是“负面”。
句子:这家餐厅的服务非常糟糕。
情绪:2
3
4
One-shot(单样本)
Prompt 中提供一个输入输出示例,让模型参考其标签含义和输出形式。
请判断下面这句话的情绪是“正面”还是“负面”。
示例:
句子:这部电影真的很好看。
情绪:正面
句子:这家餐厅的服务非常糟糕。
情绪:2
3
4
5
6
7
8
Few-shot(少样本)
Prompt 中提供少量输入输出示例,进一步展示标签、格式和任务边界。
Few-shot 的效果取决于模型、任务以及示例的质量、顺序和代表性。示例应尽量覆盖真实输入和可能出现的标签,并保持格式一致。错误、矛盾或分布失衡的示例可能误导模型,因此 Few-shot Prompt 仍需使用目标数据进行验证。
请判断下面这句话的情绪是“正面”还是“负面”。
示例:
句子:这部电影真的很好看。
情绪:正面
句子:这款产品质量很差。
情绪:负面
句子:客服耐心地解决了我的问题。
情绪:正面
句子:应用更新后频繁闪退。
情绪:负面
句子:这家餐厅的服务非常糟糕。
情绪:2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
衍生阅读及参考:
- Language Models are Few-Shot Learners
- Rethinking the Role of Demonstrations: What Makes In-Context Learning Work?
二、推理增强方法
基础 Prompt 主要解决“如何把任务说清楚”,推理增强则进一步关注“如何组织复杂问题的求解过程、降低单次生成的偶然性,以及为推理补充相关信息”。
本节从单条推理路径开始,依次介绍使用中间步骤组织推理的 CoT、通过多条路径聚合答案的 Self-Consistency、先生成候选知识再回答问题的 Generated Knowledge,以及结合文本与图像信息进行推理的 Multimodal-CoT。这些方法可能改善特定任务的表现,但不能保证推理或答案正确,实际使用时仍需结合目标模型和评估集验证效果。
1. Chain-of-Thought Prompting(CoT)
Chain-of-Thought Prompting(思维链提示) 是一种让模型在给出最终答案前,先生成中间推理步骤的提示方法。经典 CoT 通过在 Prompt 中提供带有推理过程的 few-shot 示例,引导模型按照类似方式处理新问题。
CoT 不会修改模型的结构或参数。由于大语言模型逐 token 生成内容,中间推理 token 可以看作一条更长的计算轨迹,让模型把复杂问题拆成若干步骤处理。不过,这些文字步骤并不一定完整反映模型的内部计算,也不能保证推理过程或最终答案正确。
经典研究表明,CoT 在部分算术推理、常识推理和符号推理任务上可以改善表现。对于简单任务,增加推理步骤未必有益,还可能引入错误或增加 token 成本,因此应结合目标模型和评估集验证效果。
CoT 常见的使用方式包括以下三种。
Few-shot CoT(人工示例)
在 Prompt 中人工编写带有中间步骤的示例,引导模型模仿“问题 → 推理 → 答案”的结构回答新问题。
Q:仓库原有 18 箱饮料,上午运走 7 箱,下午又到货 5 箱,现在有多少箱?
A:先计算上午运走后的数量:18 - 7 = 11。
再加上下午到货的 5 箱:11 + 5 = 16。
答案:16 箱。
Q:小李有 30 元,买了 2 本每本 8 元的笔记本,还剩多少钱?2
3
4
5
6
7
示例可以帮助模型学习期望的推理和输出格式,但模型模仿了这种形式,并不代表推理一定正确。

图 1:Chain-of-Thought Prompting 使大语言模型能够处理复杂的算术、常识和符号推理任务,图中高亮部分为思维链推理过程。来源:Jason Wei 等,Chain-of-Thought Prompting Elicits Reasoning in Large Language Models,原论文 Figure 1,CC BY 4.0。
Zero-shot CoT
Zero-shot CoT 不提供推理示例,而是在问题后加入简单的推理触发语。原论文使用的经典触发语是:
Let's think step by step.例如:
问题:一本书每天读 18 页,读了 3 天后还剩 46 页。这本书共有多少页?
Let's think step by step.2
3
原始研究表明,这类触发语在部分算术、符号和常识推理基准上能够改善表现;对现代模型和具体业务任务是否仍然有效,需要单独评估。
Automatic Chain-of-Thought(Auto-CoT)
手动编写 CoT 示例的成本较高。Auto-CoT 从问题集合中选取具有差异性的代表性问题,再让模型自动生成推理过程,用于构造 few-shot 示例。其基本流程包括两个阶段:
- 问题聚类(Question Clustering):按照语义相似度对问题进行聚类,以覆盖不同类型的问题。
- 示例构建(Demonstration Construction):根据长度等条件从各聚类中选择代表性问题,再利用 Zero-shot CoT 生成推理链,组成具有多样性的 few-shot 示例。
Auto-CoT 可以减少人工编写示例的成本,但自动生成的推理链仍可能包含错误。在生产任务中,应对示例进行筛选和验证。

图 2:Auto-CoT 方法概览。该方法先对问题进行聚类和选样,再使用带有 “Let’s think step by step” 提示的 LLM 逐个构造共 k 个推理示例,最后利用这些示例完成上下文推理。来源:Zhuosheng Zhang 等,Automatic Chain of Thought Prompting in Large Language Models,原论文 Figure 4,CC BY-SA 4.0。
CoT 与现代推理模型
现代推理模型在给出最终回答前,会先使用一部分 token 在内部拆解问题、比较方案和规划步骤,这些用于内部分析的 token 称为 reasoning tokens。可以把整个过程简单理解为:
用户输入 → 模型内部推理(reasoning tokens)→ 最终回答它与经典 CoT Prompting 不同:CoT 是通过 Prompt 引导模型写出用户可以看到的中间步骤;reasoning tokens 则用于模型内部推理,原始内容不会通过 API 返回。
以 OpenAI 推理模型为例,reasoning tokens 会占用上下文窗口并计入输出 token 用量。Responses API 会在 usage.output_tokens_details.reasoning_tokens 中报告其数量,但通常不会返回原始 reasoning tokens。部分模型还可以按需返回 reasoning summary,但它只是对推理过程的概括,并非原始的 reasoning tokens。
工程实践
工程实践中更稳妥的做法是要求模型给出可核验的简要解释、关键依据或计算步骤,并通过测试、工具执行或外部证据验证结论,而不是把冗长的自然语言推理当作正确性的证明。
衍生阅读及参考:
- Chain-of-Thought Prompting Elicits Reasoning in Large Language Models
- Large Language Models are Zero-Shot Reasoners
- Automatic Chain of Thought Prompting in Large Language Models
- auto-cot
- OpenAI Reasoning models
2. Self-Consistency
Self-Consistency(自一致性) 是一种与 CoT 配合使用的解码策略。普通 CoT 可以采用贪婪解码:模型每一步都选择当前概率最高的 token,最终只生成一条推理路径。原始研究提出用 Self-Consistency 替代这种朴素的单路径解码方式。
它基于一个直觉:复杂推理问题可能存在多条不同但有效的推理路径,而这些路径往往会收敛到同一个正确答案。与其依赖一次生成,不如采样多条推理路径,再从最终答案中选择最一致的结果。
方法流程:
- 使用 CoT Prompt 引导模型生成带有中间步骤的回答。
- 使用 temperature sampling、top-k sampling 或 nucleus sampling 等随机采样方法,生成多条候选推理路径。
- 提取并归一化每条路径的最终答案,通过边缘化这些推理路径选出最一致的答案。在答案集合固定的任务中,常见实现是使用不加权的多数投票。
Self-Consistency 可以理解为一种基于采样的推理集成方法。它适合答案能够可靠提取、归一化和比较的任务,例如部分算术与常识推理问题。对于开放式回答,需要额外处理语义等价但表述不同的答案。
这种方法并不验证推理过程本身。如果多数样本共享同一系统性错误,聚合结果仍然可能错误;采样结果缺乏多样性时,收益也会受限。生成 token 和计算量通常会随采样数量近似增长,而实际调用次数和延迟取决于接口是否支持批量或并行生成。因此,采样数量与策略应通过目标模型和评估集确定。

图 3:Self-Consistency 方法包含三个步骤:使用 CoT Prompt、采样多条不同的推理路径,以及对这些路径进行边缘化并选择最一致的最终答案。来源:Xuezhi Wang 等,Self-Consistency Improves Chain of Thought Reasoning in Language Models,原论文 Figure 1,CC BY 4.0。
衍生阅读及参考:
3. Generated Knowledge
在部分常识推理任务中,模型可能因为没有充分调动与问题相关的背景知识而回答错误。 Generated Knowledge Prompting(生成式知识提示) 的思路是:先让语言模型生成可能有助于回答问题的候选知识,再把这些知识作为额外上下文用于答案预测。
原论文中的方法分为两个阶段:
- 知识生成(Knowledge Generation): 使用少量“问题—知识”示例引导模型,并通过采样生成多条与当前问题相关的候选知识。
- 知识整合(Knowledge Integration): 将每条候选知识分别与原问题组合,由回答模型进行预测,最后选择置信度最高的答案。
候选知识并不是经过外部验证的事实,而是模型根据已有参数和当前 Prompt 生成的文本。生成多条候选知识可以增加覆盖相关信息的机会,但不能消除模型产生错误知识的风险。
下面是一个简化示例:
# 第一阶段:生成候选知识
请生成 3 条可能有助于回答问题的常识。
问题:
带钩刺的植物种子最可能借助什么方式传播?
候选知识:
1. 带钩刺的种子容易附着在动物皮毛上。
2. 轻而带翅的种子通常依靠风传播。
3. 部分果实会被动物食用并传播种子。
# 第二阶段:结合候选知识回答
请分别结合上述候选知识判断答案,并选择置信度最高的预测。
问题:
带钩刺的植物种子最可能借助什么方式传播?
选项:
A. 风
B. 动物皮毛
C. 流水
D. 果实爆裂
答案:
B. 动物皮毛2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
这个示例省略了论文中的少量示例和逐条预测过程,重点展示“生成候选知识,再利用知识回答”的核心流程。
与 RAG 的区别
两种方法都为回答问题补充上下文,但知识来源不同:
- Generated Knowledge Prompting: 由语言模型根据问题生成候选知识文本,通常没有可追溯的外部来源。
- RAG(Retrieval-Augmented Generation): 从外部文档或知识库检索相关内容,并将检索结果提供给模型。
两者并不互斥:系统可以先通过 RAG 获取资料,再让模型整理候选知识并完成推理。无论采用哪种方式,补充的内容都可能存在错误或与问题无关,因此仍需评估检索质量、生成质量和最终答案。
Generated Knowledge Prompting 更适合论文所研究的常识推理场景。对于最新信息、专业事实或高风险决策,应优先使用可追溯来源,并对关键主张进行核验。

图 4:Generated Knowledge Prompting 先使用少量示例引导语言模型采样多条与问题相关的候选知识,再结合每条知识进行答案预测,并选择置信度最高的结果。来源:Jiacheng Liu 等,Generated Knowledge Prompting for Commonsense Reasoning,原论文 Figure 1,CC BY 4.0。
衍生阅读及参考:
4. Multimodal CoT
传统 CoT 主要根据文本信息生成中间推理步骤。当问题还包含图像等非文本信息时,模型需要先理解不同模态提供的证据,再利用这些证据完成推理。
Multimodal Chain-of-Thought(多模态思维链,Multimodal-CoT) 是一种让中间推理过程建立在多模态输入之上的方法。与只依据文本的 CoT 相比,它生成的推理依据还需要结合图像中的对象、位置或关系等信息。
论文 Multimodal Chain-of-Thought Reasoning in Language Models 重点研究文本与图像两种模态,并提出一个经过微调的两阶段框架:
- 推理依据生成(Rationale Generation): 融合问题、上下文、候选答案和图像特征,生成与多模态输入相关的中间推理依据。
- 答案推断(Answer Inference): 将生成的推理依据与原始多模态输入一起用于最终答案预测。
该论文研究的具体实现需要微调模型并融合视觉与语言特征,不只是向通用模型添加一句“逐步思考”的提示。现代多模态大模型也可以通过 Prompt 生成推理说明,但具体的图像编码、模态融合和推理机制取决于模型实现。
下图中的磁铁问题同时依赖两类信息:文字给出“异极相吸、同极相斥”的规则,图像则展示两个磁铁相邻的磁极。模型需要结合两者,先判断相邻的是 N 极和 S 极,再得出磁铁会相互吸引。

图 5:Multimodal-CoT 任务示例。模型同时接收文字问题与磁铁图像,生成结合两种模态的推理依据,并预测最终答案。来源:Zhuosheng Zhang 等,Multimodal Chain-of-Thought Reasoning in Language Models,原论文 Figure 1,CC BY-SA 4.0;其中问题、图像和解释示例来自 Pan Lu 等人的 ScienceQA 数据集,CC BY-NC-SA 4.0。
多模态输入并不保证推理正确:视觉识别或模态对齐阶段的错误可能继续传递到推理和答案生成阶段,生成的推理依据也可能包含幻觉。此外,两阶段推断会增加计算量和延迟。论文的实验结论主要来自 ScienceQA 和 A-OKVQA,不能直接推广到所有多模态任务。
衍生阅读及参考:
- Multimodal Chain-of-Thought Reasoning in Language Models
- amazon-science/mm-cot
- Language Is Not All You Need: Aligning Perception with Language Models(相关多模态模型研究)
三、搜索与自我修正
前一章的方法主要增强模型生成推理过程的能力,但如果模型过早选择了错误方向,继续沿当前路径生成通常难以主动回退;即使得到错误结果,模型也未必能够把反馈转化为下一次尝试的有效经验。
本章进一步关注两类改进机制:Tree of Thoughts(ToT) 在中间状态生成、评价和搜索多个候选分支,使模型能够探索、剪枝或回溯;Reflexion 则根据任务反馈总结文字经验,并将其加入后续尝试的上下文。前者解决“如何在多条路径之间选择”,后者解决“如何从一次尝试的反馈中改进下一次尝试”。
1. Tree of Thoughts(ToT)
CoT 通常按照从左到右的顺序生成一条连续推理链。如果早期步骤选择了错误方向,后续生成很难回到先前状态重新探索。Self-Consistency 虽然会采样多条完整推理链,但主要在生成结束后聚合最终答案,不会在中间步骤显式比较和搜索不同分支。
Tree of Thoughts(思维树,ToT) 将问题求解表示为对中间状态的树搜索。每个 thought 是一个可以被生成、保存和评价的连贯文本单元,例如一道算式、一个填词候选或一段写作计划;它不是模型不可见的内部思维。一个状态由原始输入和此前生成的 thought 序列共同构成。
三种方法的主要区别如下:
| 方法 | 探索方式 | 选择方式 |
|---|---|---|
| CoT | 生成一条连续推理链 | 沿当前路径继续生成 |
| Self-Consistency | 独立生成多条完整推理链 | 对最终答案进行聚合 |
| ToT | 在中间状态生成多个候选分支 | 评价状态,并通过搜索决定扩展、剪枝或回溯哪些分支 |
典型流程:
- Thought 分解: 根据任务定义中间步骤的粒度,使其既能表达有意义的进展,又便于评价。
- 候选生成: 从当前状态采样或提出多个候选 thought。
- 状态评价: 由模型、规则或外部评价器估计各候选状态继续求解的可能性。
- 搜索控制: 使用广度优先搜索、深度优先搜索等算法保留并扩展更有希望的状态,同时剪枝或回溯。
- 终止与输出: 找到满足目标的状态或耗尽搜索预算后,输出当前评价下最合适的结果。
这里的“更有希望”来自启发式评价,并不意味着一定能找到全局最优路径。
下面使用论文中的 Game of 24 思路简化说明 ToT 如何工作:
目标:使用 4、5、6、10 和基本运算得到 24。
状态 0:[4, 5, 6, 10]
生成候选 thought:
A. 10 - 4 = 6,剩余 [5, 6, 6]
B. 10 - 6 = 4,剩余 [4, 4, 5]
C. 6 - 5 = 1,剩余 [1, 4, 10]
状态评价:
A、B 仍有希望得到 24;C 被判定为不可行。
搜索选择 A 并继续扩展:
5 × 6 = 30,剩余 [6, 30]
30 - 6 = 24
输出:(5 × (10 - 4)) - 6 = 242
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
真实实现通常会保留多个候选状态,并依据搜索宽度、深度和总调用次数限制探索范围,而不是只执行上面展示的一条成功路径。

图 6:输入输出提示、CoT、Self-Consistency 与 ToT 的问题求解结构对比。每个矩形表示一个 thought,即作为中间求解步骤的连贯文本单元;ToT 会在中间状态生成、评价并搜索不同分支。来源:Shunyu Yao 等,Tree of Thoughts: Deliberate Problem Solving with Large Language Models,原论文 Figure 1,CC BY 4.0。
限制:
- 计算成本较高: 分支数、搜索深度和评价次数会增加模型调用量,因此通常需要设置严格的搜索预算。
- 评价器可能出错: 错误的状态评价可能保留无效分支,或提前剪掉能够得到正确答案的路径。
- 搜索并不完备: 受宽度、深度和调用次数限制,ToT 不能保证找到全局最优解。
- 简单任务收益有限: 对于不需要规划或搜索的问题,额外探索可能只会增加延迟和成本。
原论文在 Game of 24、创意写作和迷你填字游戏上验证了该框架。这些结果说明 ToT 适用于部分需要规划、探索或回溯的任务,但不能直接推广到所有复杂推理问题。
衍生阅读及参考:
- Tree of Thoughts: Deliberate Problem Solving with Large Language Models
- tree-of-thought-llm
- Large Language Model Guided Tree-of-Thought(相关并行研究)
2. Reflexion
Reflexion 是一种通过语言反馈和情景记忆改进 Agent 后续决策的框架。它不会更新模型权重,而是让 Agent 根据任务反馈总结文字经验,再把这些经验加入后续尝试的上下文。
论文将这种方式称为语言强化(verbal reinforcement):评价信号不通过梯度改变模型参数,而是被转换成具体的自然语言提示,用来影响下一轮行动。因此,Reflexion 不只是让模型“再想一次”,而是一个包含执行、评价、反思和记忆的闭环。
核心组件:
- Actor: 根据环境观察和记忆生成文本或行动,可以采用 CoT、ReAct 等形式。
- Evaluator: 评价 Actor 产生的轨迹或结果,信号可以来自环境奖励、规则、测试用例或另一个模型。
- Self-Reflector: 结合任务轨迹、评价信号和已有经验,生成下一次尝试可以使用的文字反思。
记忆机制:
- 短期记忆(Short-term Memory): 当前一次尝试产生的轨迹,包括观察、思考、行动和环境反馈。
- 长期记忆(Long-term Memory): Self-Reflector 从失败轨迹中提炼出的文字经验,用于同一任务的后续尝试。
论文实现通常只保留最近 1~3 条反思,以避免记忆持续占用上下文窗口。这里的“长期”是相对于当前轨迹而言,并不表示经验已经写入模型参数,也不等于能够自动跨会话保存。
完整流程:
- Actor 与环境交互,生成一次任务轨迹。
- Evaluator 根据轨迹和任务结果产生评价信号。
- Self-Reflector 分析轨迹与评价信号,生成可执行的文字反思。
- 系统将反思写入情景记忆。
- Actor 在下一次尝试中同时读取当前观察和历史反思。
- 重复上述过程,直到任务成功或达到最大尝试次数。

图 7:Reflexion Agent 使用 Actor 与环境交互,将轨迹作为短期记忆;Evaluator 提供评价信号,Self-Reflector 将其转化为文字经验并写入长期记忆,供后续尝试使用。来源:Noah Shinn 等,Reflexion: Language Agents with Verbal Reinforcement Learning,原论文 Figure 2(a),CC BY 4.0。
下面用单元测试反馈简化说明这一过程:
任务:
实现函数 is_even(n),判断整数是否为偶数。
第一次尝试:
return n % 2 == 1
Evaluator:
测试失败。is_even(2) 期望返回 true,实际返回 false。
Self-Reflector:
偶数除以 2 的余数应为 0,当前判断条件写反了。
下一次应使用 n % 2 == 0。
写入记忆后重新尝试:
return n % 2 == 0
Evaluator:
测试通过,任务成功。2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这个示例展示了一轮完整的“执行 → 评价 → 反思 → 重试”:单元测试提供可验证的外部反馈,Self-Reflector 再把失败信号转换成具体的修改方向。只有反思而没有可靠反馈时,Agent 仍可能生成听起来合理但无法纠正错误的总结。
论文进一步通过决策、编程和推理三类任务,展示 Reflexion 如何根据不同形式的评价信号生成反思,并改进下一轮任务轨迹。

图 8:Reflexion 在决策、编程和推理任务中,根据评价进行反思并改进下一轮轨迹。来源:Noah Shinn 等,Reflexion: Language Agents with Verbal Reinforcement Learning,原论文 Figure 1,CC BY 4.0。
限制:
- 依赖反馈质量: 错误或信息不足的评价信号可能产生无效反思,甚至强化错误策略。
- 不保证持续改进: Agent 可能重复失败、陷入局部最优,或因为错误记忆而表现退化。
- 占用上下文窗口: 轨迹和反思都需要作为上下文传入,应限制数量并筛选相关经验。
- 增加调用成本: 每轮通常包含执行、评价和反思等多次模型调用。
- 外部操作存在风险: 运行生成代码或调用工具时,应使用隔离环境并限制权限。
原论文在 ALFWorld、HotPotQA 和代码生成任务上验证了 Reflexion。它更适合存在明确反馈、允许重复尝试的任务,不应被理解为适用于所有回答生成场景的通用自我纠错能力。
衍生阅读及参考:
四、工具与工作流
前面的推理增强与自我修正方法,主要关注模型如何形成、比较和改进答案;面对需要查询资料、精确计算或执行外部操作的任务,仅依靠一次模型生成往往不够。此时,需要由应用层组织多次模型调用,并将程序、搜索、知识库或其他工具接入任务流程。
本章从固定步骤的 Prompt Chaining 开始,逐步介绍交错执行推理与行动的 ReAct、借助解释器完成计算的 PAL、自动组合推理步骤与工具的 ART,以及从外部知识库检索证据的 RAG。关注点也由“如何写 Prompt”扩展到“如何设计系统”:怎样传递中间状态、定义工具接口、校验结果、限制权限,并处理失败、延迟和成本。
1. Prompt Chaining
Prompt Chaining 是将一个顺序明确的任务拆分为多个模型调用,并由应用程序按照预定义流程依次执行的工作流模式。每一步使用独立的 Prompt 处理一个子任务,再把经过选择、转换或校验的结果交给下一步,而不一定传递上一轮的全部输出。
它与 Chain-of-Thought(CoT)关注的层面不同:CoT 主要引导模型在一次生成中完成中间推理,Prompt Chaining 则由应用层编排多次模型调用。它也不等于聊天式多轮对话,因为各步骤可以只接收完成当前任务所需的结构化状态,无须保留完整会话历史。
例如,可以把文章摘要任务组织成下面的链式流程:
原始文章
↓
步骤 1:提取关键事实
→ { claims, terms, sources }
↓ JSON Schema 校验
步骤 2:根据事实生成摘要初稿
↓
步骤 3:检查事实、长度和遗漏
→ { passed, issues }
↓
步骤 4:根据检查结果修订
→ 最终摘要2
3
4
5
6
7
8
9
10
11
12
图 9:Prompt Chaining 将任务拆分为多个模型调用,并在节点之间加入结构化校验、质量检查和失败回路。作者绘制。
这种拆分适合步骤顺序和中间结果都能够预先定义的任务。它可能带来以下收益:
- 降低单次调用的复杂度: 每一步只承担范围较小的子任务。
- 提高可观测性: 可以分别记录、评估和调试每个节点。
- 增加控制节点: 可以在模型调用之间插入规则校验、人工审核或外部工具。
- 复用中间结果: 结构化产物可以被后续步骤或其他工作流使用。
Prompt Chaining 也会引入新的工程成本:调用次数增加会带来更高的延迟和费用,上游错误或信息丢失还可能沿链路传播。实现时应为每一步定义输入输出 Schema、成功条件和失败处理方式,并在关键节点加入校验、重试、回退及全链路日志。对于一次调用即可稳定完成的简单任务,链式拆分通常没有必要。
Prompt Chaining 可以作为 RAG、Agent 或内容生成系统中的固定工作流组件,但并非所有 RAG 或 Agent 都采用这种模式;路径由模型动态决定的 Agent 与预定义的链式工作流也应加以区分。
衍生阅读及参考:
- LangGraph:Prompt Chaining
- Anthropic:Building Effective Agents
- Prompt Chaining with GPT-4o and Flowise AI(实现教程)
2. ReAct
ReAct(Reason + Act) 是一种将推理轨迹与任务行动交错执行的提示与交互框架。模型先根据当前信息判断下一步,再调用搜索、数据库或 API 等外部工具;工具返回的结果会作为新的观察信息,供模型继续判断或形成最终答案。
ReAct 与 Chain-of-Thought(CoT)关注的层面不同:CoT 主要组织模型的中间推理过程,本身并不定义主动调用工具、接收结果并继续推理的交互循环。ReAct 则通过 Thought → Action → Observation 将推理与外部环境连接起来:
Question(问题)
↓
Thought(判断下一步需要什么信息)
↓
Action(调用工具或执行操作)
↓
Observation(应用或环境返回结果)
↓
继续 Thought / Action,或输出 Final Answer2
3
4
5
6
7
8
9
其中,Thought 和 Action 由模型生成,Observation 则由工具或运行环境返回,不应被视为模型自行生成的可信事实。原论文中的 ReAct Prompt 通常还会提供少量完整轨迹作为示例,让模型学习何时思考、何时行动以及如何利用观察结果。
下面是一个简化的订单查询示例:
Question: 订单 A-1042 为什么还未发货,预计何时可以处理?
Thought: 先查询订单状态和未发货原因。
Action: get_order("A-1042")
Observation: status=pending,sku=P-17,reason=inventory_unavailable
Thought: 需要继续查询商品 P-17 的库存和补货时间。
Action: get_inventory("P-17")
Observation: available=0,next_restock=7月26日
Final Answer: 订单 A-1042 因商品 P-17 暂时缺货而未发货;
预计 7 月 26 日补货后可以继续处理,实际时间以库存系统更新为准。2
3
4
5
6
7
8
9
10
11
12
这个循环的价值在于:模型可以根据观察结果调整下一步行动,而不是一次性猜测完整答案。在生产系统中,不必向终端用户展示完整的内部推理过程,可以只保留必要的行动说明、工具调用记录和最终结论。
函数调用或工具调用机制可以承载 ReAct 的 Action,但“支持工具调用”并不自动构成完整的 ReAct 循环。系统还需要负责工具选择范围、参数校验、权限控制、超时与重试、停止条件以及副作用确认。同时,应把网页、文档和工具返回值视为不可信输入,防范提示注入、错误数据和恶意内容影响后续决策;多轮调用还会增加延迟与成本,并可能陷入重复行动。

图 10:Standard、CoT(仅推理)、Act-only(仅行动)与 ReAct(推理与行动结合)在 HotpotQA 问答任务中的求解过程对比。来源:Shunyu Yao 等,ReAct: Synergizing Reasoning and Acting in Language Models,原论文 Figure 1(1),CC BY 4.0;图中问题与检索内容来自 HotpotQA 数据集,CC BY-SA 4.0。
衍生阅读及参考:
- ReAct: Synergizing Reasoning and Acting in Language Models
- ReAct 官方项目页与示例
- 让 LLM 更好用的方法:ReAct prompting(中文解读)
3. Program-Aided Language Models(PAL)
PAL(Program-Aided Language Models) 是一种让语言模型将自然语言问题转换为可执行程序,再由程序运行时完成求解的方法。语言模型负责理解题意并编写带有语义变量的求解步骤,Python 解释器等符号运行时负责执行这些步骤并得到结果。
PAL 针对的是 CoT 中“问题分解正确,但计算或符号操作出错”的情况。CoT 通常使用自然语言同时描述和执行推理步骤;PAL 则把需要精确执行的部分表示为程序:
自然语言问题
↓
LLM 生成程序化求解步骤
↓
解释器执行程序
↓
应用将运行结果转换为最终答案2
3
4
5
6
7
原论文中的 PAL 通常通过 Few-shot 示例展示自然语言与程序语句如何对应,让模型学习为新问题生成完整程序,然后进行一次执行。它与 ReAct 不同:ReAct 会根据环境返回的观察结果循环决定下一步行动,PAL 的重点则是把已经生成的求解过程交给符号解释器执行。
例如,面包店烤了 200 条面包,上午卖出 93 条,下午卖出 39 条,杂货店又退回 6 条未售出的面包。语言模型可以生成下面的程序:
def solve():
loaves_baked = 200
loaves_sold_morning = 93
loaves_sold_afternoon = 39
loaves_returned = 6
loaves_left = (
loaves_baked
- loaves_sold_morning
- loaves_sold_afternoon
+ loaves_returned
)
return loaves_left2
3
4
5
6
7
8
9
10
11
12
13
解释器执行 solve() 后得到 74,应用再将其组织为“面包店还剩 74 条面包”。这里,程序执行避免了逐字生成时可能出现的算术错误,但结果是否正确仍取决于模型有没有正确理解“退回”的含义并写出正确表达式。
因此,PAL 并不保证答案一定正确:生成的程序可能存在建模错误、遗漏条件、语法错误或运行时异常。对于能够一次调用稳定完成的简单任务,引入代码执行也可能增加不必要的延迟和系统复杂度。
生产环境不应直接运行模型生成的任意代码。执行器应放在隔离沙箱中,并限制网络、文件系统、依赖、运行时间、内存和 CPU;应用还需要校验程序输出,并通过测试用例、规则或独立计算检查关键结果。

图 11:CoT 使用自然语言生成并执行中间推理步骤;PAL 将中间步骤表示为自然语言与 Python 程序,由解释器执行程序并得到最终结果。来源:Luyu Gao 等,PAL: Program-aided Language Models,原论文 Figure 1,CC0 1.0。
衍生阅读及参考:
4. Automatic Reasoning and Tool-use(ART)
ART(Automatic Reasoning and Tool-use) 是一个让冻结的语言模型自动生成多步推理程序,并在程序中调用外部工具的框架。它不需要针对每个新任务重新微调模型,而是从 Task Library(任务库) 中选择相关任务的推理与工具使用示例,组成当前任务的 Prompt。
ART 的核心流程包括:
- 选择示例: 根据新任务,从任务库中选择包含多步推理和工具调用的相关示例。
- 生成程序: 冻结的 LLM 按照示例格式生成结构化推理步骤。
- 执行工具: 当生成内容出现搜索、代码执行等工具调用时,应用暂停模型生成并执行工具。
- 继续生成: 将工具结果写回上下文,让模型基于新信息生成后续步骤和最终答案。
为了让应用能够识别每个步骤、工具调用和结束位置,论文使用一套基于 Parsing Expression Grammar(PeG) 的轻量程序格式:
Input: ...
Q1: [工具名称] ...
#1: 工具结果或中间结果
Q2: ...
#2: ...
Q3: [EOQ]
Ans: ...2
3
4
5
6
7
Qn 表示下一项推理或工具请求,#n 保存对应结果,[EOQ] 表示程序结束。PeG 是解析这些结构的实现手段;ART 更关键的能力仍然是跨任务选择示例,以及在生成过程中暂停、执行工具并回填结果。
下面是一个简化示例。假设任务是根据某城市统计页面中的人口数据计算增长率,其中数字仅用于演示流程:
Input: 查询该城市 2020 年和 2023 年的人口,并计算增长率。
Q1: [search] 查询该城市 2020 年和 2023 年人口
#1: 2020 年为 1,000,000;2023 年为 1,150,000
Q2: [generate code] 生成计算人口增长率的 Python 代码
#2: start = 1_000_000
end = 1_150_000
growth_rate = (end - start) / start * 100
Q3: [execute code] 执行代码并返回 growth_rate
#3: 15.0
Q4: [EOQ]
Ans: 2020 年至 2023 年的人口增长率为 15%。2
3
4
5
6
7
8
9
10
11
12
13
14
15
这个过程中,搜索结果和代码执行结果均由外部工具提供,而不是由模型自行填写;模型会在收到结果后继续生成后续程序。
ART 与前述方法的侧重点不同:
- Auto-CoT 自动构造自然语言推理示例,但不以工具执行循环为核心。
- PAL 通常生成完整程序后交给解释器执行;ART 可以在生成过程中多次暂停并回填不同工具的结果。
- ReAct 同样交错进行推理与行动;ART 进一步强调从跨任务的任务库选择示例,并使用可解析的程序格式组织步骤。
人工可以修正任务库中的示例程序,或为工具库增加新的能力。原论文展示了这种方式在部分实验任务上的改进,但它不等于系统能够自动持续变好,修改效果仍需在目标任务上验证。
ART 的效果依赖任务库中是否存在可迁移的相关示例。模型也可能生成不符合语法的程序、调用不存在的工具或错误理解工具结果。生产系统需要校验程序结构与工具参数,限制搜索和代码执行权限,并处理超时、失败重试、不可信工具输出、提示注入、调用成本及停止条件。
图 12:ART 从任务库选择跨任务示例,使用冻结的 LLM 生成结构化推理程序;遇到工具调用时暂停生成,执行工具并将结果写回上下文。人工可以修正示例程序或增加工具。作者根据 ART 论文 描述绘制。
衍生阅读及参考:
5. Retrieval-Augmented Generation(RAG)
RAG(Retrieval-Augmented Generation,检索增强生成) 是一种将外部信息检索与模型生成结合起来的系统模式。它先从知识库中查找与问题相关的内容,再把这些内容作为上下文交给语言模型生成答案。
原始 RAG 论文提出的是一种由生成模型与可检索的非参数知识库共同组成的具体架构。现在工程语境中的 RAG 更宽泛,通常也包括文档处理、关键词或向量检索、结果重排、上下文组装、答案生成和引用等环节。因此,RAG 不只是一种 Prompt 写法,而是一条完整的信息处理链路。
一套常见的 RAG 系统可以分为两个阶段:
- 离线索引: 收集并解析文档,将内容分块,为文本建立关键词索引、向量索引或两者结合的混合索引,同时保存来源、版本和访问权限等元数据。
- 在线问答: 根据用户问题检索候选内容,进行权限过滤和相关性重排,再把选出的证据加入 Prompt,由模型生成带有引用的答案;证据不足时应拒绝作出确定回答。
图 13:RAG 先在离线阶段将文档处理为可检索的知识索引,再在在线阶段检索、过滤并重排证据,最后由 LLM 根据证据生成答案或在证据不足时拒答。作者根据 RAG 原始论文 与 RAG 综述 绘制。
下面是一个虚构的企业知识库示例:
用户问题:
公司员工手册规定的年假是多少?
检索结果:
《员工手册(2026 年 7 月版)》第 4.2 节:
“正式员工每个自然年度享有 15 个工作日的带薪年假。”
最终回答:
根据《员工手册(2026 年 7 月版)》第 4.2 节,
正式员工每个自然年度享有 15 个工作日的带薪年假。2
3
4
5
6
7
8
9
10
如果系统没有检索到有效条款,或者不同版本的手册内容相互冲突,就不应仅凭模型的训练记忆补全答案,而应说明证据不足并提示用户核对有效版本。
RAG 可以让模型使用知识库中的最新或私有数据,而不必重新训练模型,但信息是否最新、用户是否有权访问,仍取决于数据更新、索引频率和权限控制。它也不能消除幻觉:检索可能漏掉关键文档,返回过时、重复或冲突的内容;模型可能误读证据,生成与引用不一致的结论。
生产系统还需要防范检索内容中的提示注入,并分别评估检索质量与生成质量。例如,检索阶段关注是否召回了正确证据,生成阶段关注答案是否得到证据支持。与直接把全部文档放入长上下文相比,RAG 会先筛选相关内容;与 Agent 搜索相比,基础 RAG 通常按预设流程检索,而 Agent 可以动态决定是否搜索、搜索什么以及是否继续调用其他工具。
衍生阅读及参考:
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks
- Retrieval-Augmented Generation for Large Language Models: A Survey
- Retrieval Augmented Generation: Streamlining the creation of intelligent natural language processing models
- 教程:Retrieval Augmented Generation (RAG)
五、Prompt 自动优化与开发框架
前述方法解决了 Prompt 的表达、推理、搜索和工具调用问题,但具体指令、示例与工作流通常仍需要人工反复调整。当任务、模型或数据发生变化时,仅靠经验修改 Prompt 不仅成本较高,也难以稳定复现和比较效果。
本章将优化对象从单条 Prompt 扩展到提示线索、示例、指令和任务结构:DSP、Active-Prompt 与 APE 分别从线索生成、示例选择和指令搜索入手;Meta Prompting 提供可复用的任务结构,本身不等同于自动优化;DSPy 则进一步把模型调用组织成可编程、可评估和可优化的模块。无论采用哪种方法,优化结果都取决于数据和评价指标,并需要使用独立测试集验证。
1. Directional Stimulus Prompting(DSP)
Directional Stimulus Prompting(方向性刺激提示) 使用一个较小的可训练策略模型,为每个输入生成实例相关的提示线索,再将线索与原任务一起交给冻结的黑盒大模型。线索可以是关键词、实体、内容规划或推理提示,用于引导大模型生成更符合目标的结果。
它与人工编写固定提示的区别在于:固定提示对所有输入使用相同的要求,而 DSP 的策略模型会根据当前输入生成不同的方向性刺激。整个方法需要区分训练和推理两个阶段:
- 训练阶段: 策略模型根据输入生成方向性刺激,冻结的大模型在其引导下完成任务,再使用参考答案、任务指标或人工反馈评价输出。策略模型可以先通过标注数据进行监督微调,也可以进一步根据离线或在线奖励进行强化学习。
- 推理阶段: 已训练的策略模型为新输入生成刺激,将其与原始任务组合后交给冻结的大模型。这个阶段通常只生成线索和答案,不会在每次请求中重新训练策略模型。
下图通过一个虚构的摘要任务展示 DSP 的推理阶段,不包含策略模型的训练过程:
图 14:在虚构的社区图书馆公告摘要任务中,DSP 使用策略模型生成的关键词作为实例相关线索,引导大模型覆盖目标信息;标准提示只包含固定的摘要要求。作者根据 Zekun Li 等人的 Guiding Large Language Models via Directional Stimulus Prompting 方法绘制。
DSP 的效果取决于训练数据、奖励或评价指标、策略模型以及目标大模型。错误线索可能直接误导最终输出;评价指标与真实目标不一致时,策略模型也可能只学会迎合指标。此外,训练和部署额外的策略模型会增加工程复杂度、推理延迟与成本,在一种任务或模型上得到的策略也不一定能够直接迁移到另一种场景。
对于少量固定任务,人工添加关注点通常更加简单。当系统需要为大量输入自动生成实例相关线索,并且具备训练数据、评价指标以及维护策略模型的条件时,才有必要采用完整的 DSP 框架。
衍生阅读及参考:
- Guiding Large Language Models via Directional Stimulus Prompting
- Directional Stimulus Prompting 作者代码仓库
- 入门说明:What is directional stimulus prompting (DSP)?
2. Active-Prompt
固定使用同一组人工 CoT 示例,不一定适合难度和类型不同的推理任务。Active-Prompt 借鉴基于不确定性的主动学习思想,先从目标任务的问题池中选择最值得人工标注的问题,再把标注后的问题、推理过程和答案构造成任务相关的 few-shot CoT 示例。
需要注意的是,Active-Prompt 自动完成的是待标注问题的选择,而不是自动生成最终示例。完整流程包含四个阶段:
- 不确定性估计: 使用 Few-shot CoT 或 Zero-shot CoT,让模型对每个未标注问题进行多次推理,并记录最终答案。
- 问题选择: 根据答案的分歧度或熵等指标对问题排序,选择预测结果分歧较大、不确定性较高的问题。
- 人工标注: 由人工为选中的问题编写正确的推理过程和最终答案,形成新的 CoT 示例。
- 任务推理: 将新示例加入 few-shot Prompt,用于回答目标任务中的测试问题。原论文实验在这一阶段还结合了 Self-Consistency,通过多次采样选择最一致的答案。

图 15:Active-Prompt 对候选问题进行多次预测,根据答案分歧估计不确定性,选择不确定性最高的问题进行人工 CoT 标注,再使用新示例完成推理。来源:Shizhe Diao 等,Active Prompting with Chain-of-Thought for Large Language Models,原论文 Figure 1,CC BY 4.0。
论文主要研究了四种不确定性指标:分歧度、熵、方差和模型自报置信度。其中,分歧度关注多次预测中出现了多少种不同答案,熵关注答案分布是否分散。高不确定性并不代表模型一定回答错误,它只表示模型对该问题的预测较不稳定。论文实验中,模型自报置信度的效果较差,因为模型可能对错误答案表现得过度自信。
与 Auto-CoT 的区别
- Active-Prompt: 根据模型不确定性选择问题,再由人工编写正确的推理过程和答案。
- Auto-CoT: 通过聚类选择具有代表性的问题,并使用 Zero-shot CoT 自动生成推理示例。
两者的区别不仅在于是否需要人工标注,也在于问题选择标准:Active-Prompt 偏向选择模型不确定的问题,Auto-CoT 偏向覆盖具有代表性的不同问题类型。
Active-Prompt 需要与目标任务相近的未标注问题池。对大量问题进行多次预测会增加模型调用成本,人工 CoT 标注也可能存在错误或风格差异;如果任务分布发生变化,原先选择的示例未必仍然有效。原论文实验主要使用 code-davinci-002、text-davinci-002 和 text-davinci-003 等模型,其收益仍需在当前使用的目标模型和数据上重新验证。
衍生阅读及参考:
3. Automatic Prompt Engineer(APE)
APE(Automatic Prompt Engineer) 用于自动寻找更有效的任务指令。它不直接完成任务,也不更新模型参数,而是让模型生成多条候选 Prompt,再通过实际执行和评分选出效果更好的指令,供后续同类任务重复使用。
例如,要让模型把客服消息分为“退款”“物流”和“产品故障”,人工通常需要反复修改分类指令。APE 可以根据少量已标注样本自动提出不同写法:
已标注样本:
“商品有划痕,无法正常使用。” → 产品故障
“快递三天没有更新。” → 物流
“不想要了,怎么退钱?” → 退款
模型生成的候选指令:
A. 判断用户问题属于退款、物流还是产品故障。
B. 阅读客服消息,只输出退款、物流或产品故障中的一个标签。
C. 总结用户遇到的问题。
评估结果:
在验证样本上分别执行并计算分类准确率,
选择得分最高的指令。2
3
4
5
6
7
8
9
10
11
12
13
从流程看,APE 主要完成四件事:
- 准备样本和指标: 提供能够代表目标任务的输入—输出示例,并确定准确率等评分标准。
- 生成候选指令: 让语言模型根据示例推测任务要求,提出多种 Prompt 写法。
- 执行并评分: 使用目标模型逐条测试候选指令,保留得分较高的候选;也可以围绕高分候选继续生成变体。
- 选择最终指令: 在独立验证数据上选出效果更好的 Prompt,再使用未参与搜索的测试数据检查泛化效果。
候选生成和任务执行可以由同一个模型承担,也可以使用不同模型。关键不在于使用几个模型,而在于候选 Prompt 必须经过目标任务数据和明确指标的检验。
图 16:APE 根据已标注的客服消息生成多个候选分类指令,通过目标模型的执行结果进行评分,并可围绕高分候选继续生成语义变体。作者根据 Yongchao Zhou 等人的 Large Language Models Are Human-Level Prompt Engineers 绘制。
APE 适合任务会被大量重复执行、已有代表性样本且结果可以客观评分的场景。对于一次性提问、缺少评估数据或无法判断结果好坏的开放任务,人工直接编写 Prompt 通常更简单。
实现时应区分候选生成数据、验证数据和最终测试数据,避免在同一批样本上反复筛选造成过拟合。APE 还需要执行大量候选 Prompt,调用成本较高;评分指标、目标模型或任务分布变化后,原先选出的指令也可能不再最优。
衍生阅读及参考:
4. Meta Prompting
Meta Prompting 使用与具体问题内容无关的结构模板,规定一类任务应如何拆解、求解和组织答案。它关注可复用的求解结构,而不是为单个问题提供具体示例。
严格来说,Meta Prompting 是一种高层提示设计方法,并不等同于 APE 这类自动搜索算法。只有进一步让模型生成并迭代 Prompt 时,才属于 Recursive Meta Prompting(递归元提示) 等自动优化过程。本节将它放在自动优化章节,是为了说明 Prompt 的优化对象不仅可以是具体措辞,也可以是可复用的任务结构。
一个 Meta Prompt 通常会抽象出:
- 适用的任务类型
- 问题拆解和求解步骤
- 检查或验证规则
- 输出结构
其基本形式可以概括为:
适用任务
↓
问题表示
↓
求解步骤
↓
结果检查
↓
输出格式2
3
4
5
6
7
8
9
与只针对单个问题编写步骤不同,Meta Prompt 会保留问题占位符,使同一结构能够复用于一类任务。
示例
普通 Prompt:
解释为什么雨天开车更危险。面向“现象—风险”类问题的 Meta Prompt:
对于任意“现象—风险”类问题,请按照以下结构回答:
1. 提取与问题相关的事实。
2. 建立“条件 → 作用机制 → 后果”的因果链。
3. 检查是否存在例外或限制条件。
4. 给出简明结论。
问题:{待分析的问题}2
3
4
5
6
7
8
将“为什么雨天开车更危险”填入占位符后,模型会按照同一框架组织答案;更换为其他“现象—风险”问题时,这套结构仍可复用。结构模板可以减少回答组织方式的波动,但不能保证事实和推理一定正确,仍需通过目标任务上的样本进行验证。
Meta Prompt 与 Few-shot 的取舍:
- Meta Prompt 提供与具体内容无关的抽象结构,不依赖已解答示例,但模板本身仍会占用 token。
- Few-shot 通过具体输入输出展示任务边界,对格式、标签或风格模仿通常更直接。
- 两者并不互斥:可以先用 Meta Prompt 规定流程,再用少量示例校准输出。
衍生阅读及参考:
5. Declarative Self-improving Python(DSPy)
DSPy(Declarative Self-improving Python) 用来把多个模型调用写成可以组合、评估和优化的 Python 程序。它主要解决这样一个问题:当应用包含分类、检索、推理或工具调用等多个步骤时,如果把每一步的 Prompt 都直接写死在代码中,后续更换模型或调整流程往往需要重新手工调试大量提示词。
使用 DSPy 时,开发者先声明每一步“接收什么、返回什么”,再选择直接预测、Chain-of-Thought 或 ReAct 等执行方式,并用普通 Python 控制流把多个步骤连接起来。如果提供样本和评价指标,还可以让 Optimizer 自动尝试指令或 few-shot 示例,选择得分更高的程序配置。
可以把这个过程简单理解为:
- 定义任务接口: 例如输入一段文本,输出“正面”或“负面”。
- 选择执行方式: 决定让模型直接分类,还是先推理再分类。
- 组合工作流: 将分类、检索或其他模型调用连接成完整程序。
- 按指标优化: 使用样本测试不同指令和示例组合,保留效果更好的版本。
DSPy 通过三类核心抽象实现这套流程:
- Signature:定义任务接口,即模型要做什么、接收哪些字段、返回哪些字段。
- Module:决定任务如何执行,例如直接预测、Chain-of-Thought 或 ReAct。
- Optimizer:根据样本和评价指标,选择或生成更合适的指令与 few-shot 示例;部分 Optimizer 也能用于模型微调。
DSPy 程序不经过优化也可以直接运行。只有在提供数据和评价指标,并主动调用 Optimizer 的 compile() 后,才会进入优化阶段。这里的“编译”不是把 Python 转成机器码,而是返回一个已经配置好指令、示例或模型参数的 DSPy 程序。
与 APE 相比,APE 主要为单个任务搜索更有效的指令;DSPy 的范围更广,可以表示包含多个模型调用的工作流,并分别优化其中一个或多个模块。
1. 定义并运行基础程序
下面使用一个简化的情感分类任务说明 Signature 和 Module 的关系。模型名称是占位符,运行前需要替换为实际使用的模型并配置相应凭证。
from typing import Literal
import dspy
lm = dspy.LM("provider/model-name")
dspy.configure(lm=lm)
class Sentiment(dspy.Signature):
"""判断句子的情感倾向。"""
text: str = dspy.InputField()
label: Literal["正面", "负面"] = dspy.OutputField()
classifier = dspy.Predict(Sentiment)
prediction = classifier(text="客服很快解决了我的问题。")
print(prediction.label)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
可能输出:
正面这里的 Signature 只声明分类任务及输入输出,dspy.Predict 决定如何执行这次模型调用。将 Module 换成 dspy.ChainOfThought 等实现时,任务接口可以保持不变。
2. 使用数据和指标编译优化
如果基础程序的效果不足,可以准备带标签样本和评价指标,再由 Optimizer 编译程序:
trainset = [
dspy.Example(text="这部电影非常精彩。", label="正面").with_inputs("text"),
dspy.Example(text="更新后应用频繁闪退。", label="负面").with_inputs("text"),
]
def exact_match(example, prediction, trace=None):
return prediction.label == example.label
optimizer = dspy.BootstrapFewShot(metric=exact_match)
optimized_classifier = optimizer.compile(classifier, trainset=trainset)2
3
4
5
6
7
8
9
10
11
12
compile() 会尝试为分类模块构造可用的 few-shot 示例,并返回优化后的 optimized_classifier;它不会修改前面定义的任务接口。这个简化示例只展示调用关系。实际项目需要更具代表性的训练样本,并将优化数据、开发集和最终测试集分开,避免反复使用同一批数据导致过拟合或评估泄漏。评价指标也会决定优化方向:格式匹配或单一自动指标得分更高,不一定代表真实业务效果更好。
DSPy 中的“Self-improving”并不表示程序会在生产运行期间自动持续学习。优化发生在开发者提供数据和评价指标并主动编译程序时;模型、数据分布或工作流发生变化后,仍需重新评估,必要时重新编译。
衍生阅读及参考:
- DSPy 官方文档
- DSPy 官方代码仓库
- DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines
- DSPy Optimizers