ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring AI 的 Manus 智能体:ChatModel Base URL 改到 TaoToken 后,ReAct 循环完整跑完

Spring AI 的 Manus 智能体:ChatModel Base URL 改到 TaoToken 后,ReAct 循环完整跑完 1. 一个 ReAct 周期烧掉的 Token比你想的多在 Spring AI 里搭 Manus 智能体最麻烦的不是把 ReActAgent 的think()和act()写出来而是ChatModel一旦绑死某一家厂商的 endpoint后续每次换模型都要去改业务代码。原文里的BaseAgent用状态机控制 IDLE / RUNNING / FINISHED / ERRORReActAgent把单步拆成思考和行动ToolCallAgent再通过ChatClient反复调用大模型直到TerminateTool触发才把状态置为 FINISHED。这套逻辑跑起来之后我先把ChatModel的 Base URL 指到了 TaoToken 的统一通道官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 然后原来 YuManusTest 里“找静安寺附近租房并以 PDF 输出”那个任务居然一口气走完了完整的 think→act→Observe 循环。但代价也随之而来每走一步模型都要把当前消息列表、工具定义、历史观察结果全部再读一遍。一个任务如果调五六次工具Token 消耗就不是“单次对话”的量级而是“逐轮翻倍”的量级。原文也特别提醒过AI 存在随机性执行步骤不固定Token 消耗很大要防止陷入无限循环。所以与其等到跑完才看账单不如在配置阶段就把模型通道换成可控、可观测的统一接口。这里说的可控是指你不需要为了换模型去改YuManus构造函数里的ChatClient.builder(dashscopeChatModel)也不需要在act()方法里硬编码模型名。Spring AI 的ChatModel是一个抽象底层 endpoint 在哪里、Key 是哪把完全由配置文件决定。只要把那个 endpoint 指向 TaoToken再填上从官网拿到的 Key整个 ReAct 循环就能照常跑而且每一步工具调用的 Token 消耗都能在 TaoToken 侧看到记录。2. 不换 Spring AI 的代码只换 ChatModel 的 Base URL2.1 先去 TaoToken 创建 Key打开 TaoToken注册并登录进入控制台创建一个 API Key。创建时只需要复制那串sk-...形式的字符串后面填到 Spring AI 配置里。这个 Key 就是你的模型访问凭证TaoToken 侧会用它区分每次请求来自哪个项目也方便你在控制台查看用量。这里有一个容易混淆的点官网落地页和 API 地址不是同一个。落地页只负责注册、创建 Key、看模型广场、看用量真正填进工具的 Base URL 是https://taotoken.net/api末尾不要加/v1。比如你使用 Spring AI 的 DashScope 客户端原来的 Base URL 可能是厂商默认地址现在改成https://taotoken.net/api即可。2.2 application.yml 里把 DashScope 指到 TaoToken原文用的客户端是DashScopeChatModelSpring Boot 项目里只要引入spring-ai-starter-model-dashscope就能通过配置文件自动装配。所以你不必动YuManus的代码只需要在application.yml里覆盖两个属性api-key和base-url。spring: ai: dashscope: api-key: YOUR_API_KEY base-url: https://taotoken.net/api chat: options: model: YOUR_MODEL_ID注意YOUR_API_KEY是从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建的那把 Key不是旧厂商的 Key。base-url是https://taotoken.net/api不是官网首页也不是带/v1的地址。如果你的项目里用环境变量管理敏感信息也可以写成${TAOTOKEN_API_KEY:YOUR_API_KEY}的形式效果一样。2.3 模型 ID 别拍脑袋去看模型广场Spring AI 的DashScopeChatOptions里必须指定一个模型 ID。网上的教程经常写qwen-plus、qwen-max之类但你换了 TaoToken 统一通道之后模型 ID 要以 TaoToken 模型广场当时列表为准不要照抄网上旧教程里的名字也不要凭印象编造gpt-5这种不存在的 ID。打开模型广场找到你想用的模型直接把它的 ID 复制到model配置项里。有的开发者会问我原来的代码里写死了DashScopeChatOptions.builder().withProxyToolCalls(true)这个要不要改不需要。withProxyToolCalls(true)只是告诉 Spring AI 不要自行吞掉工具调用而是把工具调用的决策权交还给ToolCallAgent。它和 Base URL 指向哪里没有关系也不影响你切换到 TaoToken。3. YuManus 构造函数ChatClient.builder(dashscopeChatModel) 保持不变3.1 Spring Boot 自动装配下的最小改动原文中YuManus的构造函数注入了一个ChatModel dashscopeChatModel然后自己构建ChatClientComponent public class YuManus extends ToolCallAgent { public YuManus(ToolCallback[] allTools, ChatModel dashscopeChatModel) { super(allTools); // ... 设置 Name、SystemPrompt、NextStepPrompt、MaxSteps ... ChatClient chatClient ChatClient.builder(dashscopeChatModel) .defaultAdvisors(new MyLoggerAdvisor()) .build(); this.setChatClient(chatClient); } }这段代码不需要推翻。Spring Boot 启动时会根据application.yml里的spring.ai.dashscope.*配置自动创建一个DashScopeChatModelBean注入到YuManus里。你只要改配置文件这个 Bean 的 endpoint 就已经指向 TaoToken 了ChatClient.builder(dashscopeChatModel)这一行自然就走上了新通道。这也正是统一 API 通道带来的好处你的 ReAct 状态机、工具调用逻辑、消息列表维护全部和具体模型厂商解耦。今天用 Qwen 系明天换别的系列改一行配置就够业务代码完全不动。3.2 如果你是在纯 Java 里手工 new ChatModel有些项目没有用 Spring Boot 的自动装配而是在自己的Configuration类里手工创建ChatModel。这种情况下你需要显式指定 Base URL。以 Spring AI 的 DashScope 实现为例可以这样写Bean public ChatModel dashscopeChatModel() { DashScopeApi api new DashScopeApi( YOUR_API_KEY, https://taotoken.net/api, YOUR_MODEL_ID ); return new DashScopeChatModel(api); }这里唯一的改动就是把原来的厂商 endpoint 换成https://taotoken.net/apiKey 换成 TaoToken 创建的那把。YOUR_MODEL_ID同样以模型广场列表为准。因为 Dashboard 的 API 兼容 OpenAI 风格Spring AI 的 DashScope 客户端可以直接复用这个地址。4. 跑 YuManusTest观察 think→act→Observe 的完整日志4.1 测试任务原样跑通原文的测试任务是“我在上海市静安区静安寺附近请帮我找到 5 公里内性价比比较高的租房地点并区分找出附近的租房中介和房主直租制定一份详细的约看计划并以 PDF 格式输出”。在改动 Base URL 之后直接运行YuManusTest。你会在日志里看到think阶段输出的思考内容然后是模型选择了一个或多个工具接着进入act阶段执行工具工具返回结果后消息列表被更新再进入下一轮think。一个完整的 ReAct 循环会是这样think模型决定需要先搜索静安寺附近的租房信息。act调用webSearchTool搜索“静安寺 附近 租房 中介 房主直租”。Observe工具返回搜索结果消息列表追加工具响应。think模型分析搜索结果决定需要进一步抓取详情。act调用webScrapingTool或resourceDownloadTool。Observe拿到页面内容。最终模型调用doTerminate工具ToolCallAgent.act()检测到工具名后把状态置为 FINISHED。整个过程和原来用某个固定厂商 endpoint 时完全一致唯一不同的是每一次大模型请求都经过了 TaoToken。你不需要在代码里多写任何一行路由逻辑。4.2 去 TaoToken 控制台核对每一次工具调用的 Token跑通之后打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 进入控制台查看用量记录。你会发现每一次ChatClient.call()都会产生一条独立的调用记录里面包含了模型 ID、请求时间、Token 消耗等信息。这比你在本地打日志更直观因为本地日志只能看到“第几步调了工具”看不到每一次请求到底吃了多少 Token。有了这份记录你就能判断 ReAct 循环是否陷入了“空转”如果日志里模型反复调用同一个工具但返回结果没有推进任务而消耗记录里 Token 连续增长说明该干预了。原文设置的maxSteps 20是个安全阀但更好的做法是结合用量记录去调整NEXT_STEP_PROMPT提醒模型尽快收敛并调用terminate工具。5. 排障先看 401再看模型 ID最后检查有没有多写 /v15.1 401 Unauthorized如果你的应用启动后第一次调用ChatClient就报401 Unauthorized最常见的原因是把旧厂商的 Key 填进来了。TaoToken 的 Key 必须从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的控制台创建旧 Key 没有权限访问这个通道。另外检查一下application.yml里的api-key是否有多余的空格或换行。Spring Boot 读取配置时不会自动 trim一个不小心就会导致鉴权失败。5.2 404 和 model not found如果报错是404 Not Found优先检查 Base URL。填进配置的必须是https://taotoken.net/api不是https://taotoken.net也不是https://taotoken.net/api/v1。Spring AI 的 DashScope 客户端会在 Base URL 后面拼接自己的路径如果你多写了/v1最终请求地址就变成双份路径服务端自然找不到接口。如果报错是model not found或类似提示说明YOUR_MODEL_ID填了一个模型广场里不存在的名字。去模型广场复制准确的模型 ID不要凭记忆写。5.3 循环一直不调用 TerminateTool 怎么办如果你发现 ReAct 循环里模型反复“思考”但不结束先看日志里工具名称是否匹配。TerminateTool的方法名是doTerminateToolCallAgent.act()里判断的是doTerminate.equals(response.name())。如果模型返回的工具名是terminate那判断会失败永远不会触发FINISHED。原文章里也提到过NEXT_STEP_PROMPT里写的是 “use theterminatetool/function call”但实际注册的是doTerminate这个不一致需要根据你的 Spring AI 版本去适配。另外TaoToken 的用量记录能帮你看出模型是否在反复输出同样的工具调用如果发现这种情况把它当成 prompt 调优的抓手而不是盲目加大maxSteps。6. 让这次 ReAct 的体验延续到日常编码Spring AI 的 Manus 智能体跑通之后你会明显感觉到模型通道的切换成本已经低到可以忽略。以后想在别的项目里复用这套 Agent 框架只需要改api-key和model两个配置其他人的代码甚至不知道后端换了供应商。如果你希望在日常模型对话里也保持同一把 Key、同一种计费视角可以先在 TaoToken 模型对话 里发一条消息体验一下统一通道的响应速度。接着用同一条消息去对比 Spring AI 里的调用确认模型 ID 和 Base URL 都没填错。如果这周你想用 Agent 跑更多的多步任务而不是只在测试里跑一次租房需求建议打开 Coding Plan 看一下套餐是否匹配你的工具调用频率免得 ReAct 循环正跑着突然额度吃紧。Key 的管理始终在 控制台 API Keys 页面无论你配置 Spring AI、Codex 还是 Claude Code拿到的都是这把 Key。官方针对 Claude Code 的接入文档在 这里如果你还有其他基于 Anthropic 协议的工具也可以按同一个思路填 Base URL 和 Key。
返回列表