# How Reasonix's Provider Abstraction Supports Multiple LLM Backends (DeepSeek, Anthropic, OpenAI)

> Discover how Reasonix's provider abstraction seamlessly integrates DeepSeek, Anthropic, and OpenAI LLM backends. Effortlessly swap providers without code modification for ultimate flexibility.

- Repository: [YHH/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)
- Tags: architecture
- Published: 2026-08-13

---

**Reasonix implements a uniform `Provider` interface that abstracts all LLM interactions, enabling the host to swap between DeepSeek, Anthropic, and OpenAI backends without code changes.**

The provider abstraction in DeepSeek-Reasonix treats every LLM service as a pluggable extension. By defining common data structures for model catalogs, streaming completions, and error handling, the architecture eliminates provider-specific logic from the host application. This design allows developers to add new backends—proprietary or open-source—by implementing a single Go interface.

## Core Provider Interface

The foundation of Reasonix's multi-backend support resides in [`sdk/go/sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/sdk.go). Here, the `Provider` interface declares three essential operations:

```go
type Provider interface {
    Catalog(ctx context.Context) ([]ProviderDescriptor, error)
    Stream(ctx context.Context, req ProviderRequest) (<-chan ProviderChunk, error)
    // Additional methods for error normalization and capability negotiation
}

```

**`Catalog`** returns available models wrapped in `ProviderDescriptor` structs. **`*Stream`** initiates a token-by-token completion flow. Each backend adapter—OpenAI, Anthropic, or DeepSeek—implements these methods against its native API.

## Backend Implementations

### OpenAI Provider ([`internal/provider/openai/openai.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/provider/openai/openai.go))

The OpenAI adapter maps Reasonix's generic request format to OpenAI's chat completions endpoint. It handles:

- **Model mapping**: Translates Reasonix model identifiers to OpenAI model names
- **Streaming SSE**: Converts server-sent events into `ProviderChunk` values
- **Tool call serialization**: Reformats OpenAI function-calling responses into `ProviderToolCall` structs

```go
func (p *OpenAIProvider) Stream(ctx context.Context, req ProviderRequest) (<-chan ProviderChunk, error) {
    openaiReq := p.toOpenAIChatRequest(req) // Transform to OpenAI schema
    stream, err := p.client.CreateChatCompletionStream(ctx, openaiReq)
    // ... pump chunks through channel as ProviderChunk
}

```

### Anthropic Provider ([`internal/provider/anthropic/anthropic.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/provider/anthropic/anthropic.go))

Anthropic's implementation mirrors the same contract but targets the Messages API. Key adaptations include:

- **Message format conversion**: Reasonix's message array maps to Anthropic's `messages` parameter
- **System prompt handling**: Extracts system messages into Anthropic's top-level `system` field
- **Streaming protocol**: Adapts Anthropic's event-stream format to `ProviderChunk` emission

Both providers share error normalization logic, converting HTTP status codes and JSON error bodies into standardized `ProviderErrorCode` values.

### DeepSeek Integration

DeepSeek support follows the identical pattern. A DeepSeek provider implements `Catalog` and `Stream` against DeepSeek's API specification, returning the same DTOs. The host cannot distinguish between DeepSeek, OpenAI, or Anthropic at runtime—only the `providerRef` identifier differs.

## Extension and Registration

Providers load dynamically through the extension system. [`internal/extension/providerext/providerext.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/extension/providerext/providerext.go) registers provider plugins with the host:

```go
// Extension entry point wires provider into host
func NewProviderExtension(p Provider) *Extension {
    return &Extension{
        provider: p,
        // Expose provider capabilities to host RPC layer
    }
}

```

When the host initializes, it queries each extension's `Catalog` method and builds a unified model registry. Users select models via `providerRef` strings like `"plugin/openai/gpt-4o"` or `"plugin/anthropic/claude-3-opus"`.

## Data Structures: Shared Contracts

All providers communicate through types defined in [`sdk/go/types_generated.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/types_generated.go):

| Struct | Purpose |
|--------|---------|
| `ProviderDescriptor` | Model metadata: ID, display name, capabilities |
| `ProviderRequest` | Completion parameters: messages, temperature, effort, tools |
| `ProviderChunk` | Streaming output: text delta, tool calls, usage stats, finish reason |
| `ProviderError` | Normalized failure: error code, message, retryable flag |

This shared schema ensures that a `ProviderRequest` created for OpenAI transports identically to Anthropic—only the concrete `Stream` implementation interprets field semantics differently.

## Runtime Request Flow

1. **Catalog discovery**: Host calls `Catalog()` on all loaded providers, aggregating results into a single model picker
2. **Request routing**: User selects a model; host extracts `providerRef` to locate the correct provider instance
3. **Stream initiation**: Host invokes `Stream(ctx, req)` with a standardized request
4. **Chunk pumping**: Provider adapter converts native API responses into `ProviderChunk` values pushed through a Go channel
5. **Error handling**: Provider adapters translate service-specific failures into `ProviderError` codes the host handles uniformly

## Example: Configuring Multiple Providers

```go
package main

import (
    "os"
    "github.com/reasonix/sdk/go"
    "github.com/reasonix/internal/provider/openai"
    "github.com/reasonix/internal/provider/anthropic"
)

func main() {
    // OpenAI backend
    openaiProvider := openai.NewProvider(openai.Config{
        APIKey:  os.Getenv("OPENAI_API_KEY"),
        BaseURL: "https://api.openai.com/v1",
    })
    
    // Anthropic backend
    anthropicProvider := anthropic.NewProvider(anthropic.Config{
        APIKey: os.Getenv("ANTHROPIC_API_KEY"),
    })
    
    // DeepSeek backend (hypothetical custom implementation)
    deepseekProvider := &DeepSeekProvider{
        apiKey: os.Getenv("DEEPSEEK_API_KEY"),
        baseURL: "https://api.deepseek.com/v1",
    }
    
    // Host automatically discovers all three via extension registration
    host, err := reasonix.StartHost(handler, reasonix.Options{
        Extensions: []reasonix.Extension{
            providerext.New(openaiProvider),
            providerext.New(anthropicProvider),
            providerext.New(deepseekProvider),
        },
    })
}

```

Each provider operates independently. The host manages lifecycle, request multiplexing, and unified telemetry without provider-specific conditionals.

## Summary

- **Single interface**: The `Provider` contract in [`sdk/go/sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/sdk.go) abstracts all LLM operations
- **Three reference implementations**: OpenAI, Anthropic, and extensible patterns for DeepSeek in `internal/provider/`
- **Dynamic loading**: Extension system in [`internal/extension/providerext/providerext.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/extension/providerext/providerext.go) enables runtime provider registration
- **Shared DTOs**: [`sdk/go/types_generated.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/types_generated.go) defines backend-agnostic data structures
- **Uniform error handling**: All adapters normalize failures into `ProviderErrorCode` values

## Frequently Asked Questions

### How do I add a custom LLM provider to Reasonix?

Implement the `Provider` interface from [`sdk/go/sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/sdk.go) with `Catalog` and `Stream` methods. Wrap your implementation in `providerext.New()` and pass it to `reasonix.StartHost`. See [`internal/provider/openai/openai.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/provider/openai/openai.go) for a complete reference implementation.

### What happens if an LLM backend returns a non-streaming response?

The provider adapter must still return a `<-chan ProviderChunk` channel. Buffer the complete response and emit it as a single chunk, or implement client-side streaming by chunking the response artificially. The host expects uniform streaming behavior regardless of backend capabilities.

### Can I use multiple API keys for different providers simultaneously?

Yes. Each provider instance holds its own configuration including API keys. Initialize separate provider structs with distinct credentials, register all with the extension system, and the host routes requests based on model selection without key conflicts.

### How does Reasonix handle provider-specific features like Anthropic's extended thinking?

The `ProviderRequest` struct includes an `Effort` field that backends interpret according to their capabilities. Anthropic maps "high" effort to its extended thinking mode; OpenAI might map it to increased temperature sampling. Backend adapters translate generic effort levels into API-specific parameters privately.