Agent 开发入门(五):解决 Prompt 臃肿问题,实现技能按需加载
本文是「从零构建 Coding Agent」系列的第五篇,适合已经掌握基础 Agent 开发,想进一步优化系统架构的开发者。
先问一个问题
当你的 Agent 越来越强大,需要处理的任务越来越多样时,你有没有遇到过这样的困境:
- 做代码审查需要一套审查清单
- 做 Git 操作需要一套提交约定
- 做 MCP 集成需要一套专门步骤
如果你把这些知识全部塞进 system prompt,会发生什么?
语言模型的「知识过载」问题
语言模型(LLM)的上下文窗口是有限的。
当你把所有可能用到的知识都塞进 system prompt,会出现两个严重问题:
- Token 浪费:大部分 token 都浪费在当前用不到的说明上
- 维护困难:prompt 越来越臃肿,主线规则越来越不清楚
这就是技能加载系统要解决的核心问题:把"长期可选知识"从 system prompt 主体里拆出来,改成按需加载。
技能加载的核心设计:两层模型
用一个图来表示技能加载的工作原理:
system prompt
|
+-- Skills available:
- code-review: review checklist
- git-workflow: branch and commit guidance
- mcp-builder: build an MCP server
当模型需要时:
load_skill("code-review")
|
v
tool_result
|
v
<skill name="code-review">
完整审查说明
</skill>
关键点只有两个:
- 轻量目录常驻:技能目录信息常驻 system prompt
- 重内容按需加载:完整技能内容只在需要时加载
几个必须搞懂的概念
Skill(技能)
一份围绕某类任务的可复用说明书,告诉 Agent:
- 什么时候该用它
- 做这类任务时有哪些步骤
- 有哪些注意事项
Discovery(发现)
"发现有哪些 skill 可用"的过程,只需要轻量信息:
- skill 名字
- 一句描述
Loading(加载)
"把某个 skill 的完整正文真正读进来"的过程,这才是昂贵的操作。
最小实现
1. 技能目录结构
skills/
code-review/
SKILL.md
git-workflow/
SKILL.md
mcp-builder/
SKILL.md
2. 技能文档格式
使用 frontmatter 格式存储元数据:
---
name: code-review
description: 代码审查清单
---
# 代码审查指南
## 安全性
- [ ] 检查 SQL 注入
- [ ] 检查 XSS 漏洞
- [ ] 检查敏感信息泄露
## 代码质量
- [ ] 命名规范
- [ ] 代码风格
- [ ] 注释完整度
3. 核心代码实现
@dataclass
class SkillManifest:
name: str
description: str
path: Path
@dataclass
class SkillDocument:
manifest: SkillManifest
body: str
class SkillRegistry:
def __init__(self, skills_dir: Path):
self.skills_dir = skills_dir
self.documents: dict[str, SkillDocument] = {}
self._load_all()
def _load_all(self) -> None:
if not self.skills_dir.exists():
return
for path in sorted(self.skills_dir.rglob("SKILL.md")):
meta, body = self._parse_frontmatter(path.read_text())
name = meta.get("name", path.parent.name)
description = meta.get("description", "No description")
manifest = SkillManifest(name=name, description=description, path=path)
self.documents[name] = SkillDocument(manifest=manifest, body=body.strip())
def describe_available(self) -> str:
if not self.documents:
return "(no skills available)"
lines = []
for name in sorted(self.documents):
manifest = self.documents[name].manifest
lines.append(f"- {manifest.name}: {manifest.description}")
return "\n".join(lines)
def load_full_text(self, name: str) -> str:
document = self.documents.get(name)
if not document:
known = ", ".join(sorted(self.documents)) or "(none)"
return f"Error: Unknown skill '{name}'. Available skills: {known}"
return (
f"<skill name=\"{document.manifest.name}\">\n"
f"{document.body}\n"
"</skill>"
)
4. 系统提示配置
SKILL_REGISTRY = SkillRegistry(SKILLS_DIR)
SYSTEM = f"""You are a coding agent at {WORKDIR}.
Use load_skill when a task needs specialized instructions before you act.
Skills available:
{SKILL_REGISTRY.describe_available()}
"""
5. 加载技能工具
TOOL_HANDLERS = {
"load_skill": lambda **kw: SKILL_REGISTRY.load_full_text(kw["name"]),
# 其他工具...
}
TOOLS = [
# 其他工具...
{
"name": "load_skill",
"description": "Load the full body of a named skill into the current context.",
"input_schema": {
"type": "object",
"properties": {"name": {"type": "string"}},
"required": ["name"],
},
},
]
新手最容易犯的 5 个错
1. 把所有 skill 正文永远塞进 system prompt
# ❌ 错误
SYSTEM = f"""You are a coding agent.
{all_skill_text} # 这会让 prompt 变得非常臃肿
"""
# ✅ 正确
SYSTEM = f"""You are a coding agent.
Skills available:
{SKILL_REGISTRY.describe_available()}
"""
2. skill 目录信息写得太弱
如果只有名字,没有描述,模型就不知道什么时候该加载它。
3. 把 skill 当成"绝对规则"
skill 更像"可选工作手册",不是所有轮次都必须用。
4. 把 skill 和 memory 混成一类
- skill 解决的是"怎么做一类事"
- memory 解决的是"记住长期事实"
5. 一上来就讲太多多源加载细节
先理解"轻量发现,重内容按需加载"的核心思想。
技能、记忆、全局规则的边界
| 概念 | 作用 | 特点 |
|---|---|---|
| Skill | 可选知识包 | 只有在某类任务需要时才加载 |
| Memory | 跨会话记忆 | 系统记住的长期事实或偏好 |
| CLAUDE.md | 全局规则 | 更稳定、更长期的系统规则 |
一个简单判断法:
- 这是某类任务才需要的做法或知识:
skill - 这是需要长期记住的事实或偏好:
memory - 这是更稳定的全局规则:
CLAUDE.md
实际应用案例
案例:代码审查任务
用户输入:"请审查这个 PR,重点关注安全性和代码质量"
智能体执行流程:
- 分析任务:需要代码审查
- 调用工具:
load_skill("code-review") - 加载技能:获得完整的代码审查清单
- 执行审查:按照清单检查代码
- 生成报告:基于审查结果给出反馈
案例:Git 操作任务
用户输入:"帮我创建一个新分支并提交这些更改"
智能体执行流程:
- 分析任务:需要 Git 操作
- 调用工具:
load_skill("git-workflow") - 加载技能:获得 Git 工作流指南
- 执行操作:按照指南创建分支、添加文件、提交更改
- 完成任务:返回操作结果
为什么这很重要
因为 Agent 之所以「专业」,不是因为它天生什么都会。
而是因为它能在正确的时间,找到并使用正确的知识。
就像一个优秀的工程师:不是把所有手册都记在脑子里,而是知道什么时候该查什么手册。
下一章预告
有了技能加载系统,你的 Agent 已经具备了按需获取知识的能力。下一章我们将探讨如何让 Agent 与外部系统更深度集成,构建更加强大的自动化工作流。
一句话总结:技能加载系统的核心,不是"多一个工具",而是"把可选知识从常驻 prompt 里拆出来,改成按需加载"。
如果觉得有帮助,欢迎关注,我会持续更新「从零构建 Coding Agent」系列文章。