Skip to content

Commit f58b040

Browse files
author
admin
committed
feat: 三层路由架构重构 — FastRules + LLM分类器 + 配置化
- 新增 config.yaml: 模型、tier、分类器、快速规则全部配置化 - 重写 router.py: Layer 1 快速规则(<1ms) → Layer 2 LLM分类器(带缓存) → Layer 3 模型选择 - 更新 server.py: route 改为 async,支持传入 http_session - 分类器使用 MiniMax-M2.5 免费模型,支持 reasoning_content 解析 - 分类结果 LRU 缓存(可配置大小和 TTL) - 不同 tier 真正路由到不同模型(code→GLM-5, reasoning→DeepSeek, creative→GPT-5.2) - docker-compose 挂载 config.yaml,修改配置无需重建镜像 - Dockerfile 添加 pyyaml 依赖
1 parent 3e57d8c commit f58b040

7 files changed

Lines changed: 755 additions & 491 deletions

File tree

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# SmartRouter 配置
22

33
# 上游 OpenAI 兼容 API 地址
4-
NEW_API_URL=http://127.0.0.1:30080/v1/chat/completions
4+
# Docker 环境下使用 host.docker.internal 访问宿主机
5+
NEW_API_URL=http://host.docker.internal:30080/v1/chat/completions
56

67
# 上游 API 密钥(必填)
78
NEW_API_KEY=sk-your-api-key-here

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ FROM python:3.11-slim
33
WORKDIR /app
44

55
# 复制代码
6-
COPY router.py server.py ./
6+
COPY router.py server.py config.yaml ./
77

88
# 安装依赖
9-
RUN pip install --no-cache-dir -U pip aiohttp
9+
RUN pip install --no-cache-dir -U pip aiohttp pyyaml
1010

1111
# 暴露端口
1212
EXPOSE 30081

README.md

Lines changed: 57 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,72 @@
11
# SmartRouter
22

3-
智能 LLM 路由代理 — 根据请求内容自动选择最合适(最便宜)的模型,完整支持 OpenAI API 协议。
3+
智能 LLM 路由代理 — 三层架构自动选择最合适的模型,完整支持 OpenAI API 协议。
44

55
## 特性
66

7+
- **三层智能路由**:快速规则 → LLM 分类器(带缓存)→ 模型选择
78
- **透明代理**:完整透传 OpenAI `/v1/chat/completions` 协议,只替换 model 字段
89
- **Tool Calling**:完整支持 tools / tool_choice / tool_calls 透传
910
- **流式响应**:SSE (Server-Sent Events) 逐 chunk 透传
1011
- **多轮对话**:messages 数组完整转发,不丢失上下文
11-
- **智能路由**基于关键词分析自动选择 tier(simple / medium / complex / reasoning)
12+
- **全配置化**模型、规则、分类器全部在 `config.yaml` 中配置,改配置不改代码
1213
- **异步高并发**:基于 aiohttp,支持并发请求
1314
- **零侵入**:不修改请求体(除 model)和响应体,上游返回什么就返回什么
1415

15-
## 原理
16+
## 路由架构
1617

1718
```
18-
客户端请求 → SmartRouter 分析内容 → 选择最便宜的模型 → 透传到上游 API → 原样返回响应
19+
请求进入
20+
21+
22+
┌─ Layer 1: 快速规则 (<1ms) ──────────────────────────┐
23+
│ • 带 tools 参数 → code tier │
24+
│ • 消息含代码块 → code tier │
25+
│ • system prompt 含代码/推理关键词 → 对应 tier │
26+
│ • 短消息 (<10字符) → simple tier │
27+
│ 命中 → 直接路由(拦截 60-70% 请求) │
28+
└──────────────────────────────────────────────────────┘
29+
│ 未命中
30+
31+
┌─ Layer 2: LLM 分类器 (带缓存) ──────────────────────┐
32+
│ • 用便宜模型做一次任务分类 │
33+
│ • 结果缓存,相似请求直接命中 │
34+
│ • 超时/异常自动 fallback 到 general │
35+
└──────────────────────────────────────────────────────┘
36+
37+
38+
┌─ Layer 3: 模型选择 ─────────────────────────────────┐
39+
│ 根据 tier 从 config.yaml 选择首选模型 │
40+
└──────────────────────────────────────────────────────┘
1941
```
2042

21-
### Tier 路由规则
43+
### 默认 Tier 配置
2244

23-
| Tier | 触发条件 | 默认模型 |
24-
|------|----------|----------|
25-
| simple | 问候、简单问答 | MiniMax-M2.5 |
26-
| medium | 普通对话、多步骤 | MiniMax-M2.5 |
27-
| complex | 代码、创意写作、长文本 | MiniMax-M2.5 |
45+
| Tier | 场景 | 默认模型 |
46+
|------|------|----------|
47+
| simple | 问候、闲聊 | MiniMax-M2.5 |
48+
| code | 代码、调试、技术实现 | GLM-5 |
2849
| reasoning | 数学推理、逻辑证明 | SSY-DeepSeek-V3.2 |
50+
| creative | 创意写作、文案、翻译 | SSY-GPT-5.2 |
51+
| general | 通用对话、知识问答 | MiniMax-M2.5 |
2952
| premium | 手动指定 smart-premium | claude-opus-4-6 |
3053

31-
> 模型列表可在 `router.py``MODELS` 字典中自定义
54+
> 所有模型和 tier 均可在 `config.yaml` 中自定义
3255
3356
## 快速开始
3457

3558
### Docker(推荐)
3659

3760
```bash
38-
# 1. 克隆项目
3961
git clone https://github.com/qingchencloud/smart-router.git
4062
cd smart-router
4163

42-
# 2. 配置环境变量
4364
cp .env.example .env
44-
# 编辑 .env,填入你的上游 API 地址和密钥
65+
# 编辑 .env 填入上游 API 密钥
66+
# 编辑 config.yaml 自定义模型和路由规则
4567

46-
# 3. 启动
4768
docker compose up -d
4869

49-
# 4. 测试
5070
curl http://localhost:30081/v1/chat/completions \
5171
-H "Content-Type: application/json" \
5272
-d '{"model":"auto","messages":[{"role":"user","content":"你好"}]}'
@@ -55,83 +75,26 @@ curl http://localhost:30081/v1/chat/completions \
5575
### 本地运行
5676

5777
```bash
58-
# 安装依赖
59-
pip install aiohttp
78+
pip install aiohttp pyyaml
6079

61-
# 配置环境变量
6280
export NEW_API_URL="http://127.0.0.1:30080/v1/chat/completions"
6381
export NEW_API_KEY="sk-your-api-key"
6482

65-
# 启动
6683
python server.py
6784
```
6885

6986
## API
7087

7188
### POST /v1/chat/completions
7289

73-
完全兼容 OpenAI Chat Completions API。所有参数原样透传。
74-
75-
**特殊 model 值:**
90+
完全兼容 OpenAI Chat Completions API,所有参数原样透传。
7691

7792
| model | 行为 |
7893
|-------|------|
79-
| `auto` / `smart-auto` | 根据内容自动选择最便宜的模型 |
80-
| `smart-premium` | 使用 claude-opus-4-6 |
94+
| `auto` / `smart-auto` | 三层路由自动选择模型 |
95+
| `smart-premium` | 使用 premium tier 模型 |
8196
| 其他已知模型名 | 直接使用该模型 |
8297

83-
**示例 — 自动路由:**
84-
85-
```bash
86-
curl -X POST http://localhost:30081/v1/chat/completions \
87-
-H "Content-Type: application/json" \
88-
-d '{
89-
"model": "auto",
90-
"messages": [{"role": "user", "content": "写一个快排算法"}],
91-
"max_tokens": 2048
92-
}'
93-
```
94-
95-
**示例 — Tool Calling:**
96-
97-
```bash
98-
curl -X POST http://localhost:30081/v1/chat/completions \
99-
-H "Content-Type: application/json" \
100-
-d '{
101-
"model": "auto",
102-
"messages": [{"role": "user", "content": "北京现在几点?"}],
103-
"tools": [{
104-
"type": "function",
105-
"function": {
106-
"name": "get_time",
107-
"description": "获取城市当前时间",
108-
"parameters": {
109-
"type": "object",
110-
"properties": {"city": {"type": "string"}},
111-
"required": ["city"]
112-
}
113-
}
114-
}],
115-
"tool_choice": "auto"
116-
}'
117-
```
118-
119-
**示例 — 流式响应:**
120-
121-
```bash
122-
curl -X POST http://localhost:30081/v1/chat/completions \
123-
-H "Content-Type: application/json" \
124-
-d '{
125-
"model": "auto",
126-
"messages": [{"role": "user", "content": "你好"}],
127-
"stream": true
128-
}'
129-
```
130-
131-
### GET /v1/models
132-
133-
返回可用模型列表(OpenAI 格式)。
134-
13598
### POST /route
13699

137100
查看路由决策(调试用):
@@ -142,50 +105,42 @@ curl -X POST http://localhost:30081/route \
142105
-d '{"messages": [{"role": "user", "content": "证明勾股定理"}]}'
143106
```
144107

145-
### GET /
108+
### GET /v1/models
146109

147-
服务状态信息
110+
返回可用模型列表
148111

149112
## 配置
150113

151-
### 环境变量
114+
### 环境变量 (.env)
152115

153116
| 变量 | 说明 | 默认值 |
154117
|------|------|--------|
155-
| `NEW_API_URL` | 上游 OpenAI 兼容 API 地址 | `http://127.0.0.1:30080/v1/chat/completions` |
156-
| `NEW_API_KEY` | 上游 API 密钥 | (空,必填) |
157-
| `SMART_ROUTER_PORT` | 服务端口(docker-compose 用) | `30081` |
158-
159-
### 自定义模型
160-
161-
编辑 `router.py` 中的 `MODELS` 字典:
162-
163-
```python
164-
MODELS = {
165-
"simple": ["your-cheap-model"],
166-
"medium": ["your-medium-model"],
167-
"complex": ["your-strong-model"],
168-
"reasoning": ["your-reasoning-model"],
169-
"premium": ["your-premium-model"],
170-
}
171-
```
118+
| `NEW_API_URL` | 上游 API 地址 | `http://127.0.0.1:30080/v1/chat/completions` |
119+
| `NEW_API_KEY` | 上游 API 密钥 | (必填) |
120+
| `SMART_ROUTER_PORT` | 服务端口 | `30081` |
172121

173-
每个 tier 的第一个模型为默认选择。
122+
### config.yaml
174123

175-
## 响应头
124+
所有路由逻辑均在 `config.yaml` 中配置:
125+
126+
- **tiers**: 每个 tier 的模型列表,第一个为首选
127+
- **fast_rules**: Layer 1 快速规则,按顺序匹配
128+
- **classifier**: Layer 2 LLM 分类器(模型、缓存、超时、prompt)
129+
- **upstream**: 上游 API(支持 `${ENV_VAR}` 语法)
176130

177-
SmartRouter 在响应中添加 `X-SmartRouter-Model` 头,标识实际使用的模型:
131+
## 响应头
178132

179133
```
180-
X-SmartRouter-Model: MiniMax-M2.5
134+
X-SmartRouter-Model: GLM-5
181135
```
182136

183137
## 架构
184138

185139
```
186140
SmartRouter/
187141
├── server.py # aiohttp 异步透明代理服务
188-
├── router.py # 路由决策模块(纯逻辑,无网络)
142+
├── router.py # 三层路由决策模块
143+
├── config.yaml # 全量配置(模型、规则、分类器)
189144
├── Dockerfile
190145
├── docker-compose.yml
191146
└── .env.example

config.yaml

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# SmartRouter 配置文件
2+
# 所有模型名称、路由规则、分类器配置均在此处定义
3+
# 修改后重启服务即可生效
4+
5+
# ===== 上游 API =====
6+
upstream:
7+
url: "${NEW_API_URL}"
8+
key: "${NEW_API_KEY}"
9+
10+
# ===== 分类器配置 (Layer 2) =====
11+
classifier:
12+
# 用哪个模型做任务分类(建议用免费/便宜的)
13+
model: "MiniMax-M2.5"
14+
# LRU 缓存条目数
15+
cache_size: 500
16+
# 缓存过期时间(秒),0 = 不过期
17+
cache_ttl: 3600
18+
# 分类超时(秒),超时则 fallback 到 general
19+
timeout: 10
20+
# 分类 prompt 模板,{user_message} 会被替换为用户消息前 500 字符
21+
prompt: |
22+
你是一个请求分类器。根据用户消息判断任务类型,只回复类型名称,不要解释。
23+
24+
可选类型:
25+
- simple: 简单问候、闲聊、打招呼
26+
- code: 代码生成、调试、编程、技术实现、算法
27+
- reasoning: 数学推理、逻辑证明、复杂分析、多步推导
28+
- creative: 创意写作、文案、翻译、诗歌、小说
29+
- general: 通用知识问答、信息查询、日常对话
30+
31+
用户消息:
32+
{user_message}
33+
34+
任务类型:
35+
36+
# ===== Tier 模型映射 =====
37+
# 每个 tier 的 models 列表,第一个为首选
38+
tiers:
39+
simple:
40+
models: ["MiniMax-M2.5"]
41+
description: "简单问答、闲聊"
42+
43+
code:
44+
models: ["GLM-5", "SSY-DeepSeek-V3.2", "MiniMax-M2.5"]
45+
description: "代码生成、调试、技术实现"
46+
47+
reasoning:
48+
models: ["SSY-DeepSeek-V3.2", "DeepSeek-V3.2", "GLM-5"]
49+
description: "数学推理、逻辑证明、复杂分析"
50+
51+
creative:
52+
models: ["SSY-GPT-5.2", "SSY-Kimi-K2.5", "MiniMax-M2.5"]
53+
description: "创意写作、文案、翻译"
54+
55+
general:
56+
models: ["MiniMax-M2.5", "GLM-5"]
57+
description: "通用对话、知识问答"
58+
59+
premium:
60+
models: ["claude-opus-4-6", "claude-opus-4-6-thinking"]
61+
description: "手动指定的高端模型"
62+
63+
# ===== 快速规则 (Layer 1) =====
64+
# 按顺序匹配,命中即停止,不经过 LLM 分类器
65+
fast_rules:
66+
# 带 tools 参数 → 必须用支持 function calling 的模型
67+
- name: "has_tools"
68+
condition: "has_tools"
69+
tier: "code"
70+
reason: "请求包含 tools 参数,需要支持 function calling"
71+
72+
# 消息包含代码块
73+
- name: "has_code_block"
74+
condition: "has_code_block"
75+
tier: "code"
76+
reason: "消息包含代码块"
77+
78+
# system prompt 含代码相关指令
79+
- name: "system_code_hint"
80+
condition: "system_contains"
81+
keywords: ["代码", "编程", "code", "programming", "developer", "engineer", "coder", "debug"]
82+
tier: "code"
83+
reason: "system prompt 指示代码任务"
84+
85+
# system prompt 含推理相关指令
86+
- name: "system_reasoning_hint"
87+
condition: "system_contains"
88+
keywords: ["数学", "推理", "math", "reasoning", "logic", "prove", "theorem"]
89+
tier: "reasoning"
90+
reason: "system prompt 指示推理任务"
91+
92+
# 短消息问候 (< 10 字符,无特殊内容)
93+
- name: "short_greeting"
94+
condition: "short_message"
95+
max_length: 10
96+
tier: "simple"
97+
reason: "简短消息"
98+
99+
# ===== 特殊模型名映射 =====
100+
special_models:
101+
# 这些模型名触发特殊行为
102+
auto: "smart-auto" # auto 等同于 smart-auto
103+
smart-auto: "smart-auto" # 自动路由
104+
smart-premium: "premium" # 路由到 premium tier
105+
106+
# ===== 服务配置 =====
107+
server:
108+
port: 30081
109+
log_routes: true # 是否打印路由决策日志

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ services:
99
- .env
1010
environment:
1111
- NEW_API_URL=${NEW_API_URL:-http://host.docker.internal:30080/v1/chat/completions}
12+
volumes:
13+
- ./config.yaml:/app/config.yaml:ro
1214
extra_hosts:
1315
- "host.docker.internal:host-gateway"
1416

0 commit comments

Comments
 (0)