AI Agent 工程实践(05):Rule Router——如何让 Agent 自动加载正确的规则?
发布时间2026-07-11标签AI AgentLLM规则路由上下文工程工程实践系列导航上一篇AI Agent 工程实践04Review——为什么 AI Agent 必须每天复盘下一篇AI Agent 工程实践06Knowledge 如何演化成 Rules本文是 [AI Agent 工程实践] 系列的第 05 篇。分层做好的第一天我以为问题解决了。core/3 条常驻heavy/20 个按需——清爽、干净、职责清晰。第二周我翻了调用日志发现一个尴尬的事实90% 的任务加载的还是全部 heavy。不是分层没用是我压根没想清楚按需的需由谁判断。手动指定task_type一忙起来就忘改新人用更是不知道该选哪个——结果为了不出错干脆全开。分层把规则归了类但谁也没决定它们什么时候出场。这一篇讲的就是这个谁Rule Router。本文你将学到✓ 为什么分层只解决了一半问题另一半在怎么自动选✓ Rule RAG 完整链路Task → Classifier → Router → Heavy → Agent✓ 路由系统五个核心概念Router / Trigger / Priority / Conflict / Fallback✓ 没有路由器时分层为什么会偷偷退化回全加载适合阅读✓ 读了想把 core/heavy 真正用起来的人✓ 给 Agent 做规则/技能调度、被该加载哪个困扰的开发者✓ 对上下文工程和动态规则注入感兴趣的人问题背景之前解决了规则怎么组织——常驻的放core/按需的放heavy/互不打架。但分层只回答了规则住哪没回答规则什么时候出场。这个问题在 demo 阶段看不出来——手动传一个task_typereviewRouter 就是个 if-else。可一旦真正用起来它立刻暴露手动指定会忘。任务一多我经常忘了改task_type代码审查任务用着日常编码的规则集审查质量飘忽。新人不会选。heavy 文件 20 个新同事根本不知道写测试该加载20-test.md还是40-security.md索性全开图保险。全开 没分层。一旦回到所有 heavy 默认加载第 02 篇的收益响应快、噪声低、不冲突全部清零——分层名存实亡。一句话没有路由器分层只是个仓库有路由器它才是个调度系统。错误尝试第一次手动传 task_typecontext build_context(task_typereview) # 必须每次记得改结果忘了改就是错的。安全审计任务漏了40-security.md。靠人记得住的调度就不是可靠调度。第二次全部 heavy 默认开靠模型自己挑结果上下文又涨回几百行90% 是噪声原样回来规则之间还开始打架。这等于亲手把分层拆了。两次尝试指向同一个教训按需加载的需不能由人判断会忘也不能由模型在推理时判断会乱。它必须发生在加载阶段由独立的路由器决定。关键观察我把一周的调用日志导出来按应该加载和实际加载做了对比任务应该加载手动模式实际偏差代码审查reviewreview✅写单元测试test忘改daily❌ 漏安全审计security忘改daily❌ 漏架构设计architecture全开保险❌ 多pie title 按需加载失败的原因分布 手动忘记指定 : 45 怕出错直接全开 : 35 不知道选哪个 : 15 其它 : 5静态分层是仓库动态路由才是调度。仓库把东西摆整齐调度才决定它们什么时候出场。没有调度整齐的仓库也会被人图省事全搬出来。问题不在规则没分好层而在该加载哪条这个决策被甩给了人或模型——前者会忘后者会乱。正确思路是把决策提前到加载阶段由 Router 根据任务特征自动判断Task → Classifier识别任务 → Router选规则 → Heavy加载 → Agent执行这正是第 02 篇埋的伏笔——Rule RAG。传统 RAG 是问题→检索知识→生成Rule RAG 是任务→检索规则→执行。两者本质同构不在推理时把所有信息硬塞给模型而是在需要时把对的信息送进去。第 02 篇定义了它这一篇把它工程化。最终方案Rule Router 五个核心概念路由系统不是单个组件是五个概念咬合的链路。1. Router —— 调度入口接收任务、输出该加载哪些 heavy。它只做一件事把加载什么的决策从人/模型手里拿走固化成代码。def route(task: Task) - list[str]: label classifier.predict(task) # 识别任务类型 heavy match_trigger(label, task) # 按触发条件匹配 heavy resolve_conflict(sort_by_priority(heavy)) # 排序裁决 return heavy or fallback() # 都没命中就降级Router 本身很薄真正的逻辑在下面四个概念里。2. Trigger —— 出场条件每个 heavy 文件必须声明触发条件否则就是定义了但永远不被加载的死规则# heavy/20-test.md trigger: task_type: [test, refactor] # 任务类型命中 keywords: [单测, 覆盖率, pytest] # 或关键词命中 match: any # 任一满足即触发没有 Trigger 的 heavy 文件等于没有出口的仓库。给每个能力文件定义清晰触发条件是路由能跑起来的前提。3. Priority —— 谁优先多个 heavy 同时命中时任务既涉及测试又涉及安全不能全加载要有优先级。我的规则core 永远最高任何 heavy 都不能覆盖 coreheavy 之间按文件名前缀数字排10-20-40-数字小优先超过上限时砍掉低优先级的priority: core: 100 # 不可覆盖 heavy: order: filename_prefix # 10- 20- 40- max_loaded: 2 # 同一任务最多加载 2 个 heavyPriority 把多选收束成精选。4. Conflict —— 打架听谁的规则会矛盾测试规则要每个函数都有单测快速原型规则要先跑通再补测试。同时命中时模型在矛盾指令里左右摇摆。我的裁决core 不可被 heavy 覆盖——安全底线永远赢显式声明互斥heavy 文件里写conflicts_with命中其一就不加载另一个同优先级冲突保留两者 加一句元规则按当前任务目标取舍把判断权交给模型但明确告知冲突存在# heavy/20-test.md conflicts_with: - heavy/50-quick-prototype.md # 测试规范 与 快速原型 互斥Conflict 处理的不是消灭矛盾而是让矛盾被看见、被显式裁决而不是偷偷在上下文里互相打架。5. Fallback —— 没命中怎么办最危险的情况Classifier 没识别出任务类型所有 Trigger 都没命中。这时不能报错卡住也不能默认全开——默认只加载 core不加载任何 heavy。def fallback() - list[str]: return [core/00-must.md] # 没把握时加载最少Fallback 的哲学少加载最多是不够好错加载是被噪声带偏——前者可接受后者是事故。这和第 03 篇 Memory 的晋升是主动决策同源宁可漏不可滥。实际收益指标手动指定全开靠模型Rule Router正确加载率~60%常忘改100%但全错~90%平均加载 heavy 数1常选错20全开1-2精选上下文噪声中漏加载高全开低新人可用性差高高为主观估算非严格 A/B Test但反映三种模式在正确性 vs 轻量上的权衡差异。架构图 / 流程图Rule RAG 完整链路flowchart TD TASK[Taskbr/用户任务] -- CLS{Classifierbr/识别任务类型} CLS --|review/test/...| RT[Rule Routerbr/路由调度] CLS --|未识别| FB[Fallbackbr/只加载 core] RT -- TRIG{Trigger 匹配} TRIG --|命中多个| PRIO[Priority 排序] PRIO -- CFL{Conflict 裁决} CFL --|保留| H1[heavy/10-review.md] CFL --|互斥排除| H2[heavy/40-security.md] CORE[core/00-must.mdbr/常驻底线] -- AGENT H1 -- AGENT[Agent 执行] FB -- AGENT AGENT -- OUT[最终输出] style CORE fill:#e6f1fb,stroke:#185fa5 style RT fill:#ffe6cc,stroke:#d79b00 style FB fill:#eeeeee,stroke:#999999 style AGENT fill:#b5d4f4,stroke:#185fa5关键点Router 不是单一节点是 Classifier → Trigger → Priority → Conflict → Fallback 这条决策链每一步都在收窄该加载什么。路由决策状态流转stateDiagram-v2 [*] -- 接收任务 接收任务 -- 分类: 识别 task_type 分类 -- 匹配触发: 查 Trigger 匹配触发 -- 命中: 有 heavy 触发 匹配触发 -- 未命中: 无 heavy 触发 命中 -- 排优先级: 命中多个 命中 -- 直接加载: 命中单个 排优先级 -- 裁决冲突: 检查互斥 裁决冲突 -- 加载精选: 保留高优先级 未命中 -- 降级: 只加载 core 直接加载 -- 执行 加载精选 -- 执行 降级 -- 执行 执行 -- [*]代码或配置示例heavy 文件完整声明含 Trigger / Priority / Conflict# heavy/10-review.md — 代码审查规范 trigger: task_type: [review, refactor] keywords: [审查, code review, PR] match: any # 任一命中即触发 priority: level: 10 # 数字越小优先级越高 max_loaded_with_others: 2 # 同时最多配 2 个其它 heavy conflicts_with: - heavy/50-quick-prototype.md # 与 快速原型 互斥 rules: - 每个问题必须有「描述 反例 改进建议」 - 不指出缺少文档/注释等非功能性建议每个 heavy 都这样声明Router 读配置即可决策路由逻辑不必硬编码。Router 主逻辑伪代码def rule_router(task: Task, core: list, heavy_index: dict) - list[str]: Rule RAG 核心任务进来返回该加载的规则文件 loaded list(core) # 1. core 常驻 label classifier.predict(task) # 2. 分类 candidates [f for f, c in heavy_index.items() if trigger_match(c.trigger, label, task)] # 3. 匹配触发 if not candidates: return loaded # 4. Fallback只留 core candidates.sort(keylambda f: heavy_index[f].priority.level) # 5. 排优先级 kept [] # 6. 裁决冲突 for f in candidates: if not any(c in kept for c in heavy_index[f].conflicts_with): kept.append(f) loaded kept[:MAX_HEAVY_LOADED] # 7. 数量上限 return loaded七步串成一条流水线分类 → 匹配 → 排序 → 裁决 → 限量每步都在收窄保证最终加载的是少而精。设计权衡候选方案优点缺点为什么不选手动指定 task_type最简单靠人记忆忘改就错可靠性太低规模一大必崩全开靠模型挑零路由成本回到噪声爆炸、规则打架等于亲手拆掉分层纯向量检索选规则语义灵活召回噪声多、无优先级裁决没解决多选/冲突/降级Rule Router 五件套自动、有优先级、能裁决、有降级需维护 Trigger 配置选择理由唯一让按需加载真正可靠发生的方案Router 不是银弹。heavy ≤3 个、任务类型单一时手动指定就够了别上路由器。它的价值在规模上——规则越多、任务越杂越值。向量检索也不是对立面Classifier 完全可以用向量模型实现和 Trigger 规则互补。总结✅ 分层解决规则住哪Router 解决规则什么时候出场——缺了路由器分层会偷偷退化回全加载。✅ Rule RAG 链路Task → Classifier → Router → Heavy → Agent把该加载什么的决策从人/模型手里拿走。✅ 五个核心概念缺一不可Router调度/ Trigger出场条件/ Priority谁优先/ Conflict打架听谁/ Fallback没命中怎么办。✅ Fallback 哲学是没把握时加载最少——少加载是不够好错加载是事故宁可漏不可滥。✅ Router 的价值在规模上规则少、任务单一就别上规则多、任务杂才值得。参考资料Lost in the Middle 论文Liu et al., 2023→ 为什么不能全开靠模型挑直接支撑加载阶段就要收窄的设计RAG 原始论文Lewis et al., 2020→ Rule RAG 的概念原型检索→注入模式来源LangChain — LCEL Routing Conditional Chains→ 工程上实现任务路由的参考Hermes Agent — Skills 触发与调度机制[待补链接]→ 另一套按需加载能力的实践验证第 02 篇为什么 Rules 要分层→ 本文前传core/heavy 分层和 Rule RAG 概念的定义处系列导航上一篇AI Agent 工程实践04Review——为什么 AI Agent 必须每天复盘下一篇AI Agent 工程实践06Knowledge 如何演化成 Rules本文是 [AI Agent 工程实践] 系列的第 05 篇。