Agent 如何动态挂载相关知识:三层渐进加载 + 路由机制把自动化再提一档

0 阅读11分钟

核心结论:想让 Agent 更自动化,关键不是「给它更多知识」,而是「在对的时机只给它对的那一点知识」。做法是动态挂载(dynamic loading):把所有知识(Skill、领域文档、规则、经验)拆成「元数据常驻 + 正文按需注入 + 资源真需要才读」三层,Agent 先用一句话描述「有哪些能力」做路由,命中后才把完整内容拉进上下文。这就是 Anthropic 推行的 SKILL.md 三层渐进加载(progressive loading) 模式,也是当前 Agent 平台收敛出的主流架构。它解决的核心矛盾是:知识越多,全塞进上下文的成本越高、噪音越大、越容易选错——动态挂载让「看起来懂一万件事」和「实际只加载一件事」同时成立。

目录

    1. 一句话结论
    1. 为什么不能把所有知识塞进上下文
    1. 核心思路:三层渐进加载(Progressive Loading)
    1. 第一层:元数据常驻(Metadata)
    1. 第二层:正文按需注入(Instructions)
    1. 第三层:资源真需要才读(Resources)
    1. 路由机制:search → inspect → select
    1. 运行时注入与记忆层:动态信息的两个入口
    1. 完整可运行代码:一个动态知识挂载器
    1. 对照表:症状 → 原因 → 解法
    1. 判断收尾

1. 一句话结论

先建立一个直觉 🎭:这就像「公司的知识管理」——你不需要把全公司所有部门的操作手册都印在员工桌上(那样桌面早爆了),而是先给一份「目录」(哪个部门管什么),需要时再调出对应那一本。动态挂载就是给 Agent 装一个「按需调阅」的知识库。

所以核心三句话:

  • 元数据常驻:只放「知识目录」(名称 + 一句话描述),极省 token。
  • 正文按需:命中后才把完整内容注入上下文。
  • 资源懒读:脚本、参考文档真正要用才读。

一句话:动态挂载 = 把「知识」从「一次性塞满」改成「按索引调阅」——用一层薄薄的目录,撑起一个庞大的知识库。

2. 为什么不能把所有知识塞进上下文

先看「静态全塞」的三种死法:

  • 上下文膨胀:几十个 Skill / 上百篇文档全塞进 system prompt,几万 token 起步,还没开始干活就烧掉大半窗口。
  • 噪音干扰:无关知识堆在一起,模型注意力被稀释,选错知识的概率反而上升。
  • 维护地狱:加一个新 Skill 要改主提示词,改动风险高,且每次都要全量重测。

用类比 🎭:这就像「把整个图书馆塞进书包」——书越背越重,你反而找不到要的那本。聪明的做法是带一张索书号,到馆里按号取书。

💡 我在Agent规则管理:让 Memory 做索引、让 Skill 存规则——上下文上限实测与分工方案里实测过上下文上限的代价,动态挂载正是「不把所有规则塞进去」的工程答案。

3. 核心思路:三层渐进加载(Progressive Loading)

主流方案把一份知识拆成三层,逐层加载:

层级内容常驻还是按需典型体积
第一层元数据(名称 + 一句话描述)常驻每条约 20–50 字
第二层正文(完整指令 / 规则)命中时注入每条几百到几千字
第三层资源(脚本 / 参考文档 / 数据)真需要才读可任意大
  • Anthropic 的 SKILL.md 就是这套:每个 Skill 是一个目录,SKILL.md 头部是元数据,正文是指令,旁边挂脚本与参考文件。
  • 加载顺序:先看目录 → 命中就读正文 → 用到文件才读文件。
  • 收益:Agent 「看起来」掌握了所有能力(因为目录全在),但实际上下文只加载了当前要用的那一点。

用类比 🎭:这就像「点菜」——菜单(元数据)全给你看,你点了哪道(命中),厨房才做哪道(加载正文),配菜用的特殊食材(资源)用到才现取。

4. 第一层:元数据常驻(Metadata)

第一层是「目录」,必须常驻,但必须极简。

  • 内容:每个知识只保留 name(名称)和 description(一句话说明「什么时候用它」)。
  • 关键:description 要写「使用场景」,而不只是「它是什么」——因为路由是靠它匹配的。
  • 体积控制:一条 20–50 字,50 条也就一两千 token,完全可接受。

反例 vs 正例:

写法示例问题
❌ 差name: pdf-tool, description: PDF 处理工具太泛,路由不知道何时用
✅ 好name: pdf-extract, description: 需要从 PDF 里提取文字或表格时使用带场景,路由能命中

💡 第一层是整个机制的「命门」:目录写得好不好,直接决定能不能挂载对。目录写得含糊,后面全白搭。

5. 第二层:正文按需注入(Instructions)

第二层是「完整内容」——命中后,才把它注入上下文。

  • 触发条件:路由阶段判定「这个知识用得上」。
  • 注入方式:把该知识的完整说明(步骤、规则、示例)拼到上下文里。
  • 用完即弃:任务结束或切到别的知识,正文可以退出上下文(配合上下文压缩,见本专栏《Agent 上下文太长怎么办》)。

关键设计:

  • 正文要自包含:一旦注入,模型不需要再回头找别的资料,就能照着执行。
  • 正文别太长:如果一个知识正文就几千字,说明它该拆成多个子知识。
  • 可审计:注入时记录「加载了哪个知识、为什么命中」,出问题能回放。

用类比 🎭:目录是「书名」,正文是「那本书」——你不会把整本书背上,但一旦决定读它,就要读到完整内容,不能只读一半。

6. 第三层:资源真需要才读(Resources)

第三层是「附件」——脚本、模板、参考文档、数据集,用到才读。

  • 典型资源:处理脚本(如 extract.py)、模板文件、长参考手册、示例数据。
  • 加载时机:正文里提示「需要时执行这个脚本」,Agent 真执行时才读。
  • 好处:一个知识可以挂很大的资源,但不加载就不占上下文。

这三层的配合逻辑:

  • 第一层:永远在(目录)。
  • 第二层:命中才在(正文)。
  • 第三层:用到才在(资源)。

💡 三层加起来,才能做到「知识库无限大、上下文占用极小」——这就是「看起来懂一切,实际只加载一件事」。

参考资料:

7. 路由机制:search → inspect → select

三层有了,那「怎么知道该加载哪个」?靠路由(routing)。业界收敛出的标准动作是三步:

  • search(搜索):用任务描述去检索候选知识(按元数据匹配 / 向量检索)。
  • inspect(查看):对候选逐个「看细节」,确认是不是真的对。
  • select(选择):选定后加载正文,开始执行。

这套方法的精髓是:「证据不足就继续查或停止,不强行命中」。

  • 高频知识常驻(经常用,放目录甚至正文常驻)。
  • 长尾知识进 metadata 库,需要时再 search 回来。
  • 命中率不靠「单次排序高分」,而靠「边界清楚 + 可审计 + 选择可回退」。

用类比 🎭:这就像「图书馆找书」——先查目录(search),翻两页确认是不是这本(inspect),确定后借走(select)。查不到就再查,而不是硬抓一本不相干的。

参考资料:

8. 运行时注入与记忆层:动态信息的两个入口

除了「知识库」,还有两类信息需要动态挂载:

① 运行时注入(runtime injection)

  • 内容:当前时间、渠道 ID、用户偏好、会话状态等「每轮都可能变」的信息。
  • 做法:每轮按需拼入,而不是写死在系统提示里。
  • 好处:信息永远最新,且不浪费上下文。

② 记忆层(memory layer)

  • 内容:跨会话积累的经验(上次怎么解决的、用户的长期偏好)。
  • 做法:存到外部(如 MEMORY.md 或向量库),不直接进系统提示,需要时才读取。
  • 好处:Agent 能「记得」历史,但不让历史拖累当前上下文。
信息类型存放位置加载方式
静态知识Skill 目录 / 知识库三层渐进加载
运行时信息每轮计算运行时注入
跨会话经验MEMORY / 向量库按需读取

💡 这三类信息合起来,才是完整的「动态挂载」——知识按目录调、运行时按轮拼、经验按需读。

9. 完整可运行代码:一个动态知识挂载器

下面是一段复制粘贴就能跑的 Python 代码,实现完整的「三层动态挂载」:知识注册表存元数据、路由函数按任务匹配、命中后才加载正文、资源按需读取。运行无需第三方库。

# 动态知识挂载器:元数据常驻 + 正文按需 + 资源懒读
class KnowledgeRegistry:
    def __init__(self):
        self.metadata = []      # 第一层:元数据目录(常驻,极简)
        self.bodies = {}        # 第二层:正文(按需注入)
        self.resources = {}     # 第三层:资源(用到才读)

    def register(self, name, description, body, resources=None):
        """注册一个知识:元数据进目录,正文和资源存起来先不加载"""
        self.metadata.append({"name": name, "description": description})
        self.bodies[name] = body                    # 正文存着,暂不注入
        if resources:
            self.resources[name] = resources        # 资源存着,懒加载

    def route(self, task):
        """路由:按任务关键词匹配元数据,返回候选知识名"""
        hits = []
        for meta in self.metadata:
            # 简化路由:任务词命中 description 即算相关(真实场景用向量检索)
            if any(word in meta["description"] for word in task.split()):
                hits.append(meta["name"])
        return hits

    def load(self, names):
        """按需加载:只把命中知识的正文注入上下文"""
        context = []
        for name in names:
            if name in self.bodies:
                context.append(f"【{name}】{self.bodies[name]}")  # 注入正文
        return context

    def read_resource(self, name, res_key):
        """资源懒读:真正需要时才读第三层资源"""
        return self.resources.get(name, {}).get(res_key, "资源不存在")

if __name__ == "__main__":
    kb = KnowledgeRegistry()
    # 注册三个知识(元数据常驻,正文先不加载)
    kb.register("pdf-extract", "需要从 PDF 提取文字或表格时使用",
                "步骤:1. 加载 PDF 2. 调用解析 3. 输出结构化文本",
                {"script": "extract.py"})
    kb.register("image-crop", "需要裁剪或缩放图片时使用",
                "步骤:1. 读图 2. 按坐标裁剪 3. 保存")
    kb.register("email-send", "需要给用户发送邮件时使用",
                "步骤:1. 校验地址 2. 组装内容 3. 发送并确认")

    # 常驻的只有元数据目录(3 条,极省 token)
    print("常驻目录:", [m["name"] for m in kb.metadata])

    # 用户任务来了:先路由
    task = "帮我从 PDF 提取表格"
    hits = kb.route(task)
    print("路由命中:", hits)                        # → ['pdf-extract']

    # 只加载命中知识的正文
    ctx = kb.load(hits)
    print("注入上下文:", ctx)

    # 需要脚本时才读第三层资源
    print("资源读取:", kb.read_resource("pdf-extract", "script"))

怎么读这段代码:metadata 是第 4 节的「元数据常驻」——只有 3 条名称+描述,占 token 极少;bodies 存正文但注册时不注入,只有 load() 命中后才拼进上下文,这是第 5 节「正文按需注入」;resources 里的脚本只有 read_resource() 真正调用时才读,是第 6 节「资源懒读」;route() 是第 7 节的「search」简化版(真实场景换成向量检索 + inspect + select)。跑一遍你会看到:常驻 3 条目录,实际只加载了 1 条正文——这就是「看起来懂三件事,实际只加载一件」。

10. 对照表:症状 → 原因 → 解法

症状原因解法
system prompt 几万 token、上下文不够用所有知识全塞进去元数据常驻,正文按需注入
知识越多越容易选错无关知识稀释注意力路由先筛候选,只加载命中的
加一个新 Skill 要改主提示词知识硬编码在 prompt 里知识注册表 + 目录动态扩展
命中率低、经常挂载错元数据 description 没写使用场景描述改成「什么时候用它」
命中不到就硬套一个不相干的路由强行命中search/inspect/select,证据不足就停
跨会话记不住经验没有记忆层经验存外部,按需读取

11. 判断收尾

什么时候该上动态挂载:你的 Agent 拥有较多能力或知识(十几个 Skill、上百篇文档)、或需要持续扩展知识库、或已经遇到上下文吃紧/选错知识的问题——这时三层渐进加载 + 路由是刚需,否则迟早被知识量拖垮。什么时候可以不用:你的 Agent 只有两三个固定能力、知识量很小——这时全塞进 prompt 反而更简单直接,动态挂载是过度设计。判断标准只有一条:知识量是否已经让「全塞」变得不划算——不划算,就上动态挂载;还很轻,就先别加复杂度。

本专栏《AI-Agent 工具》从 Agent 记忆、上下文、工具调用一路讲到知识挂载、架构与评测,每篇配可直接运行的代码,持续更新。想在做 Agent 产品时少踩坑,可在专栏页订阅。

参考资料(综合):