ToolCallAgent 的 DashScopeChatOptions 调不通?TaoToken 只补模型 Key 和 Base URL
2026/9/20 1:09:57 网站建设 项目流程

一、ToolCallAgent 调不通的真实场景:think() 请求直接失败

如果你正在用 Spring AI 仿写 OpenManus 的 ToolCallAgent,大概率会踩到下面这个坑:think()里通过ChatClient发起带工具的请求,结果要么抛异常,要么返回的AssistantMessagegetToolCalls()是空列表,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_source=taotoken_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())这段上下文回写逻辑。要改的只有两处:

  1. 模型 Key:从 TaoToken 控制台创建,替换掉原来准备填 DashScope 官方 Key 的位置。
  2. 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 代码里手动构建ChatModelOpenAiChatModel,对应写法如下:

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注入进去构建ChatClient

ChatClient 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而不是OpenAiChatOptions,Base 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()就能返回 true,ToolCallingManager.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/v1https://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。这两处日志能直接反映工具调用信息是否正常回传。

六、语义一致 CTA

ToolCallAgent 的排障链路里,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 任务。如果只是想先验证模型对话和工具调用是否通,可以直接在模型对话里试一次带工具的请求,确认返回体结构符合预期。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询