讲讲 Agent 的反思机制?为什么要用反思?具体怎么实现?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. 本质理解:不光考你 "反思" 是啥,还得说清楚它到底在 Agent 哪个环节起作用,跟 ReAct、CoT 这些概念是什么关系。
  2. 实践深度:反思机制几条主流实现路线(Self-RefineReflexionReAct + Reflection)你心里有没有数?各自适合什么场景,代价在哪?
  3. 工程权衡:反思要烧 Token、要等延迟,面试官想看你懂不懂什么时候该反思、什么时候不该,而不是无脑套模板。

核心答案

反思(Reflection)说白了就是:Agent 干完一件事之后,先停下来回头看一眼自己的输出,自己给自己当评审,发现问题再改、再试,别闷头一条道走到黑。

为什么要反思?一句话:LLM 不是一次就能答对的,但绝大多数错误它自己能看出来。你写代码的时候是不是经常 review 一眼就能发现 bug?Agent 也一样,差的就是这一眼。

常见的三种反思落地方式:

模式 核心思路 反馈来源 典型场景
Self-Refine 自己生成 → 自己批评 → 自己修订 LLM 自评 文案润色、代码生成
Reflexion 执行 → 环境反馈 → 语言化反思 → 记入记忆 → 下一轮改进 环境反馈(工具结果/报错) 工具调用、代码执行、Agent 多轮试错
ReAct + Reflection Thought-Action-Observation 循环 + 失败后反思重规划 Observation + 反思 复杂多步推理任务

深度解析

一、为什么 Agent 一定要有反思机制?

先说个真实场景。我之前给一个客户做代码生成 Agent,第一版没加反思,让 LLM 直接生成 SQL,结果经常出现表名拼错、字段名瞎编的情况。后来加了一层 "反思 + 重试",让 LLM 自己拿着数据库 schema 再 review 一遍生成的 SQL,错误率直接降了 60% 以上。

反思机制主要解决 LLM 这几个老大难问题:

  • 幻觉问题:LLM 会一本正经地胡说八道,生成不存在的 API、错误的参数。一次生成很难发现,但回头 review 时往往能挑出来
  • 长程任务容易跑偏:复杂任务需要多步推理,中间任何一步错了,后面全跟着错。反思相当于在每步后面加了个 "校验点"
  • 不会从失败中学习:传统 Agent 错了就错了,下次遇到类似问题还会错。Reflexion 把反思写进记忆,相当于 "吃一堑长一智"

这一点其实跟人特别像。你写完代码会自己 review,做错题会看错在哪,为啥 Agent 就不能?反思机制就是把这个 "自我修正" 的能力搬到了 Agent 身上。

二、反思机制的核心原理:执行-评估-反思-修订 循环

Agent 反思机制流程图
Agent 反思机制流程图

上图就是反思机制的标准循环,关键节点我挨个拆给你看:

  • Actor(执行者):负责实际干活,可以是代码生成、工具调用、写文案。它每次执行时会带上之前的反思记忆
  • Evaluator(评估者):判断这次执行的结果行不行。判断依据可以是 LLM 自评,也可以是外部环境反馈(比如代码跑没跑通、SQL 报没报错、单测过没过)
  • Self-Reflection(自我反思):这一步最要命。别只丢一句 "错了" 完事,得用大白话把 "错在哪、为什么错、下次怎么改" 写清楚。这段文字会进记忆
  • Memory(反思记忆):把反思结论存起来,下次 Actor 执行时带上这段记忆,避免重蹈覆辙

循环结束的条件通常是这几种:执行成功、达到最大重试次数(防止死循环)、Token 预算用完。

三、三种典型反思模式的区别

这块面试官特别爱深挖,我挨个给你说清楚。

1. Self-Refine:最轻量的自我修订

思路最简单,就三步走:Generate(生成)→ Feedback(自我批评)→ Refine(修订)。一个 LLM 自己扮演三个角色。

适合场景:写公众号文章润色、代码风格优化这类 "没有客观对错、但有质量高低" 的任务。

缺点:LLM 自己评自己,容易 "自嗨",明明写得烂也觉得挺好。

2. Reflexion:带环境反馈的强化式反思

这是 Shinn 等人 2023 年提出来的,新就新在两块:外部环境反馈长期反思记忆

它把反馈分成三种:

  • Observation(观察反馈):比如代码执行的 stdout、工具调用的返回值
  • External Critique(外部批评):比如跑单测的结果、linter 报的错
  • Self-Reflection(自我反思):LLM 基于上面两种反馈,生成一段文字总结

关键点在于反思结果会写进一个独立的 Memory,下一轮重试时 Prompt 里会带上 "上一轮你犯了 XX 错,这次要注意"。

适合场景:HumanEval 这类编程任务、ALFWorld 这类决策任务,效果比裸 ReAct 提升很明显。

3. ReAct + Reflection:推理行动循环 + 失败反思

ReAct 本身是 Thought → Action → Observation 的循环,毛病在于一旦走错路,会顺着错路一路走到底。加了 Reflection 之后,相当于在循环外面套了一层:连续失败 N 次就停下来,反思一下整体策略再重新规划。

这其实就是 Andrew Ng 在《Agentic Design Patterns》里讲的反思模式落地形态。

四、Java 代码实现(Spring AI 版)

这块我直接给你上一段能跑的生产级代码,用的是 Spring AI,思路是把反思做成一个可复用的循环。

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class ReflexionAgent {

    private final ChatClient chatClient;

    // 最大反思重试次数,防止死循环烧 Token
    private static final int MAX_ITERATIONS = 3;

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

    /**
     * 执行带反思机制的任务
     * 循环:生成 -> 执行/验证 -> 反思 -> 携带记忆重试
     */
    public String executeWithReflection(String task, List<Message> context) {
        // 反思记忆,跨轮次保留
        StringBuilder reflectionMemory = new StringBuilder();
        String lastResult = "";

        for (int i = 0; i < MAX_ITERATIONS; i++) {
            // 第 1 步:Actor 执行任务(带上历史反思记忆)
            String result = generate(task, reflectionMemory.toString(), context);
            lastResult = result;

            // 第 2 步:Evaluator 评估结果是否合格
            // 这里可以换成真正的工具执行结果,比如跑 SQL、执行代码
            EvaluationResult eval = evaluate(task, result);

            if (eval.isPassed()) {
                return result; // 通过评估,直接返回
            }

            // 第 3 步:Self-Reflection 生成反思
            String reflection = selfReflect(task, result, eval.getFeedback());
            reflectionMemory.append("【第 ").append(i + 1).append(" 轮反思】")
                           .append(reflection).append("\n\n");

            // 第 4 步:带着反思记忆进入下一轮重试
        }
        return lastResult; // 重试次数用尽,返回最后一次结果
    }

    /**
     * Actor:生成结果,带上反思记忆避免重复犯错
     */
    private String generate(String task, String reflectionMemory, List<Message> context) {
        String systemPrompt = """
            你是一个任务执行 Agent。
            请基于以下要求完成任务。
            %s
            """.formatted(
                reflectionMemory.isBlank() ? "" :
                "【历史反思,请避免重复犯错】\n" + reflectionMemory
            );

        return chatClient.prompt()
                .system(systemPrompt)
                .user(task)
                .messages(context)
                .call()
                .content();
    }

    /**
     * Evaluator:评估结果质量
     * 实际项目中建议换成可执行验证(如编译、单测、SQL 执行)
     */
    private EvaluationResult evaluate(String task, String result) {
        String evalPrompt = """
            你是一个严格的评审专家。
            任务:%s
            待评审结果:%s
            请判断结果是否合格,返回 JSON:
            {"passed": true/false, "feedback": "具体问题说明"}
            """.formatted(task, result);

        String evalResult = chatClient.prompt()
                .user(evalPrompt)
                .call()
                .content();
        // 实际项目用 StructuredOutputConverter 解析 JSON
        return parseEvaluation(evalResult);
    }

    /**
     * Self-Reflection:生成结构化反思
     * 关键:不是 "错了",而是 "错在哪、为什么、下次怎么改"
     */
    private String selfReflect(String task, String result, String feedback) {
        String reflectPrompt = """
            你刚才执行的任务失败了,请认真反思。
            任务:%s
            你的输出:%s
            环境反馈:%s
            请用一段话总结:错在哪里、为什么会错、下次应该怎么做才能避免。
            """.formatted(task, result, feedback);

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

    private EvaluationResult parseEvaluation(String json) {
        // 简化实现,实际用 JSON 库解析
        boolean passed = json.contains("\"passed\": true");
        return new EvaluationResult(passed, json);
    }

    record EvaluationResult(boolean isPassed, String getFeedback) {}
}

说明:这里评估器和反思器都用了 LLM 自评,生产环境强烈建议把 Evaluator 换成可执行的客观验证,比如代码就真的编译跑一下、SQL 就真的去 EXPLAIN 一下、回答就真的去对一下知识库。LLM 自评容易 "护短",客观反馈才是反思机制真正发挥威力的关键。

五、用 LangChain4j 实现更轻量的 Self-Refine

如果不需要那么重的反思记忆,LangChain4jAiServices 配合自定义 Prompt 就能搞定一个轻量版:

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.service.AiServices;

public class SelfRefineDemo {

    interface Generator {
        @SystemMessage("你是一个专业的文案撰写助手,根据要求生成内容。")
        String generate(@V("task") String task, @V("reflection") String reflection);
    }

    interface Critic {
        @SystemMessage("""
            你是一个严格的文案评审。
            指出以下文案的问题,给出具体修改建议。
            如果没有明显问题,返回 "PASS"。
            """)
        String critique(@V("content") String content);
    }

    public String refine(String task) {
        Generator generator = AiServices.builder(Generator.class)
                .chatLanguageModel(OllamaChatModel.builder().build())
                .build();
        Critic critic = AiServices.builder(Critic.class)
                .chatLanguageModel(OllamaChatModel.builder().build())
                .build();

        String content = generator.generate(task, "");
        for (int i = 0; i < 3; i++) {
            String feedback = critic.critique(content);
            if ("PASS".equals(feedback)) {
                break;
            }
            content = generator.generate(task, "上一版问题:" + feedback);
        }
        return content;
    }
}

六、生产环境的坑和最佳实践

这块是我踩过的真实坑,面试时说出来绝对是加分项:

坑 1:无限反思烧 Token

反思不收敛是个大问题,LLM 可能会陷入 "改了又改" 的死循环。必须设置最大重试次数,再加一个 Token 预算上限,超了直接返回当前最优结果。

坑 2:LLM 自评护短

让一个 LLM 评自己,它多半会给好评。要么用更强的模型来评,要么直接上客观环境反馈(编译、单测、SQL 执行结果)。Reflexion 论文效果好,关键就靠环境反馈,不是让 LLM 自己评自己。

坑 3:反思记忆污染上下文

反思记忆越来越长,会把上下文撑爆,还可能把早期错误的结论带偏后续判断。生产实践里建议只保留最近 N 条反思,或者做反思的总结而不是堆叠全部。

坑 4:不是所有任务都该反思

简单任务加反思纯属浪费 Token。反思适合那种 "一次做不对、但反馈明确的复杂任务",比如代码生成、SQL 生成、数学推理。简单问答类加了反而拖慢响应。

最佳实践一句话总结:客观反馈 > LLM 自评,有界循环 > 无限反思,按需启用 > 全局开启。

面试高频追问

  1. 反思机制和 ReAct 是什么关系?

    ReAct 是 "边推理边行动",本身就带 Observation 反馈,但它不会主动总结失败经验。Reflection 是在 ReAct 基础上加了 "失败后停下来反思总结" 的能力,可以理解为 ReAct 的增强版。

  2. 反思和 RLHF、Fine-tuning 有什么区别?

    反思是 推理时(inference-time) 的自我修正,不动模型权重;微调和 RLHF 是 训练时(training-time) 的优化,改的是模型参数。反思即用即生效、零成本上线,但解决不了模型本身能力的天花板;微调是治本但要花钱花数据。

  3. 反思机制会不会反而让结果变差?

    会,这种情况叫 "过度反思"。LLM 可能本来答对了,反思一通反而改错了。论文里也有讨论。所以评估器要尽量客观,重试次数要有上限。

  4. 反思和 Tree of Thoughts(ToT)啥区别?

    ToT 是 "同时探索多条路径再选最优",是广度搜索;反思是 "一条路走错了回头总结再走",是深度迭代。两者可以结合,比如 Reflexion 的反思配上树搜索效果更好。

常见面试变体

  • "你了解哪些 Agent 设计模式?"(反思是 Andrew Ng 总结的四大模式之一,另外三个是工具使用、规划、多智能体协作)
  • "Agent 生成结果不准,你怎么优化?"(反思是标准答案之一,配合 RAG、Prompt 优化一起说)
  • "讲讲 Reflexion 这篇论文的核心思想?"(直接考论文,重点说环境反馈 + 语言化反思记忆)

记忆口诀

反思四步走:执行 → 评估 → 反思 → 重试。两个关键:客观反馈比自评靠谱,反思记忆比单次重试更值钱。

总结

反思机制说白了就是给 Agent 装了个 "自我纠错" 的刹车,核心是 执行-评估-反思-修订 这个闭环。面试时把 Self-RefineReflexionReAct + Reflection 三种模式讲清楚,再带点 "客观反馈优先、有界循环防失控" 的生产经验,这块基本就稳了。