Files
ewoooc/docs/adr/ADR-034-dynamic-model-router.md
OoO 390c32b05d
All checks were successful
CD Pipeline / deploy (push) Successful in 2m45s
feat(p21): Caller × Context 動態 Model Router + ADR-034
Operation Ollama-First v5.0 / Phase 21 — 動態路由治理

services/llm_model_router.py (160+ 行)
- 純規則引擎,零 LLM 成本(Python lambda predicate)
- 6 caller × 12 條路由規則:
  • sales_copy: 短文 < 100 字 → gemma3:4b / 長文 → llama3.1:8b
  • hermes_analyst: gap > 20% 或銷量 < -50% → qwen3:14b / 預設 hermes3
  • aider_heal: diff > 200 行 → qwen2.5-coder:32b / 預設 7b
  • openclaw_qa: query > 200 字或 multi_turn → qwen3:14b / 預設 qwen2.5:7b-instruct
  • ppt_vision: minicpm 不健康 → llava / 預設 minicpm-v
  • ea_engine: require_chain_of_thought → deepseek-r1:14b / 預設 Gemini
- feature flag MODEL_ROUTER_ENABLED 預設 OFF(向下相容)
- 失敗安全:predicate 例外 skip 到下一條

tests/test_llm_model_router.py (18 tests 全綠)
- T1 flag OFF 不路由
- T2 sales_copy 短/長文路由
- T3 hermes 簡單/複雜 SKU
- T4 aider_heal 簡單/重構
- T5 ppt_vision 主備援
- T6 ea_engine CoT 路由
- T7 predicate 例外容錯
- T8 utility 函數

ADR-034 — Caller × Context 動態 Model Router
- 6 caller 路由規則對應表
- 5 段否決方案(LLM-based / hardcode / 配置檔 / 統一升級)
- Phase 21.2-21.6 戰略性遷移計畫
- V1-V3 驗收 SQL(caller 整合後 model 分布觀察)

關聯:Primary + Secondary 兩台 GCP 已備齊 10 模型(67GB 對稱)支援所有
路由規則;caller 整合可分階段進行(Phase 21.2-21.5)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:54:12 +08:00

177 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-034: Caller × Context 動態 Model Router
- **Status**: Accepted (待整合到 caller 後 Active)
- **Date**: 2026-05-04
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0 / Phase 21
- **Related**: ADR-028LLM 路由、ADR-029雙塔分工、ADR-030多供應商
---
## Context
戰役 v5.0 累積完成 Primary + Secondary 兩台 GCP × 各 10 個 Ollama 模型(~67GB。但既有 caller 多用單一寫死 model如 sales_copy 永遠用 `llama3.1:8b`),無法動態根據 context 選最佳 model。
**痛點**
1. **資源浪費**sales_copy 短文(< 100 字)也用 8B 模型 → 應走 `gemma3:4b`4GB vs 5GB延遲 -50%
2. **品質瓶頸**Hermes 競價遇複雜 SKUgap > 20%)仍用 `hermes3:latest`8B→ 應升 `qwen3:14b`
3. **重構斷層**AiderHeal 大型重構diff > 200 行)用 `qwen2.5-coder:7b` 不夠 → 應升 `qwen2.5-coder:32b`
4. **推理空缺**EA HITL 需 chain-of-thought 時無 deepseek-r1 路徑
**前置已完成**
- Primary + Secondary 各 10 模型完整對稱
- `services/llm_caller_registry.py` 30+ caller 集中
- `services/cost_throttle_service.py` 成本守門
本 ADR 鎖定**動態路由規則**設計。
---
## Decision
### 1. 純規則引擎,零 LLM 成本
```python
# services/llm_model_router.py
ROUTING_RULES: Dict[str, list] = {
'sales_copy': [
(lambda ctx: ctx.get('expected_length', 0) < 100, 'gemma3:4b'),
(lambda ctx: True, 'llama3.1:8b'),
],
'hermes_analyst': [
(lambda ctx: ctx['max_gap_pct'] > 20 or ctx['min_sales_delta'] < -50,
'qwen3:14b'),
(lambda ctx: True,
'hermes3:latest'),
],
# ... 6 個 caller 共 12 條規則
}
```
### 2. 路由規則對應表
| Caller | Context 觸發條件 | 升級 Model | 預設 Model |
|---|---|---|---|
| `sales_copy` | expected_length < 100 字 | `gemma3:4b` | `llama3.1:8b` |
| `hermes_analyst` | max_gap_pct > 20% 或 銷量 < -50% | `qwen3:14b` | `hermes3:latest` |
| `aider_heal` | diff_lines > 200 | `qwen2.5-coder:32b` | `qwen2.5-coder:7b` |
| `openclaw_qa` | query_length > 200 或 multi_turn | `qwen3:14b` | `qwen2.5:7b-instruct` |
| `ppt_vision` | minicpm_unhealthy | `llava:latest` | `minicpm-v:latest` |
| `ea_engine` | require_chain_of_thought | `deepseek-r1:14b` | (回 default = Gemini|
### 3. Feature Flag 灰度
- `MODEL_ROUTER_ENABLED` 預設 OFF
- caller 端 `select_model(caller, context, default='既有 model')`
- flag OFF → 直接回 default不評估規則→ 行為與戰前完全相同
### 4. 失敗安全
- predicate 拋例外 → log warning + skip 到下一條
- caller 不在 ROUTING_RULES → 回 default
- 所有規則都不命中 → 回 default
### 5. 整合方式(建議分階段)
```python
# Caller 範例(如 ollama_service.generate_sales_copy
from services.llm_model_router import select_model
def generate_sales_copy(self, product_name, ...):
model = select_model(
caller='sales_copy',
context={'expected_length': len(product_name) * 3},
default='llama3.1:8b',
)
return self.generate(prompt=..., model=model, ...)
```
**戰略性遷移**
- Phase 21.1: model_router service + test 落地(本 commit
- Phase 21.2: sales_copy 整合(低風險示範)⏳
- Phase 21.3: aider_heal 整合(中風險,需 diff_lines 取得)
- Phase 21.4: hermes_analyst 整合(高風險,動戰術主流程)
- Phase 21.5: 全 caller 遷移完成 → MODEL_ROUTER_ENABLED 預設 ON
---
## Alternatives Considered
| 方案 | 否決理由 |
|---|---|
| **A. LLM-based routing**(用 LLM 決定用哪個 model| 循環燒錢 + 引入新延遲 |
| **B. caller 各自 hardcode 多 model**(不集中)| 規則漂移無 single source of truth |
| **C. 直接統一升級到大模型**(如全用 qwen3:14b| 浪費資源,短文不需 14B |
| **D. 配置檔 YAML/JSON**(運行時讀檔)| 過度工程Python lambda 已夠彈性 |
---
## Consequences
### 正面5
1. **資源節省**:短文 sales_copy 用 4GB gemma3 vs 5GB llama3.1,延遲 -50%
2. **品質提升**複雜場景自動升大模型hermes 14B / aider 32B
3. **零 LLM 成本**:純 Python lambda 規則
4. **失敗安全**:規則例外不阻擋主流程
5. **集中治理**:規則改動只需 PR `llm_model_router.py`,不動 caller
### 負面3
1. **規則維護成本**:新 caller / 新 context 條件需更新 rules但這正是 ADR 治理目標)
2. **context 取得負擔**caller 必須先計算 context如 diff_lines才能呼叫 router
3. **debug 複雜度**:路由命中哪條規則需看 logger.debug
### 風險3
1. **規則設計失誤**閾值20% / 200 lines可能不準 → mitigate by Phase 21.2-21.5 灰度觀察
2. **GCP 主機沒拉到對應 model**select 回的 model 不存在 → mitigate by 拉模型前提(已完成 10 模型對稱)
3. **caller 整合不完整**:部分 caller 仍 hardcode → 文件化遷移計畫
---
## Verification
### V1unit test
```bash
pytest tests/test_llm_model_router.py -v
# 預期 18 tests 全綠
```
### V2caller 整合後 ai_calls 觀察
```sql
SELECT model, COUNT(*), AVG(duration_ms)
FROM ai_calls
WHERE caller = 'sales_copy' AND called_at > NOW() - INTERVAL '7 days'
GROUP BY model;
-- 期望gemma3:4b 短文佔 60%+llama3.1:8b 長文佔 40%-
-- 平均 duration: gemma3 < llama3.1 約 50%
```
### V3cost throttle 整合
```python
# Phase 22 規劃cost_throttle 觸發時自動切便宜 model
# 例claude throttled → select_model 改回 default Gemini Flash
```
---
## Migration Plan
| Phase | 工作 | 狀態 |
|---|---|---|
| 21.1 | services/llm_model_router.py + 18 tests | ✅ 本 commit |
| 21.2 | sales_copy 整合generate_sales_copy 加 select_model| ⏳ |
| 21.3 | aider_heal 整合(需 diff_lines context| ⏳ |
| 21.4 | hermes_analyst 整合(需 max_gap_pct context| ⏳ |
| 21.5 | openclaw_qa / ppt_vision / ea_engine | ⏳ |
| 21.6 | MODEL_ROUTER_ENABLED 預設 ON觀察 1 週後)| ⏳ |
---
## References
- `services/llm_model_router.py`(本 commit
- `tests/test_llm_model_router.py`18 tests
- `docs/llm_model_full_evaluation_20260504.md` 路由優化建議
- ADR-028LLM 路由統一準則)
- ADR-029Hermes-First 雙塔分工)
- ADR-030Frontier 多供應商策略)