Skip to content

在llm配置器中加入deepseek Anthropic API格式的支持新页面#7760

Open
MostimaBridges wants to merge 3 commits intoAstrBotDevs:masterfrom
MostimaBridges:feature/deepseek-anthropic-api-support
Open

在llm配置器中加入deepseek Anthropic API格式的支持新页面#7760
MostimaBridges wants to merge 3 commits intoAstrBotDevs:masterfrom
MostimaBridges:feature/deepseek-anthropic-api-support

Conversation

@MostimaBridges
Copy link
Copy Markdown
Contributor

@MostimaBridges MostimaBridges commented Apr 24, 2026

Closes #7757

新增 DeepSeek Anthropic API 格式支持,并补充对应的 WebUI 配置入口与文案说明。

Modifications / 改动点

  • 在后端 provider 模板中新增 DeepSeek Anthropic 模板,并将 DeepSeek OpenAI 兼容入口默认值调整为 https://api.deepseek.com。
  • 在 anthropic provider 适配器中补齐 DeepSeek Anthropic 兼容逻辑,包括 thinking/output_config 归一化、tool_choice 兼容,以及对不支持图片输入场景的降级处理。
  • 在 WebUI 的 provider source schema 中为 DeepSeek OpenAI / DeepSeek Anthropic 增加专属提示、说明和页面注记。
  • 更新中英俄三套 i18n 文案与配置提示,使 DeepSeek V4、thinking 默认行为和 effort/max 说明与当前官方文档一致。

This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

  • c:/Users/hogwa/Desktop/astrbot/AstrBot/.venv/Scripts/python.exe -m ruff format .
  • c:/Users/hogwa/Desktop/astrbot/AstrBot/.venv/Scripts/python.exe -m ruff check .
  • Python 片段验证:确认 DeepSeek Anthropic 模板默认值存在,并验证 _apply_provider_specific_payload_overrides 会将 thinking 归一化为 enabled、仅保留 output_config.effort。
  • VS Code diagnostics:已检查本次改动文件,未发现错误。

Checklist / 检查清单

  • 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txt 和 pyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

Add DeepSeek Anthropic-compatible support across backend provider templates, Anthropic adapter logic, and the WebUI provider configuration experience.

New Features:

  • Introduce a DeepSeek Anthropic chat provider template with default endpoint and thinking config in the backend configuration.
  • Expose dedicated DeepSeek OpenAI and DeepSeek Anthropic configuration hints, labels, and notes in the WebUI provider source forms.

Enhancements:

  • Extend the Anthropic provider adapter with DeepSeek-specific payload normalization for thinking and output_config, generalized tool_choice handling, and graceful fallback when image input is not supported.
  • Refine provider configuration schema handling via a reusable builder that injects generic and DeepSeek-specific hints into provider source schemas.
  • Update default DeepSeek OpenAI API base URL, thinking-related configuration hints, provider descriptions, and DeepSeek model examples to align with current DeepSeek and Anthropic documentation.

Documentation:

  • Refresh English, Chinese, and Russian i18n strings for provider configuration, DeepSeek usage, and thinking options to match the latest platform terminology.

@auto-assign auto-assign Bot requested review from Soulter and anka-afk April 24, 2026 05:21
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. area:webui The bug / feature is about webui(dashboard) of astrbot. labels Apr 24, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • In buildProviderSourceSchema you deep-clone via JSON.parse(JSON.stringify(schema)), which will silently strip non-JSON-safe values (e.g. functions, Dates); consider using a more robust clone utility or structuredClone to avoid unexpected loss of metadata if the schema becomes richer in the future.
  • The DeepSeek-specific checks (isDeepSeekAnthropicSource, isDeepSeekOpenAISource, _is_deepseek_provider) currently rely on hardcoded provider/type strings and a substring match on api.deepseek.com/anthropic; it may be worth centralizing these rules or making the URL match slightly more flexible to tolerate regional/alternative DeepSeek Anthropic endpoints.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `buildProviderSourceSchema` you deep-clone via `JSON.parse(JSON.stringify(schema))`, which will silently strip non-JSON-safe values (e.g. functions, Dates); consider using a more robust clone utility or `structuredClone` to avoid unexpected loss of metadata if the schema becomes richer in the future.
- The DeepSeek-specific checks (`isDeepSeekAnthropicSource`, `isDeepSeekOpenAISource`, `_is_deepseek_provider`) currently rely on hardcoded `provider`/`type` strings and a substring match on `api.deepseek.com/anthropic`; it may be worth centralizing these rules or making the URL match slightly more flexible to tolerate regional/alternative DeepSeek Anthropic endpoints.

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/anthropic_source.py" line_range="36-38" />
<code_context>
 class ProviderAnthropic(Provider):
+    IMAGE_PLACEHOLDER_TEXT = "[Image Attachment]"
+
     @staticmethod
     def _ensure_usable_response(
         llm_response: LLMResponse,
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Handle dict-style `tool_choice` values that use OpenAI-style `"required"` semantics.

In `_normalize_tool_choice`, the string value `"required"` is mapped to `{ "type": "any" }`, but when `tool_choice` is a dict, only `"auto" | "any" | "none" | "tool"` are handled. A dict like `{ "type": "required" }` currently results in `None` and then defaults to `{ "type": "auto" }`, changing the intended behavior.

To keep behavior consistent and avoid subtle bugs, either handle dict `{"type": "required"}` the same as the string case (map to `{ "type": "any" }`) or explicitly reject unsupported dict values instead of silently falling back to `auto`.

Suggested implementation:

```python
    def _normalize_tool_choice(self, tool_choice: Any) -> dict | None:
        """
        Normalize various tool_choice formats into Anthropic's expected schema.

        Supports:
        - String values: "auto" | "any" | "none" | "tool" | "required"
        - Dict values:   {"type": "...", ...} with the same allowed types

        OpenAI-style `"required"` semantics are mapped to Anthropic's `"any"`:
        - "required"     -> {"type": "any"}
        - {"type": "required"} -> {"type": "any"}
        """
        # String-style tool_choice
        if isinstance(tool_choice, str):
            normalized = tool_choice.strip().lower()
            if normalized == "required":
                # OpenAI "required" => Anthropic "any"
                return {"type": "any"}
            if normalized in ("auto", "any", "none"):
                return {"type": normalized}
            # For "tool" as a bare string we cannot know which tool, so treat as "any"
            if normalized == "tool":
                return {"type": "any"}
            return None

        # Dict-style tool_choice
        if isinstance(tool_choice, dict):
            type_value = str(tool_choice.get("type", "")).strip().lower()

            # Keep behavior consistent with string-style "required"
            if type_value == "required":
                return {"type": "any"}

            if type_value in ("auto", "any", "none"):
                return {"type": type_value}

            if type_value == "tool":
                # Anthropic expects {"type": "tool", "name": "<tool_name>"}
                tool_name = tool_choice.get("name")
                if isinstance(tool_name, str) and tool_name:
                    return {"type": "tool", "name": tool_name}
                # If tool name is missing/invalid, fall back to "any" rather than silently "auto"
                return {"type": "any"}

            # Explicitly reject unsupported dict values instead of silently falling back to "auto"
            raise ValueError(
                f"Unsupported tool_choice dict type: {tool_choice!r}. "
                'Expected "auto", "any", "none", "tool", or "required".'
            )

        # Unsupported type, let caller decide default behavior
        return None

    def _is_deepseek_provider(self) -> bool:
        provider = str(self.provider_config.get("provider", "")).strip().lower()
        if provider == "deepseek":
            return True
        return "api.deepseek.com/anthropic" in str(self.base_url).strip().lower()

    def _supports_image_input(self) -> bool:

```

I had to infer the location and signature of `_normalize_tool_choice` because it wasn’t present in the provided snippet. To integrate this correctly you should:
1. Remove or adjust any existing `_normalize_tool_choice` implementation to avoid duplicate definitions, merging the new dict-handling logic (especially the `"required"` mapping and the explicit `ValueError` for unsupported types) into your current function.
2. Ensure callers of `_normalize_tool_choice` are prepared for the possibility that it now raises `ValueError` for invalid dict-style `tool_choice` values; if you prefer not to raise, you can instead return `None` in that branch, but the `"required"``{"type": "any"}` mapping should remain.
3. If your codebase uses different typing conventions (e.g., `Dict[str, Any]` instead of `dict` or no `| None`), adjust the type hints accordingly to match your existing style.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/provider/sources/anthropic_source.py
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for DeepSeek's Anthropic-compatible endpoint, including a new provider template and logic for handling thinking configurations and image placeholders. It also enhances the dashboard with provider-specific hints and localized descriptions. A critical issue was identified in the Anthropic provider adapter where enabling thinking for DeepSeek removes the required budget_tokens field, which could lead to API validation errors.

Comment thread astrbot/core/provider/sources/anthropic_source.py Outdated
Comment thread astrbot/core/provider/sources/anthropic_source.py Fixed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. area:webui The bug / feature is about webui(dashboard) of astrbot. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]希望加入对deepseekV4的支持

2 participants