Lucaju 的技术笔记
type: channel
link: https://www.lucaju.cn/
description: Java 开发者的自留地
items: 分布式智能体｜A2A Agent实战
items: 吃透 Spring AI Alibaba 多智能体｜四大协同模式+完整代码
items: Agent Skill 踩坑记录 | SpringBoot 打包后 Skill 加载失败问题排查与解决
items: OpenClaw 🦞 还没玩明白，腾讯QClaw又来了？
items: Spring AI Alibaba + MCP：调用MCP市场公开服务实操
items: 一文吃透 Spring AI Alibaba + MCP：服务端搭建 + 客户端调用全流程
items: Agent Skills | Spring Ai Alibaba从零构建可扩展 AI 智能体
items: Spring AI Alibaba 人工介入实战｜Human-in-the-Loop 让 AI 更可靠
items: 使用Spring AI Alibaba构建智能体Agent
items: 大模型“无脑复读”？3分钟搞懂原因+解决办法

分布式智能体｜A2A Agent实战
type: item
date: 2026-04-02T15:55:00+08:00
description: 随着智能体应用的广泛应用，智能体的分布式部署、跨网络、跨框架、跨组织调用，成为当下智能体落地急需解决的问题。针对这一痛点，Google推出了Agent2Agent（简称A2A）协议，专为智能体之间的互联互通、协同协作提供标准化的解决方案。本文基于Spring AI Alibaba框架，使用Nacos作为注册中心，落地完整的分布式智能体方案。整体架构：一、Nacos注册中心安装本次选用的Nacos版本为3.2.0，安装配置流程可参考官方文档，这里不再赘述基础安装步骤。Nacos官方地址：https://nacos.io/二、项目依赖引入使用官方推荐的BOM方式进行依赖管理<dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-bom</artifactId> <version>1.1.2.0</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>1.1.2</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-extensions-bom</artifactId> <version>1.1.2.2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-agent-framework</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-a2a-nacos</artifactId> </dependency> </dependencies> 三、Agent服务注册配置完成依赖引入后，需要将自定义的智能体交由Spring容器管理，同时配置Nacos注册参数，实现智能体的自动注册。1. 配置Bean对象本次以讲笑话的智能体jokeAgent为例@Configuration public class A2AAgentConfig { @Bean(name = "jokeAgent") public ReactAgent jokeAgent() { // 构建通义千问API对象 DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); // 初始化对话模型 DashScopeChatModel chatModel = DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .defaultOptions(DashScopeChatOptions.builder() .model(DashScopeChatModel.DEFAULT_MODEL_NAME) .temperature(0.5) .maxToken(1000) .build()) .build(); // 创建并返回笑话智能体 return ReactAgent.builder() .name("jokeAgent") .model(chatModel) .description("负责讲笑话。") .instruction…

吃透 Spring AI Alibaba 多智能体｜四大协同模式+完整代码
type: item
date: 2026-03-30T13:21:00+08:00
description: 当一个Agent要处理很多复杂的事情，就会出现效果不佳的情况，这时候Multi-Agent就可以将复杂任务进行拆分，更好的完成我们的任务。本文基于Spring AI Alibaba框架，详解Multi-Agent的核心概念、占位符用法，以及顺序执行、并行执行、路由调度、监督者管控四大核心模式，搭配完整可运行的代码示例，快速上手多智能体开发。一、Multi-Agent 核心概念官方对Multi-Agent的定义清晰直白：Multi-agent 将复杂的应用程序分解为多个协同工作的专业化Agent。与依赖单个Agent处理所有步骤不同，Multi-agent架构允许你将更小、更专注的Agent组合成协调的工作流。Multi-agent系统在以下情况下很有用：单个Agent拥有太多工具，难以做出正确的工具选择决策上下文或记忆增长过大，单个Agent难以有效跟踪任务需要专业化（例如：规划器、研究员、数学专家）二、指令占位符（Instruction）用法支持使用占位符来动态引用状态中的数据。比如AgentB需要使用AgentA处理后的数据，就需要通过Instruction来获取1、支持的占位符占位符说明使用场景{input}用户输入的原始内容第一个Agent或需要用户输入的 Agent{outputKey}引用其他Agent通过 outputKey 存储的输出顺序执行中，后续Agent引用前面Agent的输出{stateKey}引用状态中的任意键值访问状态中的任何数据2、占位符工作原理自动替换：系统会在执行 Agent 的 instruction 时，自动将占位符替换为对应的实际值状态查找：占位符会从当前状态（OverAllState）中查找对应的值类型安全：占位符的值会被转换为字符串并插入到 instruction 中三、公共代码（ChatModel获取）我先把获取ChatModel这个公共代码放在这里，后面就不重复写进来了默认模型qwen-pluspublic static ChatModel getChatModel() { DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); return DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .defaultOptions(DashScopeChatOptions.builder() // Note: model must be set when use options build. .model(DashScopeChatModel.DEFAULT_MODEL_NAME) .temperature(0.5) .maxToken(1000) .build()) .build(); }四、顺序执行（Sequential Agent）顾名思义，多个Agent按照顺序依次执行，上一个Agent的输出结果可以传递给下一个Agent1. 执行流程Agent A处理初始输入Agent A的输出传递给Agent BAgent B处理并传递给Agent C最后一个Agent返回最终结果2. 示例代码import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; import com.alibaba.cloud.ai.graph.NodeOutput; import com.alibaba.cloud.ai.graph.agent.ReactAgent; import com.alibaba.cloud.ai.graph.agent.flow.agent.SequentialAgent; import com.alibaba.cloud.ai.graph.exception.GraphRunnerException; import com.alibaba.cloud.ai.graph.streaming.StreamingOutput; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.spring…

Agent Skill 踩坑记录 | SpringBoot 打包后 Skill 加载失败问题排查与解决
type: item
date: 2026-03-24T13:23:00+08:00
description: 在之前的开发中，我使用 ClasspathSkillRegistry 作为 Agent Skill 的查找策略，本地开发环境下调试、运行都一切正常，没有出现任何异常。感兴趣的小伙伴可以回顾上一篇相关内容：https://www.lucaju.cn/index.php/archives/168/一、问题出现：上线后频繁报「Skill not found」本以为本地测试无误后，上线就能顺利运行，结果程序部署到服务器后，日志中频繁出现 Skill not found: 错误，导致相关功能完全无法使用。二、问题排查：排除常见误区遇到问题后，首先排查了最容易出现问题的两个点，均排除异常：确认 Skill 已成功打包：检查部署的 jar 包，解压后确认 skill 相关文件已正常包含在内，不存在打包遗漏的情况；确认 Skill Name 无误：核对代码中调用 Skill 的名称与配置文件中的名称，完全一致，排除拼写错误、大小写错误等问题。三、问题根源：找到官方 Issue排除上述常见问题后，推测可能是框架本身的兼容性问题，于是去 GitHub 上搜索相关问题，果然发现已有其他开发者遇到过相同情况，并且提交了 Issue：https://github.com/alibaba/spring-ai-alibaba/issues/4426从 Issue 中得知，问题根源在于 SpringBoot 项目打包成 jar 包后，路径机制发生变化，导致 ClasspathSkillRegistry 无法正常加载 resources 下的 Skill 目录，这是目前 spring-ai-alibaba 框架的一个已知 bug。四、临时解决方案：改用 FileSystemSkillRegistry由于官方尚未修复该 bug，为了不影响线上功能正常使用，我采用了临时解决方案：将 Skill 目录存放在服务器的文件系统中，通过指定真实路径获取 Skill，对应的查找策略改用 FileSystemSkillRegistry。修改后的核心代码如下：/** * 获取技能智能体钩子。 */ private static SkillsAgentHook getSkillsAgentHook() { // 注释掉原有的ClasspathSkillRegistry方式（本地可用，打包后失效） // SkillRegistry registry = ClasspathSkillRegistry.builder() // .classpathPath("skills") // .build(); /* 临时解决方案说明： spring ai alibaba 目前使用 ClasspathSkillRegistry 打包后，无法获取 Resource 下的目录 因此修改为使用 FileSystemSkillRegistry，从文件系统真实路径获取 Skill 相关 Issue：https://github.com/alibaba/spring-ai-alibaba/issues/4426 */ String skillPath = SpringUtils.getProperty("doc.skills-path"); log.info("skillPath: {}",skillPath); FileSystemSkillRegistry registry = FileSystemSkillRegistry.builder() .projectSkillsDirectory(skillPath) .build(); return SkillsAgentHook.builder() .skillRegistry(registry) .build(); }五、后续需要说明的是，这只是一个临时解决方案——使用该方案后，需要手动将 Skill 配置文件同步到服务器的指定路径（即配置项 doc.skills-path 对应的路径），增加了少量部署成本。后续会持续关注官方 Issue 的修复进度，待 bug 修复后，再切换回 ClasspathSkillRegistry 方式，减少部署环节的手动操作。也希望遇到相同问题的小伙伴，能通过这篇踩坑记录少走弯路～

OpenClaw 🦞 还没玩明白，腾讯QClaw又来了？
type: item
date: 2026-03-23T13:17:00+08:00
description: OpenClaw 🦞 还没玩明白，腾讯QClaw又来了？3月20日，腾讯 QClaw 正式开启全量公测，无需邀请码，用户通过官网下载最新版本，其实本质上也是对OpenClaw的封装，主要吸引我的是他可以与微信深度集成，那么我们来体验一下效果如何呢～第一步：下载安装——零难度入门首先是下载安装，从官网下载，安装可以说是毫无难度。安装成功后，我们可以进行微信绑定第二步：微信绑定——初期体验有点繁琐绑定流程很简单，跟着提示操作就行。初期QClaw是以「客服号」的形式与微信集成，每次想和它互动，都得二次点击才能进入聊天界面，多了一步操作，偶尔会觉得麻烦。第三步：功能测试——任务生成频频翻车😅我先试了让它帮我生成一个定时任务，结果等了好一会儿，直接提示失败，给我整懵了…不死心的我，又按照官网提示，让它生成一个「推送天气」的任务，这次倒是没直接失败——等了大概十分钟，它回复了“好的”，还输出了一大堆内容，看起来像是成功了？结果等到第二天，我全程没收到任何天气推送… 两次任务都翻车，瞬间有点emo了😭后续更新——体验终于升级！刚刚提示我Qclaw可以更新了，我更新到了v0.1.16更新日志显示QClaw可以不再通过客服号的形式即成到微信了，而是直接以聊天卡片的形式，然后我去试了一下绑定微信。赶紧更新后重新绑定微信，发现这次是通过「ClawBot插件」连接到OpenClaw（毕竟本质还是对OpenClaw的封装嘛），绑定后直接就能在微信聊天页面和QClaw互动，少了一步点击，体验感有了提升～这样就可以直接在聊天页面与QClaw聊天了，减少了一步点击操作实测总结如今QClaw已经全面开放，微信免费“养龙虾”的时代已经来临，不过目前我对它的使用欲望暂时不高，后续如果有兴趣，会再测试一下它操作Excel文件等其他功能～大家有好用的skill可以推荐给我，我去试试～

Spring AI Alibaba + MCP：调用MCP市场公开服务实操
type: item
date: 2026-03-21T21:08:00+08:00
description: 上一篇博客，我们介绍了如何将本地工具封装为 MCP 服务，并成功创建客户端实现连接，感兴趣的朋友可以回顾：https://www.lucaju.cn/index.php/archives/169/今天，我们聚焦实操——如何调用 MCP 市场上的公开服务，以「高德地图 MCP 服务」为例，步骤清晰可复现，新手也能快速上手。一、先了解：MCP 公开服务市场首先给大家推荐一个优质的 MCP 公开服务平台：https://mcp.so/zh这个平台类似 MCP 服务的「GitHub」，目前已收录超过一万八千个公开 MCP 服务，涵盖地图、工具、接口等各类场景，我们今天要用的高德地图 MCP 服务也收录其中。高德地图 MCP 服务直达链接：https://mcp.so/zh/server/amap-maps/amap进入链接后，注意保存页面中的「服务器配置 JSON」（如下所示），后续配置项目时会直接用到，重点留意 env 中的 AMAP_MAPS_API_KEY 字段。二、前置准备：申请高德 API-Key调用高德地图 MCP 服务，需先获取个人 API-Key，步骤如下（3步搞定）：1. 登录高德开放平台访问高德开放平台：https://lbs.amap.com/ ，注册一个用户，完成认证后登录到后台2. 创建一个应用3. 生成 API-Key注意：服务平台选择Web服务，填写完成后提交，即可生成 API-Key，保存好该 Key，后续替换配置使用。三、编写客户端代码连接高德服务前置准备完成后，开始配置项目、编写代码，全程分为3个步骤，也很简单操作。1. 拷贝高德MCP服务中的json文件到项目中注意: 替换api_key，使用我们刚刚创建好的api_key{ "mcpServers": { "amap-maps": { "command": "npx", "args": [ "-y", "@amap/amap-maps-mcp-server" ], "env": { "AMAP_MAPS_API_KEY": "api_key" } } } }把这个json放到项目resource目录下，命名为 mcp-servers-config.json （可自定义，但需与后续配置对应）2. 修改application.yml配置文件添加 MCP 客户端配置，核心是指定上述 JSON 文件的路径spring: application: name: spring-ai-alibaba-agent ai: dashscope: api-key: ${AliQwen_API} mcp: client: type: async request-timeout: 10s toolcallback: enabled: true stdio: servers-configuration: classpath:/mcp-servers-config.json3. 编写测试代码测试代码其实和上一篇的客户端代码基本没有什么改动，我就简单放上来一些啦～@GetMapping("mcpTest") private void mcpTest() throws GraphRunnerException { ChatModel chatModel = getChatModel(); ToolCallback[] toolCallbacks = toolCallbackProvider.getToolCallbacks(); System.out.printf(""" =====Find the tools from spring ToolCallbackProvider===== %s """, JSON.toJSONString(toolCallbacks)); // 构建智能体并绑定mcp服务 ReactAgent agent = ReactAgent.builder() .name("ip_search") .model(chatModel) .description("你是一个天气查询助手") .saver(new MemorySaver()) .toolCallbackProviders(toolCallbackProvider) .build(); // 运行时配置 RunnableConfig config = RunnableConfig.builder() .threadId("session") .build(); // 流式调用agent Flux<NodeOutput> stream = agent.stream("上海未来天气怎么样", config); StringBuffer answerString = new StringBuffer();…

一文吃透 Spring AI Alibaba + MCP：服务端搭建 + 客户端调用全流程
type: item
date: 2026-03-19T16:22:00+08:00
description: 一、MCP概念介绍MCP（Model Context Protocol，模型上下文协议）是 Anthropic 于 2024 年推出的AI 领域统一连接协议，被称为 “AI 的 USB-C 接口”，核心是让大模型（LLM）通过标准化方式安全、灵活地调用外部工具、数据库、API 与文件系统，打破数据孤岛。从架构来看，MCP基于C/S（客户端-服务端）模式实现，因此要完成MCP调用，需分别搭建MCP服务端（暴露工具方法）和MCP客户端（调用服务端方法）。本文将基于Spring Ai Alibaba生态，完整实现“本地方法封装为MCP服务 + 客户端调用MCP服务”的全流程，步骤清晰、可直接落地。二、Spring AI MCP的介绍Spring AI MCP 为模型上下文协议提供 Java 和 Spring 框架集成。它使 Spring AI 应用程序能够通过标准化的接口与不同的数据源和工具进行交互，支持同步和异步通信模式。整体架构如下：三、搭建本地MCP服务端1. 添加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webflux</artifactId> <version>1.1.2</version> </dependency>注意：此处未使用常规的spring-boot-starter-web（内置Tomcat），因为spring-ai-starter-mcp-server-webflux与Tomcat存在冲突。使用spring-boot-starter会默认通过Netty启动服务，适配MCP服务端要求。2. 配置服务端application.ymlserver: port: 8088 # 服务端口，可自定义 servlet: encoding: enabled: true force: true charset: UTF-8 # 避免中文乱码 spring: application: name: local-mcp-server # 服务端应用名称 ai: mcp: server: type: async # 异步模式，提升调用性能 name: local-mcp-server # MCP服务名称 version: 1.0.0 # 服务版本3. 添加工具方法创建工具类，将需要对外暴露的方法用@Tool注解标记，并将该类交给Spring容器管理：@Service public class WeatherService { /** * 根据城市名称获取天气信息 * @param city 城市名称 * @return 天气描述 */ @Tool(description = "根据城市名称获取天气信息") public String getWeatherByCity(String city) { return city + " 今天天气很好！"; } }4. 添加MCP服务配置（McpServerConfig）创建配置类，通过ToolCallbackProvider将工具类（WeatherService）封装为MCP服务：@Configuration public class McpServerConfig { @Bean public ToolCallbackProvider weatherTools(WeatherService weatherService) { return MethodToolCallbackProvider.builder() .toolObjects(weatherService) .build(); } }5. 启动mcp-server 服务启动Spring Boot应用，查看控制台输出，确认服务启动成功（重点关注Netty启动信息）：2026-03-19T14:33:17.730+08:00 INFO 35517 --- [local-mcp-server] [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8088 (http) 2026-03-19T14:33:17.734+08:00 INFO 35517 --- [local-mcp-server] [ main] com.jcq.server.McpServerAppli…

Agent Skills | Spring Ai Alibaba从零构建可扩展 AI 智能体
type: item
date: 2026-03-18T13:32:04+08:00
description: 在当今AI应用开发领域，让AI智能体具备灵活的工具调用能力和可扩展的技能体系，是落地复杂业务场景的核心挑战。Spring AI Alibaba 原生提供了完善的 Skill 技能支持，能让智能体实现「技能发现→按需加载→工具执行」的全流程自动化。本文将从核心概念、组件解析、实战场景、最佳实践四个维度，手把手教你掌握 Spring AI Alibaba Skill 的使用方法。一、核心概念1.1 渐进式披露（核心设计思想）Spring AI Alibaba Skill 采用渐进式披露机制，最大化提升模型效率：系统初始仅注入技能元数据（名称、描述、路径）；模型判断需要使用某技能时，调用 read_skill(skill_name) 加载完整的 SKILL.md 文档；最后按需访问技能资源、执行绑定工具。1.2 Skill 标准目录结构每个技能独立为一个子目录，SKILL.md 为强制必需文件，目录结构如下：skills/ # 技能根目录 └── pdf-extractor/ # 单个技能目录（自定义命名） ├── SKILL.md # ✅ 必需：技能核心定义文档 ├── references/ # 可选：技能参考资料 ├── examples/ # 可选：使用示例 └── scripts/ # 可选：执行脚本1.3 SKILL.md 格式规范SKILL.md 采用元数据+正文结构，元数据通过 --- 包裹，是模型识别技能的关键：--- name: pdf-extractor # 必需：小写字母、数字、连字符，最长64字符 description: 用于从PDF文档中提取文本、表格和表单数据 # 必需：简洁描述，超长会被截断 --- # PDF 提取技能 ## 功能说明 You are a PDF extraction specialist. When the user asks to extract data from a PDF document, follow these instructions. ## 使用方法 1. **Validate Input** - Confirm the PDF file path is provided. - The default path for the pdf file is the current working directory. - Use the `shell` or `read_file` tool to check if the file exists - Verify it's a valid PDF format 2. **Extract Content** - Execute the extraction script using the `shell` tool: ```bash python scripts/extract_pdf.py <pdf_file_path> ``` - The script will output JSON format with extracted data 3. **Process Results** - Parse the JSON output from the script - Structure the data in a readable format - Handle any encoding issues (UTF-8, special characters) 4. **Present Output** - Summarize what was extracted - Present data in the requested format (JSON, Markdown, plain text) - Highlight any issues or limitations ## Script Location The extraction script is located at: `scripts/extract_pdf.py` ## Output Format The script returns JSON: ```json { "success": true, "filename": "report.pdf", "text": "Full text content...", "page_count": 10, "tables": [ { "page": 1, "data": [["Header1", "Header2"], ["Value1", "Value2"]] } ], "metadata": { "title": "Document Title", "author": "Author Name", "cr…

Spring AI Alibaba 人工介入实战｜Human-in-the-Loop 让 AI 更可靠
type: item
date: 2026-03-16T14:29:00+08:00
description: 引言在构建AI智能体应用时，我们经常面临一个关键挑战：如何让AI在执行某些敏感操作前获得人工确认？Spring AI Alibaba框架提供了强大的人工介入（Human-in-the-Loop）机制，让开发者能够精确控制AI工具的执行流程，在关键节点引入人工审批环节。本文将通过一个完整的实战示例，详细介绍如何在Spring AI Alibaba应用中实现人工介入功能。什么是人工介入？人工介入是一种机制，它允许AI智能体在执行特定工具前暂停执行，等待人工审批后再继续。这种机制特别适用于：敏感操作：如数据删除、资金转账等内容生成：如文章发布、诗歌创作等需要质量把控的场景权限控制：某些需要特定权限才能执行的操作审计要求：需要记录人工决策过程的场景实战示例：诗歌创作的人工审批让我们通过一个具体的例子来理解人工介入Hook的使用。这个示例展示了如何让AI在创作诗歌前获得人工确认。1. 项目依赖配置首先，确保你的项目中包含了Spring AI Alibaba相关依赖：<dependencies> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-agent-framework</artifactId> <version>1.1.2.0</version> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> <version>1.1.2.0</version> </dependency> </dependencies>2. 代码实现解析步骤1：构建AI模型// 构建DashScope API对象 DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); // 创建聊天模型 ChatModel chatModel = DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .build();步骤2：配置工具public class PoetTool implements BiFunction<String, ToolContext, String> { public int count = 0; public PoetTool() { } @Override public String apply( @ToolParam(description = "The original user query that triggered this tool call") String originalUserQuery, ToolContext toolContext) { count++; System.out.println("Poet tool called : " + originalUserQuery); return "在城市的缝隙里， \n" + "一束光悄悄发芽， \n" + "穿过钢筋水泥的沉默， \n" + "在风中轻轻说话。 \n" + "\n" + "夜色如墨，却不再黑， \n" + "星星点亮了每一个角落， \n" + "我站在时间的边缘， \n" + "等一朵云，轻轻落下"; } public static ToolCallback createPoetToolCallback() { return FunctionToolCallback.builder("poem", new PoetTool()) .description("用来写诗的工具") .inputType(String.class) .build(); } public static ToolCallback createPoetToolCallback(String name, PoetTool poetTool) { return FunctionToolCallback.builder(name, poetTool) .description("用来写诗的工具") .inputType(String.class) .build(); } }步骤3：构建带有Hook的智能体// 这里我们配置了poem工具需要人工审批，并提供了审批时的描述信息。 Map<String, ToolConfig> approvalOn = Map.of( "poem"…

使用Spring AI Alibaba构建智能体Agent
type: item
date: 2026-03-13T15:58:00+08:00
description: 前言随着大语言模型(LLM)技术的快速发展，构建智能Agent应用变得越来越简单。本文将通过两个实际的代码示例，展示如何使用Spring AI Alibaba框架构建功能丰富的天气查询Agent，从基础的测试实现到生产级的完整应用。技术栈概述Spring AI Alibaba: 阿里巴巴开源的AI应用开发框架DashScope: 阿里云的AI模型服务平台React Agent: 基于ReAct(Reasoning and Acting)范式的智能代理示例一：SimpleTest - 快速入门添加核心依赖<dependencies> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-agent-framework</artifactId> <version>1.1.2.0</version> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> <version>1.1.2.0</version> </dependency> </dependencies>代码结构分析@Test void agentTest() throws GraphRunnerException { // 1. 初始化 DashScope API DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); // 2. 创建 ChatModel ChatModel chatModel = DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .build(); // 3. 定义天气工具 ToolCallback weatherTool = FunctionToolCallback.builder("get_weather", new WeatherTool()) .description("获取某个城市的天气") .inputType(String.class) .build(); // 4. 构建React Agent ReactAgent agent = ReactAgent.builder() .name("weather_agent") .model(chatModel) .tools(weatherTool) .systemPrompt("你是一个非常有帮助的助手") .saver(new MemorySaver()) .build(); // 5. 调用Agent AssistantMessage response = agent.call("上海今天天气怎么样？"); System.out.println(response.getText()); }核心特性简洁的配置: 通过Builder模式快速构建Agent工具集成: 使用FunctionToolCallback将自定义函数包装为Agent可调用的工具内存存储: 使用MemorySaver保存对话历史中文支持: 完整的中文提示词和工具描述自定义工具实现class WeatherTool implements BiFunction<String, ToolContext, String> { @Override public String apply(String city, ToolContext toolContext) { return city + "今天天气非常好！"; } }这个简单的工具类展示了如何将业务逻辑封装为Agent可调用的函数。示例二：RealAgent - 真实的智能体高级特性概览相比SimpleTest，RealAgent展示了更多生产级特性：精细的模型配置多工具协同结构化输出对话上下文管理核心代码解析1. 系统提示词设计String SYSTEM_PROMPT = """ 你是一位擅长说**天气冷笑话/谐音梗**的专业天气预报员。 你可以使用两个工具： - **get_weather_for_location**：用于获取指定地点的天气 - **get_user_location**：用于获取用户当前所在位置 如果用户询问天气，**必须先确认地点**。 如果从问题中能判断出他们指的是**自己所在的地方**， 就使用 **get_user_location** …

大模型“无脑复读”？3分钟搞懂原因+解决办法
type: item
date: 2026-03-10T17:30:00+08:00
description: 最近在调用大模型时，遇到了一个十分棘手的怪象——模型输出陷入“死循环”，不停重复相同内容，像一台复读机，如下图所示。为了解决这个问题，我查阅了相关资料，梳理出大模型重复输出的现象分级、核心原因以及可解决办法，整理成文分享给大家，帮大家快速摆脱“复读机”困扰。一、现象分级：大模型“复读”分3种大模型的重复输出并非单一情况，根据重复的范围和程度，可分为以下3个级别，大家可以对照判断自己遇到的情况：词汇/短语级重复：最基础的重复形式，模型生成的文本中，同一个词语、短语或短句反复出现，比如一句话在同一段落中被多次复制粘贴，阅读起来十分冗余。段落级重复：当生成较长文本（如文章、方案）时，模型可能生成重复的句子群或完整段落，甚至出现与前文几乎完全一致的内容段，严重影响内容的完整性和可读性。内容结构级重复：针对结构化回答需求（如分点解析、步骤说明），模型可能多次使用相似的结构、句式进行解释，虽然核心内容略有差异，但整体框架重复，显得拖沓且缺乏新意。二、核心原因：3大因素导致模型“卡壳复读”1. 提示词问题（最常见，占比最高）需求提示不清晰：如果给模型的提示过于模糊、笼统，没有明确回答方向、范围或要求，模型无法精准捕捉需求，就会通过重复内容“凑数”，形成冗余输出。上下文缺失：模型的回答依赖上下文信息，如果提问时没有提供足够的背景、前提，或对话过程中上下文断裂，模型无法理解需求的核心，就容易陷入重复循环。2. 模型参数设置不合理温度（temperature）设置过低：温度值控制模型输出的随机性，当温度设置过低（如0），模型会生成保守、确定的内容，倾向于重复高概率词汇和句式，进而出现重复。Top-k/Top-p采样策略不当：这两个参数用于控制模型选择词汇的范围，若设置不合理，会导致模型只能选择少数高概率词汇，无法生成多样化内容，最终陷入重复。3. 模型本身的局限性最终的输出内容由大模型的核心算法、参数配置和训练数据决定。如果模型本身存在训练不充分、参数优化不足等问题，也可能导致其在生成内容时，容易出现重复输出的情况。三、解决办法：对症施策，快速解决“复读”问题针对上述原因，整理了可直接落地的解决办法，从易到难，大家可以按需尝试，基本能解决80%以上的重复输出问题：1. 优化提示词明确禁止重复：在提示词中直接添加“禁止输出重复信息”“避免重复句式和内容”等要求，直接约束模型的输出行为。丰富上下文：补充足够的背景信息、前提条件，或在对话中逐步递进提问，让模型清晰理解需求，避免因信息不足导致重复。细化需求+拆分问题：将模糊的需求拆解成更小的子问题，明确每个问题的回答方向（如“从3个不同角度解析XX”“分步骤说明XX”），引导模型生成多样化内容。2. 调整模型参数调整temperature：将温度值设置在0.7-0.9之间，这个区间既能保证输出内容的准确性，又能增加随机性，鼓励模型生成更多不同的内容，避免重复。优化Top-p采样：适当调整Top-p的值（通常设置在0.9左右），扩大模型选择词汇的范围，让模型有更多创作空间，减少重复概率。