AI Agent 的推理引擎:从 Chain-of-Thought 到推理模型的深度解析与 Java 实战

系列文章

本系列持续更新,以下是已发布文章索引:

  1. 理解 AI Agent 的大脑:ReAct 模式从入门到实战
  2. AI Agent 的灵魂对话:Prompt Engineering 系统提示词设计的艺术与工程
  3. AI Agent 的规划大脑:从任务分解到自适应执行策略
  4. AI Agent 的工具箱:深入理解 Tool Use 与 Spring AI Function Calling 实战
  5. AI Agent 的记忆系统:从 ChatMemory 到持久化记忆的 Java 实战
  6. AI Agent 的记忆力是怎么实现的——LangChain4j Memory 机制深度解析
  7. MCP 模型上下文协议:AI 的万能接口与 MCP Server 实战
  8. 让 AI 学会”说人话”——Spring AI 结构化输出实战
  9. 从零理解 RAG:检索增强生成完整指南
  10. Embedding 向量化的魔法:从文本到向量的数学之旅与 Java 实战
  11. AI Agent 的知识检索引擎:从向量搜索到智能检索策略的 Java 实战
  12. 当 RAG 遇上知识图谱:GraphRAG 原理与 Java 实战
  13. 当 RAG 遇到 Agent:Agentic RAG 的架构设计与 Java 实战
  14. AI Agent 团队协作:多 Agent 系统架构设计与 Java 实战
  15. AI Agent 的安全防线:Prompt 注入防御与生产级安全防护实战
  16. AI Agent 的可观测性:从链路追踪到成本监控的 Java 实战
  17. AI Agent 的评估与优化:从基准测试到生产环境的质量守护实战
  18. AI Agent 的流式响应与实时交互:从 SSE 到 WebSocket 的 Java 实战
  19. Spring AI 核心架构全解析:从 ChatModel 到 Advisor Chain 的设计哲学
  20. AI Agent 的工作流编排:从顺序链到自适应 DAG 的 Java 实战
  21. AI Agent 的推理引擎:从 Chain-of-Thought 到推理模型的深度解析与 Java 实战(本文)

引言:一个让所有 LLM 都”翻车”的经典问题

先来看一道小学数学题:

一个农夫有 17 只羊,除了 9 只以外都死了。农夫还剩几只羊?

如果你问 GPT-3.5,它大概率会自信地回答”8 只”——因为它”直觉地”做了减法 17 - 9 = 8。但正确答案是 9 只(”除了 9 只以外都死了”意味着 9 只活了下来)。

这个问题暴露了 LLM 最根本的弱点:**默认模式下,模型倾向于”凭直觉”给出答案,而不是”想清楚再回答”**。就像一个聪明但毛躁的学生,看到题目就提笔算,连题都没读完。

这就是今天要聊的主题:AI Agent 的推理引擎

在之前的系列文章中,我们已经深入理解了 Agent 的记忆系统工具调用ReAct 模式规划能力。但有一个核心问题我们一直没有正面回答:Agent 的”思考”本身,到底是怎么工作的?

这篇文章会从一个看似简单的技巧出发——在 Prompt 里加一句”让我们一步步思考”——一路讲到 OpenAI o1、DeepSeek-R1 这类”推理模型”的内部机制。你会发现,整个 AI 推理能力的进化史,本质上就是一场**”让 LLM 学会慢思考”**的工程实践。


第一章:Chain-of-Thought——一句话撬动推理能力的魔法

1.1 从”直接回答”到”先想再说”

2022 年,Google Brain 的 Jason Wei 等人在论文《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》中发现了一个惊人的现象:只要在 Prompt 中给出一个”展示推理过程”的示例,LLM 的推理准确率就会飙升

这是什么意思?看两个例子:

传统 Prompt(直接要答案)

1
2
3
4
5
Q: Roger 有 5 个网球,他又买了 2 罐网球,每罐 3 个。他现在有几个网球?
A: 11

Q: 食堂有 23 个苹果,用掉了 20 个,又买了 6 个。现在有几个苹果?
A:

模型可能会输出 27(正确),也可能会输出 29(错把减法做成加法)。因为模型看到的是”输入→输出”的映射,它在用模式匹配来猜答案。

Chain-of-Thought Prompt(展示推理过程)

1
2
3
4
5
6
Q: Roger 有 5 个网球,他又买了 2 罐网球,每罐 3 个。他现在有几个网球?
A: Roger 一开始有 5 个球。买了 2 罐,每罐 3 个,就是 2×3=6 个。总共 5+6=11 个。
答案是 11。

Q: 食堂有 23 个苹果,用掉了 20 个,又买了 6 个。现在有几个苹果?
A:

现在模型会模仿示例的推理风格,输出:

食堂一开始有 23 个苹果。用掉了 20 个,剩下 23-20=3 个。又买了 6 个,现在有 3+6=9 个。答案是 9。

关键洞察:模型的能力并没有改变,改变的是输出的结构。当你要求模型”展示推理过程”时,模型被迫把一个复杂问题分解成多个简单的中间步骤——而每个中间步骤,都在模型的能力范围之内。

打个比方:你让一个实习生直接算”这个项目需要多少预算”,他可能拍脑袋给你一个数字。但如果你要求他”先列出人员成本、再算服务器费用、然后加上第三方服务费……”,他算出来的数字就靠谱得多。不是他变聪明了,是你改变了他思考的方式

1.2 Few-shot CoT vs. Zero-shot CoT

Chain-of-Thought 有两种形式:

Few-shot CoT(需要示例):在 Prompt 中提供 2-3 个带推理过程的示例,让模型模仿。这就是原始论文提出的方法。

Zero-shot CoT(零样本,更通用):2022 年 Kojima 等人发现,只需要在 Prompt 末尾加上一句”Let’s think step by step”(让我们一步步思考),模型就会自动展开推理链,不需要任何示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Few-shot CoT 的 Prompt 模板
String fewShotCoT = """
问题:一个商店有 45 个苹果,卖掉了 1/3,又进货 12 个,现在有多少?

思考过程:
1. 商店原有 45 个苹果
2. 卖掉 1/3:45 × 1/3 = 15 个
3. 剩下:45 - 15 = 30 个
4. 又进货 12 个:30 + 12 = 42 个

答案:42 个苹果

问题:%s

思考过程:
""";

// Zero-shot CoT 的 Prompt 模板
String zeroShotCoT = """
问题:%s

让我们一步步思考这个问题:
""";

在 Spring AI 中,你可以轻松地使用 ChatClient 来实现这两种 CoT 策略:

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
@Component
public class CoTReasoningAgent {

private final ChatClient chatClient;

public CoTReasoningAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

/**
* Zero-shot CoT:通过提示词让模型自行展开推理链
*/
public String thinkStepByStep(String question) {
return chatClient.prompt()
.user(question + "\n\n让我们一步步思考这个问题,先分析题目,然后列出解题步骤,最后给出答案。")
.call()
.content();
}

/**
* Few-shot CoT:提供推理示例,引导模型模仿推理模式
*/
public String thinkWithExamples(String question, List<QAExample> examples) {
StringBuilder prompt = new StringBuilder();
prompt.append("请参考以下示例的推理方式来回答问题:\n\n");

for (QAExample ex : examples) {
prompt.append("问:").append(ex.question()).append("\n");
prompt.append("思考过程:").append(ex.reasoning()).append("\n");
prompt.append("答:").append(ex.answer()).append("\n\n");
}

prompt.append("问:").append(question).append("\n");
prompt.append("思考过程:");

return chatClient.prompt()
.user(prompt.toString())
.call()
.content();
}
}

record QAExample(String question, String reasoning, String answer) {}

1.3 CoT 的本质:用生成换准确率

从信息论的角度看,CoT 的原理其实很简单:LLM 的每一步推理都有一定的错误概率,而把一步大推理拆成多步小推理,每步的错误率都会大幅降低

假设有一步推理的准确率是 80%。如果模型试图一步到位完成一个需要 5 步子推理的复杂问题,总准确率是 0.8^5 ≈ 33%。但如果模型逐步推理,每步都输出中间结果(给下一步提供上下文),虽然总准确率会因步骤增多而累积下降,但远好于一步到位——因为每一步都有明确的中间锚点来约束下一步的推理方向。

这也是为什么ReAct 模式中的”思考”步骤如此重要——它本质上就是 CoT 在 Agent 场景中的应用。Agent 在调用工具之前先”想清楚”要做什么,比直接调用工具的准确率高得多。


第二章:超越简单 CoT——高级推理策略

2.1 Self-Consistency:多数投票的智慧

2022 年 Wang 等人提出了 Self-Consistency(自洽性)策略。核心思想非常朴素:对同一个问题,让模型用 CoT 推理多次,然后取出现次数最多的答案

为什么这有效?因为模型在推理过程中可能走错某一步,但错误的方向是随机的——如果走错路有 3 种错误方向,走对路只有 1 种正确方向,那么多次采样后,走对路的样本数量会占多数。

1
2
3
4
5
6
7
推理路径 1:…→ 3+6=9 ✓
推理路径 2:…→ 3+6=9 ✓
推理路径 3:…→ 3×6=18 ✗(乘法搞混了)
推理路径 4:…→ 3+6=9 ✓
推理路径 5:…→ 6-3=3 ✗(减法搞混了)

多数投票结果:9(3 票 vs 18 的 1 票 vs 3 的 1 票)→ 正确

用 Spring AI 实现 Self-Consistency:

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
74
75
76
77
78
@Component
public class SelfConsistencyAgent {

private final ChatClient chatClient;

// 采样次数——通常 5-10 次就能获得很好的效果
private static final int SAMPLE_COUNT = 7;

public SelfConsistencyAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

/**
* Self-Consistency 推理:多次 CoT 采样 + 多数投票
*/
public ConsistencyResult reasonWithConsistency(String question) {
// 并行采样多条推理路径
List<String> reasoningPaths = new ArrayList<>();

for (int i = 0; i < SAMPLE_COUNT; i++) {
String reasoning = chatClient.prompt()
.user(buildCoTPrompt(question))
.options(ChatOptions.builder()
.temperature(0.7) // 需要一定的随机性来获得多样化的推理路径
.build())
.call()
.content();
reasoningPaths.add(reasoning);
}

// 从每条路径中提取最终答案
List<String> answers = reasoningPaths.stream()
.map(this::extractFinalAnswer)
.toList();

// 多数投票
String majorityAnswer = answers.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("无法确定");

// 计算一致性得分
long maxVotes = answers.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.values().stream()
.max(Long::compareTo)
.orElse(0L);

double confidence = (double) maxVotes / SAMPLE_COUNT;

return new ConsistencyResult(majorityAnswer, confidence, reasoningPaths);
}

private String buildCoTPrompt(String question) {
return "问题:" + question + "\n\n"
+ "请一步步思考这个问题,最后用"最终答案:XXX"的格式给出答案。";
}

private String extractFinalAnswer(String reasoning) {
// 尝试从推理文本中提取"最终答案:"后面的内容
Pattern pattern = Pattern.compile("最终答案[::]\\s*(.+?)(?:\\n|$)");
Matcher matcher = pattern.matcher(reasoning);
if (matcher.find()) {
return matcher.group(1).trim();
}
// 备选:取最后一行作为答案
String[] lines = reasoning.split("\n");
return lines[lines.length - 1].trim();
}
}

record ConsistencyResult(
String answer,
double confidence,
List<String> reasoningPaths
) {}

Self-Consistency 的代价是推理成本线性增长(采样 N 次就是 N 倍的 token 消耗),但它在数学推理、逻辑推理等任务上能显著提升准确率。在生产环境中,你可以根据问题的难度动态调整采样次数——简单问题采样 1 次就够了,复杂问题可以采样 10 次以上。

2.2 Tree of Thoughts:分叉的推理树

在之前的规划大脑文章中,我们简单提到了 Tree of Thoughts(ToT)。这里从推理引擎的角度做一个更深入的解析。

传统的 CoT 是一条线性推理链——A→B→C→D→答案。但真实世界的推理往往是树状的——从一个起点出发,可能有多个合理的推理方向,需要”探索”和”回溯”。

Tree of Thoughts(2023 年 Yao 等人提出)把推理过程建模为一棵搜索树

1
2
3
4
5
6
7
8
9
           [问题]
/ | \
[思路A] [思路B] [思路C] ← 第1层:生成多个初始思路
/ \ | |
[A1] [A2] [B1] [C1] ← 第2层:每个思路继续展开
| | | |
[A1'] [A2'] [B1'] [C1'] ← 第3层:继续深入

评估→选择最优路径

ToT 和普通 CoT 的核心区别

特性 普通 CoT Tree of Thoughts
推理路径 单条线性链 多条分支,可回溯
错误处理 一步错,步步错 可以”撤回”错误步骤
探索方式 贪心(每步选最优) 搜索(BFS/DFS + 剪枝)
适用场景 简单推理、知识问答 创意写作、策略规划、数学证明
Token 消耗 高(多次生成 + 评估)

用 Java 实现一个简化版的 ToT 推理器:

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
@Component
public class TreeOfThoughtsReasoner {

private final ChatClient chatClient;

// 每层最多保留的候选思路数
private static final int BRANCHING_FACTOR = 3;
// 最大搜索深度
private static final int MAX_DEPTH = 4;
// 评估阈值:低于此分数的分支会被剪枝
private static final double PRUNE_THRESHOLD = 0.4;

public TreeOfThoughtsReasoner(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

/**
* Tree of Thoughts 推理:生成多条推理分支,评估并选择最优路径
*/
public ToTResult solveWithTreeOfThoughts(String problem) {
// 初始思路生成
List<ThoughtNode> rootChildren = generateThoughts(problem, null, BRANCHING_FACTOR);

// BFS 搜索最优路径
PriorityQueue<ThoughtNode> frontier = new PriorityQueue<>(
Comparator.comparingDouble(ThoughtNode::score).reversed()
);
frontier.addAll(rootChildren);

ThoughtNode bestLeaf = null;
int depth = 0;

while (!frontier.isEmpty() && depth < MAX_DEPTH) {
ThoughtNode current = frontier.poll();

// 评估当前节点是否已经是有效答案
double terminalScore = evaluateTerminal(current);
if (terminalScore > 0.8) {
bestLeaf = current;
break;
}

// 生成子思路
List<ThoughtNode> children = generateThoughts(
problem, current, BRANCHING_FACTOR
);

// 剪枝:只保留高分分支
for (ThoughtNode child : children) {
if (child.score() > PRUNE_THRESHOLD) {
frontier.add(child);
}
}

if (bestLeaf == null || current.score() > bestLeaf.score()) {
bestLeaf = current;
}

depth++;
}

// 回溯最优路径
List<String> bestPath = reconstructPath(bestLeaf);

return new ToTResult(
bestLeaf.content(),
bestLeaf.score(),
bestPath
);
}

/**
* 生成候选思路:给定当前状态,生成 N 个可能的下一步推理
*/
private List<ThoughtNode> generateThoughts(String problem, ThoughtNode current, int n) {
String context = current != null
? "问题:" + problem + "\n\n当前推理过程:\n" + reconstructPathText(current)
: "问题:" + problem;

String prompt = context + "\n\n"
+ "请生成 " + n + " 个不同的下一步推理思路。"
+ "每个思路用 [思路N] 开头标记,包含具体的推理内容。\n"
+ "要求:思路之间要有明显差异,不要只改措辞。";

String response = chatClient.prompt()
.user(prompt)
.options(ChatOptions.builder().temperature(0.8).build())
.call()
.content();

// 解析多个思路
List<String> thoughts = parseMultipleThoughts(response, n);

// 为每个思路生成评估分数
return thoughts.stream()
.map(thought -> {
double score = evaluateThought(problem, thought, current);
return new ThoughtNode(thought, score, current);
})
.toList();
}

/**
* 评估某个思路的质量(0-1 分)
*/
private double evaluateThought(String problem, String thought, ThoughtNode parent) {
String prompt = """
请评估以下推理思路的质量,给出 0-10 分的评分。

原始问题:%s

推理思路:%s

评分标准:
- 逻辑是否正确(3分)
- 是否朝着正确方向推进(3分)
- 推理步骤是否清晰(2分)
- 是否有明显的错误或偏题(2分)

请只输出一个数字分数(0-10),不要解释。
""".formatted(problem, thought);

String scoreText = chatClient.prompt()
.user(prompt)
.options(ChatOptions.builder().temperature(0.1).build())
.call()
.content();

try {
return Double.parseDouble(scoreText.replaceAll("[^0-9.]", "")) / 10.0;
} catch (NumberFormatException e) {
return 0.5; // 解析失败时给中间分
}
}

/**
* 评估叶子节点是否已经是有效答案
*/
private double evaluateTerminal(ThoughtNode node) {
// 简单启发式:内容中包含"答案"、"结论"等关键词则可能是最终答案
String content = node.content().toLowerCase();
if (content.contains("答案") || content.contains("结论") || content.contains("因此")) {
return node.score();
}
return 0.0;
}

private List<String> reconstructPath(ThoughtNode node) {
List<String> path = new ArrayList<>();
ThoughtNode current = node;
while (current != null) {
path.add(0, current.content());
current = current.parent();
}
return path;
}

private String reconstructPathText(ThoughtNode node) {
return String.join("\n→ ", reconstructPath(node));
}

private List<String> parseMultipleThoughts(String response, int expected) {
// 按 [思路N] 标记分割
String[] parts = response.split("\\[思路\\d+\\]");
List<String> thoughts = Arrays.stream(parts)
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
return thoughts.size() >= expected
? thoughts.subList(0, expected)
: thoughts;
}
}

record ThoughtNode(
String content,
double score,
ThoughtNode parent // 用于回溯路径
) {}

record ToTResult(
String answer,
double confidence,
List<String> reasoningPath
) {}

2.3 自反思(Reflexion):从错误中学习

前面的策略都是在单次推理中提升质量。但还有一种更强大的方式:让 Agent 检查自己的推理,发现错误后重试

这就像考试做完后的”检查”环节——很多学生发现,检查时能找出第一遍做错的题。AI Agent 也可以做同样的事。

Reflexion(2023 年 Shinn 等人提出)的流程是:

1
初始推理 → 自我评估 → 发现错误 → 反思原因 → 修正推理 → 再次评估 → …

关键代码实现:

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
@Component
public class ReflexionAgent {

private final ChatClient chatClient;
private static final int MAX_RETRIES = 3;

public ReflexionAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

/**
* Reflexion 推理:生成→评估→反思→修正 的闭环
*/
public ReflexionResult solveWithReflection(String problem) {
List<ReflectionAttempt> attempts = new ArrayList<>();
String previousReflection = null;

for (int attempt = 0; attempt < MAX_RETRIES; attempt++) {
// 第一步:生成推理和答案
String reasoning = generateReasoning(problem, previousReflection);
String answer = extractAnswer(reasoning);

// 第二步:自我评估
String evaluation = selfEvaluate(problem, reasoning, answer);

// 第三步:判断是否需要修正
if (evaluation.contains("正确") || evaluation.contains("无需修正")) {
attempts.add(new ReflectionAttempt(reasoning, answer, evaluation, null));
return new ReflexionResult(answer, true, attempts);
}

// 第四步:反思错误原因
String reflection = reflectOnError(problem, reasoning, answer, evaluation);
previousReflection = reflection;

attempts.add(new ReflectionAttempt(reasoning, answer, evaluation, reflection));
}

// 达到最大重试次数,返回最后一次的答案
ReflectionAttempt last = attempts.get(attempts.size() - 1);
return new ReflexionResult(last.answer(), false, attempts);
}

private String generateReasoning(String problem, String previousReflection) {
StringBuilder prompt = new StringBuilder();
prompt.append("问题:").append(problem).append("\n\n");

if (previousReflection != null) {
prompt.append("你之前犯了以下错误,请注意避免:\n");
prompt.append(previousReflection).append("\n\n");
}

prompt.append("请仔细思考并给出推理过程和最终答案。");

return chatClient.prompt()
.user(prompt.toString())
.call()
.content();
}

private String selfEvaluate(String problem, String reasoning, String answer) {
String prompt = """
请仔细检查以下推理过程和答案是否正确。

问题:%s

推理过程:
%s

给出的答案:%s

请检查:
1. 每一步推理是否逻辑正确
2. 计算是否有误
3. 是否遗漏了重要条件
4. 最终答案是否合理

如果完全正确,回复"正确,无需修正"。
如果有错误,详细指出错误在哪一步、错的原因是什么。
""".formatted(problem, reasoning, answer);

return chatClient.prompt()
.user(prompt)
.options(ChatOptions.builder().temperature(0.1).build())
.call()
.content();
}

private String reflectOnError(String problem, String reasoning, String answer, String evaluation) {
String prompt = """
你的推理出现了错误。请深入反思错误的根本原因。

问题:%s
你的推理:%s
你的答案:%s
错误分析:%s

请回答:
1. 错误的根本原因是什么(不只是表面原因)
2. 你在推理过程中忽略了什么
3. 下次遇到类似问题,应该注意什么

用简洁的要点列出反思结论。
""".formatted(problem, reasoning, answer, evaluation);

return chatClient.prompt()
.user(prompt)
.call()
.content();
}

private String extractAnswer(String reasoning) {
Pattern pattern = Pattern.compile("(?:答案|结论|最终结果)[::]\\s*(.+?)(?:\\n|$)");
Matcher matcher = pattern.matcher(reasoning);
if (matcher.find()) {
return matcher.group(1).trim();
}
String[] lines = reasoning.split("\n");
return lines[lines.length - 1].trim();
}
}

record ReflectionAttempt(
String reasoning,
String answer,
String evaluation,
String reflection
) {}

record ReflexionResult(
String answer,
boolean converged,
List<ReflectionAttempt> attempts
) {}

自反思机制和我们之前讲的ReAct 模式有一个关键区别:ReAct 是在外部行动中观察结果并调整(工具调用的返回值是客观事实),而 Reflexion 是在内部推理中检查逻辑并修正(评估和反思都由模型自己完成)。两者并不冲突——你完全可以在一个 Agent 中同时使用 ReAct 和 Reflexion:ReAct 负责与外部世界交互,Reflexion 负责内部推理质量。


第三章:推理模型——让 LLM 原生支持”慢思考”

3.1 从 Prompt 技巧到模型架构

前面讲的 CoT、ToT、Self-Consistency 都是 Prompt 层面的推理增强——模型本身的架构没有变,只是通过巧妙的提示词引导模型输出推理过程。

但从 2024 年底开始,一种新的范式出现了:推理模型(Reasoning Models)。这些模型在训练阶段就内化了推理能力——它们不再需要你”教”它一步步思考,而是默认就会先推理再回答

代表性的推理模型包括:

模型 发布时间 核心特点
OpenAI o1 2024.09 第一个商用推理模型,内部使用”思维链”推理
OpenAI o3 2025.01 o1 的增强版,推理能力更强
DeepSeek-R1 2025.01 开源推理模型,通过 RL 训练获得推理能力
Claude 3.5 Sonnet (extended thinking) 2025 Anthropic 的扩展思考能力
QwQ 2025.03 阿里的推理模型

3.2 推理模型的内部机制

推理模型到底是怎么工作的?以 OpenAI o1 为例,它的推理过程包含两个阶段:

阶段一:隐式推理(Hidden Reasoning)

当你发送一个问题给 o1 时,模型会先在内部进行一系列”思考”。这些思考过程对用户不可见(隐藏的),但会消耗大量的 token。OpenAI 称之为 “reasoning tokens”。

阶段二:可见输出(Visible Output)

内部推理完成后,模型才会生成用户可见的回答。这个回答通常是精炼的、结论性的,因为它已经把复杂的推理过程在内部消化了。

1
2
3
4
5
6
7
8
9
10
用户提问: "17只羊除了9只以外都死了,剩几只?"

[隐式推理 - 用户不可见]
"让我仔细分析这个问题。'除了9只以外都死了'意味着有9只没有死。
所以活下来的是9只,而不是17-9=8只。
这道题的关键是理解'除了X以外'这个表述的含义。
答案应该是9只。"

[可见输出 - 用户看到的]
"还剩9只羊。"

这就是为什么 o1 在数学和编程问题上表现特别好——它在内部做了大量的推理,但只给用户一个干净的结果。

3.3 DeepSeek-R1:开源推理模型的突破

DeepSeek-R1 的有趣之处在于,它是通过纯强化学习(RL)训练出来的推理能力。传统方法需要大量人工标注的”思维链”数据来训练模型推理,而 DeepSeek-R1 发现:只要给模型足够的试错机会,它能自己”悟”出推理策略

训练过程中,模型会生成大量的推理尝试,通过最终答案的正确与否获得奖励信号。经过数百万次这样的试错,模型逐渐学会了:

  • 什么时候需要”想得更深”
  • 什么时候可以”直接回答”
  • 遇到困难问题时如何”换一种思路”

这和我们在规划大脑中讨论的”自适应执行策略”异曲同工——好的 Agent 不是每次都执行相同的策略,而是根据问题复杂度动态调整。

3.4 Spring AI 中使用推理模型

在 Spring AI 中使用推理模型,关键在于 ChatOptions 的配置:

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
74
75
76
77
78
79
80
81
82
83
84
@Component
public class ReasoningModelAgent {

private final ChatClient openAIClient;
private final ChatClient deepSeekClient;

public ReasoningModelAgent(
ChatClient.Builder builder,
@Qualifier("openai") ChatClient openaiBuilder,
@Qualifier("deepseek") ChatClient deepseekBuilder) {
this.openAIClient = openaiBuilder;
this.deepSeekClient = deepseekBuilder;
}

/**
* 使用 OpenAI o3-mini 进行推理
* reasoning_effort: low / medium / high
* 控制模型内部推理的"努力程度"
*/
public String reasonWithOpenAI(String question, ReasoningEffort effort) {
return openAIClient.prompt()
.user(question)
.options(ChatOptions.builder()
.model("o3-mini")
// o3-mini 支持 reasoning_effort 参数
// low: 快速但浅层的推理(适合简单问题)
// medium: 平衡推理深度和速度
// high: 深度推理(适合复杂数学、编程题)
.build())
.call()
.content();
}

/**
* 使用 DeepSeek-R1 进行推理
* R1 的思维链是隐式的(不输出中间推理过程)
* 但可以通过 API 参数获取思维链
*/
public String reasonWithDeepSeekR1(String question) {
return deepSeekClient.prompt()
.user(question)
.options(ChatOptions.builder()
.model("deepseek-reasoner")
.temperature(0.6) // R1 推荐 temperature
.build())
.call()
.content();
}

/**
* 混合推理策略:先用推理模型思考,再用快模型总结
* 适用于需要深度分析但输出简洁的场景
*/
public String deepThinkThenSummarize(String question) {
// 第一步:用推理模型进行深度思考
String deepReasoning = openAIClient.prompt()
.user("请深入分析以下问题,给出详细的推理过程:\n\n" + question)
.options(ChatOptions.builder().model("o3-mini").build())
.call()
.content();

// 第二步:用快模型精炼输出
String summary = openAIClient.prompt()
.user("""
以下是一段深度分析的结果。请提炼出核心结论,用简洁清晰的语言重新组织。
要求:保留关键洞察,去掉冗余的推理细节,让非专业人士也能理解。

分析内容:
%s
""".formatted(deepReasoning))
.options(ChatOptions.builder()
.model("gpt-4o-mini") // 快速、便宜
.temperature(0.3)
.build())
.call()
.content();

return summary;
}
}

enum ReasoningEffort {
LOW, MEDIUM, HIGH
}

第四章:生产环境中的推理策略选择

4.1 不同场景,不同策略

在生产环境中,推理策略的选择需要平衡准确率、延迟和成本三个维度。以下是一个实用的决策矩阵:

场景 推荐策略 原因
客服问答(简单) 直接回答 问题简单,不需要推理链
客服问答(复杂投诉) Zero-shot CoT 需要分析但不值得多次采样
数学/编程题 推理模型(o3-mini) 推理模型在这些场景准确率最高
代码审查 Reflexion 需要多轮检查和修正
战略分析/创意写作 Tree of Thoughts 需要探索多个方向
高准确率要求的决策 Self-Consistency 多次采样 + 投票降低错误率
实时对话 直接回答 + 推理模型 fallback 先快后精

4.2 推理成本控制

推理策略的最大成本来源是 token 消耗。以下是几种策略的 token 开销对比(以同一个中等复杂度问题为基准):

1
2
3
4
5
6
直接回答:           ~200 tokens(输入 + 输出)
Zero-shot CoT: ~800 tokens(输出更长)
Self-Consistency ×7: ~5,600 tokens(7 次采样)
Tree of Thoughts: ~10,000+ tokens(多次生成 + 评估)
Reflexion ×3: ~3,000 tokens(3 轮生成 + 评估 + 反思)
推理模型 (o3-mini): ~2,000 tokens(推理 token + 输出 token)

在 Spring AI 中,你可以通过 Advisor 来实现一个自适应推理路由

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
74
75
76
77
78
79
@Component
public class AdaptiveReasoningAdvisor implements CallAdvisor {

private final ChatClient chatClient;

// 复杂度评估阈值
private static final double COMPLEXITY_THRESHOLD_HIGH = 0.8;
private static final double COMPLEXITY_THRESHOLD_MEDIUM = 0.5;

public AdaptiveReasoningAdvisor(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public String getName() {
return "AdaptiveReasoningAdvisor";
}

@Override
public int getOrder() {
return 0;
}

@Override
public AdvisedResponse aroundCall(AdvisedRequest request, CallChain chain) {
String userMessage = request.userText();

// 评估问题复杂度
double complexity = assessComplexity(userMessage);

if (complexity > COMPLEXITY_THRESHOLD_HIGH) {
// 高复杂度:使用推理模型
String result = chatClient.prompt()
.user(userMessage)
.options(ChatOptions.builder().model("o3-mini").build())
.call()
.content();
return new AdvisedResponse(
new ChatResponse(List.of(new Generation(result))),
request.adviseContext()
);
} else if (complexity > COMPLEXITY_THRESHOLD_MEDIUM) {
// 中复杂度:使用 CoT
String cotPrompt = userMessage + "\n\n让我们一步步思考这个问题。";
AdvisedRequest newRequest = AdvisedRequest.from(request)
.withUserText(cotPrompt)
.build();
return chain.nextAroundCall(newRequest);
} else {
// 低复杂度:直接回答
return chain.nextAroundCall(request);
}
}

/**
* 评估问题复杂度(0-1)
* 基于启发式规则:关键词、问题长度、是否涉及计算等
*/
private double assessComplexity(String question) {
double score = 0.0;

// 长度因子
if (question.length() > 200) score += 0.2;

// 复杂关键词
String[] complexKeywords = {"证明", "分析", "设计", "比较", "评估", "优化", "为什么", "如果", "假设"};
for (String keyword : complexKeywords) {
if (question.contains(keyword)) score += 0.1;
}

// 数学/编程关键词
String[] mathKeywords = {"计算", "公式", "算法", "方程", "概率", "代码", "实现"};
for (String keyword : mathKeywords) {
if (question.contains(keyword)) score += 0.15;
}

return Math.min(score, 1.0);
}
}

4.3 推理模型的局限与陷阱

推理模型并不是万能的。在生产环境中使用时需要注意以下问题:

陷阱一:过度推理(Overthinking)

推理模型有时候会对简单问题”想太多”。比如问它”1+1等于几”,它可能会在内部做一通复杂的数论分析,消耗大量 token 后回答”2”。这就是为什么 OpenAI 引入了 reasoning_effort 参数——你可以根据问题复杂度控制推理深度。

陷阱二:推理 token 不可见

推理模型的内部推理过程(reasoning tokens)通常是隐藏的。这意味着你无法审查它的推理链是否正确——如果最终答案错误,你很难定位是哪一步推理出了问题。在需要可解释性的场景(如医疗、法律),这是一个严重的问题。

陷阱三:成本翻倍甚至更多

推理模型的 token 价格通常比普通模型高 2-5 倍,而且推理 token 也计费。一个使用 o3-mini 的推理请求,token 消耗可能是普通 GPT-4o 的 3-5 倍。

陷阱四:延迟不可控

推理模型的响应时间波动很大——简单问题可能 1 秒内返回,复杂问题可能需要 30 秒甚至更久(因为内部推理时间不确定)。如果你的服务有严格的 SLA 要求,需要做好超时处理和降级策略。

最佳实践:分级推理架构

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
/**
* 三级推理架构:
* Level 0: 直接回答(快速、低成本)
* Level 1: CoT 推理(中速、中成本)
* Level 2: 推理模型(慢速、高成本,最高准确率)
*
* 按问题复杂度动态选择,同时支持用户手动升级
*/
@Component
public class TieredReasoningService {

private final ChatClient fastModel; // gpt-4o-mini
private final ChatClient smartModel; // gpt-4o
private final ChatClient reasoner; // o3-mini

public TieredReasoningService(
@Qualifier("fast") ChatClient fastModel,
@Qualifier("smart") ChatClient smartModel,
@Qualifier("reasoner") ChatClient reasoner) {
this.fastModel = fastModel;
this.smartModel = smartModel;
this.reasoner = reasoner;
}

public ReasoningResponse answer(String question, int level) {
return switch (level) {
case 0 -> directAnswer(question);
case 1 -> cotReasoning(question);
case 2 -> deepReasoning(question);
default -> directAnswer(question);
};
}

private ReasoningResponse directAnswer(String question) {
String answer = fastModel.prompt()
.user(question)
.call()
.content();
return new ReasoningResponse(answer, "direct", 0);
}

private ReasoningResponse cotReasoning(String question) {
String answer = smartModel.prompt()
.user(question + "\n\n请一步步思考后回答。")
.call()
.content();
return new ReasoningResponse(answer, "cot", 1);
}

private ReasoningResponse deepReasoning(String question) {
String answer = reasoner.prompt()
.user(question)
.call()
.content();
return new ReasoningResponse(answer, "reasoning_model", 2);
}
}

record ReasoningResponse(String answer, String strategy, int level) {}

第五章:推理能力与 Agent 其他组件的协同

推理不是孤立存在的。一个成熟的 AI Agent 需要推理能力与记忆、工具、规划等组件紧密配合。这一节我们看推理能力如何与其他核心组件协同工作。

5.1 推理 + 记忆

记忆系统为推理提供了上下文。没有记忆的推理就像失忆的人做数学题——每道题都要从头理解规则。

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
/**
* 带记忆的推理 Agent
* 推理过程中自动检索相关历史经验
*/
@Component
public class MemoryAwareReasoner {

private final ChatClient chatClient;
private final ChatMemory memory;

public MemoryAwareReasoner(ChatClient.Builder builder, ChatMemory memory) {
this.chatClient = builder.build();
this.memory = memory;
}

public String reasonWithMemory(String sessionId, String question) {
// 检索相关历史对话
List<Message> history = memory.get(sessionId, 10);

// 检索相关的推理经验(之前的反思结论)
String relevantExperience = findRelevantExperience(question, history);

String prompt = """
历史对话:
%s

相关经验:
%s

当前问题:%s

请结合历史对话和相关经验,一步步推理回答当前问题。
""".formatted(
formatHistory(history),
relevantExperience != null ? relevantExperience : "无",
question
);

String answer = chatClient.prompt()
.user(prompt)
.call()
.content();

// 将本次推理过程存入记忆
memory.add(sessionId, List.of(
new UserMessage(question),
new AssistantMessage(answer)
));

return answer;
}

private String findRelevantExperience(String question, List<Message> history) {
// 在历史对话中搜索包含"反思"、"教训"、"注意"等关键词的内容
return history.stream()
.filter(m -> m instanceof AssistantMessage)
.map(Message::getContent)
.filter(content -> content.contains("反思") || content.contains("教训") || content.contains("注意"))
.findFirst()
.orElse(null);
}

private String formatHistory(List<Message> messages) {
return messages.stream()
.map(m -> (m instanceof UserMessage ? "用户:" : "AI:") + m.getContent())
.collect(Collectors.joining("\n"));
}
}

5.2 推理 + 工具调用

推理能力可以显著提升工具调用的质量。一个会推理的 Agent 在调用工具之前会先想清楚:

  1. 我需要什么信息?
  2. 哪个工具能提供这个信息?
  3. 这个工具需要什么参数?
  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
/**
* 推理驱动的工具选择
* 不是直接让模型选工具,而是先推理"我需要什么",再选工具
*/
@Component
public class ReasoningToolSelector {

private final ChatClient chatClient;
private final List<ToolDefinition> availableTools;

public ReasoningToolSelector(ChatClient.Builder builder, List<ToolDefinition> tools) {
this.chatClient = builder.build();
this.availableTools = tools;
}

/**
* 推理式工具选择:
* 第一步:分析需要什么信息
* 第二步:匹配最合适的工具
* 第三步:构造正确的参数
*/
public ToolCallDecision selectTool(String task, String context) {
// 构建工具目录
String toolCatalog = availableTools.stream()
.map(t -> "- %s: %s".formatted(t.name(), t.description()))
.collect(Collectors.joining("\n"));

String prompt = """
任务:%s

上下文:%s

可用工具:
%s

请先分析:
1. 完成这个任务需要什么信息?
2. 现有的上下文中已经有哪些信息?
3. 还缺少什么信息?
4. 哪个工具能提供缺少的信息?

然后给出你的工具调用决策(JSON 格式):
{"tool": "工具名", "reasoning": "选择原因", "params": {"key": "value"}}
""".formatted(task, context, toolCatalog);

String decision = chatClient.prompt()
.user(prompt)
.call()
.content();

return parseDecision(decision);
}

private ToolCallDecision parseDecision(String json) {
// 解析 JSON 决策
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(extractJson(json), ToolCallDecision.class);
} catch (Exception e) {
return new ToolCallDecision("unknown", "解析失败", Map.of());
}
}

private String extractJson(String text) {
int start = text.indexOf('{');
int end = text.lastIndexOf('}');
return (start >= 0 && end > start) ? text.substring(start, end + 1) : "{}";
}
}

record ToolCallDecision(String tool, String reasoning, Map<String, Object> params) {}
record ToolDefinition(String name, String description, Map<String, Object> parameterSchema) {}

5.3 推理 + 多 Agent 协作

多 Agent 团队协作的场景中,推理能力可以用于冲突解决。当多个 Agent 给出不同的答案时,一个”裁判 Agent”可以通过推理来评判谁对谁错:

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
/**
* 推理驱动的冲突解决器
* 当多个 Agent 的输出不一致时,通过推理选出最佳答案
*/
@Component
public class ReasoningConflictResolver {

private final ChatClient judgeClient;

public ReasoningConflictResolver(ChatClient.Builder builder) {
this.judgeClient = builder.build();
}

/**
* 收到多个 Agent 的回答后,通过推理选择最佳答案
*/
public ConflictResolution resolve(String question, List<AgentAnswer> answers) {
StringBuilder prompt = new StringBuilder();
prompt.append("问题:").append(question).append("\n\n");
prompt.append("以下是不同 Agent 的回答:\n\n");

for (int i = 0; i < answers.size(); i++) {
AgentAnswer a = answers.get(i);
prompt.append("Agent ").append(a.agentName()).append(" 的回答:\n");
prompt.append(a.answer()).append("\n");
if (a.reasoning() != null) {
prompt.append("推理过程:").append(a.reasoning()).append("\n");
}
prompt.append("\n");
}

prompt.append("""
请作为裁判,分析每个回答的质量:
1. 逐个检查推理过程是否逻辑正确
2. 检查是否有事实性错误
3. 比较不同回答之间的差异
4. 选出最准确、最完整的回答
5. 如果所有回答都有问题,给出你的独立分析

输出格式:
最佳答案: Agent名称
分析: 你的详细分析
""");

String judgment = judgeClient.prompt()
.user(prompt.toString())
.options(ChatOptions.builder().model("o3-mini").build())
.call()
.content();

String bestAgent = extractBestAgent(judgment, answers);

return new ConflictResolution(bestAgent, judgment);
}

private String extractBestAgent(String judgment, List<AgentAnswer> answers) {
for (AgentAnswer a : answers) {
if (judgment.contains(a.agentName())) {
return a.agentName();
}
}
return "judge"; // 裁判给出了独立答案
}
}

record AgentAnswer(String agentName, String answer, String reasoning) {}
record ConflictResolution(String winnerAgent, String analysis) {}

第六章:横向上比——推理策略全景对比

6.1 主流推理策略对比

策略 核心思想 准确率提升 Token 开销 延迟影响 适用场景
Zero-shot CoT 加一句”一步步想” 中等 2-4x 通用推理
Few-shot CoT 提供推理示例 较高 3-5x 特定领域推理
Self-Consistency 多次采样+投票 N倍 高(可并行) 数学、逻辑
Tree of Thoughts 树状搜索 最高 10-50x 最高 创意、策略
Reflexion 自我反思纠错 较高 3-5x 代码、分析
推理模型 模型原生推理 2-5x 不可控 数学、编程
混合策略 先推理后精炼 最高 3-8x 生产环境

6.2 与 Agent 其他能力的关系图谱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
              ┌─────────────────────────────────────────┐
│ AI Agent 能力图谱 │
└─────────────────────────────────────────┘

┌───────────┬──────────┼──────────┬───────────┐
▼ ▼ ▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ 推理 │ │ 记忆 │ │ 工具 │ │ 规划 │ │ 协作 │
│引擎 │←→│ 系统 │←→│ 调用 │←→│ 策略 │←→│ 机制 │
└──────┘ └──────┘ └──────┘ └──────┘ └──────┘
↑ ↑ ↑ ↑ ↑
│ │ │ │ │
CoT/ToT │ 短期/长期 Function Plan-and-Execute
推理模型 │ ChatMemory Calling 分解/重规划
│ │ │ │ │
└───┴────────┴──────────┴──────────┘
推理能力是其他所有能力的"底层基座"

推理能力之所以是”底层基座”,是因为:

  • 记忆需要推理来决定”记住什么、遗忘什么”
  • 工具调用需要推理来决定”调用哪个工具、用什么参数”
  • 规划本身就是一种高级推理(分解问题、安排顺序)
  • 多 Agent 协作需要推理来解决冲突、分配任务

总结

让我们回顾一下今天聊的核心内容:

1. Chain-of-Thought 是推理的起点。一句”让我们一步步思考”,就能让模型从”直觉式回答”切换到”推理式回答”。原理虽然简单,但它揭示了一个深刻的洞察:LLM 的能力瓶颈往往不在知识量,而在推理方式

2. 高级推理策略各有适用场景。Self-Consistency 通过”多数投票”降低随机错误,Tree of Thoughts 通过”树状搜索”探索多个方向,Reflexion 通过”自我反思”修正推理错误。在生产环境中,根据问题复杂度动态选择策略是最优解。

3. 推理模型是推理能力的范式转移。o1/o3、DeepSeek-R1 等模型把推理能力内化到了模型架构中,不再依赖 Prompt 技巧。但它们也有成本高、延迟不可控、推理过程不透明等局限。

4. 推理是 Agent 所有能力的底层基座。记忆需要推理来筛选信息,工具调用需要推理来选择策略,规划本身就是推理的一种形式。提升 Agent 的推理能力,就是在提升它的”智商”。

在实际开发中,建议采用分级推理架构:简单问题直接回答,中等问题用 CoT,复杂问题用推理模型。配合 可观测性 监控推理链路的 token 消耗和延迟,配合 评估体系 持续优化推理策略的准确率。

推理能力是 AI Agent 从”能用”到”好用”的关键跨越。当你的 Agent 不再是”凭直觉猜答案”,而是”想清楚再回答”时,它才能真正胜任生产环境中的复杂任务。