Spring AI Alibaba 实战:集成 OpenManus 实现智能体应用开发

📅 发布时间:2026/10/12 15:38:16
Spring AI Alibaba 实战:集成 OpenManus 实现智能体应用开发
1. 从一次“工具调用不生效”说起Spring AI Alibaba 集成 OpenManus 的智能体应用开发到底难在哪如果你正在用 Spring AI Alibaba 做智能体应用开发大概率会遇到这样一个场景模型明明“听懂”了用户要查天气、要读文件、要发邮件但就是不触发你注册的工具函数最后返回一段“我无法直接访问外部系统”的客套话。这不是模型笨而是工具描述、参数 Schema、调用链路三者没对齐。OpenManus 作为一套通用型 Agent 编排思路核心价值在于把“规划—执行—反思”拆成可观测的步骤而 Spring AI Alibaba 提供的是 Java 侧模型接入与工具注册的底座。把两者接起来本质是让 Java 工程既能调用通义系列模型又能按 OpenManus 的任务分解逻辑去驱动多轮工具调用。这篇文章面向的是已经写过 Spring Boot、想落地智能体但卡在“配置能跑、行为不可控”的 Java 开发者。我会从工程结构、依赖配置、工具注册、任务编排、多轮记忆、日志回放验证六个角度给出一套可复制的最小可运行示例。你不需要先精通 Agent 理论只要跟着把配置片段贴进项目再用日志确认每一步工具是否被触发即可。实测下来最容易踩的坑不是模型能力而是 Base URL、API Key、Model ID 三件套没写全以及工具方法的参数注解缺失导致 Schema 为空。先明确一个边界OpenManus 在这里是“编排理念与任务分解范式”的参考不是让你把它的 Python 运行时塞进 JVM。我们要做的是用 Spring AI Alibaba 的 ChatClient ToolCallback Advisor 机制复现 OpenManus 那种“先规划再执行、每步可回放”的智能体行为。下面从环境准备开始一步步把链路搭起来。2. 前置准备TaoToken 接入 Spring AI Alibaba 的 Base URL 与 Key 怎么配Spring AI Alibaba 默认对接 DashScope但很多团队希望用统一的 OpenAI 兼容入口来管理多模型这时候就需要一个兼容层。TaoToken 提供的就是这种 OpenAI 兼容的 API 入口你可以在不改动 Spring AI Alibaba 核心依赖的前提下把 Base URL 指向它从而在同一套代码里切换模型。下面是我实际验证过的配置方式。首先确认你的工程是 JDK 17、Spring Boot 3.2这是 Spring AI Alibaba 1.0.0-M2 的硬性要求。然后去 TaoToken 控制台创建一个 API Key路径是 console 页面里的 api-keys 管理。拿到 Key 之后不要硬编码在代码里用环境变量注入。# application.yml spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: qwen-plus temperature: 0.3这里有个关键点Spring AI Alibaba 的 starter 默认读的是spring.ai.dashscope如果你要走 OpenAI 兼容协议需要引入spring-ai-openai-spring-boot-starter或者用 Spring AI Alibaba 提供的 OpenAI 兼容适配。我试过两种方式最稳的是直接用 OpenAI starter然后把 base-url 指向 TaoToken 的 API 地址。Model ID 填qwen-plus或qwen-max具体以你账号下可用的模型为准。如果你更习惯用 DashScope 原生协议也可以保留spring.ai.dashscope.api-key但那样就无法统一走 TaoToken 入口。两种方式不冲突按团队规范选一种即可。配置完成后先别急着写 Agent用一段最小请求验证连通性RestController public class PingController { private final ChatClient chatClient; public PingController(ChatClient.Builder builder) { this.chatClient builder.build(); } GetMapping(/ping) public String ping() { return chatClient.prompt().user(只回复两个字通了).call().content(); } }启动后访问/ping如果返回“通了”说明 Base URL、Key、Model ID 三件套正确。如果报 401优先检查 Key 是否带了多余空格如果报 model not found检查 Model ID 拼写。这一步过了再进入工具调用环节。3. 可复制配置工具注册、任务编排与多轮记忆的完整 settings 片段智能体的核心不是聊天而是“能动手”。Spring AI Alibaba 里让模型触发 Java 方法靠的是Tool注解或FunctionCallback注册。下面这段配置我放在一个AgentConfig类里包含工具定义、ChatClient 构建、记忆 Advisor 三部分你可以直接复制。Configuration public class AgentConfig { Bean public ChatClient agentChatClient(ChatClient.Builder builder, ChatMemory chatMemory) { return builder .defaultSystem(你是一个任务型智能体。收到用户请求后先判断是否需要调用工具 需要时按步骤调用每步只做一件事完成后汇总结果。) .defaultTools(new ReportTools(), new FileTools()) .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) .build(); } Bean public ChatMemory chatMemory() { return new InMemoryChatMemory(); } }工具类这样写注意每个参数都要有ToolParam描述否则模型拿到的 Schema 是空的就不会触发调用Component public class ReportTools { Tool(description 根据给定内容生成一份 Markdown 格式的季度报告) public String generateReport( ToolParam(description 报告正文包含数据与结论) String content) { String fileName report- System.currentTimeMillis() .md; // 实际项目替换为真实文件写入 return 已生成报告文件 fileName 内容长度 content.length(); } }任务编排部分我用一个AgentExecutor风格的 Service 来串多步。OpenManus 的思路是先规划再执行这里用两阶段 Prompt 模拟第一阶段让模型输出步骤列表第二阶段逐步执行并回填结果。Service public class AgentExecutorService { private final ChatClient chatClient; public AgentExecutorService(ChatClient chatClient) { this.chatClient chatClient; } public String run(String userInput) { String plan chatClient.prompt() .user(把下面任务拆成不超过3步只输出步骤列表\n userInput) .call() .content(); String result chatClient.prompt() .user(按以下步骤执行任务需要工具就调用工具。\n步骤\n plan \n原始任务 userInput) .call() .content(); return 规划\n plan \n\n执行结果\n result; } }多轮记忆用MessageChatMemoryAdvisor配合conversationId参数隔离会话。如果你要持久化把InMemoryChatMemory换成基于 Redis 的实现即可接口不变。这套配置跑起来后模型会在需要时自动调用generateReport日志里能看到工具名和入参。4. 验证请求用日志与接口回放确认智能体行为是否符合预期配置写完不代表行为正确。我习惯用“接口回放 日志断点”来验证。先发一个明确需要工具的请求curl http://localhost:8080/agent?input帮我把Q3营收数据整理成报告营收1200万同比增长18%然后在日志里找三类信息一是模型是否输出了步骤列表二是是否出现ToolCallback调用记录三是工具返回值是否被回填进最终回答。Spring AI Alibaba 默认会打印工具调用日志如果没有在application.yml里打开logging: level: org.springframework.ai: DEBUG正常回放应该看到类似这样的顺序Planning - ToolCall(generateReport) - ToolResponse - FinalAnswer。如果只看到 Planning 和 FinalAnswer中间没有 ToolCall说明工具没被触发。这时候先检查工具方法的description是否足够具体模型对模糊描述会倾向于不调用。另一个验证手段是接口回放把同一段输入连续发两次观察第二次是否因为记忆 Advisor 而带上上下文。比如先问“营收多少”再问“那利润呢”如果第二次能关联到“营收”这个上下文说明记忆生效。实测下来InMemoryChatMemory在单实例下够用多实例部署必须换 Redis否则会话会漂移。我还建议加一个/trace接口把每次请求的 plan、toolCalls、finalAnswer 结构化返回方便前端或测试脚本断言。这样智能体行为就从“感觉对”变成“可断言”。5. 常见报错排查401、local proxy failed、reading choices、OAuth 逐个拆接入过程中有几类报错几乎必现我按出现频率排一下。第一类是 401 Unauthorized。多数情况是 Key 没读到环境变量或者base-url末尾多了斜杠导致路径拼接错误。检查https://taotoken.net/api不要写成https://taotoken.net/api/Spring AI 拼接/chat/completions时多一个斜杠会 404 或 401。第二类是local proxy failed或连接超时。这通常是本机网络策略或容器 DNS 问题不是 Key 的问题。先在容器内curl -v https://taotoken.net/api确认能通再排查 Spring 的 RestClient 超时配置。把超时调大spring: ai: openai: chat: options: timeout: 60s第三类是reading choices解析失败报 JSON 反序列化异常。这往往是因为返回体不是标准 OpenAI 格式或者模型返回了空 choices。先确认 Model ID 是否正确再确认请求里没有传模型不支持的参数比如某些模型不支持temperature之外的采样参数。把temperature先去掉试一次。第四类是 OAuth 相关报错。如果你用的是企业账号或走了网关鉴权可能会要求 Bearer Token 之外的额外头。Spring AI 支持自定义RestClientCustomizer可以手动加 HeaderBean public RestClientCustomizer restClientCustomizer() { return builder - builder.defaultHeader(X-App-Id, your-app-id); }排查顺序建议先 curl 直连 API 确认服务端正常再回到 Java 侧看日志。多数“模型不调用工具”的问题根因是工具描述太泛或参数缺注解而不是网络。6. 语义一致 CTA把智能体从 Demo 推到可用走到这里你已经有了一个能规划、能调工具、能记忆的最小智能体。下一步通常是两件事一是把模型调用稳定下来二是把编码和 Agent 编排长期跑起来。如果你还在验证阶段建议先用模型对话页面快速对比不同 Model ID 的输出差异确认哪个模型在你的任务分解场景下更稳接入文档里有完整的参数说明和错误码对照排障时比翻源码快。对于要长期做编码类 Agent 的团队Coding Plan 更适合因为它把调用额度和并发策略都预设好了不用每次手动调参。控制台里的 api-keys 页面可以按项目维度建多个 Key方便做灰度。最后提醒一句工具方法的description和参数注解值得你花比写业务逻辑更多的时间去打磨这是智能体行为可控的真正开关。