系列文章
本系列持续更新,以下是已发布文章索引:
理解 AI Agent 的大脑:ReAct 模式从入门到实战
AI Agent 的灵魂对话:Prompt Engineering 系统提示词设计的艺术与工程
AI Agent 的规划大脑:从任务分解到自适应执行策略
AI Agent 的工具箱:深入理解 Tool Use 与 Spring AI Function Calling 实战
AI Agent 的记忆系统:从 ChatMemory 到持久化记忆的 Java 实战
AI Agent 的记忆力是怎么实现的——LangChain4j Memory 机制深度解析
MCP 模型上下文协议:AI 的万能接口与 MCP Server 实战
让 AI 学会”说人话”——Spring AI 结构化输出实战
从零理解 RAG:检索增强生成完整指南
Embedding 向量化的魔法:从文本到向量的数学之旅与 Java 实战
AI Agent 的知识检索引擎:从向量搜索到智能检索策略的 Java 实战
当 RAG 遇上知识图谱:GraphRAG 原理与 Java 实战
当 RAG 遇到 Agent:Agentic RAG 的架构设计与 Java 实战
AI Agent 团队协作:多 Agent 系统架构设计与 Java 实战
AI Agent 的安全防线:Prompt 注入防御与生产级安全防护实战
AI Agent 的可观测性:从链路追踪到成本监控的 Java 实战
AI Agent 的评估与优化:从基准测试到生产环境的质量守护实战
AI Agent 的流式响应与实时交互:从 SSE 到 WebSocket 的 Java 实战
Spring AI 核心架构全解析:从 ChatModel 到 Advisor Chain 的设计哲学
AI Agent 的工作流编排:从顺序链到自适应 DAG 的 Java 实战
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 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 思考过程: """ ;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(); } public String thinkStepByStep (String question) { return chatClient.prompt() .user(question + "\n\n让我们一步步思考这个问题,先分析题目,然后列出解题步骤,最后给出答案。" ) .call() .content(); } 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; private static final int SAMPLE_COUNT = 7 ; public SelfConsistencyAgent (ChatClient.Builder builder) { this .chatClient = builder.build(); } 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(); } public ToTResult solveWithTreeOfThoughts (String problem) { List<ThoughtNode> rootChildren = generateThoughts(problem, null , BRANCHING_FACTOR); 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 ); } 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(); } 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) { 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(); } 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; } public String reasonWithOpenAI (String question, ReasoningEffort effort) { return openAIClient.prompt() .user(question) .options(ChatOptions.builder() .model("o3-mini" ) .build()) .call() .content(); } public String reasonWithDeepSeekR1 (String question) { return deepSeekClient.prompt() .user(question) .options(ChatOptions.builder() .model("deepseek-reasoner" ) .temperature(0.6 ) .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) { String cotPrompt = userMessage + "\n\n让我们一步步思考这个问题。" ; AdvisedRequest newRequest = AdvisedRequest.from(request) .withUserText(cotPrompt) .build(); return chain.nextAroundCall(newRequest); } else { return chain.nextAroundCall(request); } } 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 @Component public class TieredReasoningService { private final ChatClient fastModel; private final ChatClient smartModel; private final ChatClient reasoner; 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 @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 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) { 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 @Component public class ReasoningConflictResolver { private final ChatClient judgeClient; public ReasoningConflictResolver (ChatClient.Builder builder) { this .judgeClient = builder.build(); } 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 不再是”凭直觉猜答案”,而是”想清楚再回答”时,它才能真正胜任生产环境中的复杂任务。