Skip to content

fix: ToolChoice.None 映射错误导致强制调用工具#2226

Closed
BG0527 wants to merge 4 commits into
agentscope-ai:mainfrom
BG0527:fix-AnthropicTools-mapping
Closed

fix: ToolChoice.None 映射错误导致强制调用工具#2226
BG0527 wants to merge 4 commits into
agentscope-ai:mainfrom
BG0527:fix-AnthropicTools-mapping

Conversation

@BG0527

@BG0527 BG0527 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

关联 issue

AgentScope-Java Version

2.0.1-SNAPSHOT

Description

Background

ToolChoice 抽象定义了四种工具调用策略:Auto(模型自主决定)、None(禁止工具调用,仅返回文本)、Required(强制调用工具)和 Specific(强制调用指定工具)。其中 ToolChoice.None 的语义明确为"阻止模型调用任何工具"。

OpenAI API 原生支持 tool_choice: "none" 值,可直接表达此语义。但 Anthropic API 的 tool_choice 参数仅支持 autoanytool 三种类型,不存在 none 值。

Root Cause

AnthropicToolsHelper.applyToolChoice() 在处理 ToolChoice.None 时,将其映射为 Anthropic SDK 的 ToolChoiceAny(即 API 值 "any")。"any" 的语义是强制模型必须调用某个工具,与 None 的预期语义"禁止工具调用"完全相反。

原代码注释 // Anthropic doesn't have None, use Any instead 表明这是一个有意识的 fallback 决策,但选择了语义错误的映射方向。

影响: 当调用方指定 ToolChoice.None 试图获取纯文本响应时,模型反而被强制进行工具调用,导致非预期行为。

Fix

AnthropicToolsHelper.applyTools() 方法中,检测到 ToolChoice.None 时直接返回,不向 MessageCreateParams.Builder 添加任何工具定义。Anthropic API 在请求中不包含 tools 字段时,模型不会进行工具调用,自然产生纯文本响应——这是 Anthropic 平台上表达"禁用工具"的唯一正确方式。

applyToolChoice() 移除了 None → any 的错误映射,添加防御性日志以防此方法被直接调用时误传 None

Changed files:

1. agentscope-extensions/agentscope-extensions-model/agentscope-extensions-model-anthropic/src/main/java/io/agentscope/extensions/model/anthropic/formatter/AnthropicToolsHelper.java

  • applyTools(): 在工具添加逻辑之前增加 ToolChoice.None 检查,若匹配则记录 debug 日志并直接返回,不向请求添加任何工具
  • applyToolChoice(): 移除 ToolChoice.None → ToolChoiceAny 的错误映射,增加防御性 warn 日志

2. agentscope-extensions/agentscope-extensions-model/agentscope-extensions-model-anthropic/src/test/java/io/agentscope/extensions/model/anthropic/formatter/AnthropicToolsHelperTest.java

  • testApplyToolChoiceNone(): 修正断言,验证 None 时 tools 为空且 toolChoice 为空(原错误断言 isAny()
  • 新增 testApplyToolChoiceNoneWithMultipleTools(): 验证多个工具场景下 None 同样抑制所有工具
  • 新增 testApplyToolChoiceNoneWithNullOptions(): 验证 options 为 null 时工具正常应用
  • 新增 testApplyToolChoiceNoneWithEmptyOptions(): 验证无 toolChoice 的空 options 时工具正常应用

Checklist

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (e.g. links, examples, etc.)
  • Code is ready for review

@BG0527 BG0527 force-pushed the fix-AnthropicTools-mapping branch from 02fddba to 78e951e Compare July 15, 2026 09:38
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...odel/anthropic/formatter/AnthropicToolsHelper.java 60.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment on lines +58 to +60
// ToolChoice.None means "prevent the model from calling any tools".
// The Anthropic API has no native "none" value for tool_choice,
// so the only correct way to enforce this is to omit tools entirely.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前项目中依赖的 anthropic-sdk(com.anthropic:anthropic-java:2.14.0)中有 ToolChoice.ofNone() 选项,是不是应该保留 tools,并在 applyToolChoice() 显示设置:builder.toolChoice(ofNone(ToolChoiceNone.builder().build()))
这样才正确表达“这些工具存在,但本轮禁止调用工具”?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢您的宝贵评论!我之前没有区分两种禁用工具的实现逻辑,忽略了 SDK 自带的ToolChoice.ofNone()标准写法。
现已按照您的建议修改代码:保留tools字段,通过显式配置toolChoice.ofNone()实现 “存在工具、但本轮禁止调用” 的语义,原有防御日志也做保留。相关修改已提交新 PR #2232

@BG0527 BG0527 closed this Jul 15, 2026
@BG0527 BG0527 deleted the fix-AnthropicTools-mapping branch July 15, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: ToolChoice.None 被映射为 Anthropic any

2 participants