Reborn 的技术博客

Agent Skill 渐进式加载 —— 按需激活工具,告别 Prompt 膨胀

2026-06-23·AI, Agent, Skill, LLM

核心模块:SkillManager.py(115 行)+ 主循环集成代码

一、问题:工具多了怎么办?

基础 Agent 只有 search_webcalculate 两个工具,prompt 很小。但真实场景中,Agent 可能拥有几十上百个工具。

直接把所有工具塞进 system prompt 会有什么后果?

| 问题 | 影响 | | --- | --- | | Token 浪费 | 每次调用附带全部工具定义 | | 注意力稀释 | tool_choice 准确率下降 | | 幻觉工具调用 | LLM 可能调用不该用的工具 | | 维护困难 | 改一个工具要改全局注册表 |

核心矛盾:Agent 需要很多能力,但每次对话只需要其中一小部分。

二、设计思路:工具 → Skill → 按需激活

核心思想:把「选工具」这件事也交给 Agent 自己。LLM 通过 load_skillunload_skill 两个元工具,自主决定什么时候加载 / 卸载哪些技能模块。

三、数据结构:Skill

@dataclass
class Skill:
    """一个 Skill = 一组工具 + 一段领域知识"""
    name: str                         # 唯一标识,如 "calculator"
    description: str                  # 给 LLM 看的简介
    tools: list[dict]                 # OpenAI tool 定义列表
    tool_map: dict[str, Callable]     # 工具名 → 实际函数
    system_prompt: str = ""           # 激活时追加到 system prompt

一个 Skill 打包三个东西:

  1. 工具定义tools)—— LLM 需要知道"有哪些工具、什么参数"
  2. 工具实现tool_map)—— Host 端执行的函数
  3. 领域知识system_prompt)—— 这个技能该怎么用

四、元工具:让 Agent 自己管理工具

META_TOOLS = [
    {"type": "function", "function": {
        "name": "load_skill",
        "description": "加载一个技能模块。可用技能: {available_skills}",
        "parameters": {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]},
    }},
    {"type": "function", "function": {
        "name": "unload_skill",
        "description": "卸载一个技能模块。当前已加载: {loaded_skills}",
        "parameters": {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]},
    }},
]

{available_skills}{loaded_skills}每次查询时动态填充的占位符。

五、主循环集成

for step in range(max_steps):
    active_tools = skills.get_active_tools()
    active_tool_map = skills.get_active_tool_map()
    system_prompt = build_system_prompt(base_system_prompt, skills)
    messages[0]["content"] = system_prompt

    response = client.chat.completions.create(
        model="your-model-name",
        messages=messages,
        tools=active_tools,      # 按需的,不是全部
        tool_choice="auto",
    )

完整交互流程

用户: "北京天气怎么样?顺便算 156*23"

Round 1:  tools = [load_skill, unload_skill]
          LLM → load_skill("search")

Round 2:  tools = [+ search_web]
          LLM → search_web("北京天气")

Round 3:  LLM → load_skill("calculator")

Round 4:  tools = [+ calculate]
          LLM → calculate("156*23")

Round 5:  LLM → 最终回答

会话恢复时自动恢复 Skill 状态

if session_id:
    state = pm.load_session(session_id)
    for name in state.get("active_skills", []):
        skills.load(name)

六、设计精要

三个不变原则

  1. 主循环不变 —— 仍是 ReAct 循环,只是 tools 和 prompt 每轮动态生成
  2. 工具执行不变 —— TOOL_MAP[name](**args) 没变,map 来源从全局变动态
  3. LLM 调用不变 —— 参数结构完全一致

"元工具"是高杠杆设计

两个 meta-tool 让 Agent 获得自省能力。可无限扩展:list_skillssearch_skillsskill_status

为什么不用 MCP 动态发现

| | 本方案 | MCP dynamic | | --- | --- | --- | | 延迟 | 0(本地 dict) | 网络往返 | | 上下文控制 | 精确到单个 tool | tools/list 返回全部 | | 领域知识 | 随激活注入 | 需另行处理 |

#AI#Agent#Skill#LLM