从 Multi-Agent 到 Skill+CLI:个人助理 1.0 → 2.0 架构演进

📎skill快检.md

从 Multi-Agent 到 Skill+CLI:架构演进与快检路由

依据:1.0/2.0 架构演进背景 + 《skill快检.md》(三层漏斗路由设计)。

个人分工 :团队将架构从 1.0 Multi-Agent 升级到 2.0 Skill+CLI 后,Skill 数量增多、触发边界模糊,我参与设计了快检方案 ,主要负责静态评分方案(Tier 0 正则确定性匹配)的设计与实现 ,并参与完成 routing 评分(语义/LLM 层)的实现 。

全文结构:背景简述(一)→ 快检总体方案(二)→ 静态评分方案·主要负责(三) → routing 评分·参与实现(四)→ 场景走查(五)→ 工程保障(六)→ 配置与取舍(七、八)。

先说结论

1.0:一个业务雇一个专职员工(Multi-Agent),新业务 = 写代码招人,越做越臃肿;

2.0:一个大脑 + 一柜子手册(Single Agent + Skill),新业务 = 写一份 SKILL.md,纯配置活;

但手册一多,触发边界就模糊了(「帮我报销」和「报销制度是什么」该走哪本手册?)------于是有了快检路由:我主要负责的静态评分层用规则把 70%+ 的明确问法在 1ms 内本地解决,拿不准的才逐层下沉到语义评分和 LLM 仲裁。


一、背景简述:1.0 → 2.0 与新矛盾

1.1 两代架构一段话讲清

1.0(Multi-Agent) :每个业务场景开发一个独立子 Agent(自带 prompt、工具、流程),调度者决定用户的话给谁。病根:业务逻辑和 Agent 运行时焊死------新业务五步全工程活(写 prompt、接工具、流程编排、配路由、部署),排期以周计;公共能力重复建设;子 Agent 间传话导致错误复利放大;子 Agent 越多调度越难。

2.0(Skill + CLI) :一个主 Agent 大脑 + N 份 SKILL.md 配置手册 + 开放平台接口(业务能力服务化,Skill 通过 CLI 脚本调用)。新业务接入变成配置活:写一份 SKILL.md 放进目录即可,热重载自动生效,主 Agent 零改动。

css 复制代码
flowchart TD
    U[用户提问] --> R[快检路由<br/>三层漏斗 选出该用的 Skill]
    R -->|命中| B[主 Agent · 唯一的大脑<br/>只装入选中 Skill 的指令和工具]
    B --> S[Skill 柜子<br/>SKILL.md × N 份]
    B --> C[CLI 脚本工具] --> O[开放平台接口]

1.2 SKILL.md 三段结构(理解快检的前提)

部分 内容 什么时候被读
frontmatter(封面) name / description / triggers / scripts 启动时就登记,供路由判断用
instructions(正文) 完整业务指令 只有被快检命中才加载
scripts/tools(工具) CLI 脚本、可调用接口 只有被快检命中才加载

封面随时可查(便宜)、正文命中才加载(昂贵)------这是「先路由后加载」的物质基础。

1.3 新矛盾:Skill 多了,触发边界模糊

升级后 Skill 可以低成本堆积,新问题随之而来:

  1. 触发边界模糊 (快检要解的核心题):Skill 一多,「这句话该翻哪本手册」变得曖昧------「帮我报销 」是业务操作、「报销制度是什么」是知识问答,泛化词(时间/地点)到处误触发,两个 Skill 的触发条件互相重叠抢占;
  2. prompt 爆炸:全量注入所有 Skill 指令,token 成本随 Skill 数线性上涨,LLM「顾头不顾尾」;
  3. 工具误用:工具列表越长,选错工具、传错参数概率越高。

本质矛盾:Skill 越多,System Prompt 越大、工具越杂、LLM 越容易误用工具。 这就是快检方案的出发点,我参与了整体方案设计,并主要负责其中静态评分层。


二、快检总体方案:三层漏斗(参与设计)

2.1 两条设计原则

原则一:先路由,后加载。 启动只扫描封面元数据,不读正文、不导入工具;快检命中才完整加载。无论多少 Skill,每轮 system prompt 只注入选中的 1~2 个。

lua 复制代码
stateDiagram-v2
    [*] --> Scanned: 启动时只登记封面信息
    Scanned --> Loaded: 快检命中 → 完整加载正文和工具
    Loaded --> Scanned: SKILL.md 被编辑(热重载自动重置)
    Scanned --> Loaded: 再次命中

原则二:先便宜,后昂贵。 路由决策按成本分层,上层命中即短路:

层 策略 延迟 成本 定位 我的分工
Tier 0 正则 / 触发词确定性匹配(静态评分) <1ms $0,纯本地 覆盖高频明确问法,目标短路 70%+ 主要负责:设计与实现
Tier 1 BGE-M3 语义向量检索(动态评分) ~80ms 本地推理 同义改写、近义词泛化 参与实现
Tier 2 LLM 判定器(动态仲裁) ~500ms 数百 token 兜底歧义,可输出 null 参与实现

关键闭环 :三层只做「选谁」的决策(便宜),load_skill 只对选中者付出加载成本(昂贵)------路由与加载解耦。


三、静态评分方案(Tier 0)------ 我主要负责的设计与实现 ★

「静态」的含义:不依赖任何模型推理,纯本地字符串/正则匹配,规则写死、结果确定、完全可解释。它是三层漏斗的第一道闸门,目标是用 $0 成本短路 70%+ 的高频明确问法。

3.1 要解决的三个设计难题

难题 具体表现
规则互相抢占 多个 Skill 的规则同时命中一句话,该听谁的?「报销制度是什么」被业务规则抢走就是误路由
泛化词误触发 「明天」「北京」这类高频万金油词,会让工具类 Skill 到处乱触发
复合问法 「订机票再记个日程」一句话横跨两个能力,需要一次命中多个 Skill

3.2 我的方案:六步瀑布 + 冲突抑制 + 确定性排序

位置:_deterministic_route()。六步按「可信度」从高到低排成瀑布,依次尝试:

rust 复制代码
flowchart TD
    IN[用户文本] --> S1{"① 防误伤特殊检测<br/>易混淆知识型问法先定界"}
    S1 -->|命中| OK1[✅ 专用 Skill]
    S1 -->|未命中| S2{"② 组合路由<br/>复合场景一次返回多个"}
    S2 -->|命中| OK2[✅ Skill 组合]
    S2 -->|未命中| S3["③ 平台 Route Rules<br/>预定义正则(带优先级)"]
    S3 --> S4["④ Trigger 子串匹配<br/>作者声明触发短语(最高优先级)"]
    S4 --> S5["⑤ Token 降级匹配<br/>name+description 关键词兜底"]
    S5 --> C{有匹配?}
    C -->|是| SUP["冲突抑制<br/>+ 按 priority 和注册顺序排序"] --> OK3[✅ Skill 列表]
    C -->|否| S6{"⑥ 辅助 Skill 叠加<br/>业务命中 + 特定语境词?"}
    S6 -->|是| OK4[✅ 追加工具类 Skill]
    S6 -->|否| OUT[❌ 未命中 → 进入 Tier 1]

每一步的设计意图:

步 干什么 为什么这么设计
① 防误伤特殊检测 为易混淆的知识型问法设专用规则,最优先定界 直接解「规则抢占」难题:「报销制度是什么」先被知识问答规则兜住,不会被后面的业务规则抢走
② 组合路由 复合场景一条规则同时返回多个 Skill 解「复合问法」难题:一次点齐两本手册,不拆成多次判定
③ 平台 Route Rules 平台预定义正则规则,带优先级数字 通用入口;优先级数字只用于同级排序,不跨级
④ Trigger 子串匹配 Skill 作者在 frontmatter 声明的触发短语 作者触发词可信度最高:写手册的人最懂什么话该翻这本手册,显式声明 > 平台猜测
⑤ Token 降级匹配 name + description 关键词兜底 前四步都没中时的最后尝试:覆盖面广、精度低,所以放最后
⑥ 辅助 Skill 叠加 已命中业务 Skill 且含特定语境词时,追加工具类 Skill 命中「日程安排」且提到「明天」→ 顺手捎上日历工具;业务 Skill 不感知此能力,由静态评分层透明装配

命中后的两道后处理:

  • 冲突抑制:主规则命中业务 Skill 后,抑制工具类 Skill 的模糊触发词(时间/地点类泛化词)------直接解「泛化词误触发」难题;
  • 确定性排序 :多命中时按 (priority, registry_order) 排序,保证同样输入永远同样输出(可解释、可回归)。

3.3 静态评分

  1. 确定性优先:指标名、内部术语这类特化关键词,在语义空间里聚类不稳定,精确匹配比语义相似度可靠------所以静态层放最前;
  2. 可信度分层:作者显式声明 > 平台规则 > 关键词猜测,瀑布顺序即可信度顺序;
  3. 可解释可回归:每次命中都能说清「哪条规则、为什么」,配合 Golden 题库,规则改动可验证;
  4. 零成本短路:<1ms、$0,把 70%+ 流量挡在模型之外,是整个漏斗的成本基石。

四、routing 评分(Tier 1 / Tier 2)------ 参与实现

4.1 Tier 1:语义向量评分

静态层未命中才进入。需要 embedding 推理(Ollama),但不需要 LLM------依然便宜。

sql 复制代码
flowchart LR
    Q[查询文本] --> EMB[BGE-M3 → 1024 维向量]
    EMB --> IDX[向量索引<br/>InMemory 或 Qdrant]
    IDX --> CAND[top-3 候选]
    CAND --> RR{启用 Reranker?}
    RR -->|是| RER[BGE-Reranker-V2-M3<br/>pair 打分 + sigmoid 归一]
    RR -->|否| DEC
    RER --> DEC{top-1 ≥ 0.72?}
    DEC -->|是| SEL[✅ 只取 top-1 短路]
    DEC -->|否| T2[↓ 带候选去 Tier 2]
细节 解释
语料从哪来 语义文档 = name + description + triggers 拼接------Skill 作者写封面时就在维护路由语料,零额外标注成本
为什么选 BGE-M3 原生中英混排 embedding,适配「帮我 cancel 一下 booking」这类中英夹杂问法
索引两种模式 InMemory(默认,warmup 缓存全部向量);Qdrant(生产,source_hash 增量同步,多实例共享)
可选 Reranker BGE-Reranker-V2-M3 对「查询×候选」逐对精打分,更准但多一次推理;默认关------够用就不加成本
只取 top-1 top-1 后相似度衰减快,多选引入噪音;多选是确定性需求,应由 Tier 0 组合规则显式表达,语义层不碰运气
阈值 0.72 ≥0.72 视为语义足够确定直接短路;有候选但不够高 =「有点像但拿不准」→ 交给 Tier 2

4.2 Tier 2:LLM 判定器

rust 复制代码
sequenceDiagram
    participant R as 路由器
    participant L as LLM 判定器
    R->>L: 判定 Prompt:用户输入 + 语义候选<br/>只输出 JSON {selectedSkill, confidence, reason}
    L-->>R: 原始输出
    R->>R: 解析(兼容 dict / JSON 字符串 / Markdown 代码块)
    alt selectedSkill 在注册表中
        R-->>R: ✅ selected
    else selectedSkill = null
        R-->>R: ❌ rejected(不路由,走通用对话)
    else 解析失败
        R->>L: 带 previousError 重试(≤ retry_count)
        L-->>R: 仍失败 → ❌ failed,返回 []
    end
细节 解释
只看候选不看全量 LLM 只拿语义层的 2~3 个候选做选择题------题目小、答案有据,不做「大海捞针式」瞎猜
允许拒绝 prompt 明确「没把握返回 null」------快检的产出不仅是『选中』,也包括高置信度地『排除』;强行路由比不路由危害大
解析容错 + 失败安全 输出兼容三种形态;解析失败带错误上下文重试,耗尽后降级不路由,绝不阻断会话
独立小模型 SKILL_ROUTING_LLM_MODEL 与主 LLM 解耦,判定任务简单可换便宜模型

五、三个典型问法走一遍漏斗(场景走查)

用户问法 漏斗路径 结果
「帮我报销上周的差旅费」 Tier 0 ④:Trigger「报销」子串命中 ✅ <1ms 静态评分短路,零成本
「我下周想去杭州出差,帮我安排下行程要注意啥」 Tier 0 全瀑布未命中 → Tier 1:语义相似度 0.85 ≥ 0.72 ✅ ~80ms 语义评分短路
「看看这段合同有没有坑,顺便翻成英文」 Tier 0 未命中 → Tier 1 候选分数均 <0.72 → Tier 2 LLM 仲裁 ✅ 选中组合 / ❌ 高置信度拒绝走通用对话

第三行两种结局都是好结局:选对是赢,拒绝也是赢(没污染 prompt)。唯一输的是「硬塞一个错的」。


六、工程保障------快检凭什么敢大规模堆 Skill

6.1 热插拔

  • watchfiles 后台监听 Skill 目录,SKILL.md 的 mtime + hash 一变化自动重扫;
  • 新手册放进目录即登记进漏斗;编辑过的 Skill 自动重置为未加载(旧工具实例可能失效,下次命中按新 frontmatter 重建,避免脏状态)。

6.2 可回溯:routing_trace 留小票

css 复制代码
[  { "stage": "regex",     "status": "missed",          "reason": "no regex or trigger matched" },  { "stage": "semantic",  "status": "below_threshold", "candidates": [{"name": "candidate-a", "score": 0.65}], "threshold": 0.72 },
  { "stage": "llm_judge", "status": "selected",        "selected_skill": "candidate-a", "confidence": 0.85 }
]
字段 含义
stage / status 走到哪层、该层结局------静态评分层的 missed reason 能直接看出是哪条规则没配上
candidates + score 语义候选与分数------区分「候选就不对」vs「阈值卡太严」
confidence LLM 判定自信度

6.3 可回归

  • 「标准问法 + 期望 Skill」标注集,CI 复放三层漏斗,按层统计 regex_hit_rate(静态层短路率)、整体准确率;
  • 规则/阈值每次修改前后跑同一份考卷对比;线上 bad case 从 trace 捞出标注后沉淀回题库------越用越准。

相关推荐
2301_786756602 小时前
2026 JCR 秋季数据重载解读:影响因子为什么会变?附期刊影响力数据批量追踪方案
java·服务器·前端
数据掘金2 小时前
小程序埋点方案的埋点灰度发布怎么做?
前端
AiMan2 小时前
读取Meta Muse列表并导出这个功能,是没办法做到的是吗?
前端
老于11112 小时前
AI 生成内容标识落地:显式角标 + EXIF 隐式标识 + 内容编号台账
前端
RaaS1002 小时前
AI网关选型指南:MAI Gateway(魔芋企业级AI网关)vs 开源方案全面对比
前端·后端
小画家~2 小时前
vue3 里面的 itemList.reduce
前端·数据结构·算法
锋行天下3 小时前
langgraph 循环节点的静态和动态实现
前端·后端
keyipatience3 小时前
JS学习笔记(2)数组,函数,作用域,对象
前端·javascript·笔记·学习·html
2603_965148113 小时前
商品价格监控 API 接口:从原理到实战的完整指南
java·前端·数据库·python·生活