ai-switch

module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 21, 2026 License: MIT

README

ai-switch

Go Report Card

English | 中文

A lightweight local proxy that lets any AI CLI tool (Claude Code, Codex CLI, etc.) use third-party LLM APIs through a unified local endpoint.

One binary, one config, any AI CLI → any LLM API.

Features

  • Multi-protocol: Auto-detects client protocol (Responses API, Anthropic Messages, Chat Completions) and converts transparently
  • Zero-intrusion: No changes to your CLI config files, just point base_url to the local proxy
  • Scene routing: Route Claude Code requests to different models based on request type (thinking, web search, background tasks)
  • Model mapping: Map client model names to upstream model names at the route level
  • Cross-provider routing: Route different scenes to different providers (e.g. thinking → DeepSeek, web search → Zhipu)
  • Hot reload: Update config without restart (POST /api/reload or kill -HUP)
  • Admin UI: Built-in web dashboard for managing providers and routes
  • Lightweight: Pure Go, single binary, no CGO

Installation

git clone https://github.com/keepmind9/ai-switch.git
cd ai-switch
make build-all   # build frontend + Go binary (includes Admin UI)

If you don't need the Admin UI, use make build instead (Go only, faster).

Quick Start

1. Create config
cp config.example.yaml config.yaml

Edit config.yaml with your provider credentials:

server:
  host: "0.0.0.0"
  port: 12345

default_route: "gw-default"

providers:
  deepseek:
    name: "DeepSeek"
    base_url: "https://api.deepseek.com/v1"
    api_key: "${DEEPSEEK_API_KEY}"
    format: "chat"

routes:
  "gw-default":
    provider: "deepseek"
    default_model: "deepseek-chat"

Note: base_url can include /v1 or not — just copy it from your provider's documentation.

2. Start the server
./bin/server -c config.yaml
3. Point your CLI tool

Claude Code:

export ANTHROPIC_BASE_URL=http://localhost:12345
export ANTHROPIC_API_KEY=gw-default

Codex CLI:

[model_providers.proxy]
name = "ai-switch"
base_url = "http://localhost:12345/v1"
api_key = "gw-default"
wire_api = "responses"

Any OpenAI-compatible tool:

export OPENAI_BASE_URL=http://localhost:12345/v1
export OPENAI_API_KEY=gw-default

That's it — your CLI tool will now route requests through ai-switch to your configured provider.

How It Works

Claude Code ──→ ai-switch ──→ DeepSeek (chat)
Codex CLI  ──→          ──→ Zhipu    (anthropic)
Any tool   ──→          ──→ MiniMax  (chat)

ai-switch sits between your CLI tool and upstream LLM providers. It:

  • Detects the client protocol automatically (Anthropic / Responses / Chat)
  • Routes requests to the correct provider based on the API key (route key)
  • Converts between protocols when needed (e.g. Anthropic → Chat Completions)
  • Detects request scenes (thinking, web search, etc.) for smart routing

The route key (gw-default in the example above) serves as both the API key for authentication and the routing identifier.

Configuration

Providers

Define your upstream LLM vendor connections:

providers:
  deepseek:
    name: "DeepSeek"
    base_url: "https://api.deepseek.com/v1"
    api_key: "${DEEPSEEK_API_KEY}"    # supports ${ENV_VAR} expansion
    format: "chat"                     # chat (default) | responses | anthropic
    think_tag: "think"                 # optional: strip reasoning tags from responses
    models:                            # optional: for validation warnings
      - "deepseek-chat"
      - "deepseek-reasoner"
Routes

Routes map API keys to providers and models:

routes:
  "gw-default":
    provider: "deepseek"
    default_model: "deepseek-chat"
Scene Map

Route Claude Code requests to different models based on what it's doing:

routes:
  "gw-claude":
    provider: "zhipu"
    default_model: "glm-5.1"
    long_context_threshold: 60000
    scene_map:
      default: "glm-5.1"
      think: "glm-5.1"
      websearch: "glm-4.7"
      background: "glm-4.5-air"
      longContext: "glm-5.1"
Scene Key Detection
Long Context longContext Token count exceeds long_context_threshold
Background background Model name contains "haiku"
Web Search websearch Tools contain web_search_* type
Thinking think thinking field present
Image image User messages contain image blocks
Default default Fallback

Priority: longContext > background > websearch > think > image > default

Model Map

Map client model names to upstream models:

routes:
  "gw-default":
    provider: "deepseek"
    default_model: "deepseek-chat"
    model_map:
      "claude-sonnet-4-5": "deepseek-chat"
      "gpt-4o": "deepseek-chat"
Cross-Provider Routing

Use provider:model to route to a different provider within the same route:

routes:
  "gw-default":
    provider: "minimax"
    default_model: "MiniMax-M2.5"
    scene_map:
      default: "MiniMax-M2.5"
      think: "deepseek:deepseek-chat"
      websearch: "zhipu:glm-4.7"
Model Resolution Priority
  1. ModelMap — exact model name match (case-insensitive)
  2. SceneMap — scene detection (Anthropic protocol only)
  3. DefaultModel — fallback

CLI

ai-switch serve -c config.yaml    # Start the server
ai-switch check -c config.yaml    # Validate config without starting

Running without a subcommand defaults to serve:

ai-switch -c config.yaml          # Same as: ai-switch serve -c config.yaml
Config validation
$ ai-switch check -c config.yaml

Checking config.yaml ...

  Providers: 3
  Routes:    3
  Default:   gw-default

✓ Config is valid.

Exit codes: 0 = valid, 1 = has errors, 2 = warnings only.

Admin UI

Open http://localhost:12345 in your browser for a built-in dashboard to manage providers, routes, and view usage statistics.

Build

make build      # fmt + vet + compile
make build-all  # build frontend + Go binary
make dev        # run in dev mode
make test       # run tests
make clean      # remove binary

License

MIT

Directories

Path Synopsis
cmd
server command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL