Agent Skill 渐进式加载 —— 按需激活工具,告别 Prompt 膨胀
2026-06-23·AI, Agent, Skill, LLM
核心模块:
SkillManager.py(115 行)+ 主循环集成代码
一、问题:工具多了怎么办?
基础 Agent 只有 search_web 和 calculate 两个工具,prompt 很小。但真实场景中,Agent 可能拥有几十上百个工具。
直接把所有工具塞进 system prompt 会有什么后果?
| 问题 | 影响 | | --- | --- | | Token 浪费 | 每次调用附带全部工具定义 | | 注意力稀释 | tool_choice 准确率下降 | | 幻觉工具调用 | LLM 可能调用不该用的工具 | | 维护困难 | 改一个工具要改全局注册表 |
核心矛盾:Agent 需要很多能力,但每次对话只需要其中一小部分。
二、设计思路:工具 → Skill → 按需激活
核心思想:把「选工具」这件事也交给 Agent 自己。LLM 通过 load_skill 和 unload_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 打包三个东西:
- 工具定义(
tools)—— LLM 需要知道"有哪些工具、什么参数" - 工具实现(
tool_map)—— Host 端执行的函数 - 领域知识(
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)
六、设计精要
三个不变原则
- 主循环不变 —— 仍是 ReAct 循环,只是 tools 和 prompt 每轮动态生成
- 工具执行不变 ——
TOOL_MAP[name](**args)没变,map 来源从全局变动态 - LLM 调用不变 —— 参数结构完全一致
"元工具"是高杠杆设计
两个 meta-tool 让 Agent 获得自省能力。可无限扩展:list_skills、search_skills、skill_status。
为什么不用 MCP 动态发现
| | 本方案 | MCP dynamic | | --- | --- | --- | | 延迟 | 0(本地 dict) | 网络往返 | | 上下文控制 | 精确到单个 tool | tools/list 返回全部 | | 领域知识 | 随激活注入 | 需另行处理 |
#AI#Agent#Skill#LLM