Prompt高级推理:COT思维链、Self-Consistency与ReAct模式实战

导读 :在与大模型交互的过程中,简单的"一问一答"往往难以胜任复杂的推理任务。本文将深入介绍三种提升大模型推理能力的核心技术------思维链(Chain of Thought, COT)自我一致性(Self-Consistency)ReAct 模式。从"让模型先想再答"的基本思路,到"多次采样投票取最优"的暴力美学,再到"推理与行动交织"的 Agent 底层逻辑,逐步带你掌握 Prompt 高级推理的完整技能树。


一、思维链 COT:让模型先想再答

1.1 什么是思维链?

思维链(Chain of Thought,简称 COT)的核心思想非常直观:强制让模型在输出最终答案之前,先把推理过程写出来

举个简单的例子:

小明有 5 个苹果,给了小红 2 个,又从超市买了 3 个,后来发现有 1 个烂了。请问小明现在有几个苹果?

人类的大脑会自动进行分步计算:5 - 2 + 3 - 1 = 5。但没有思维链的大模型可能会"凭感觉"直接给出一个数字,准确率难以保证。

1.2 为什么 COT 有效?

大模型生成 Token 是一个自回归过程------后面的 Token 依赖前面已生成的内容。当模型先写出:

  • 步骤 1:5 - 2 = 3
  • 步骤 2:3 + 3 = 6
  • 步骤 3:6 - 1 = 5

再生成最终答案时,答案的生成依赖于前面正确的推理链路,整体准确率自然就提升了。这就好比考试时要求你"写出解题过程"------过程对了,答案大概率不会错。

1.3 Zero-Shot COT:一句话激活思维链

最简单的使用方式,不需要给任何示例,只需在 Prompt 末尾加上一句"魔法咒语":

复制代码
请一步一步思考。

示例对比

不加 COT 的 Prompt:

复制代码
一个项目有三名开发,每人每天完成两个功能点,项目共60个功能点,
其中20%需要双人协作完成,完成项目需要多少天?

加上 COT 的 Prompt:

复制代码
一个项目有三名开发,每人每天完成两个功能点,项目共60个功能点,
其中20%需要双人协作完成,完成项目需要多少天?
让我们一步一步思考。

加上 COT 后,模型会自动拆解:先计算单人功能点数,再计算协作功能点的耗时,最后汇总得出正确的总天数。

常用的 COT 触发语句包括:

  • 让我们一步一步思考
  • 请先分析再给出结论
  • 请展示你的推理过程
  • Think step by step

1.4 Few-Shot COT:用示例教会模型推理

当零样本效果不够理想时,可以通过提供带推理过程的示例来引导模型学习思考模式。

以"判断代码是否存在并发安全问题"为例,我们项目中的 code-review.st 模板(位于 prompt/src/main/resources/prompts/code-review.st)就使用了类似的思路:

复制代码
请 review 以下 {language} 代码:

{code}

检查重点:
1. 空指针和异常处理
2. 性能问题(循环、IO、数据库查询)
3. 并发安全
4. 资源释放(IO流、连接等)
5. 代码可读性

对每个问题:标注【严重程度】,说明原因,给出修复示例。

CodeReviewServicecom.jichi.prompt.service.CodeReviewService)中,我们通过 PromptTemplate 加载这个模板,并结合 System Message 引导模型按 COT 风格逐步分析:

复制代码
@Service
public class CodeReviewService {

    private final DashScopeChatModel chatModel;

    @Value("classpath:prompts/code-review.st")
    private Resource codeReviewPromptResource;

    public CodeReviewService(DashScopeChatModel chatModel) {
        this.chatModel = chatModel;
    }

    public String review(String code, String language) {
        PromptTemplate pt = new PromptTemplate(codeReviewPromptResource);
        String userPrompt = pt.render(Map.of(
                "language", language,
                "code", code
        ));

        return chatModel.call(new Prompt(
                List.of(
                        new SystemMessage("""
                                你是一个资深工程师,专注代码质量。
                                找出 Bug、性能问题和最佳实践违反,每个问题标注严重程度。
                                """),
                        new UserMessage(userPrompt)
                )
        )).getResult().getOutput().getText();
    }
}

通过 System Message 中"找出 Bug、性能问题和最佳实践违反,每个问题标注严重程度"的指令,模型会按照"操作拆解 -> 场景分析 -> 风险判断"的链路来逐一分析。

1.5 COT + 结构化输出:推理完毕打包带走

在实际工程中,我们往往需要模型先推理,再输出结构化的结果 ,以便程序直接消费。在项目中,BugAnalysisControllercom.jichi.prompt.controller.BugAnalysisController)就是一个典型案例:

复制代码
@RestController
@RequestMapping("/api/bug")
public class BugAnalysisController {

    private final ChatClient chatClient;

    public BugAnalysisController(DashScopeChatModel chatModel) {
        this.chatClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一个资深 Java 工程师,擅长 bug 分析。
                        分析代码时,先推理出 bug 类型和根因,再填写结构化结论。
                        不确定的字段填 null。
                        """)
                .build();
    }

    record BugAnalysis(
            String bugType,
            String rootCause,
            List<String> affectedScenarios,
            String severity,
            String fix
    ) {}

    @PostMapping("/analyze")
    public BugAnalysis analyzeBug(@RequestBody String code) {
        return chatClient.prompt()
                .user("分析这段代码的 bug:\n\n" + code)
                .call()
                .entity(BugAnalysis.class);
    }
}

注意 System Prompt 中的关键语句:"先推理出 bug 类型和根因,再填写结构化结论"------这就是 COT 与结构化输出的结合。模型会先进行推理分析,然后输出类似这样的结构化结果:

复制代码
{
  "bugType": "并发安全问题",
  "rootCause": "count++ 不是原子操作,多线程下会产生数据竞争",
  "affectedScenarios": ["高并发计数", "多线程累加"],
  "severity": "HIGH",
  "fix": "使用 synchronized 关键字或 AtomicInteger 替代 int 类型"
}

Spring AI 的 .entity(BugAnalysis.class) 会自动将模型的 JSON 输出反序列化为 Java Record,非常适合在企业内部构建代码审核助手

1.6 COT 的适用场景与局限

适合使用 COT 的场景:

场景 原因
数学逻辑计算 需要中间步骤保证准确性
代码 Bug 分析 需要追踪执行路径
法律/合同分析 需要逐条审查条款
需求分析与拆解 需要先拆分再逐一评估
复杂决策 需要衡量多个因素

不适合使用 COT 的场景:

  • 简单翻译、简单分类
  • 纯创意写作
  • 追求极致响应速度的场景

需要注意的是,COT 会增加 Token 消耗。只有在对准确率有较高要求的场景下,才值得开启思维链。

1.7 内置思考模式:COT 的进化

如今主流模型已经将 COT 能力内置到模型内部 ,无需在 Prompt 中显式要求。在项目的 ThinkingControllercom.jichi.prompt.controller.ThinkingController)中,我们通过开启 enableThinking 参数来使用内置思考模式:

复制代码
@RestController
@RequestMapping("/api/thinking")
public class ThinkingController {

    private final DashScopeChatModel chatModel;

    public ThinkingController(DashScopeChatModel chatModel) {
        this.chatModel = chatModel;
    }

    @GetMapping("/qwen3")
    public String deepAnalysis(@RequestParam String question) {
        return chatModel.call(new Prompt(
                new UserMessage(question),
                DashScopeChatOptions.builder()
                        .withModel("qwen3-235b-a22b")  // Qwen3 支持思考模式的模型
                        .withEnableThinking(true)       // 开启内置思考模式
                        .build()
        )).getResult().getOutput().getText();
    }
}

内置思考模式与手动 COT 的区别在于:手动 COT 的推理过程会出现在普通输出中,而内置思考模式(withEnableThinking(true))的推理过程对用户不可见,但效果通常更好。


二、Self-Consistency:多次推理取最优答案

2.1 核心思想:一次算不对,多算几次

Self-Consistency(自我一致性)是一种"稍显暴力但效果极佳"的技术。其核心逻辑非常朴素:

同一个问题让模型推理多次,然后取出现次数最多的答案------多数投票机制。

这就好比十个人做同一道数学题,八个人得出的答案都是 5,另外两个人分别算出 6 和 7,那我们有充分理由相信 5 是正确答案。

2.2 原理解析

大模型每次生成时本身带有一定的随机性(由 temperature 参数控制)。对同一个问题多次采样时:

  • 正确答案倾向于在多次采样中反复出现
  • 错误答案通常具有随机性,难以重复

因此,通过统计出现频率最高的答案,就能有效排除偶然的推理错误。

关键参数temperature 必须大于 0,否则每次输出完全相同,多次采样就失去了意义。

2.3 基础实现:并行采样 + 投票

项目中的 SelfConsistencyServicecom.jichi.prompt.service.SelfConsistencyService)完整实现了这个模式:

复制代码
@Service
public class SelfConsistencyService {

    private final DashScopeChatModel chatModel;

    public SelfConsistencyService(DashScopeChatModel chatModel) {
        this.chatModel = chatModel;
    }

    /**
     * Self-Consistency:采样 N 次,多数投票
     *
     * @param question    问题
     * @param sampleCount 采样次数(建议 3-7 次)
     * @return 出现最多的答案
     */
    public String query(String question, int sampleCount) throws Exception {
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

        // Self-Consistency 需要 temperature > 0,否则每次输出相同,没有意义
        DashScopeChatOptions options = DashScopeChatOptions.builder()
                .withTemperature(0.7)
                .build();

        List<CompletableFuture<String>> futures = new ArrayList<>();
        for (int i = 0; i < sampleCount; i++) {
            futures.add(CompletableFuture.supplyAsync(
                    () -> chatModel.call(new Prompt(
                            new UserMessage(question + "\n\n让我们一步一步思考。"),
                            options
                    )).getResult().getOutput().getText(),
                    executor));
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .get(60, TimeUnit.SECONDS);

        List<String> answers = futures.stream()
                .map(f -> {
                    try { return f.get(); }
                    catch (Exception e) { return null; }
                })
                .filter(Objects::nonNull)
                .toList();

        return majorityVote(answers);
    }

    private String majorityVote(List<String> answers) {
        return answers.stream()
                .collect(Collectors.groupingBy(a -> a, Collectors.counting()))
                .entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(answers.get(0));
    }
}

实现要点

  1. 使用 Executors.newVirtualThreadPerTaskExecutor() 创建虚拟线程池并行发起请求,避免串行等待
  2. 每次请求的 Prompt 末尾追加 "\n\n让我们一步一步思考。",结合 COT 提升单次推理质量
  3. temperature 设为 0.7 保证每次采样的多样性
  4. majorityVote 方法对所有结果进行 groupingBy 统计,取频次最高的作为最终答案
  5. 设置 60 秒超时,防止个别请求拖住整体

对应的 Controller 暴露了 REST 接口,默认采样 5 次:

复制代码
@RestController
@RequestMapping("/self-consistency")
public class SelfConsistencyController {

    private final SelfConsistencyService selfConsistencyService;

    public SelfConsistencyController(SelfConsistencyService selfConsistencyService) {
        this.selfConsistencyService = selfConsistencyService;
    }

    @GetMapping("/query")
    public String query(@RequestParam String question,
                        @RequestParam(defaultValue = "5") int sampleCount) throws Exception {
        return selfConsistencyService.query(question, sampleCount);
    }
}

2.4 结构化输出 + 自我一致性

在实际业务中,往往需要对结构化结果进行多次采样后聚合。项目中的 ContractAnalysisServicecom.jichi.prompt.service.ContractAnalysisService)完整展示了这个模式------合同风险分析场景。

首先定义结构化输出模型,使用 Java Record + 枚举:

复制代码
// com.jichi.prompt.enums.Verdict
public enum Verdict { YES, NO, UNCERTAIN }

// com.jichi.prompt.entity.ContractRisk
public record ContractRisk(
    Verdict hasRisk,
    String riskType,
    int severity   // 1-10
) {}

然后在 ContractAnalysisService 中实现多次采样 + 聚合:

复制代码
@Service
public class ContractAnalysisService {

    private final DashScopeChatModel chatModel;
    private final BeanOutputConverter<ContractRisk> converter;

    public ContractAnalysisService(DashScopeChatModel chatModel) {
        this.chatModel = chatModel;
        this.converter = new BeanOutputConverter<>(ContractRisk.class);
    }

    public ContractRisk analyzeWithConsistency(String clause) throws Exception {
        int sampleCount = 5;
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

        DashScopeChatOptions options = DashScopeChatOptions.builder()
                .withTemperature(0.5)
                .build();

        String userContent = "分析这个合同条款:\n" + clause
                + "\n\n请先逐步分析,再给出结论。\n\n" + converter.getFormat();

        List<CompletableFuture<ContractRisk>> futures = new ArrayList<>();
        for (int i = 0; i < sampleCount; i++) {
            futures.add(CompletableFuture.supplyAsync(() -> {
                String raw = chatModel.call(new Prompt(
                        List.of(
                                new SystemMessage("你是合同法律顾问,分析合同条款是否存在法律风险。先思考,再给出结论。"),
                                new UserMessage(userContent)
                        ),
                        options
                )).getResult().getOutput().getText();
                return converter.convert(raw);
            }, executor));
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .get(60, TimeUnit.SECONDS);

        List<ContractRisk> results = futures.stream()
                .map(f -> { try { return f.get(); } catch (Exception e) { return null; } })
                .filter(Objects::nonNull)
                .toList();

        return aggregateResults(results);
    }

聚合逻辑是 Self-Consistency 与结构化输出结合的关键------对不同字段分别采用投票和取均值策略:

复制代码
    private ContractRisk aggregateResults(List<ContractRisk> results) {
        // 1. 风险判定投票:统计 YES 和 NO 的次数,多数决定最终结论
        long yesCount = results.stream().filter(r -> r.hasRisk() == Verdict.YES).count();
        long noCount = results.stream().filter(r -> r.hasRisk() == Verdict.NO).count();
        Verdict majorityVerdict = yesCount >= noCount ? Verdict.YES : Verdict.NO;

        // 2. 风险等级取均值:对多数派结果的严重程度取平均
        double avgSeverity = results.stream()
                .filter(r -> r.hasRisk() == majorityVerdict)
                .mapToInt(ContractRisk::severity)
                .average()
                .orElse(5.0);

        // 3. 风险类型聚合:统计出现频率最高的风险类型
        String topRiskType = results.stream()
                .filter(r -> r.hasRisk() == majorityVerdict)
                .map(ContractRisk::riskType)
                .filter(Objects::nonNull)
                .collect(Collectors.groupingBy(t -> t, Collectors.counting()))
                .entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse("未知风险");

        return new ContractRisk(majorityVerdict, topRiskType, (int) Math.round(avgSeverity));
    }
}

注意这里使用了 BeanOutputConverter<ContractRisk> 来自动处理模型输出到 Java Record 的转换,converter.getFormat() 会在 Prompt 中追加 JSON Schema 格式说明,引导模型输出符合规范的 JSON。

2.5 置信度评估

多次采样还带来一个额外好处------可以计算置信度

复制代码
置信度 = 最高票答案出现次数 / 总采样次数

例如 5 次采样中有 4 次得出 Verdict.YES(有风险),则置信度为 80%。

在生产环境中,可以设置置信度阈值:

  • 置信度 >= 80%:直接采信结果
  • 置信度 60%-80%:标记为"建议人工复核"
  • 置信度 < 60%:触发人工审核流程

这种机制避免了将不确定的结果直接推送给用户。

2.6 成本权衡

Self-Consistency 本质是用N 倍的 API 费用换取更高的准确率,因此需要根据场景权衡:

场景类型 是否值得使用 说明
合同审查、安全检测 值得 高准确率要求,错误代价高
关键决策辅助 值得 关键问题值得多花成本
情感分析、内容分类 不值得 低风险场景,成本过高
日常内容生成 不值得 无需高精度
新一代推理模型 不值得 模型本身准确率已足够高,边际收益低

采样次数建议 :3-5 次通常足够,超过 7 次边际收益递减明显。建议选择奇数次,方便投票决胜。项目中 SelfConsistencyController 默认使用 5 次采样。

2.7 与推理模型的关系

Self-Consistency 是 Prompt 层面的技术,不依赖特定模型。但对于已经内置深度推理能力的模型(如 Qwen3-235B 开启 enableThinking),这些模型在内部已经做了类似的"多路径探索",此时再叠加 Self-Consistency 的意义不大。

因此:

  • 普通/快速模型 + Self-Consistency = 性价比之选
  • 推理增强模型 (如 qwen3-235b-a22b + withEnableThinking(true))= 不需要额外加 Self-Consistency

三、ReAct 模式:推理与行动交织

3.1 什么是 ReAct?

ReAct 来自 2022 年的同名论文,全称是 Re asoning + Act ing,即推理与行动的交替执行。它是 Agent 系统中最核心的 Prompt 模式,也是后续 Agent 开发的底层逻辑基础。

与纯 COT 不同,ReAct 的循环模式是:

复制代码
思考(Thought) -> 行动(Action) -> 观察(Observation) -> 思考 -> 行动 -> ... -> 最终答案

COT vs ReAct 的本质区别

  • COT:思考 -> 答案(信息全部来自模型内部知识)
  • ReAct:思考 -> 行动 -> 观察 -> 思考 -> ... -> 答案(可以获取外部实时数据)

3.2 一个直观的例子

用户问:"北京天气怎么样,适合穿什么?"

ReAct 的执行过程:

复制代码
[Thought] 用户问的是北京的实时天气,我需要查询天气数据
[Action]  调用天气工具 getWeather("北京")
[Observation] 返回结果:城市:北京,温度:18°C,天气:晴,风力:3级
[Thought] 18度的晴天,早晚可能偏凉
[Answer] 北京今天晴天,气温 18°C,风力 3 级,建议穿轻薄外套,方便早晚增减。

模型在每一步推理后,判断是否需要调用外部工具获取信息,然后根据工具返回的结果继续推理,直到信息充足后给出最终答案。

3.3 传统 ReAct Prompt 的写法

在框架封装之前,需要手动编写 ReAct 格式的 System Prompt:

复制代码
你是一个智能助手,可以使用以下工具完成任务:

【工具列表】
1. getWeather(city): 查询指定城市的实时天气
2. getStockPrice(symbol): 查询股票实时价格
3. calculate(expression): 计算数学表达式

【工作流程】
1. 先思考(Thought):分析用户问题,判断需要什么信息
2. 再行动(Action):调用合适的工具获取数据
3. 观察结果(Observation):根据工具返回的结果继续思考
4. 重复步骤 1-3,直到收集到足够信息
5. 给出最终答案(Final Answer)

【格式要求】
Thought: <你的思考过程>
Action: <工具名称>(参数)
Observation: <工具返回结果>
... (重复直到完成)
Final Answer: <最终回答>

【注意事项】
- 每次只调用一个工具
- 如果不需要工具就能回答,直接给出 Final Answer

3.4 框架封装:Spring AI 的 ReAct 托管

手动编写 ReAct Prompt 比较繁琐,Spring AI 框架已经将 ReAct 模式进行了封装,自动管理思考-行动-观察的循环。

第一步:定义工具

项目中使用 @Tool@ToolParam 注解定义工具。以下是实际代码(位于 com.jichi.prompt.tools 包下):

复制代码
@Component
public class WeatherTools {

    @Tool(description = "查询指定城市的实时天气,返回温度、天气状况和风力")
    public String getWeather(
            @ToolParam(description = "城市名称,例如:北京、上海") String city) {
        return String.format("城市:%s,温度:18°C,天气:晴,风力:3级", city);
    }
}

@Component
public class StockTools {

    @Tool(description = "查询股票实时价格")
    public String getStockPrice(
            @ToolParam(description = "股票代码,例如:AAPL、600036") String symbol) {
        return String.format("股票代码:%s,当前价格:168.42 USD", symbol);
    }
}

@Component
public class CalculatorTools {

    @Tool(description = "计算数学表达式")
    public String calculate(
            @ToolParam(description = "要计算的数学表达式,例如:(10 + 5) * 3 / 2") String expression) {
        return expression + " = 计算结果(实际应接入表达式求值库)";
    }
}

第二步:注册工具到 ChatClient 并设置 System Prompt

AgentControllercom.jichi.prompt.controller.AgentController)中,通过 defaultTools() 注册工具:

复制代码
@RestController
@RequestMapping("/agent")
public class AgentController {

    private final ChatClient agentClient;

    public AgentController(
            DashScopeChatModel chatModel,
            WeatherTools weatherTools,
            StockTools stockTools,
            CalculatorTools calculatorTools) {

        this.agentClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一个智能助手,可以查天气、查股价、做计算。
                        根据用户问题决定是否需要使用工具,使用工具后结合结果给出准确答案。
                        """)
                .defaultTools(weatherTools, stockTools, calculatorTools)
                .build();
    }

    @GetMapping("/ask")
    public String ask(@RequestParam String question) {
        return agentClient.prompt()
                .user(question)
                .call()
                .content();
    }
}

第三步:直接提问,框架自动处理 ReAct 循环

复制代码
// GET /agent/ask?question=苹果公司(AAPL)的股价折合人民币是多少?
String answer = agentClient.prompt()
        .user("苹果公司(AAPL)的股价折合人民币是多少?")
        .call()
        .content();

Spring AI 在内部自动完成了以下过程:

  1. 发送请求给模型
  2. 模型决定调用 getStockPrice("AAPL") -> 获取美元股价
  3. 模型决定调用 getExchangeRate("USD", "CNY") -> 获取汇率
  4. 模型决定调用 calculate("168.42 * 7.24") -> 计算人民币价格
  5. 模型组织自然语言回复给用户

整个多步推理过程由框架自动托管,开发者只需定义好工具即可。

3.5 金融场景:多工具组合实战

项目中还有一个更专业的金融 Agent 示例------FinanceAgentControllercom.jichi.prompt.controller.FinanceAgentController),使用 FinanceTools 将股票、汇率、计算三个工具合并到一个类中:

复制代码
@Component
public class FinanceTools {

    @Tool(description = "查询股票实时价格")
    public String getStockPrice(@ToolParam(description = "股票代码") String symbol) {
        return symbol + " 当前价格:168.42 USD";
    }

    @Tool(description = "查询货币汇率")
    public String getExchangeRate(
            @ToolParam(description = "源货币代码") String from,
            @ToolParam(description = "目标货币代码") String to) {
        return from + "/" + to + " = 7.24";
    }

    @Tool(description = "计算数学表达式")
    public String calculate(@ToolParam(description = "数学表达式") String expression) {
        return expression + " ≈ 1219.36";
    }
}

@RestController
@RequestMapping("/finance-agent")
public class FinanceAgentController {

    private final ChatClient agentClient;

    public FinanceAgentController(DashScopeChatModel chatModel, FinanceTools financeTools) {
        this.agentClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                        你是一个金融助手,可以查询实时股价、汇率,并做数学计算。
                        遇到需要数据的问题,先调工具获取数据,再给出完整答案。
                        """)
                .defaultTools(financeTools)
                .build();
    }

    @GetMapping("/ask")
    public String ask(@RequestParam String question) {
        return agentClient.prompt()
                .user(question)
                .call()
                .content();
    }
}

ReAct 真正强大之处在于自动串联多个工具调用。查询"苹果公司股价折合人民币是多少"时,模型会自动拆解为三步:

复制代码
Step 1: 调用 getStockPrice("AAPL") -> 获取股价 168.42 USD
Step 2: 调用 getExchangeRate("USD", "CNY") -> 获取汇率 7.24
Step 3: 调用 calculate("168.42 * 7.24") -> 计算得 1219.36
Final Answer: 苹果公司当前股价为 168.42 美元,按当前汇率 1 美元约等于 7.24 人民币,折合约 1219.36 元人民币。

3.6 循环控制

ReAct 理论上可以进行无限次的思考-行动循环,因此在生产环境中务必设置最大循环次数 ,防止死循环导致资源耗尽。在 Spring AI 中可以通过 toolCallingChatOptions 或 Advisor 来限制:

复制代码
ChatClient client = ChatClient.builder(chatModel)
    .defaultTools(tools)
    .build();

// 调用时可通过 ChatOptions 控制最大工具调用轮次
client.prompt()
    .user(question)
    .options(DashScopeChatOptions.builder()
        .withMaxTokens(2048)  // 限制输出长度,间接控制循环
        .build())
    .call()
    .content();

3.7 COT vs ReAct 对比总结

对比维度 COT ReAct
信息来源 模型内部知识 模型知识 + 外部工具/API
适用场景 逻辑推演、数学计算 实时查询、执行动作、多步任务
调用成本 较低(单次调用) 较高(多次 API 交互)
是否需要工具 不需要 需要 @Tool 定义并注册到 ChatClient
典型应用 Bug 分析、合同审查 智能助手、金融查询、自动化操作

四、总结

本文介绍了三种提升大模型推理能力的关键技术,它们形成了一个递进的体系:

  1. COT(思维链) :最基础的推理增强手段。通过强制模型"先推理再回答",利用自回归生成的特性,让后续 Token 依赖前面正确的推理步骤,从而提升复杂问题的准确率。使用门槛极低,一句"让我们一步一步思考"即可激活。在项目中,BugAnalysisController 的 System Prompt 中 "先推理出 bug 类型和根因,再填写结构化结论" 就是 COT 的典型应用。

  2. Self-Consistency(自我一致性) :在 COT 基础上的进一步增强。通过多次并行采样、投票取最优,利用概率统计的力量过滤掉偶然的推理错误。项目中 SelfConsistencyService 使用虚拟线程并行采样 + majorityVote 投票,ContractAnalysisService 则展示了结构化输出场景下的多维度聚合策略。适用于对准确率要求极高的场景(如合同审查、安全检测),但需要权衡 N 倍的 API 成本。

  3. ReAct(推理+行动) :从"纯思考"升级为"思考+行动"。模型不再局限于内部知识,而是可以调用外部工具获取实时信息,并在"思考-行动-观察"的循环中逐步解决问题。项目中 AgentControllerFinanceAgentController 通过 Spring AI 的 ChatClient.defaultTools() 注册 @Tool 注解的工具类,框架自动托管 ReAct 循环,开发者只需关注工具实现。

在实际项目中,这三种技术可以灵活组合:ReAct 的每一步推理都可以使用 COT 来保证质量,而关键决策节点还可以叠加 Self-Consistency 来提升置信度。理解它们的原理和适用边界,才能在不同场景下做出最优选择。

相关推荐
绵满13 小时前
"Natural-Language Agent Harnesses" 论文笔记
大模型·多智能体
大数据AI人工智能培训专家培训讲师叶梓14 小时前
Merlin:面向腹部 CT 的三维视觉语言基础模型
人工智能·计算机视觉·大模型·医疗·ct·视觉大模型·医疗人工智能
guslegend16 小时前
系统整体设计方案
人工智能·大模型·知识图谱
guslegend17 小时前
4月5日(大语言模型训练原理)
人工智能·大模型
一 铭17 小时前
Claude Code实现原理分析-架构设计
人工智能·大模型
handsomestWei17 小时前
OneAPI网关使用简介
ai·大模型·llm·oneapi
行者无疆_ty19 小时前
如何在个人电脑部署大模型实现Token自由
人工智能·大模型·agent
装不满的克莱因瓶19 小时前
Cursor中agent、plan、ask三种模式区别于对比
人工智能·ai·大模型·ai编程·cursor
handsomestWei1 天前
sqlbot智能问数使用简介
ai·大模型·llm·智能问数·sqlbot