← Back to Plugins
Tools

Complexity Router

coco850058 By coco850058 👁 14 views ▲ 0 votes

OpenClaw plugin — classify input complexity and route to the best-fit model. Supports multi-provider cross-vendor switching.

GitHub

Configuration Example

{
  "plugins": {
    "allow": ["complexity-router"],
    "entries": {
      "complexity-router": {
        "enabled": true,
        "config": {
          "classifier": {
            "provider": "your-provider",
            "model": "lightweight-model",
            "timeoutMs": 5000
          },
          "routes": {
            "simple":  { "provider": "...", "model": "..." },
            "medium":  { "provider": "...", "model": "..." },
            "complex": { "provider": "...", "model": "..." },
            "code":    { "provider": "...", "model": "..." }
          }
        }
      }
    }
  }
}

README

# Complexity Router

[中文文档](./README.zh-CN.md)

An OpenClaw plugin that uses a lightweight LLM to pre-classify input complexity and automatically route requests to the most suitable model. Supports multi-provider cross-vendor switching with built-in routing stats and token usage tracking.

## How It Works

On every user message, the plugin hooks into `before_model_resolve`:

1. Sends the user input to a lightweight classifier model (e.g. `gpt-5-nano`)
2. The classifier returns a complexity level: `simple` / `medium` / `complex` / `code`
3. Looks up the routing table and forwards the request to the corresponding model

Falls back to OpenClaw's default model on classification failure.

## Complexity Levels

| Level | Meaning | Typical Scenarios |
|-------|---------|-------------------|
| `simple` | Simple chat | Greetings, small talk, short Q&A |
| `medium` | General questions | Knowledge Q&A, everyday topics |
| `complex` | Complex analysis | Technical discussion, multi-step reasoning, deep analysis |
| `code` | Programming | Code generation, debugging, SQL, algorithms |

## Installation

Copy the `complexity-router` directory to OpenClaw's extensions directory:

```bash
cp -r complexity-router ~/.openclaw/extensions/
```

## Configuration

Add to `openclaw.json`:

```json
{
  "plugins": {
    "allow": ["complexity-router"],
    "entries": {
      "complexity-router": {
        "enabled": true,
        "config": {
          "classifier": {
            "provider": "your-provider",
            "model": "lightweight-model",
            "timeoutMs": 5000
          },
          "routes": {
            "simple":  { "provider": "...", "model": "..." },
            "medium":  { "provider": "...", "model": "..." },
            "complex": { "provider": "...", "model": "..." },
            "code":    { "provider": "...", "model": "..." }
          }
        }
      }
    }
  }
}
```

### Configuration Fields

**classifier** — Classifier settings

| Field | Required | Description |
|-------|----------|-------------|
| `provider` | Yes | Provider for the classifier (must be configured in `models.providers`) |
| `model` | Yes | Classifier model ID (lightweight model recommended to reduce latency) |
| `timeoutMs` | No | Classification request timeout (default: 5000ms) |

**routes** — Routing table

Each of the 4 levels maps to a `{ provider, model }` target. Providers must be configured in `models.providers`.

### Example: Single Provider

All models from the same provider:

```json
{
  "classifier": { "provider": "openai", "model": "gpt-4o-mini" },
  "routes": {
    "simple":  { "provider": "openai", "model": "gpt-4o-mini" },
    "medium":  { "provider": "openai", "model": "gpt-4o" },
    "complex": { "provider": "openai", "model": "o3" },
    "code":    { "provider": "openai", "model": "codex" }
  }
}
```

### Example: Multi-Provider Cross-Vendor

Use a cheap model for classification, high-end models for complex tasks, mixing vendors:

```json
{
  "classifier": { "provider": "dashscope", "model": "qwen-turbo" },
  "routes": {
    "simple":  { "provider": "dashscope", "model": "qwen-turbo" },
    "medium":  { "provider": "crs",       "model": "gpt-5" },
    "complex": { "provider": "crs",       "model": "gpt-5.1" },
    "code":    { "provider": "crs",       "model": "gpt-5.2-codex" }
  }
}
```

Requires both `dashscope` and `crs` configured in `models.providers`.

## Supported API Formats

The plugin automatically selects the request/response format based on the provider's `api` field:

| API Type | Description | Auth Method |
|----------|-------------|-------------|
| `openai-completions` | OpenAI-compatible API (default) | `Authorization: Bearer` |
| `anthropic-messages` | Anthropic Claude Messages API | `x-api-key` |
| `google-generative-ai` | Google Gemini API | `x-goog-api-key` |

The `api` field is configured in `models.providers` and read automatically by the plugin.

### Example: Claude as Classifier

```json
{
  "models": {
    "providers": {
      "anthropic": {
        "baseUrl": "https://api.anthropic.com/v1",
        "apiKey": "sk-ant-...",
        "api": "anthropic-messages"
      }
    }
  },
  "plugins": {
    "entries": {
      "complexity-router": {
        "config": {
          "classifier": { "provider": "anthropic", "model": "claude-haiku-4-5-20251001" },
          "routes": { "..." : "..." }
        }
      }
    }
  }
}
```

### Example: Gemini as Classifier

```json
{
  "models": {
    "providers": {
      "google": {
        "baseUrl": "https://generativelanguage.googleapis.com/v1beta",
        "apiKey": "AIza...",
        "api": "google-generative-ai"
      }
    }
  },
  "plugins": {
    "entries": {
      "complexity-router": {
        "config": {
          "classifier": { "provider": "google", "model": "gemini-2.0-flash" },
          "routes": { "..." : "..." }
        }
      }
    }
  }
}
```

## Prerequisites

The plugin reads provider credentials (baseUrl, apiKey, api) from `models.providers` in `openclaw.json`. Ensure:

1. `classifier.provider` is configured in `models.providers`
2. All providers referenced in `routes` are configured in `models.providers`

## Logs

The plugin outputs to the gateway log:

```
[complexity-router] registered — classifier: crs/gpt-5-nano
[complexity-router] classified as "code" in 1528ms
[complexity-router] routing to crs/gpt-5.2-codex
```

On classification failure:

```
[complexity-router] classifier timed out after 5001ms
[complexity-router] fallback to default model
```

## Stats & Observability

### Chat Command `/router-stats`

Type `/router-stats` in chat to view live statistics:

```
📊 Complexity Router Stats
Uptime: 2h 35m | Total: 42 | Fallback: 1

Routing:
  simple     12 ( 28.6%)  → gpt-5-nano       | In:    3.2k  Out:    8.1k tokens
  medium     15 ( 35.7%)  → gpt-5.1          | In:   12.5k  Out:   45.2k tokens
  complex     8 ( 19.0%)  → gpt-5.2          | In:    8.7k  Out:   32.1k tokens
  code        7 ( 16.7%)  → gpt-5.3-codex    | In:   15.3k  Out:   52.8k tokens

Classifier (gpt-5-nano): 42 calls | Avg 2,341ms | In: 1.8k Out: 0.2k tokens
```

### HTTP Endpoint `GET /complexity-router/stats`

Returns full statistics in JSON format, suitable for monitoring systems:

```bash
curl http://localhost:18789/complexity-router/stats
```

```json
{
  "startedAt": 1772288992234,
  "uptimeMs": 9300000,
  "total": 42,
  "fallback": 1,
  "classifier": {
    "requests": 42,
    "totalMs": 98322,
    "inputTokens": 1823,
    "outputTokens": 210
  },
  "levels": {
    "simple":  { "count": 12, "inputTokens": 3200,  "outputTokens": 8100 },
    "medium":  { "count": 15, "inputTokens": 12500, "outputTokens": 45200 },
    "complex": { "count": 8,  "inputTokens": 8700,  "outputTokens": 32100 },
    "code":    { "count": 7,  "inputTokens": 15300, "outputTokens": 52800 }
  }
}
```

### Stats Fields

| Field | Description |
|-------|-------------|
| `classifier.inputTokens/outputTokens` | Tokens consumed by the classifier itself (extracted from classification API response) |
| `levels.*.inputTokens/outputTokens` | Tokens consumed by routed models (collected via `llm_output` hook) |
| `fallback` | Number of times classification failed and fell back to the default model |

## Compatibility

- Supports OpenAI, Anthropic, and Google Gemini API formats
- Auto-adapts to streaming/non-streaming APIs (auto-downgrades when provider forces streaming)
- Classification timeout triggers automatic fallback without affecting replies
- Token stats auto-adapt to each API's usage field format
tools

Comments

Sign in to leave a comment

Loading comments...