ToolCallAgent 的 DashScopeChatOptions 调不通?TaoToken 只补模型 Key 和 Base URL

ToolCallAgent 的 DashScopeChatOptions 调不通?TaoToken 只补模型 Key 和 Base URL 一、ToolCallAgent 调不通的真实场景think() 请求直接失败如果你正在用 Spring AI 仿写 OpenManus 的 ToolCallAgent大概率会踩到下面这个坑think()里通过ChatClient发起带工具的请求结果要么抛异常要么返回的AssistantMessage里getToolCalls()是空列表act()里toolCallChatResponse.hasToolCalls()直接返回 false整个 Agent Loop 卡在第一步。这个现象背后通常不是DashScopeChatOptions.builder().withProxyToolCalls(true)写错了也不是ToolCallingManager的上下文维护逻辑有问题而是模型客户端根本没配通。ToolCallAgent 的设计思路是用withProxyToolCalls(true)禁用 Spring AI 内置的工具执行让模型只负责返回tool_calls决策信息真正的工具执行交给ToolCallingManager.executeToolCalls()自己维护。这个链路要跑起来前提是think()里的那次 LLM 调用必须成功返回带tool_calls的响应。一旦模型 Key 或 Base URL 配错getChatClient().prompt(prompt).system(...).tools(availableTools).call().chatResponse()这一步就会失败后面的toolCallChatResponse拿不到act()自然无从执行。本文就从这个排障视角出发把模型客户端配置这一步单独拎出来讲清楚让think()/act()所需的 LLM 调用先跑通。TaoToken 在这个链路里只做一件事提供可用的模型 Key 和兼容 OpenAI 协议的 Base URL。它不替 ToolCallAgent 执行工具也不接管ToolCallingManager的上下文维护只负责让think()里的那次请求能正常发出并拿到tool_calls。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册后创建 Key 即可。二、TaoToken 前置只补 Key 和 Base URL不动 Agent 逻辑在动手改代码之前先把边界说清楚避免把排障方向带偏。ToolCallAgent 的核心逻辑分三层think()调用 LLM拿到AssistantMessage和其中的tool_calls列表决定下一步用哪些工具。act()把think()拿到的ChatResponse交给ToolCallingManager.executeToolCalls()由它执行工具并把结果写回conversationHistory。chatOptions用DashScopeChatOptions.builder().withProxyToolCalls(true).build()关闭 Spring AI 内置工具执行保证工具调用信息原样回传给act()。这三层里TaoToken 只影响第一层里ChatClient背后的模型服务地址和鉴权。也就是说你不需要改withProxyToolCalls(true)不需要改ToolCallingManager的构建方式也不需要动setMessageList(toolExecutionResult.conversationHistory())这段上下文回写逻辑。要改的只有两处模型 Key从 TaoToken 控制台创建替换掉原来准备填 DashScope 官方 Key 的位置。Base URL填https://taotoken.net/api注意不要带/v1也不要把带 UTM 的官网地址写进配置。很多人排障时习惯先去翻ToolCallingManager的源码或者怀疑withProxyToolCalls没生效其实先确认think()里那次请求的返回体里有没有tool_calls字段比什么都快。如果请求本身 401 或 404后面所有工具调用逻辑都不会被触发。三、可复制配置Spring AI 里改 Key 和 Base URL下面给出一个最小可复制的配置片段假设你用的是 Spring AI 的 OpenAI 兼容客户端来对接 TaoToken。核心是把base-url指向https://taotoken.net/apiapi-key用 TaoToken 创建的 Key。spring: ai: openai: api-key: YOUR_API_KEY base-url: https://taotoken.net/api chat: options: model: gpt-4o-mini temperature: 0.7如果你是在 Java 代码里手动构建ChatModel或OpenAiChatModel对应写法如下OpenAiApi openAiApi OpenAiApi.builder() .baseUrl(https://taotoken.net/api) .apiKey(YOUR_API_KEY) .build(); OpenAiChatModel chatModel OpenAiChatModel.builder() .openAiApi(openAiApi) .defaultOptions(OpenAiChatOptions.builder() .model(gpt-4o-mini) .temperature(0.7) .build()) .build();然后在 ToolCallAgent 的构造里把这个chatModel注入进去构建ChatClientChatClient chatClient ChatClient.builder(chatModel) .defaultAdvisors(new MyLoggerAdvisor()) .build(); this.setChatClient(chatClient);注意几个容易写错的地方Base URL 只写到https://taotoken.net/api不要写成https://taotoken.net/api/v1也不要写成带?utm_source...的官网地址。UTM 参数是给浏览器访问官网用的不能进代码配置。api-key填 TaoToken 控制台创建的 Key不要混用 DashScope 官方 Key。withProxyToolCalls(true)保持原样它是 ToolCallAgent 自己维护工具调用上下文的关键不要因为请求失败就把它去掉。如果你用的是DashScopeChatOptions而不是OpenAiChatOptionsBase URL 的配置位置可能不同但原则一样指向 TaoToken 的兼容端点Key 用 TaoToken 的。具体接入方式可以参考接入文档里面有不同客户端的配置示例。四、验证请求确认 think() 能拿到 tool_calls配置改完后不要直接跑完整的 Manus 测试用例先单独验证think()这一步的请求是否成功。最直接的方式是写一个最小测试只调用一次带工具的ChatClient看返回体里有没有tool_calls。Test void testThinkRequest() { Prompt prompt new Prompt( List.of(new UserMessage(帮我查一下北京今天的天气)), chatOptions ); ChatResponse response chatClient.prompt(prompt) .system(你是一个可以使用工具的助手) .tools(availableTools) .call() .chatResponse(); AssistantMessage assistantMessage response.getResult().getOutput(); System.out.println(text: assistantMessage.getText()); System.out.println(toolCalls: assistantMessage.getToolCalls()); Assertions.assertNotNull(response); }如果配置正确你会看到类似下面的输出text字段可能有内容也可能为空取决于模型是否在返回工具调用时同时输出文本。toolCalls字段应该是一个非空列表里面包含工具名称和参数比如get_weather和{city:北京}。只要toolCalls有值就说明think()所需的 LLM 调用已经通了act()里的toolCallChatResponse.hasToolCalls()就能返回 trueToolCallingManager.executeToolCalls()也能正常拿到ChatResponse去执行工具。如果toolCalls是空列表先检查两件事一是请求里.tools(availableTools)是否真的传了工具定义二是模型是否支持工具调用。有些模型对tool_choice的处理不同可以尝试在chatOptions里显式设置toolChoice。验证通过后再跑完整的SunnyManus.run()测试用例观察日志里think()输出的工具选择信息和act()输出的工具执行结果。正常情况下你会看到每一步的toolCalls被正确解析conversationHistory被回写Agent Loop 持续推进直到调用terminate工具。五、本篇常见错排查排障时按下面顺序检查基本能覆盖大部分think()请求失败的情况。错误一Base URL 带了/v1或 UTM 参数这是最常见的配置错误。https://taotoken.net/api/v1和https://taotoken.net/api?utm_source...都会导致请求路径不对返回 404 或重定向失败。正确写法就是https://taotoken.net/api不带路径后缀不带查询参数。错误二Key 混用或未替换如果你之前代码里写的是 DashScope 官方 Key改配置时只改了 Base URL 没改 Key请求会返回 401。TaoToken 的 Key 需要在控制台单独创建创建后直接替换api-key字段。错误三把官网地址写进了配置官网地址是给浏览器访问的带 UTM 参数用于统计来源。代码里的 Base URL 必须是 API 端点两者不能混用。如果你在配置里看到taotoken.net/?utm_source...说明填错了。错误四误删withProxyToolCalls(true)有些人看到请求失败以为是withProxyToolCalls导致的就把它去掉了。实际上这个配置是 ToolCallAgent 自己维护工具调用上下文的前提去掉后 Spring AI 会尝试内置执行工具反而破坏act()的逻辑。请求失败要查 Key 和 Base URL不要动这个配置。错误五toolCalls为空但请求成功如果请求返回 200但toolCalls是空列表检查.tools(availableTools)是否传入了有效的ToolCallback[]以及模型是否支持工具调用。可以换一个明确支持 function calling 的模型再试。错误六act()里hasToolCalls()返回 false如果think()已经拿到toolCalls但act()里判断为 false检查toolCallChatResponse是否被正确赋值。在think()里this.toolCallChatResponse chatResponse;这行必须在返回 true 之前执行否则act()拿不到响应对象。排查时建议打开日志观察think()里打印的toolCallInfo以及act()里打印的results。这两处日志能直接反映工具调用信息是否正常回传。六、语义一致 CTAToolCallAgent 的排障链路里TaoToken 的角色很明确只补模型 Key 和 Base URL让think()里的 LLM 调用先通工具选择信息能正常回传act()里的ToolCallingManager才有东西可执行。它不替 Agent 执行工具也不接管上下文维护。如果你正在配 Key 和 Base URL 这一步卡住可以先到 API Keys 页面创建 Key再对照接入文档确认 Base URL 的写法。配置改完后用本文第四节的验证请求先单独测一次think()确认toolCalls有值再跑完整的 Agent Loop。对于需要长期跑编码类 Agent、频繁调用模型做工具决策的场景可以了解 Coding Plan它在调用额度和稳定性上更适合持续性的 Agent 任务。如果只是想先验证模型对话和工具调用是否通可以直接在模型对话里试一次带工具的请求确认返回体结构符合预期。