从规则到混合 ML:SAG 自动调参与优化器实践
> SAG 检索有 7 个超参数,手动调参不现实。我们用三层递进式优化解决这个问题。
SAG 检索有 7 个超参数,手动调参不现实。我们用三层递进式优化解决这个问题。
1. SAG 自动调参:三层架构
Layer 1: Rule-based Search (基础层)
│ 网格搜索 / 随机搜索
│ 纯程序,无需 LLM
│ 遍历参数空间 → 评测 → 输出最优
│
Layer 2: Bayesian Optimization (进阶层)
│ Optuna 贝叶斯搜索
│ 根据历史评测结果自适应调整搜索方向
│ ~50 trials 找到近优解
│
Layer 3: LLM Agent (高级层)
LLM 分析调参历史 → 生成洞察 → 提出新参数组合
"上次 vector_weight=0.6 recall 下降,可能因为..."
→ 生成新建议 → 评测 → 循环
评测指标
def evaluate_config(config: dict, max_cases: int = 100) -> dict:
"""对单个参数配置运行 eval cases,计算 recall。"""
params = SAGParams.from_dict(config)
hits = 0
for case_id in case_ids:
results = sag_retrieve(query, top_k=10, params=params)
retrieved = {r.chunk_id for r in results}
if retrieved & expected_ids:
hits += 1
return {"recall": hits / len(case_ids), "config": config, ...}调参历史持久化
// reports/sag_tuning/history.jsonl
{"trial": 1, "config": {"vector_weight": 0.5, ...}, "recall": 0.72, "ts": "..."}
{"trial": 2, "config": {"vector_weight": 0.6, ...}, "recall": 0.68, "ts": "..."}
{"trial": 3, "config": {"structural_base": 0.7, ...}, "recall": 0.78, "ts": "..."}2. TicketPilot 优化器:从规则到混合 ML
一个具体的应用场景——客服工单自动分类(intent / severity / risk):
初始状态:纯规则分类
├─ intent: 关键词匹配 (8 类意图)
├─ severity: risk flag 计数推导 (LOW/MEDIUM/HIGH)
├─ risk: 5 个关键词 × 6 个 risk flag
└─ composite score: 0.624
优化路径:
├─ Phase 1: 规则优化
│ ├─ 扩展 risk 关键词 (21% → 50%+)
│ ├─ severity 直接分类 (54% → 65%+)
│ ├─ confidence 阈值修复
│ └─ batch 优化器 (一轮多 fix)
│
├─ Phase 2: 轻量 ML
│ ├─ FastText 混合分类器 (intent 61% → 70%+)
│ ├─ 外部数据扩充 (JDDC/COLDataset)
│ └─ NSGA-II 多目标优化
│
└─ Phase 3: LLM-Guided
└─ LLM 分析错误模式 → 生成规则变异
混合分类器架构
Input (用户文本)
│
├─→ Rule Classifier (关键词匹配)
│ └─ confidence_score (基于匹配关键词数/权重)
│
├─→ FastText Classifier (subword n-gram)
│ └─ probability (400 样本训练)
│
└─→ Ensemble
├─ rule_conf > 0.8 → 用 rule
├─ fasttext_prob > 0.7 → 用 fasttext
└─ 都不确定 → 人工审核
NSGA-II 多目标优化
同时优化 8 个 intent 的 F1,约束无回归:
class TicketPilotRuleOpt(ElementwiseProblem):
# 8 个目标:每个 intent 的 1-F1 (最小化)
# 约束:每个 intent 的 F1 ≥ baseline
# 决策变量:每个 intent 的关键词包含/排除 (0/1)
# 结果:帕累托前沿
# 解 A:intent_1 F1=0.85, intent_2 F1=0.72
# 解 B:intent_1 F1=0.80, intent_2 F1=0.78
# → 人工选择 trade-off