---
name: semantic-router
description: 让 AI 代理根据对话内容自动选择最合适的模型。层2（多词非连续命中）+ 层1（单词兜底）并行决定模型池；层3（embedding）永远独立运行决定会话切换。B+ 连续漂移计数器（第3次警告，第4次强制 C-auto）。soft_keywords 泛用词降权机制。四池架构（高速/智能/人文/代理），五分支路由，全自动 Fallback 回路。
version: 8.0.0
author: halfmoon82
tags: [semantic, routing, model-pools, task-classification, fallback, system-passthrough, production, layer-parallel]
requires_approval: true
---

> 🔒 **安全声明**：本技能需要修改 OpenClaw 配置以实现模型路由功能。所有配置变更前会自动备份，支持一键回滚。建议在测试环境验证后再部署到生产环境。

## ⚠️ Security & Permissions Declaration

**This skill performs the following privileged operations — all are intentional and explicitly user-initiated:**

| Operation | Purpose | Scope |
|-----------|---------|-------|
| Read/patch `~/.openclaw/openclaw.json` | Configure model routing pools | Local config only |
| Read/write `~/.openclaw/workspace/.lib/pools.json` | Store model pool configuration | Workspace only |
| Read/write `~/.openclaw/workspace/.lib/tasks.json` | Store task type definitions | Workspace only |
| Run `semantic_check.py` locally | Classify user messages for routing | No network required |
| Patch session model via `sessions.patch` | Switch active model pool | Current session only |
| Restart OpenClaw Gateway (`openclaw gateway restart`) | Apply routing config changes | Local service only |
| Inject `prependContext` into agent turns | Output routing declaration in first line | Read-only context injection |
| Update Cron Job `sessionTarget` to `"isolated"` | Prevent background tasks from polluting user sessions | Affects only background Cron jobs |

**What this skill does NOT do:**
- Does NOT exfiltrate conversation content or model credentials to external servers
- Does NOT access API keys or secrets directly
- Does NOT modify files outside `~/.openclaw/` and the skill's own workspace
- Does NOT run with elevated (sudo/root) privileges
- Does NOT auto-install additional packages

**Requires:** Python 3.8+, OpenClaw Gateway running, configured model providers

# 🔷 Semantic Router v7.9.3 — 生产级会话路由系统 🔷

**ClawHub**: https://clawhub.ai/halfmoon82/semantic-router  
**版本**: 7.6.3 (生产环境)  
**作者**: halfmoon82
**状态**: ✅ ROM 级固化，完全测试通过

## 🎯 这个技能解决什么问题？

### 核心问题（v7.2 新解决）

你是否遇到过：
- **Cron Job 导致会话频繁重置** — 后台定时任务打断用户交互
- **Discord/Telegram 渠道会话突然清空** — 长任务无法延续
- **AGENTS.md 被截断注入** — 大文件超过 20KB 限制
- **模型自动切换被全局配置覆盖** — 切换不生效

### 解决方案

**会话隔离架构**：
```
用户直连渠道（稳定）
    ├─ 主代理会话 → semantic-router（精准路由）
    └─ Cron Job 隔离会话（独立环境）
        ├─ cloudflared-watchdog
        ├─ Fallback 回切检查
        └─ 自定义后台任务
```

**完整配置引导**：
- 零冲突的智能合并配置
- 预检脚本防止覆盖现有设置
- 自动回滚失败的配置修改

---

## 🔒 安全与权限说明

### 为什么需要这些权限？

| 权限 | 用途 | 安全措施 |
|------|------|----------|
| 读取 `openclaw.json` | 检测现有模型配置 | 只读，不修改 |
| 修改 `openclaw.json` | 添加模型池配置 | **自动备份** + **一键回滚** |
| 执行本地脚本 | 运行配置向导和验证 | 开源脚本，可审计 |
| 重启 Gateway | 应用新配置 | 失败自动回滚 |

### 配置保护机制

1. **前置备份**：任何修改前自动创建带时间戳的备份
2. **语法验证**：JSON 修改后自动验证语法
3. **健康检查**：Gateway 重启后验证服务可用性
4. **自动回滚**：任何步骤失败立即恢复原配置

```bash
# 手动回滚命令
python3 ~/.openclaw/workspace/.lib/config-rollback-guard.py rollback
```

### 代码审计

- 所有脚本开源，位于 `scripts/` 目录
- 核心逻辑 `semantic_check.py` 62KB，完全可审计
- 无网络请求，无数据上报，纯本地运行

---

## 🚀 快速安装

### 第一步：安装技能

```bash
# 从 ClawHub 安装
clawhub install https://clawhub.ai/halfmoon82/semantic-router

# 或手动复制到本地
cp -r ~/.openclaw/workspace/skills/semantic-router ~/my-projects/
```

### 第二步：运行配置引导

```bash
# 启动交互式配置向导
python3 ~/.openclaw/workspace/skills/semantic-router/scripts/setup_wizard.py

# 向导将：
# 1. 检测你的已有配置
# 2. 扫描可用模型
# 3. 推荐三池配置
# 4. 生成 pools.json 和 tasks.json
```

### 第三步：启动 Webhook 服务（重要！）

```bash
# 复制核心文件到 .lib 目录
cp ~/.openclaw/workspace/skills/semantic-router/scripts/semantic_check.py \
   ~/.openclaw/workspace/.lib/
cp ~/.openclaw/workspace/skills/semantic-router/scripts/semantic-webhook-server.py \
   ~/.openclaw/workspace/.lib/

# 启动 Webhook 服务（端口 9811）
python3 ~/.openclaw/workspace/.lib/semantic-webhook-server.py --port 9811 &

# 验证服务是否运行
curl http://127.0.0.1:9811/health
# 预期输出: {"status": "ok", "version": "7.9.x"}
```

### 第四步：隔离现有 Cron Job（重要！）

```bash
# 列出你的所有 Cron Job
cron list | jq '.jobs[] | {id, name, sessionKey}'

# 对每个使用了渠道会话（telegram/discord/whatsapp）的 Job，执行隔离
cron update {job_id} \
  --patch '{"sessionKey": null, "sessionTarget": "isolated"}'

# 示例（cloudflared-watchdog）
cron update ba28e228-473a-4963-8413-c228762bf2d1 \
  --patch '{"sessionKey": null, "sessionTarget": "isolated"}'
```

### 第五步：验证安装

```bash
# 测试 Webhook 路由接口
curl -X POST http://127.0.0.1:9811/route \
  -H "Content-Type: application/json" \
  -d '{"message": "帮我写个Python爬虫", "current_pool": "Highspeed"}'

# 预期输出
# {
#   "branch": "C",
#   "task": "development",
#   "target_pool": "Intelligence",
#   "primary_model": "claude-opus-4.6",
#   "declaration": "【语义检查 by DeepEye@halfmoon82】P1-任务切换..."
# }
```

---

## 🎓 核心概念

### 四池模型架构

| 池名 | 用途 | 模型示例 | 特点 |
|------|------|---------|------|
| **Highspeed** | 查询、检索、信息搜索 | gemini-2.5-flash | 快速、成本低 |
| **Intelligence** | 开发、编程、复杂任务 | claude-sonnet-4.6 | 精准、能力强 |
| **Humanities** | 内容生成、翻译、写作 | gemini-2.5-pro | 平衡、流畅 |
| **Agentic** | 长上下文代理、Computer Use、专业知识工作 | gpt-5.4 | 1M上下文、工具调用、多步骤 |

### 两步判断法

**Step 1: 关键词 + 指示词检测**
```
"帮我写个爬虫" → 关键词 "写" + "爬虫" → 开发任务 → Intelligence
"继续刚才的" → 指示词 "继续" → 延续当前池 → B 分支
"查一下天气" → 关键词 "查" + "天气" → 查询任务 → Highspeed
"帮我整理这些材料做成PPT" → trigger_groups_all 规则命中 → 代理任务 → Agentic
```

**trigger_groups_all 非连续词组命中（v7.7 新增）**

支持在 tasks.json 中定义分组规则，每条规则内所有分组取 AND，分组内词取 OR，多条规则取 OR：
```json
"trigger_groups_all": [
  [["帮我","自动","用AI"], ["操作","填写","截图"]],
  [["处理","生成","制作"], ["报告","表格","文档","PPT"]]
]
```
说"帮我自动操作浏览器"→ 规则①命中 → Agentic 池。无需精确关键词，口语自然表达即可触发。

**Step 2: 上下文关联度评分**（当 Step 1 无结果时）
```
相似度 ≥ 0.15 → 延续当前会话（B 分支）
相似度 0.08~0.15 → 延续但警告（B+ 分支）
相似度 < 0.08 → 新话题，重置会话（C-auto 分支）
```

### 五分支路由决策

| 分支 | 触发条件 | 动作 | 会话行为 |
|------|--------|------|--------|
| **A** | 关键词完全匹配 | 直接切到目标池 | 切换模型，不重置 |
| **B** | 指示词（延续） | 保持当前 | 无动作 |
| **B+** | 中等关联度（0.08~0.15） | 保持 + 警告 | 输出漂移警告 |
| **C** | 新任务关键词 | 切到目标池 | 切换模型，不重置 |
| **C-auto** | 低关联度（<0.08） | 重置 + 切池 | `/new` + 切换模型 |

---

## ⚙️ 完整配置指南（无冲突）

### 问题：为什么配置容易冲突？

你的 OpenClaw 配置可能已经存在：
- 已配置的模型提供商（OpenAI、Claude、本地 LLM 等）
- 已配置的模型池（可能与语义路由的池名冲突）
- 已定义的任务类型（可能与 tasks.json 冲突）

直接覆盖会导致：❌ 原有配置丢失  
❌ 某些模型无法使用  
❌ Cron Job 执行失败

### 解决方案：智能合并流程

#### **Step 1: 环境检测**

```bash
# 检查现有配置
cat ~/.openclaw/openclaw.json | jq '.models | keys'
# 输出: ["anthropic", "openai", "google-ai", "minimax-cn"]

cat ~/.openclaw/openclaw.json | jq '.agents[0].model'
# 输出: "custom-llmapi-lovbrowser-com/anthropic/claude-haiku-4.5"
```

#### **Step 2: 冲突预检**

```bash
# 备份当前配置
cp ~/.openclaw/openclaw.json \
   ~/.openclaw/backup/openclaw.json.backup-$(date +%s)

# 运行预检脚本
python3 ~/.openclaw/workspace/.lib/config-rollback-guard.py check

# 查看冲突报告
cat ~/.openclaw/logs/config-modification.log
```

#### **Step 3: 智能合并（推荐）**

```bash
# 选项 A: 使用自动合并脚本
python3 ~/.openclaw/workspace/.lib/merge-config.py \
  --existing ~/.openclaw/openclaw.json \
  --new ~/.openclaw/workspace/skills/semantic-router/config/pools.json \
  --output ~/.openclaw/openclaw.json.merged \
  --mode append  # 仅追加，不覆盖

# 选项 B: 手动合并（更安全）
# 编辑 ~/.openclaw/openclaw.json，按以下步骤：
# 1. 检查 .models 字段，仅追加缺失的提供商
# 2. 检查 .agents[].model，如果已有则不修改
# 3. 检查 .env，仅追加缺失的环境变量（如 LOVBROWSER_API_KEY）
```

#### **Step 4: 验证 & 激活**

```bash
# 验证 JSON 语法
python3 -c "import json; json.load(open('~/.openclaw/openclaw.json'))" && echo "✅ JSON 有效"

# 备份原配置
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.bak

# 应用新配置
cp ~/.openclaw/openclaw.json.merged ~/.openclaw/openclaw.json

# 重启 Gateway（失败时自动回滚）
openclaw gateway restart

# 如果启动失败，自动回滚
python3 ~/.openclaw/workspace/.lib/config-rollback-guard.py rollback
```

---

## 🔧 Cron Job 隔离最佳实践

### ❌ 错误做法（会导致会话重置）

```bash
cron add \
  --name "my-background-task" \
  --sessionKey "agent:main:telegram:direct:123456" \
  --sessionTarget "main" \
  --payload '{"kind": "agentTurn", "message": "执行任务..."}'
```

**为什么错？**
- sessionKey 使用了 Telegram 渠道的直连会话
- 任务消息可能无法匹配 tasks.json 中的关键词
- semantic-router 触发 C-auto 分支 → 会话被强制重置
- 用户的长任务被打断 ❌

### ✅ 正确做法 A：隔离会话（推荐）

```bash
cron add \
  --name "my-background-task" \
  --sessionTarget "isolated" \
  --payload '{
    "kind": "agentTurn",
    "message": "运维任务：执行后台清理。检查磁盘空间...",
    "timeoutSeconds": 60
  }'

# 关键字段：
# - sessionKey: null （让 Gateway 自动分配隔离会话）
# - sessionTarget: "isolated" （完全隔离，语义路由只在这个会话内生效）
```

**优点：**
- ✅ 后台任务不影响用户会话
- ✅ 完全隔离，无须担心关键词匹配
- ✅ 自动过期清理（24h）

### ✅ 正确做法 B：包含显式关键词（如果需要直连会话）

```bash
cron add \
  --name "my-background-task" \
  --sessionKey "agent:main:cron:manual" \
  --payload '{
    "kind": "agentTurn",
    "message": "【运维检查】执行磁盘空间检查。关键词: 检查、运维、系统。"
  }'

# 消息中必须包含 tasks.json 中的关键词
# （检查、运维、系统）→ 可以匹配到 "query" 或 "operations" 任务类型
```

---

## 📊 监控与故障排除

### 检查隔离状态

```bash
# 验证 Cron Job 已隔离
cron list | jq '.jobs[] | select(.name == "cloudflared-watchdog") | {id, name, sessionKey, sessionTarget}'

# 期望输出
# {
#   "id": "ba28e228-473a-4963-8413-c228762bf2d1",
#   "name": "cloudflared-watchdog",
#   "sessionKey": null,              ✅ 已隔离
#   "sessionTarget": "isolated"      ✅ 隔离会话
# }
```

### 查看语义路由日志

```bash
# 实时监控路由决策
tail -f ~/.openclaw/logs/gateway.log | grep "semantic-router"

# 查看特定消息的路由结果
cat ~/.openclaw/workspace/.lib/semantic_check.log | jq '.[] | select(.input | contains("爬虫"))'
```

### 故障排除表

| 症状 | 根因 | 解决方案 |
|------|------|--------|
| "Cron Job 执行失败，超时 30s" | 消息文本不在 tasks.json 中，semantic-router 无法识别 | 方案 A: 改用隔离会话 / 方案 B: 添加关键词 |
| "Discord 会话仍在被重置" | sessionKey 未清空，仍使用渠道会话 | `cron update {id} --patch '{"sessionKey": null}'` |
| "模型没有切换到目标池" | 全局 default_model 覆盖了切换结果 | 改用隔离会话避免全局影响 |
| "配置修改后 Gateway 启动失败" | JSON 语法错误 或 模型不可用 | 运行 `config-rollback-guard.py rollback` 回滚 |

---

## 📋 语义检查声明格式

semantic-router 自动生成的声明格式规范：

### 声明示例
```
【语义检查 by DeepEye@halfmoon82】P2-延续｜模型池:【智能池】｜实际模型:claude-opus-4.6
【语义检查 by DeepEye@halfmoon82】P1-执行开发任务｜新会话→智能池｜实际模型:claude-opus-4.6
```

### 字段说明
| 字段 | 说明 |
|------|------|
| `PX` | P1=开发/自动化, P2=信息检索, P3=内容生成 |
| `模型池:【XXX池】` | 当前所属模型池中文名 |
| `实际模型:` | 当前调用的模型 ID |
| `新会话→` | C分支专用，表示触发 session reset |

完整规范见：[references/declaration-format.md](references/declaration-format.md)

## ⚡ 架构变更说明（2026-03-06）

### M1 机制更新（FIX-0 第一轮）

**原实现**：`prependContext` 包含声明字符串（`declarationPrepend`），用于让 LLM 在回复首行输出声明。

**问题根因**：声明字符串含 `ctx_score`（每消息均不同的浮点相似度）等易变字段，导致：
- 每条用户消息前缀不同 → LLM provider 前缀缓存（prefix cache）每轮全部 miss
- 20 轮对话的历史 input tokens 每轮都重新计费

**新实现**：
- `declarationPrepend` 从 `prependContext` 数组中移除（声明改由 `semantic_check.log` 记录）
- `extractDeclKey` → `extractSkillKey`：缓存键只关心 skill/retry/degrade 激活状态
- 普通消息（无技能激活）`prependContext = undefined` → 用户消息完全干净 → 对话历史 100% cache 命中
- 技能激活时：`prependContext = skillPrepend`（技能指令相对稳定）→ 高缓存命中率

**节省估算**：单活跃会话每日约节省 6-10M tokens（对话历史从 input 变为 cache_read，约 1/10 价格）

### Option C 路由标签（FIX-0 第二轮，2026-03-06 续）

**背景**：用户需要在 Discord/Telegram 回复中看到语义路由声明（当前使用的模型池+模型）。
由于 OpenClaw 主网关的 `message_sending` hook 从未被触发（架构限制：`deliver-DCtqEVTU.js` 的 `globalHookRunner` 在主网关上下文中从不初始化），无法在发送前修改消息内容。
选择 Option C：通过 `prependContext` 注入路由标签指令，由 LLM 自行在首行输出。

**新增函数**：`extractStableRoutingParts(declarationText, fallbackModel)`
- 从 `declarationText` 提取：`pool`、`model`、`sessionType`
- `sessionType: "延续" | "新对话"` — 通过解析 `P\d+-XXX` 分支标签判断：`延续` → 延续，其他 → 新对话

**路由标签格式**：
```
【语义检查·路由】高速池｜gemini-2.5-flash｜延续
【语义检查·路由】智能池｜claude-sonnet-4.6｜新对话
```

**注入逻辑**（`before_agent_start`）：
```typescript
const isChannelSession = isMainAgentSession
  && !sessionKey.includes(":cron:")
  && !sessionKey.includes(":subagent:");   // subagent 不注入

const routingInstruction = routingTag
  ? `请在你回复的第一行，原样输出以下路由标签（不要修改）：${routingTag}`
  : undefined;

// M1 stability: combinedKey = skillKey + routingTagKey
// routingTagKey = "rt:{pool}:{model}:{sessionType}"
// 相同池+模型+会话类型 → 相同 prependContext → LLM prefix cache 命中
```

**缓存稳定性分析**：
| 场景 | routingTagKey | 结果 |
|------|---------------|------|
| 连续对话（同池同模型） | `rt:高速池:gemini-2.5-flash:延续` 不变 | M1 命中，cache hit ✅ |
| 首条新话题消息 | `rt:xxx:yyy:新对话` | cache miss（pool 切换本来就 miss）✅ |
| Gateway 重启后首条 | 任意 key | cache miss（M1 state 清空），第二条起命中 ✅ |

**subagent 排除**：`isChannelSession` 新增 `!sessionKey.includes(":subagent:")` 条件。
原因：subagent session 如 `agent:main:subagent:xxx` 满足 `startsWith("agent:main:")`，若不排除会注入两份 routingInstruction，导致 Discord 回复中路由标签重复出现。

### FIX-4（lockModel 毒化修复）

`modelOverride`/`providerOverride` 已从 `before_agent_start` 返回值中移除。路由仅通过 `sessions.patch` 实现。原 lockModel 时返回 override 会毒化所有 fallback（kimi-coding/zai/minimax 等非 lovbrowser 渠道），导致 All models failed。

## 📚 完整文档

| 文档 | 内容 | 位置 |
|------|------|------|
| **SKILL.md** | 技能说明（本文件） | `/skills/semantic-router/` |
| **README_v3_PRODUCTION.md** | 完整部署指南（英文） | `/skills/semantic-router/` |
| **README_v7.2_生产部署指南_中文.docx** | 完整部署指南（中文 DOCX） | `/skills/semantic-router/` |
| **declaration-format.md** | 声明格式规范（已内置） | `/skills/semantic-router/references/` |
| **完整架构指南** | 五分支、评分算法、Fallback 回路 | `docs/INTELLIGENT_ROUTING_SYSTEM.md` |
| **部署清单** | 7 步完整部署流程 | `docs/ROUTING_DEPLOYMENT_CHECKLIST.md` |

---

## 💡 常见问题

**Q: 我应该选择哪种隔离方案？**
A: 99% 的情况下，选择方案 A（隔离会话）。只有在特殊需求下（需要在用户可见的会话中执行）才选方案 B。

**Q: 隔离会话会占用额外资源吗？**
A: 不会。隔离会话是临时的，自动过期（24h），不会额外占用内存。

**Q: 如何自定义三池模型？**
A: 编辑 `~/.openclaw/workspace/.lib/pools.json`，或运行 `setup_wizard.py` 交互式配置。

**Q: 我的原有配置会被覆盖吗？**
A: 不会。使用智能合并流程（Step 3），仅追加缺失配置，保留原有设置。

---

## 🎓 学习路径

1. **快速体验（5 分钟）**
   - 运行 `setup_wizard.py`
   - 隔离现有 Cron Job
   - 测试语义检查

2. **深入理解（30 分钟）**
   - 阅读本文档
   - 自定义 tasks.json 关键词
   - 配置三池模型

3. **生产部署（1 小时）**
   - 完整配置指南
   - 智能合并配置
   - 故障排除与监控

---

## 📊 版本对比

| 特性 | v7.0 | v7.1 | v7.2 |
|------|------|------|------|
| 关键词匹配 | ✅ | ✅ | ✅ |
| 上下文评分 | ✅ | ✅ | ✅ |
| 三池架构 | ✅ | ✅ | ✅ |
| **会话隔离规则** | ❌ | ❌ | **✅ 新增** |
| **无冲突配置** | ❌ | ❌ | **✅ 新增** |
| **完整故障排除** | ❌ | ❌ | **✅ 新增** |

---

## 📝 许可与支持

- **许可证**: MIT
- **ClawHub**: https://clawhub.ai/halfmoon82/semantic-router
- **反馈**: 在 ClawHub 提交 issue 或改进建议

---

**最后更新**: 2026-03-06 GMT+8
**维护者**: halfmoon82  
**稳定性**: ⭐⭐⭐⭐⭐ (生产级)

---

## ⚖️ 知识产权与归属声明 (Intellectual Property & Attribution)

**Powered by halfmoon82** 🔷

本技能（Semantic Router）由 **halfmoon82** 开发并维护。

- **版权所有**: © 2026 halfmoon82. All rights reserved.
- **官方发布**: [ClawHub](https://clawhub.ai/halfmoon82/semantic-router)
- **许可证**: 本技能采用 MIT 许可证。您可以自由使用、修改和分发，但必须保留原始作者信息及此版权声明。
- **贡献与支持**: 欢迎通过 ClawHub 提交 Issue 或参与讨论。

---
