@wangjy_john/domainrouter
v0.2.0
Published
Domain-Aware Smart LLM Router — 12-domain classification with per-domain model rankings, Chinese LLM support, user-owned API key routing
Maintainers
Readme
DomainRouter
领域感知智能大模型路由器 — 12 领域分类 × 14 维难度评估 × 加权模型打分,将每个问题自动路由到最优模型。
核心原理
DomainRouter 解决的核心问题是:你手里有多个模型的 API Key,每个问题应该发给哪个模型?
简单做法是"全发给最强的模型"(浪费钱)或"全发给最便宜的模型"(复杂问题得不到好回答)。DomainRouter 的做法是先理解问题,再选择模型——分五步:
第一步:领域分类 — 这是什么类型的问题?
系统用分类器判断问题属于 12 个领域中的哪一个(或多个),输出一个 12 维相似度向量:
| 领域 | 说明 |
|------|------|
| math_reasoning | 数学证明、定理推导、方程求解 |
| code_generation | 编写代码、实现功能、创建应用 |
| code_debugging | 修复 bug、排查错误、调试代码 |
| data_analysis | 数据分析、统计、SQL、机器学习 |
| creative_writing | 故事、诗歌、文案、内容创作 |
| translation | 语言翻译、本地化 |
| factual_qa | 事实问答、定义查询、常识 |
| summarization | 文本摘要、要点提炼 |
| system_design | 架构设计、系统设计、技术选型 |
| instruction_following | 格式遵循、模板输出、严格指令 |
| multimodal | 图像理解、OCR、视觉识别 |
| agentic_task | 多步骤自主操作、工具调用 |
四种可选的分类器:
| 分类器 | 延迟 | 准确率 | 中文 | 原理 | 依赖 |
|--------|------|--------|------|------|------|
| ngram ⭐ | <1ms | ~82% | 好 | 字符级 TF-IDF n-gram,中英双语混合特征空间余弦相似度 | 零依赖 |
| keyword | 0ms | ~75% | 好 | 中英双语关键词匹配,分段命中数映射 | 零依赖 |
| embedding-minilm | ~5ms | ~85% | 一般 | WASM 本地运行 all-MiniLM-L6-v2,余弦相似度 | 需安装 @xenova/transformers |
| embedding-bge | ~5ms | ~88% | 很好 | WASM 本地运行 bge-small-zh-v1.5,中文语义更好 | 需安装 @xenova/transformers |
ngram 分类器原理: 将每个领域的 250+ 中英双语关键词拼接为"原型文档",提取字符 bigram + trigram + 单词特征构建 TF-IDF 加权向量(模块加载时预计算)。用户输入同样提取 n-gram 后计算与 12 个领域向量的余弦相似度。IDF 自动降低跨领域常见词权重,比纯关键词匹配更细粒度。
第二步:难度评估 — 这个问题有多难?
系统用 14 个维度 对问题加权评分,输出 0~1 的难度分数和四个等级:
| 难度等级 | 分数区间 | 典型场景 |
|----------|----------|----------|
| SIMPLE | < 0.05 | "1+1 等于几?" |
| MEDIUM | 0.05 ~ 0.30 | "写一个排序函数" |
| COMPLEX | 0.30 ~ 0.55 | "设计一个分布式缓存系统" |
| REASONING | ≥ 0.55 | "证明黎曼猜想" |
14 个评估维度:
| 维度 | 权重 | 说明 |
|------|------|------|
| reasoningMarkers | 0.20 | 含"证明"/"prove"/"推导"等 → 难度⬆ |
| codePresence | 0.15 | 含 function/class/import 等 → 难度⬆ |
| technicalTerms | 0.10 | 含"分布式"/"kubernetes"等 → 难度⬆ |
| multiStepPatterns | 0.10 | 含"第一步…第二步…"/step 1 等 → 难度⬆ |
| tokenCount | 0.08 | 输入长度 >500 token → ⬆;<50 token → ⬇ |
| constraintCount | 0.06 | 含"不超过"/"至少"/"限制"等 → ⬆ |
| imperativeVerbs | 0.05 | 含"构建"/"创建"/"部署"等 → ⬆ |
| questionComplexity | 0.05 | 含 ≥3 个问号 → ⬆ |
| outputFormat | 0.05 | 要求 JSON/YAML/表格等 → ⬆ |
| simpleIndicators | 0.05 | 含"什么是"/"define"等 → ⬇ |
| creativeMarkers | 0.03 | 含"故事"/"创意"等 → ↑ |
| referenceComplexity | 0.03 | 含"上文"/"之前"等 → ↑ |
| domainSpecificity | 0.03 | 含"量子"/"基因组"等 → ↑ |
| negationComplexity | 0.02 | 含"不要"/"避免"等 → ↑ |
命中 ≥2 个推理关键词时,难度直接提升至 ≥0.55。
第三步:加权模型打分 — 哪个模型最适合?
针对你配置的每个可用模型,从四个维度独立打分,然后按偏好加权求和:
① 领域匹配度 — 对于每个领域 d:问题相似度 × 模型在该领域的能力评分,取加权平均。模型能力数据来源于公开 benchmark(MMLU、HumanEval、MATH 等)综合评估。
② 难度适配度 — 模型能力等级与问题难度比对:REASONING 问题遇到弱模型 → 严厉惩罚;SIMPLE 问题遇到强模型 → 适度惩罚。
③ 价格效率 — 对数尺度比较所有模型价格,最便宜的得 1.0。
④ 延迟评分 — 线性归一化,最快的得 1.0。
加权公式依赖于你的路由偏好:
| 权重项 | cheapest(省钱) | balanced(均衡) | best_quality(质量优先) |
|--------|-------------------|--------------------|--------------------------|
| 领域匹配 | 0.30 | 0.45 | 0.50 |
| 难度适配 | 0.15 | 0.25 | 0.30 |
| 价格效率 | 0.45 | 0.20 | 0.05 |
| 延迟 | 0.05 | 0.05 | 0.10 |
| 用户偏好 | 0.05 | 0.05 | 0.05 |
totalScore = domainMatch × w₁ + difficultyFit × w₂ + priceEfficiency × w₃ + latency × w₄
所有模型按 totalScore 降序排列。第一名当选,第 2~6 名组成容错链。
第四步:Provider 适配与调用
根据模型的 provider 字段选择 SDK:
| Provider | 适配方式 |
|----------|----------|
| anthropic | Anthropic SDK 原生调用 |
| openai | OpenAI SDK 原生调用 |
| google | Gemini SDK 原生调用 |
| deepseek | OpenAI 兼容 API(含 R1 推理模型 reasoning_content 处理) |
| 其他 10+ 厂商 | 通用 OpenAI 兼容适配器(自动推断 baseUrl) |
所有适配器统一接收 OpenAI 兼容格式的 messages,内部翻译为各厂商原生格式,响应再翻译回 OpenAI 兼容格式。对使用者完全透明。
第五步:自动容错
如果首选模型调用失败,系统自动尝试容错链中的下一个模型,最多尝试 4 个(首选 + 3 个备选)。全部失败才返回错误。
快速开始
1. 安装
npm install -g @wangjy_john/domainrouter2. 配置模型
domainrouter init交互式向导会引导你选择分类器、路由偏好,并逐一配置模型的 API Key。
也可以手动创建 domainrouter.config.json:
{
"classifier": "ngram",
"routingPreference": "balanced",
"models": {
"deepseek/deepseek-chat": {
"apiKey": "你的 DeepSeek API Key"
},
"openai/gpt-4o": {
"apiKey": "你的 OpenAI API Key"
},
"anthropic/claude-sonnet-4.6": {
"apiKey": "你的 Anthropic API Key"
}
}
}运行
domainrouter list-models查看全部 35 个支持的模型 ID。
3. 启动
# 先测试路由是否正常(不消耗 API 额度)
domainrouter test "写一个快速排序算法" --verbose
# 启动代理服务器
domainrouter start --port 8080然后将你的工具指向 http://localhost:8080/v1 即可:
# curl
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"你好!"}]}'
# Python
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8080/v1", api_key="any")
response = client.chat.completions.create(
model="auto",
messages=[{"role": "user", "content": "你好!"}]
)CLI 命令
| 命令 | 说明 |
|------|------|
| domainrouter init | 交互式配置向导 |
| domainrouter test "prompt" | Dry-run 路由测试(不调用 LLM) |
| domainrouter test "prompt" --verbose | 详细模式:领域柱状图 + 14 维难度明细 + Top-10 候选 |
| domainrouter test "prompt" --classifier keyword --preference best_quality | 指定分类器和偏好 |
| domainrouter start --port 8080 | 启动代理服务器 |
| domainrouter list-models | 查看全部 35 个支持的模型 |
配置参考
配置文件格式
domainrouter.config.json:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| classifier | string | 否 | "ngram" | ngram / keyword / embedding-minilm / embedding-bge |
| routingPreference | string | 否 | "balanced" | cheapest / balanced / best_quality |
| port | number | 否 | 0(随机) | 代理服务器端口 |
| models | object | 是 | — | 模型 ID → 配置的映射 |
| journal.enabled | boolean | 否 | true | 是否记录路由日志 |
| journal.maxEntries | number | 否 | 500 | 内存中最多保留条数 |
| journal.file | boolean | 否 | false | 设为 true 持久化到磁盘 |
每个模型的配置:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| apiKey | string | 是 | 你的 API Key |
| baseUrl | string | 否 | 自定义 API 地址(大部分厂商自动推断) |
| enabled | boolean | 否 | 设为 false 临时禁用此模型 |
OpenClaw 插件模式
在 openclaw.yaml 中配置:
plugins:
domainrouter:
enabled: true
config:
domainrouter:
classifier: ngram
routingPreference: balanced
models:
deepseek/deepseek-chat:
apiKey: sk-xxxxxxxxxxxxxxxx
openai/gpt-4o:
apiKey: sk-xxxxxxxxxxxxxxxx重启 OpenClaw 后可使用斜杠命令:
/domain-router— 查看路由状态/my-models— 列出已配置模型及状态
API 端点
启动代理后可用:
| 端点 | 方法 | 说明 |
|------|------|------|
| /v1/chat/completions | POST | 路由查询并返回 OpenAI 兼容响应 |
| /v1/models | GET | 列出你已配置的可用模型 |
| /health | GET | 健康检查 |
| /dashboard | GET | Web Dashboard |
| /test-route | POST | Dry-run 路由测试(不调用 LLM) |
| /journal | GET | 查询路由日志(支持 ?limit=&domain=&model=&difficulty=) |
| /journal/:id | GET | 查看单条日志详情 |
| /journal/stats | GET | 聚合统计 |
| /journal/config | GET | Journal 配置 |
| /journal | DELETE | 清空日志 |
| /config/models | POST | 从 Dashboard 编辑模型配置并写入文件 |
响应头会携带路由信息:
X-Routed-Model— 实际调用的模型 IDX-Routing-Reason— 路由决策文本摘要
Dashboard
浏览器打开 http://localhost:<port>/dashboard,提供四个标签页:
| 标签页 | 功能 | |--------|------| | Route Test | 输入 prompt → 查看完整路由决策(领域柱状图、难度详情、Top-10 候选、容错链) | | Journal | 所有路由记录的时间线表格,可按领域/难度筛选,点击查看详情 | | Stats | 聚合统计卡片 + 模型/领域/难度分布柱状图 | | Settings | 编辑模型配置(API Key、Base URL、启用开关),一键保存到配置文件 |
Route Test 页面支持
Ctrl+Enter快捷键触发,测试结果自动记入 Journal。
Journal 日志
每次路由决策自动记录到内存环形缓冲区(默认 500 条)。开启 journal.file: true 后持久化到 ~/.domainrouter/journal.jsonl。
# 通过 API 查询
curl http://localhost:8080/journal?limit=20
curl http://localhost:8080/journal?domain=code_generation
curl http://localhost:8080/journal/stats
# 持久化后直接查看文件
cat ~/.domainrouter/journal.jsonl | jq '.'
tail -f ~/.domainrouter/journal.jsonl支持的模型
国际模型 (21 个)
| 厂商 | 模型 ID | 特点 |
|------|---------|------|
| Anthropic | anthropic/claude-opus-4.7 | 最佳:创意写作、指令遵循、智能代理 |
| Anthropic | anthropic/claude-sonnet-4.6 | 最佳:代码生成、代码调试 |
| Anthropic | anthropic/claude-haiku-4.5 | 轻量快速 |
| OpenAI | openai/gpt-5.5 | 综合最强 |
| OpenAI | openai/gpt-5.4 | 综合能力强 |
| OpenAI | openai/gpt-5.4-mini | 高性价比 |
| OpenAI | openai/gpt-5.4-nano | 超低价 |
| OpenAI | openai/gpt-5.3-codex | 代码生成最强 |
| OpenAI | openai/gpt-4o | 经典多模态 |
| OpenAI | openai/gpt-4o-mini | 轻量多模态 |
| OpenAI | openai/o3 | 最强数学推理 |
| OpenAI | openai/o4-mini | 轻量推理 |
| Google | google/gemini-3.1-pro | 百万上下文 |
| Google | google/gemini-2.5-pro | 性价比高 |
| Google | google/gemini-2.5-flash | 低延迟 |
| Google | google/gemini-2.5-flash-lite | 超低价 |
| xAI | xai/grok-4-0709 | 事实问答突出 |
| xAI | xai/grok-4.1-fast-reasoning | 极低价推理 |
| xAI | xai/grok-3 | — |
| Meta | meta/llama-4-maverick | 开源低价 |
| Mistral | mistral/mistral-large | 翻译出色 |
中国模型 (14 个)
| 厂商 | 模型 ID | 特点 |
|------|---------|------|
| DeepSeek | deepseek/deepseek-chat | 高性价比通用 |
| DeepSeek | deepseek/deepseek-reasoner | 顶级数学推理 |
| 阿里 Qwen | qwen/qwen-max | 综合顶级 |
| 阿里 Qwen | qwen/qwen-plus | 冲量 |
| 阿里 Qwen | qwen/qwen3-coder-480b | 顶级代码生成,免费 |
| 阿里 Qwen | qwen/qwen3-next-80b-a3b-thinking | 推理,免费 |
| 智谱 Z.AI | zai/glm-5.1 | 新一代综合 |
| 智谱 Z.AI | zai/glm-5 | 全能力均衡 |
| 月之暗面 | moonshot/kimi-k2.6 | 综合强,含视觉 |
| 月之暗面 | moonshot/kimi-k2.5 | 性价比 |
| MiniMax | minimax/minimax-m2.7 | 高性价比 |
| 字节豆包 | bytedance/doubao-pro | 创意写作突出 |
| 百度 | baidu/ernie-4.0 | 翻译出色 |
| 零一万物 | 01ai/yi-large | 均衡 |
项目结构
src/
├── index.ts # OpenClaw 插件入口(薄层)
├── cli.ts # CLI 工具(start / test / list-models / init)
├── server.ts # HTTP 服务器工厂(插件与 CLI 共用)
├── types.ts # OpenClaw 插件 API 类型
├── router/
│ ├── types.ts # Domain、ScoringWeights、RoutingDecision 等核心类型
│ ├── classifier.ts # IClassifier 接口 + getClassifier() 注册工厂
│ ├── classifier-ngram.ts # TF-IDF n-gram 分类器(默认,零依赖)
│ ├── classifier-keyword.ts # 关键词分类器(0ms 延迟)
│ ├── classifier-embed.ts # 嵌入分类器(MiniLM / BGE,可选依赖)
│ ├── difficulty.ts # 14 维难度评估器
│ └── scorer.ts # 加权模型打分器 + route() 全流程
├── models/
│ ├── index.ts # 重导出
│ └── capabilities.ts # 35 模型 × 12 领域能力矩阵
├── providers/
│ ├── types.ts # ProviderAdapter 接口
│ ├── index.ts # getAdapter(provider) 工厂
│ ├── anthropic.ts # Anthropic SDK 适配器
│ ├── openai.ts # OpenAI SDK 适配器
│ ├── google.ts # Gemini SDK 适配器
│ ├── deepseek.ts # DeepSeek 适配器(含 R1 推理)
│ └── generic-openai-compat.ts # 通用 OpenAI 兼容适配器(10+ 厂商)
├── journal/
│ ├── types.ts # JournalEntry / JournalConfig / JournalStats
│ └── store.ts # 环形缓冲 + query + stats + JSONL 持久化
├── dashboard/
│ └── static/
│ ├── index.html # 页面结构(4 标签页)
│ ├── app.js # 前端逻辑(含 Settings 配置编辑)
│ └── styles.css # 全部样式
└── config/
└── wizard.ts # 交互式 CLI 配置向导开发指南
git clone <your-repo-url> && cd DomainRouter
npm install
npm run build # tsup 编译
npm run typecheck # TypeScript 检查
npm run dev # 开发模式(自动重编译)
node dist/cli.js test "你的测试 prompt" --verbose
node dist/cli.js start --port 8080License
MIT
作者
wangjy_john
