Skip to content

[backend] Deepseek LLMBackend — OpenAI-compatible factory + pricing + key + doctor #327

@dep0we

Description

@dep0we

Parent

Part of meta-issue #325 (expand LLM provider catalog). Architectural decision to land in core (not separate package) is documented there.

Scope

Add Deepseek as a registered LLM backend. Deepseek's chat-completions endpoint is OpenAI-compatible (POST https://api.deepseek.com/v1/chat/completions with OpenAI request/response shape), so implementation is a thin factory over atomic_agents/llm/openai_compat.py mirroring moonshot.py.

Implementation

atomic_agents/llm/deepseek.py (new file, ~50 LOC)

"""DeepseekLLMBackend factory over OpenAICompatibleLLMBackend.

Deepseek's chat-completions API is OpenAI-shape with base URL
https://api.deepseek.com/v1 and model strings like deepseek-chat,
deepseek-reasoner. Mirrors moonshot.py's factory pattern.

Deepseek-reasoner is a thinking model; output may include <think>...</think>
tags depending on API version. Handle gracefully in the openai_compat layer
or in a Deepseek-specific post-processor.
"""

from .openai_compat import OpenAICompatibleLLMBackend, OpenAICompatibleConfig

DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1"
DEEPSEEK_PROVIDER_NAME = "deepseek"

DEEPSEEK_MODEL_CATALOG = ("deepseek-chat", "deepseek-reasoner")


def make_deepseek_backend(api_key: str) -> OpenAICompatibleLLMBackend:
    """Construct a Deepseek backend with Deepseek base URL + catalog."""
    return OpenAICompatibleLLMBackend(
        config=OpenAICompatibleConfig(
            base_url=DEEPSEEK_BASE_URL,
            api_key=api_key,
            provider_name=DEEPSEEK_PROVIDER_NAME,
            model_catalog=DEEPSEEK_MODEL_CATALOG,
        )
    )

Registration in atomic_agents/llm/__init__.py

Add to _register_default_backends(). Resolve via _llm._get_deepseek_key(); skip silently if no key.

atomic_agents/_llm.py — key resolver

def _get_deepseek_key() -> str:
    return _get_key(
        env_vars=["ATOMIC_AGENTS_DEEPSEEK_KEY", "DEEPSEEK_API_KEY"],
        keychain_name="atomic-agents-deepseek",
        config_key="deepseek",
    )

atomic_agents/_costs.py — pricing table

# Deepseek pricing as of impl date. Source: https://api-docs.deepseek.com/quick_start/pricing.
"deepseek/deepseek-chat":     {"input": 0.27, "output": 1.10},   # USD per 1M tokens (cache-miss)
"deepseek/deepseek-reasoner": {"input": 0.55, "output": 2.19},

Deepseek publishes cache-hit and cache-miss prices separately. Use cache-miss for safety (worst case); document the convention in a _costs.py comment. Verify exact numbers at impl time.

Deepseek-specific quirks to handle

  • Reasoner thinking-token output. deepseek-reasoner returns thinking content. Decide where to surface or strip — possibly add a reasoning_content field to _RawLLMResponse if not already present, or treat as part of normal content. Resolve in plan-eng-review.
  • Cache pricing tiers. Cache-hit prices are ~10x lower than cache-miss. If the framework wants to track cache-hit ratios for cost accuracy, that's a cross-cutting concern that affects every provider eventually (Anthropic prompt caching also has this shape). Out of scope here; file separately if pursued.

Doctor integration

Same shape as Grok — extend check_provider_keys iteration.

Spec/31 amendment

Add DeepseekLLMBackend to §"Reference implementations". Note the thinking-token handling decision in §"Open questions" or a new §"Reasoning-model output handling" subsection if it warrants standing reference.

Conformance suite parametrization

Verify parametrization picks up Deepseek. Add Deepseek-specific smoke test for the base URL + request shape.

Acceptance criteria

  • atomic_agents/llm/deepseek.py shipped with make_deepseek_backend factory.
  • Registration skips silently when no Deepseek key resolves.
  • _get_deepseek_key() resolver in _llm.py.
  • Pricing table entries for deepseek-chat + deepseek-reasoner in _costs.py with cache-miss convention documented.
  • Doctor check_provider_keys enumerates Deepseek.
  • Conformance suite passes.
  • Smoke test for request shape.
  • spec/31 amended.
  • CHANGELOG entry.
  • Thinking-token handling decision documented (in spec/31 or a follow-up issue).

Out of scope

  • Cache-hit pricing tier tracking (cross-cutting; separate issue if pursued).
  • Deepseek streaming.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendProtocol-pattern backend abstractions (memory, logs, locks, etc.)enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions