LangGraph多智能体实战:循环反思机制与死循环熔断怎么设计

单 Prompt 梭哈解决不了长流程业务:复杂任务需要拆解,错误需要反馈环,上下文需要裁剪。解法是「规划者-执行者-审查者」三角色状态机,但一旦引入循环,死循环风险就跟着来了——审查者永远不满意,或者模型陷进逻辑死胡同,API 账单指数级暴涨。这篇讲怎么在 Java 技术栈里把循环反思和熔断降级一起做进生产。

为什么不用 Python 版 LangGraph

LangChain4j 加自定义状态机引擎,就能实现一套轻量、线程安全的 StateGraph:共享状态(State)、节点(Node)、路由器(Router)、熔断器(Circuit Breaker)四件套。对 Java 团队来说,不必为一套编排模式引入第二门语言的运行时。

三方案对比:

维度 单 Prompt 线性 Chain 状态机
控制流 不可控 线性无回头 有向有环,条件分支+循环
错误自愈 无 无 Reviewer 提供反思反馈
上下文控制 极差 随步骤线性累积 各节点只看自己需要的字段
死循环风险 无 无 有,靠步数熔断兜住

核心实现:三个节点加一个熔断器

环境基准:Java 17、Spring Boot 3.2.x、LangChain4j 0.30.0。

共享状态用标准 POJO 承载,带熔断计数器:

@Data
@Builder
public class AgentState {
    private String taskId;         // 任务唯一ID
    private String taskInput;      // 原始输入任务
    private String plan;           // Planner 生成的步骤规划
    private String currentDraft;   // Executor 生成的当前草稿
    private List<String> feedbacks;// Reviewer 历史反馈记录
    private boolean isApproved;    // 是否通过审查
    private int currentStep;       // 当前迭代步数(防死循环计数器)
    private boolean isTruncated;   // 是否被熔断器强行截断

    public void addFeedback(String feedback) {
        if (this.feedbacks == null) {
            this.feedbacks = new ArrayList<>();
        }
        this.feedbacks.add(feedback);
    }
}

三个节点各自独立 System Prompt。规划者拆任务;执行者首跑按规划生成、迭代轮次只针对审查反馈改草稿;审查者被强约束输出 JSON:

String prompt = """
    你是一个严苛的代码质量审查专家。请评估以下草稿是否完全满足原始任务的要求。

    原始任务: %s
    当前草稿: %s

    你必须严格以下列 JSON 格式输出,不要包含任何 markdown 标记或多余字符:
    {
      "approved": true/false,
      "feedback": "如果未通过,请写明具体的修改意见;如果通过,请写 'PASS'"
    }
    """.formatted(state.getTaskInput(), state.getCurrentDraft());

状态机引擎是核心,调度加熔断都在这:

@Service
public class StateGraphExecutor {

    private final PlannerNode plannerNode;
    private final ExecutorNode executorNode;
    private final ReviewerNode reviewerNode;

    // 生产级安全阀:最大允许迭代审查次数
    private static final int MAX_RECURSION_LIMIT = 3;

    public StateGraphExecutor(PlannerNode plannerNode, ExecutorNode executorNode, ReviewerNode reviewerNode) {
        this.plannerNode = plannerNode;
        this.executorNode = executorNode;
        this.reviewerNode = reviewerNode;
    }

    public AgentState startWorkflow(String taskInput) {
        AgentState state = AgentState.builder()
                .taskId(UUID.randomUUID().toString())
                .taskInput(taskInput)
                .feedbacks(new ArrayList<>())
                .currentStep(0)
                .isApproved(false)
                .isTruncated(false)
                .build();

        state = plannerNode.execute(state);

        while (!state.isApproved()) {
            // 【死循环熔断检查】
            if (state.getCurrentStep() >= MAX_RECURSION_LIMIT) {
                state.setTruncated(true);
                state.setApproved(true); // 强行终止循环
                break;
            }
            state = executorNode.execute(state);
            state = reviewerNode.execute(state);
        }
        return state;
    }
}

验证反思回路真的在工作

用一个故意带缺陷的任务做回归验证:「写一个 Java 方法计算两个日期之间的天数差,必须考虑时区,不能用第三方库」。

正常通关路径:首轮 Executor 生成了 ChronoUnit.DAYS.between 方案但漏了 ZoneId 转换,Reviewer 判不通过并给出具体反馈,第二轮 Executor 加入 ZonedDateTime 转换后过审。反思回路起作用的判定标准很明确——反馈必须落到具体缺陷上(这里就是时区转换缺失),而不是「质量有待提升」这类空话;如果连续两轮反馈都空泛,说明 Reviewer 的 Prompt 要收紧。

熔断路径用悖论任务验证(「写代码证明 1+1=3」),Reviewer 永远不通过,第三轮触发熔断,返回报文里 isTruncated: true,前端据此提示用户转人工核对。

熔断阈值别拍脑袋定 3 了事,要和 token 预算联动:每轮 Executor 如果全量重写,成本是草稿长度乘轮次的线性累积,上限 3 意味着最坏情况 4 倍单次成本。预算紧的任务把阈值降到 2,并强制 Executor 只输出补丁而非全文重写。

模型选型上还有一层容易忽略的账:三个节点可以用不同档位的模型——规划拆解和反馈判断其实不需要旗舰模型,把预算花在 Executor 的生成质量上更划算。三个节点独立 System Prompt 的设计正好为这种混搭留了口子,改配置就行,不用动代码。温度统一压到 0.2 上下,理由很朴素:编排系统要的是可复现的判定,不是发散的创意。

三个生产级的坑

Token 失控。循环反思最烧钱的是全量重写,每次让 Executor 只改有问题的部分、输出补丁,账单立省一大截。

路由幻觉。Reviewer 偶尔不按格式输出 JSON,字符串解析直接炸。生产环境上强 Schema 约束(JSON Schema 或 Structured Outputs),解析失败降级为「未通过」并记录原文,宁可多跑一轮也不能把没过审的草稿放出去。

状态并发冲突。AgentState 绝不能是 Spring 单例 Bean。方法内局部变量、ThreadLocal 或 Redis,三选一——高并发下状态串了,比死循环还难查。

另外两个细节:模型选性价比款即可(gpt-4o-mini 这一级),温度压到 0.2 保输出格式稳定;REST 接口 /api/agent/run 上记得加异步和超时,状态机一跑几十秒是常态,同步阻塞 Servlet 线程池会被拖垮。上线前把正常通关和触发熔断两条路径的日志各留一份基线,后续每次调整 Prompt 或阈值,重跑这两条路径对比日志,是成本最低的回归手段。

0

评论0

请先
显示验证码
没有账号?注册  忘记密码?