第 19 章 · AI 工具循环与条件路由:管住 recursionLimit

[OrCad电路板设计系统].Orcad.Pspice.9.2下载安装 Orcad.Pspice.9.2详细下载安装图文步骤1 安装前准备工作1.1 下载安装包1.2 解压2 安装时步骤2.1 安装文件2.2 破解文件3 安装完成 1 安装前准备工作 1.1 下载安装包 打开百度网盘APP 链接:https://pan.baidu.com/s/1cMFxHUvuh5iEhFVT-lvciQ 提取码:7m65 1.2 解压 解压下载好的安装包 2 安装时步骤 2.1 安装文件 1.点击Setup安装文件,出现警告对话框,告诉你应该关闭所有病毒防火墙,点击确定 2.进入安装界面, 阅读详情

版本:LangGraph4j 1.8.25

目标:搭 agent ⇄ tools 环,用条件边退出;分清业务轮次(rounds)和 recursionLimit(默认 25);会看轨迹、会处理超限。

本章不接模型:用 needTool / rounds 模拟 ReACT 形状。

上图左边是拓扑:START → agent,条件边按 needTool 去 tools 或 END,tools 再回到 agent。右边是本章示例跑完后的轨迹:2 轮工具,进了 5 次业务节点。


19.1 环的边怎么接

对话 Agent 多轮形状是:推理 → 调工具 → 带着结果再推理。画在图上:

边含义
START → agent入口
agent 条件边 → tools 或 END读状态决定下一跳
tools → agent工具跑完,回到推理

条件边返回映射表的 key,再用 mappings 翻成节点 id(或 END):

.addConditionalEdges("agent", edge_async(afterAgent), Map.of(
        "tools", "tools",   // key → 节点 id
        "end", END))        // key → 虚拟终点

EdgeMappings 可以少写重复字符串:

import org.bsc.langgraph4j.utils.EdgeMappings;
​
.addConditionalEdges("agent", edge_async(afterAgent),
        EdgeMappings.builder()
                .to("tools")      // "tools" → "tools"
                .toEND("end")     // "end" → END
                .build())

互斥分支用条件边。同一 source 挂多条无条件边,会扇出成并行。

退出条件放在条件边所读的状态键上(本例是 needTool;接模型时可以是结构化 toolCalls)。条件边只读状态,不解析自然语言凑合判断。

把环画在边上,再用 stream 看轨迹,步数上限由 CompileConfig.recursionLimit 卡住。


19.2 一整段能跑的环

agent 用 rounds 限制最多进几次 tools;tools 只记账。是否收工由 agent 改 needTool,条件边再读这个键。对照上图读。

import static org.bsc.langgraph4j.StateGraph.END;
import static org.bsc.langgraph4j.StateGraph.START;
import static org.bsc.langgraph4j.action.AsyncEdgeAction.edge_async;
import static org.bsc.langgraph4j.action.AsyncNodeAction.node_async;
​
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
​
import org.bsc.langgraph4j.CompileConfig;
import org.bsc.langgraph4j.CompiledGraph;
import org.bsc.langgraph4j.RunnableConfig;
import org.bsc.langgraph4j.StateGraph;
import org.bsc.langgraph4j.action.EdgeAction;
import org.bsc.langgraph4j.action.NodeAction;
import org.bsc.langgraph4j.state.AgentState;
import org.bsc.langgraph4j.state.Channel;
import org.bsc.langgraph4j.state.Channels;
​
public class ToolLoopGraph {
​
    public static class LoopState extends AgentState {
        public static final String NEED_TOOL = "needTool";
        public static final String ROUNDS = "rounds";
        public static final String LOGS = "logs";
​
        public static final Map<String, Channel<?>> SCHEMA = Map.of(
                NEED_TOOL, Channels.base(() -> false),
                ROUNDS, Channels.base(() -> 0),
                LOGS, Channels.appenderWithDuplicate(ArrayList::new)
        );
​
        public LoopState(Map<String, Object> initData) {
            super(initData);
        }
    }
​
    public static void main(String[] args) throws Exception {
        NodeAction<LoopState> agent = state -> {
            int rounds = state.<Integer>value(LoopState.ROUNDS).orElse(0);
            boolean need = state.<Boolean>value(LoopState.NEED_TOOL).orElse(false);
            // rounds 到 2 就收工;否则继续要工具
            if (!need || rounds >= 2) {
                return Map.of(
                        LoopState.NEED_TOOL, false,
                        LoopState.LOGS, List.of("agent:end")
                );
            }
            return Map.of(
                    LoopState.ROUNDS, rounds + 1,
                    LoopState.NEED_TOOL, true,
                    LoopState.LOGS, List.of("agent:call-tools")
            );
        };
​
        NodeAction<LoopState> tools = state -> Map.of(
                LoopState.LOGS, List.of("tools:done")
        );
​
        EdgeAction<LoopState> afterAgent = state ->
                Boolean.TRUE.equals(state.<Boolean>value(LoopState.NEED_TOOL).orElse(false))
                        ? "tools"
                        : "end";
​
        CompiledGraph<LoopState> compiled = new StateGraph<>(LoopState.SCHEMA, LoopState::new)
                .addNode("agent", node_async(agent))
                .addNode("tools", node_async(tools))
                .addEdge(START, "agent")
                .addConditionalEdges("agent", edge_async(afterAgent), Map.of(
                        "tools", "tools",
                        "end", END))
                .addEdge("tools", "agent")
                .compile(CompileConfig.builder()
                        .recursionLimit(25)
                        .build());
​
        var config = RunnableConfig.builder().threadId("loop-1").build();
​
        compiled.stream(Map.of(LoopState.NEED_TOOL, true, LoopState.ROUNDS, 0), config)
                .forEachAsync(out ->
                        System.out.println(out.node() + " → " + out.state().data()))
                .join();
    }
}

接模型时:agent 写出 toolCalls(或布尔 needTool),条件边读该字段;tools 执行调用并把结果写回状态。拓扑不用改。


19.3 轨迹:轮次和步数不是一回事

输入:needTool=true,rounds=0。

顺序节点状态要点下一跳
1agentrounds=1,needTool=true→ tools
2toolslogs 追加 tools:done→ agent
3agentrounds=2,needTool=true→ tools
4tools再记一笔→ agent
5agentrounds >= 2,needTool=false→ END

轨迹:agent → tools → agent → tools → agent → END(与上图右侧一致)。

概念本例谁维护
业务轮次2(rounds 加到 2)状态字段
进业务节点次数5(3×agent + 2×tools)图推进
recursionLimit默认 25,限制运行迭代CompileConfig

粗算:N 轮工具 ≈ 2N+1 次进业务节点(每轮 agent+tools,最后多一次 agent 收工)。因此「最多 8 轮工具」不要写成 recursionLimit(8),上限按步数留余量。


19.4 recursionLimit:设置与超限

CompileConfig.builder()
        .recursionLimit(25)   // 必须 > 0;默认就是 25
        .build();

迭代超过上限时,运行以错误结束,异常信息为:

java.lang.IllegalStateException: Maximum number of iterations (N) reached!

invoke 和 stream 都会撞上。直线图很少碰到 25;有环时要按上面的 2N+1 估。

把 19.2 那张图的 recursionLimit 改成 3,同一输入会触顶:

CompiledGraph<LoopState> tight = new StateGraph<>(LoopState.SCHEMA, LoopState::new)
        .addNode("agent", node_async(agent))
        .addNode("tools", node_async(tools))
        .addEdge(START, "agent")
        .addConditionalEdges("agent", edge_async(afterAgent), Map.of(
                "tools", "tools",
                "end", END))
        .addEdge("tools", "agent")
        .compile(CompileConfig.builder().recursionLimit(3).build());
​
try {
    tight.invoke(Map.of(LoopState.NEED_TOOL, true, LoopState.ROUNDS, 0));
} catch (Exception e) {
    // 根因:IllegalStateException: Maximum number of iterations (3) reached!
    Throwable root = e;
    while (root.getCause() != null) {
        root = root.getCause();
    }
    System.out.println(root.getMessage());
}

超限时先查这三件事:

  1. 映射有没有 "end" → END。

  2. 退出条件会不会一直为真(needTool / toolCalls 从未被清掉,又没有 rounds 上限)。

  3. recursionLimit 是否小于实际需要的步数。

业务「最多几轮」用状态计数;recursionLimit 做图级上限。调大之前用 stream 打印 out.node(),对照轨迹。


19.5 环上的条件路由补充

返回值必须是 mappings 的 key。 afterAgent 返回 "tools" / "end",表里就要有这两项。返回了节点 id 却不在表里,运行会失败。

未知意图落到明确出口。 若条件边还承担意图分流,未知标签应映到 fallback 或 END,不要映到带副作用的 tools。

Command:选路并改状态。 下一跳和改键要一起做时:

import org.bsc.langgraph4j.action.AsyncCommandAction;
import org.bsc.langgraph4j.action.Command;
import org.bsc.langgraph4j.action.CommandAction;
​
CommandAction<LoopState> afterAgentCmd = (state, config) -> {
    boolean need = Boolean.TRUE.equals(
            state.<Boolean>value(LoopState.NEED_TOOL).orElse(false));
    if (need) {
        return new Command("tools");
    }
    return new Command("end", Map.of(LoopState.NEED_TOOL, false));
};
​
// graph.addConditionalEdges("agent",
//         AsyncCommandAction.command_async(afterAgentCmd),
//         Map.of("tools", "tools", "end", END));

节点返回 partial Map、条件边只选路,是更常见的拆法。

同形环:重试 / 反省。 把节点换成 generate 与 critique:critique 的条件边回到 generate,或去 END。退出条件可以是 score 达标,或 retries 用尽。边的接法与本章相同。


19.6 常见错误

现象处理
本想二选一,两个分支都跑了互斥改成 addConditionalEdges
环空转直到触顶查退出条件与 "end" → END;stream 看停在哪
Maximum number of iterations退出边是否生效;或按 2N+1 加大 recursionLimit
条件边运行失败映射漏 key,或返回值与 key 不一致
addNode / 条件边类型不对同步逻辑用 node_async / edge_async
recursionLimit(8) 当 8 轮工具按节点步数估,一轮大约 agent+tools
节点里 while 调模型改成图级环 + 条件边退出

先把无模型的最小环 stream 跑通,确认轨迹和步数,再换成真实的 agent / tools 节点。

《活用数据——驱动业务的数分析实战》读书笔记 (实战篇) 第四章、战略分析案例解析         如思维篇所述,分析思路是从研究目的到研究内容的分解过程。因此需要考虑如下两个问题: 战略分析的研究目的 战略分析的研究内容 1、研究目的:战略选择         战略分析的研究目的是帮助企业进行战略选择,选择适合自己的目标市场。需要回答以下两个问题: 市场吸引力:这个市... 阅读详情

相关推荐

视频倍速 - 在线调倍速的加速器APP工具

一刀工具箱APP提供一键可将手机上的视频倍速播放,可以调整视频倍速的加速器,调节视频的速度也就是调节视频的播放速度!一键可将手机上的视频倍速播放,可以调整视频倍速的加速器,调节视频的速度也就是调节视频的播放速度!视频倍速-在线调倍速的加速器-一刀工具箱APP。...

无涯教程 7558

【项目推荐】基于 SpringBoot3 + Spring AI 的游泳馆管理系统:Agent + RAG + Function Calling 一次学全

它不是玩具 Demo,而是一个「业务 + AI」双主线交织的真实系统——预约业务在跑,AI 客服在旁边实时查库作答,两条线通过 Function Calling、RAG、站内消息串成一体。面试官问「你做过什么 AI 项目」时,你能从业务场景讲到架构取舍,从 RAG 切分参数讲到降级兜底——这和「我调了一下 ChatGPT 的 API」是完全不同的两个段位。项目已包含完整的建表 SQL、初始化数据、部署文档,克隆下来就能跑。获取方式:见文末说明 / 后台回复关键词获取。—— 完 ——

深耕开发,专注编程实战。分享源码解析、项目搭建、问题排查笔记,沉淀技术,持续更新。 347

iphone查看/private/var/mobile/Containers/Data/Application/文件

xcode查看iPhone的private/var/文件夹xcode连接iPhone真机选择app下载Containers文件夹到mac电脑中查看手机中下载的文件 使用xcode真机调试的时候,文件目录都是这种/private/var/mobile/Containers/Data/Application/FAEFDF4D-5CE4-474F-9C53-C19789DB59F6/tmp/ xcode连接iPhone真机 不需要越狱,使用xcode上连接iPhone,然后选择运行的app,选择window-&g

小手琴师的博客 101万+

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 289

拆解爆火AI图文日报!用扣子(Coze)工作流,10分钟实现自动化新闻早报

当用户提供一则新闻内容时,仔细分析新闻中的关键信息。提取新闻事件的核心要点,包括事件主体、发生时间、地点、主要情节等。用简洁的语言对新闻进行总结,控制在[X]字以内(可根据实际需求设定字数限制)。若用户提供多条新闻,对比各新闻之间的异同点。从事件类型、影响范围、发展趋势等方面进行分析。综合总结多条新闻的整体情况,以有条理的方式呈现给用户。

一身都是月 2426

《哥谭神话-工程篇》01.Palantir 平台架构解析-混乱数据如何转化唯一真相源?

Palantir 平台的架构哲学可以概括为将洞察落地为行动,其核心是将“获取唯一真相”能力深度嵌入现有的、复杂的工作流程中,成为提升运营效率和决策质量的倍增器。

897

MCP 2026-07-28 无状态协议大改版:Spring AI 2.1 多轮往返请求与网关路由落地

无状态,所以任何实例都能处理任何请求,扩容不再需要粘性会话;显式句柄,所以跨调用状态是可审计、可过期的,而不是藏在进程内存里;幂等重放,所以交互式中断在分布式环境下也可恢复,代价是你要自己保证副作用可对账;头部路由,所以网关能在不解析 body 的前提下做治理,而校验 header/body 一致性成了新的安全底线。这些没有一个是在发明新概念。它们是分布式系统里被验证过二十年的老手艺:无状态、显式上下文、幂等、网关治理、fail-fast、可观测。

qq_36021478的博客 150

YOLOv11 改进 - 注意力机制 | LS-YOLO MSFE 多尺度特征提取模块:并行分支结构增强多尺度感知,优化遥感与小目标检测

本文介绍了一种用于滑坡检测的模型LS-YOLO及其在YOLOv11中的结合应用。LS-YOLO首先构建多尺度滑坡数据集MSLD,为模型训练提供丰富数据。设计了基于高效通道注意力、平均池化和空间可分离卷积的多尺度特征提取模块MSFE,充分提取滑坡特征信息。在解耦头中采用膨胀卷积增加模型感受野。我们将MSFE模块集成进YOLOv11,替换部分原有模块。实验表明,改进后的YOLOv11在数据集中表现出色 。

魔改工程师的博客 870

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 346

Vue2 - 详细实现接入使用海康威视监控云端显示及控制功能,网站集成安装海康监控及实时监控显示、回放、放大缩小画面、视频画面截图、截屏抓拍、摄像头控制,实时推流及播放器解决延迟卡顿等问题(详细代码)

vue2,nuxt2,海康威视,海康监控,摄像头监控,vue对接海康处理接口认证规则,监控实时预览和回放功能,海康api接口,安全认证,海康开放平台,官方文档,播放海康摄像头的监控视频,海康实时监控播放详细步骤,web,黑屏,特别卡不流畅怎么办,解决无法推流,录像,连接不上,vue,海康,vue海康视频监控,海康开放平台,实时监控画面,海康插件,视频播放,回放,视频流地址,取流协议,视频sdk播放,hik,rtsp,rtmp,hls,ws,网站,网页,h5页面,后台管理系统,vue2对接海康监控设备,无法连

🏆 前端领域优质创作者 8245

YOLOv11 TensorRT极致加速:C++部署性能优化完全指南

购买即可解锁300+YOLO优化文章,并且还有海量深度学习复现项目,价格仅需两杯奶茶的钱,别人有的本专栏也有!

LXY_LOVE36的博客 118

实际工程问题:AI 生成 Spring Cache(@Cacheable / @CachePut / @CacheEvict)缓存注解踩坑

商品详情服务,要求:商品基础信息走缓存,减少 DB 查询;典型:AI 只贴注解,忽略 AOP 代理、key 设计、缓存穿透/击穿/过期、序列化、同步刷新,本地单测正常,上线后缓存脏数据、命中率异常、雪崩。如果业务在事务中,@CacheEvict / @CachePut 如果在事务提交前执行,一旦事务回滚,缓存已经被删掉/更新,数据不一致。• 如果在同一个类里用 this.xxx() 调用带缓存注解的方法,不走代理,缓存直接失效;// 更新商品:先更新 DB,再删除缓存,而不是直接 @CachePut。

2401_89363342的博客 467

优化翼型形状的遗传算法实现

在每一代种群中,通过计算每个个体的适应度值,选择具有较高适应度值的个体,并使用交叉和变异算子对它们进行操作,从而生成新的个体。具体而言,我们将采用一个参数化的翼型模型,其中包括几何设计变量,如角度、弯曲和厚度等,以及性能指标,如升阻比和扭矩等。总之,本文提供了一个基于遗传算法的优化方法,用于寻找最优的翼型形状,并提供MATLAB源代码。需要注意的是,上述代码中的objFunc函数是一个示例性质的目标函数,实际应用中需要根据具体的问题进行修改。1.初始化一个随机的种群,其中每个个体代表一个参数化的翼型模型。

与其临渊羡鱼,不如退而结网 517

SpringBoot 新闻推荐系统:88个Java文件105个接口,首页推荐位是后端按点击数排出来的

# SpringBoot 新闻推荐系统:88个Java文件105个接口,首页推荐位是后端按点击数排出来的 > 这是一套基于 Spring Boot 的新闻推荐系统源码,配套 `db.sql` 建表脚本,业务覆盖新闻发布、排行榜管理、评论回复、点赞点踩、收藏夹和轮播图配置。形态是**前后台双端**:前台是读者用的 layui 静态站,后台是管理员用的 Vue 单页应用(编译产物已嵌在工程里)。最值

面朝大海 252

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Spring 事务详解:@Transactional 如何生效、何时回滚、传播行为怎么选

从订单与库存写入出发,拆解 @Transactional 的代理调用链、默认回滚规则与自调用问题;通过 Spring Boot + H2 的五个验证用例比较 REQUIRED、REQUIRES_NEW、NESTED,并说明数据库事务与 Redis、消息和远程接口的边界。

qq_74421990的博客 306

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 501

Spring Framework 7 HTTP Interface 实战:声明式 RestClient、超时与测试

Spring Framework 7 中,Java 开发者如何使用 HTTP Interface 管理外部服务调用?本文从传统 RestClient 出发,介绍 @HttpExchange、`@GetExchange`、`RestClientAdapter` 和 HttpServiceProxyFactory 的使用方式,并结合商品服务案例说明客户端配置、超时控制、异常处理及 Mock 测试。最后讨论从 RestTemplate、Feign 迁移时的技术取舍,帮助开发者建立更清晰的 HTTP 客户端架构。

代码不止,探索不息 219

基于 Springboot3+SpringAI+Agent+RAG+Function Calling的校园闲置物品循环流转 AI 智能估价平台

基于SpringBoot3+SpringAI1.0,打造校园闲置循环平台,实现从发布、智能估价(规则+大模型校准)、担保交易到信用治理与运营看板的闭环。通过RAG问答、FunctionCalling工具调用、流式SSE输出及本地降级策略,将AI能力深度嵌入业务链路。项目强调可落地性:无APIKey也能演示,向量存MySQL,状态机防绕过,代码清晰可读。适合想做真实AI全栈项目、准备面试或提升工程化思维的开发者。

深耕开发,专注编程实战。分享源码解析、项目搭建、问题排查笔记,沉淀技术,持续更新。 297

SpringBoot「衣依」服装销售平台:144个Java文件180个接口,从挑衣服到收货评价整条链路都在

# SpringBoot「衣依」服装销售平台:144个Java文件180个接口,从挑衣服到收货评价整条链路都在 > 这是一套基于 Spring Boot 的服装销售平台源码,配套 `db.sql` 建表脚本,业务覆盖商品展示、购物车、订单流转、收货地址、订单评价、商品评论、在线客服、轮播图和资讯。形态是**前后台双端**:前台是顾客逛的商城,后台是管理员管的控制台。本文带你看清里面有什么、怎么跑

面朝大海 226

基于SpringBoot的营养食谱管理系统设计与实现-附源码

基于SpringBoot的营养食谱管理系统,实现食谱、食材与营养数据的数字化管理,支持多条件筛选、个性化饮食方案定制及收藏功能,助力用户科学饮食,提升营养师管理效率。系统采用前后端分离架构,技术栈成熟,功能完整,测试验证通过,具备良好可扩展性,未来可集成体质测评、饮食打卡等智能功能。

专注于大学生项目实战开发,讲解,毕业答疑辅导,java就业辅导,高校老师/讲师/同行合作。以及产品测评宣传、工具推广等合作。全网粉丝10w+,平台优质java、小程序创作者。 324

《Springboot3-AOT》

AOT:提前编译 程序执行前,全部被编译成机器码JIT:即时编译 程序边编译边运行编译:源代码 ====== 机器码 机器才能执行。

shuoshuohaohao的博客 209

Spring系列03:Bean 的三种注册方式

写 Spring 的人,几乎天天在「把一个对象交给容器」。@Service标一下、配置类里@Bean写一个、或者丢一堆方法——但它们本质不是一回事。很多开发者能把三种写法都写出来,一被问「@Bean放在@Component和里到底差在哪」「为什么有的@Bean互相调用拿的是同一个实例、有的却 new 了好几个」,就卡壳了。这一篇把三种注册方式的身世、边界,以及那个最容易被忽略的 full/lite 玄机一次讲透。方式一:组件扫描( Stereotype +——类上贴注解,容器扫包自动认。@Bean方法。

liangbo7的博客 207

(开源)宠物共享平台实战指南 基于 Java + SpringBoot + Web + MySQL

这是一个基于 Java + SpringBoot + Vue + MySQL 构建的完整宠物共享平台(管理端为 Vue,用户端为纯静态 Web 站,由后端直接托管),功能持续优化中...用户登录 / 注册 宠物寄养管理 / 寄养审核 寻宠启事管理 / 认领审核 宠物视频管理 / 视频收藏 / 视频留言 感谢信管理 公告管理 轮播图信息管理 基础数据管理 用户管理 / 管理员管理 个人中心 其它...

小小码农身兼魔法师职位!除你武器~ 413

同一需求三套写法:用 Spring AI、LangChain4j、AgentScope Java 各实现一个带工具调用的 RAG 助手(实战对比)

本文以“技术问答助手”为例,对比Spring AI、LangChain4j与AgentScope Java实现RAG+工具调用的三套方案。三者均支持流式输出与知识检索,但风格迥异:Spring AI强调命令式流畅,LangChain4j采用声明式接口,AgentScope则以Agent编排为核心。代码量与心智模型差异显著,适用于单体智能(前两者)或多智能体系统(后者)。最终建议根据项目形态选型,实现从“能用”到“好用”的跃迁。

weixin_43128865的博客 463

第17课:SpringBoot 任务处理:异步任务@Async、定时任务@Scheduled,线程池配置

本文详解Spring Boot 4.x异步与定时任务的实战应用,聚焦虚拟线程带来的范式变革。基于Java 21+,@Async默认使用高效虚拟线程,大幅提升IO密集型任务吞吐量;@Scheduled支持动态配置与多任务并发。重点讲解线程池自定义、异常处理、上下文传递、cron表达式及生产级排查技巧,结合AOP代理与源码分析,构建高可用任务体系。

Java 后端|Python|AI 实战博主。专注微服务、分布式、大模型应用开发,输出可落地项目、源码剖析与面试总结。用通俗文字拆解技术难点,记录开发路上的学习与踩坑,期待和大家一起交流成长。 353

注解与 Spring 核心注解

注解仅为元数据,需被代码读取才生效。Spring核心注解如@Component、@Autowired、@Configuration等依赖反射机制在运行期被容器解析,若类未被扫描、对象非容器管理或方法未被代理,注解将失效。关键点:注解本身不执行逻辑,真正起作用的是读取它的代码是否执行。正确使用@Retention(RUNTIME)、合理选择@Component与@Bean、理解@Autowired与@Resource匹配差异,是避免“注解没反应”的核心。

2401_89855466的博客 164

Maven 聚合工程实读:10 个模块混用 Spring 2.0.8 与 3.0.5、Struts 1 与 2,我是怎么把账算清的

一个真实企业 Maven 聚合工程实读:10 个模块、86656 行 Java、6 个 war,同一 reactor 里混用 Spring 2.0.8 与 3.0.5、Struts 1.2.6 与 2.2.1,四个 war 各抄一份 Spring 配置,src/test 全空。我逐个模块统计打包方式、框架版本、配置对应关系,列出可低成本动手的三件事:路由对应测试、构建可重复性、配置去重。

qq_28884591的博客 331
上一篇: 第 18 章 · 跑通 AI 图:CompiledGraph 的 compile、invoke、stream
下一篇: 第 20 章 · AI 流式输出与异步调度:别堵死线程
AI深栈
博客等级 码龄14年 1粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值