摘要 :本文介绍 Agent Skills 的四种形态 ------Inline(内联)、File-based(文件型)、External(外部型)、Meta(元技能),帮助架构师根据场景选择合适形态、实现可复用技能库。案例介绍 :配套 demo 实现一个「技能工厂」智能体,具备四类能力------(1) Inline 形态的快速格式化规则;(2) File-based 形态的博客写作与 SEO 技能;(3) External 形态的社区研究技能(模拟从 awesome-claude-skills 拉取);(4) Meta 形态的技能创造器,根据用户需求生成符合 agentskills.io 规范的 SKILL.md。技术要点 :用 LangGraph 编排条件路由(任务执行 vs 技能创建),统一 skill_loader_ext 支持多种形态的发现与加载,Meta 技能通过 references/skill-spec.md 与 references/example-skill.md 引导 LLM 生成新技能。
关键词:Agent Skills;Inline;File-based;External;Meta;技能工厂;agentskills.io;LangGraph
源代码链接:LangGraph 18. Skill 四种形态 示例源代码
1. 为什么需要区分 Skill 的多种形态?
1.1 现实场景的多样性
想象你正在搭建一个企业级内容智能体。有些能力是稳定的、简短的 ------例如「输出时用 Markdown 标题分级」「避免使用第一人称」。这些规则不需要外部文件,改动的频率低。另一些能力则复杂且需要大量参考资料------例如 SEO 优化涉及 9 类检查项、每类有详细指南;博客写作需要风格手册、禁忌列表、段落模板。若把所有知识塞进一个 Python 字符串,既难维护,也无法版本控制。
进一步,你可能希望复用社区已有技能 ------awesome-claude-skills 等仓库中有上百个现成技能,直接拉取即可使用,无需自己撰写。更有甚者,你希望智能体具备「自我扩展」能力------当用户说「帮我创建一个 Python 安全审查技能」时,智能体能根据 agentskills.io 规范生成新的 SKILL.md,并将其纳入技能库。
💡 理解要点:不同形态的 Skill 适用于不同生命周期、来源和复杂度。统一用「一种写法」会导致要么过度简单(Inline 撑不住复杂技能),要么过度笨重(所有技能都拆成目录和 references,增加维护成本)。
1.2 四种形态的核心定义
参考 Lavi Nigam 的 ADK Skills 系列 与 agentskills.io 规范,可将 Skill 归纳为四种形态:
| 形态 | 定义 | 来源 | 典型场景 |
|---|---|---|---|
| Inline | Python 内联定义,{name, description, instructions} 字典 |
代码 | 稳定、无需外部文件的简单规则 |
| File-based | SKILL.md + references/,符合 agentskills.io 目录结构 | 本地目录 | 需要 L3 资源的复杂技能,可版本控制 |
| External | 与 File-based 结构相同,来源为社区仓库或外部路径 | 克隆/下载目录 | 复用他人已写好的技能 |
| Meta | 技能的输出是新的 SKILL.md,使智能体能「写出新技能」 | 技能 + 规范资源 | 按需创建新能力,自我扩展 |
🔍 实际例子:Inline 适合「用项目符号输出清单」;File-based 适合 blog-writer(含 references/style-guide.md);External 适合从 awesome-claude-skills 克隆的 content-research-writer;Meta 则是一个 skill-creator,其 instructions 描述「如何撰写 SKILL.md」,resources 嵌入规范与示例,LLM 据此生成新技能文件。
1.3 与 17. Progressive Disclosure 的关系
17. Progressive Disclosure 介绍了 L1/L2/L3 分层加载与 load_skill_resource 按需调用。四种形态是技能来源与定义方式的分类,与 Progressive Disclosure 正交:无论 Inline 还是 File-based,都可以按 L1→L2→L3 的方式加载;External 与 File-based 在加载逻辑上完全一致,仅根路径不同;Meta 是特殊形态,其「执行」结果是生成新的 SKILL.md 文件。
2. 示例设定:「技能工厂」智能体
2.1 案例背景
我们构建一个技能工厂智能体,具备以下能力:
- Inline 形态 :
format-output------输出格式规则(用 Markdown、项目符号、避免冗长句子); - File-based 形态 :
blog-writer、seo-checklist,来自skills_library/; - External 形态 :
content-research,模拟从社区拉取,存放在external_skills/; - Meta 形态 :
skill-creator------根据用户需求生成新的 SKILL.md,写入skills_library/并可供后续使用。
用户可能提出两类请求:
- 任务执行:「写一篇关于 LangGraph 的博客开头并做 SEO 优化」→ 使用 blog-writer + seo-checklist + format-output;
- 技能创建:「帮我创建一个 Python 代码安全审查技能」→ 调用 skill-creator,生成 SKILL.md 并加载。
2.2 方案设计
配套 demo 实现基于 LangGraph 的技能工厂:
START
↓
[意图路由] user_task
↓
┌────────────┴────────────┐
↓ ↓
"创建技能" / "生成技能" 其他任务
↓ ↓
meta_skill_node discover_node (Inline + File + External)
↓ ↓
生成 SKILL.md select_node → load_l2_node → execute_node
↓ ↓
写入 skills_library END
↓
END
- 意图路由:LLM 判断用户是否在请求「创建/生成新技能」,若是则进入 meta 分支,否则进入任务执行分支。
- discover_node:从 Inline、File-based、External 三处汇总 L1 元数据,统一呈现给 select。
- skill_loader_ext :扩展
skill_loader,支持 (1) Inline 字典直接返回 (2) 指定根路径加载 File-based / External。
2.3 典型流程示例
场景 A:用户输入「请写一段关于 LangGraph 的博客开头,并检查 SEO」。
- 意图路由 → 任务执行;
- Discover 汇总 format-output、blog-writer、seo-checklist、content-research 的 L1;
- Select 选出 blog-writer、seo-checklist、format-output;
- Load L2,Execute 时按需调用 load_skill_resource 加载 L3;
- 输出格式遵循 format-output,内容遵循 blog-writer 与 seo-checklist。
场景 B:用户输入「帮我创建一个用于检查 Python 代码安全的技能」。
- 意图路由 → 技能创建;
- 加载 skill-creator 的 L2 + references(skill-spec.md、example-skill.md);
- LLM 根据规范与示例生成 python-security-review SKILL.md;
- 写入
skills_library/python-security-review/SKILL.md; - 可立即通过 discover 发现并用于后续任务。
3. 状态与图结构:LangGraph 编排
3.1 状态定义
python
class SkillFactoryState(TypedDict):
user_task: str
intent: str # "create_skill" | "execute_task"
l1_skills: list
selected_skill_names: list
l2_content: dict
l3_content: dict
created_skill_name: str # meta 分支:新技能名
created_skill_path: str # meta 分支:写入路径
final_response: str
verbose: NotRequired[bool]
3.2 图结构
text
START
↓
route_node # LLM 判断 intent: create_skill | execute_task
↓
条件边 ─┬─ create_skill → meta_skill_node → END
└─ execute_task → discover_node → select_node → load_l2_node → execute_node → END
流程中,state["verbose"]=True 时,各节点通过 _log(state, msg, node) 输出日志到 terminal / notebook,便于调试与观察。
3.3 核心节点逻辑与代码详解
下文逐一说明每个节点的职责、调用链路、verbose 日志及关键代码。
3.3.1 route_node:意图路由
职责 :根据 user_task 判断用户意图------是「创建/生成新技能」还是「使用现有技能执行任务」。LLM 根据 ROUTE_PROMPT 返回 create_skill 或 execute_task,写入 state["intent"]。未配置 API 或任务为空时,默认 execute_task。这里,我们是通过LLM嵌入到Langgraph node来实现意图识别。
调用链路 :route_node → ChatPromptTemplate.from_template(ROUTE_PROMPT) → _llm.invoke → 解析响应 → 更新 intent。
verbose 日志:用户输入摘要、未配置 API 时的默认行为、最终意图。
route_node 实现 (skill_factory_graph.py):
python
def route_node(state: SkillFactoryState) -> SkillFactoryState:
"""意图路由:判断 create_skill 或 execute_task。"""
user_task = state.get("user_task") or ""
_log(state, f"用户输入: {user_task[:80]}{'...' if len(user_task) > 80 else ''}", "route")
if not _config.api_key or not user_task.strip():
_log(state, "未配置 API 或任务为空,默认 execute_task", "route")
return {**state, "intent": "execute_task"}
prompt = ChatPromptTemplate.from_template(ROUTE_PROMPT)
chain = prompt | _llm
response = chain.invoke({"user_task": user_task})
content = (response.content if hasattr(response, "content") else str(response)).strip().lower()
intent = "create_skill" if "create_skill" in content else "execute_task"
_log(state, f"意图: {intent}", "route")
return {**state, "intent": intent}
ROUTE_PROMPT (prompt.py):引导 LLM 仅返回 create_skill 或 execute_task,用于条件边分支。
py
ROUTE_PROMPT = """你是一个技能工厂助手。用户可能提出两类请求:
1. **创建/生成新技能**:如「帮我创建一个 XXX 技能」「生成一个 YYY 技能」
2. **执行任务**:使用现有技能完成某任务,如写博客、检查 SEO、做研究等
用户输入:
{user_task}
请判断用户意图。仅返回以下之一(不要解释):
- create_skill:用户明确要求创建/生成/编写一个新的技能
- execute_task:用户在使用现有技能执行任务,或意图不明确时"""
3.3.2 meta_skill_node:Meta 技能执行
如果上面的 route_node 根据用户的输入判断 create_skill,即,创建新的skill支线,这个时候系统会调用 skill_meta.run_meta_skill,根据用户需求生成符合 agentskills.io 的 SKILL.md,写入 skills_library/{name}/SKILL.md。成功时更新 created_skill_name、created_skill_path、final_response;失败时 final_response 为错误信息。
调用链路 :meta_skill_node → run_meta_skill(user_task, ...) → 内部加载 skill-creator 的 references、调用 LLM 生成、解析 frontmatter、写入文件。
verbose 日志:执行开始、run_meta_skill 内部的「加载 references」「调用 LLM」「已写入路径」、最终结果。
meta_skill_node 实现:
python
def meta_skill_node(state: SkillFactoryState) -> SkillFactoryState:
"""Meta 技能:生成新 SKILL.md 并写入 skills_library。"""
user_task = state.get("user_task") or ""
_log(state, "执行 Meta 技能:生成新 SKILL.md...", "meta_skill")
name, path = run_meta_skill(
user_task, DEFAULT_SKILLS_LIBRARY, _config, verbose=bool(state.get("verbose"))
)
if name:
final = f"已创建技能「{name}」,路径:{path}。可通过 discover 发现并用于后续任务。"
_log(state, final, "meta_skill")
return {
**state,
"created_skill_name": name,
"created_skill_path": path,
"final_response": final,
}
else:
final = path or "[Meta 技能执行失败]"
return {
**state,
"created_skill_name": "",
"created_skill_path": "",
"final_response": final,
}
py
def run_meta_skill(
user_demand: str,
skills_library: Optional[Path] = None,
config: Optional[SkillFactoryConfig] = None,
verbose: bool = False,
) -> Tuple[str, str]:
"""
执行 Meta 技能:根据用户需求生成 SKILL.md 并写入 skills_library。
Returns:
(created_skill_name, output_path)
若失败则 created_skill_name 为空,output_path 为错误信息。
"""
config = config or SkillFactoryConfig()
skills_library = Path(skills_library) if skills_library else DEFAULT_SKILLS_LIBRARY
if not config.api_key:
return "", "[未配置 OPENAI_API_KEY 或 DASHSCOPE_API_KEY]"
if verbose:
print(" [meta_skill] 加载 skill-creator 的 references...")
skill_spec, example_skill, creator_instructions = _load_meta_references()
if verbose:
print(" [meta_skill] 调用 LLM 生成 SKILL.md...")
prompt = ChatPromptTemplate.from_template(META_SYSTEM_PROMPT)
llm = ChatOpenAI(
model=config.model,
api_key=config.api_key,
base_url=config.base_url if config.base_url else None,
temperature=0.3,
)
chain = prompt | llm
try:
response = chain.invoke({
"skill_spec": skill_spec,
"example_skill": example_skill,
"creator_instructions": creator_instructions,
"user_demand": user_demand,
})
content = (response.content if hasattr(response, "content") else str(response)).strip()
except Exception as e:
return "", f"[LLM 调用失败: {type(e).__name__}] {e}"
if not content:
return "", "[生成内容为空]"
# 确保以 --- 开头(可能 LLM 多输出了解释)
if "---" in content:
idx = content.index("---")
content = content[idx:]
else:
content = "---\nname: generated-skill\ndescription: 自动生成的技能。\n---\n\n" + content
name = _extract_skill_name_from_output(content)
if not name:
name = "generated-skill"
safe_name = _sanitize_skill_name(name)
output_dir = skills_library / safe_name
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "SKILL.md"
try:
output_path.write_text(content, encoding="utf-8")
if verbose:
print(f" [meta_skill] 已写入: {output_path}")
return safe_name, str(output_path)
except OSError as e:
return "", f"[写入失败] {e}"
对应的 prompt(META_SYSTEM_PROMPT) 是:
py
META_SYSTEM_PROMPT = """你是一个技能撰写专家,根据用户需求生成符合 agentskills.io 规范的 SKILL.md。
## 规范摘要
{skill_spec}
## 参考示例
{example_skill}
## 技能创建指令(skill-creator)
{creator_instructions}
## 用户需求
{user_demand}
请直接输出**完整的 SKILL.md 内容**,从 `---` 开始,到正文结束。不要输出任何解释或前后缀。"""
3.3.3 discover_node:多形态 L1 发现
如果上面的 route_node 根据用户的输入判断 execute_task,即,创建根据用户的输入匹配skills然后回复。
从 Inline(skill_inline.get_inline_skill_l1)、File-based(skills_library/)、External(external_skills/)三处汇总 L1 元数据,去重时 Inline > File > External 优先;计算 L1 token 写入 token_usage["l1"]。
调用链路 :discover_node → get_inline_skill_l1() → discover_all_skills() → count_tokens(l1_text)。
verbose 日志:汇总开始、发现的技能列表(含形态来源)、L1 token。
discover_node 实现:
python
def discover_node(state: SkillFactoryState) -> SkillFactoryState:
"""发现 Inline + File-based + External 的 L1。"""
_log(state, "汇总 Inline、File-based、External 技能...", "discover")
inline_l1 = get_inline_skill_l1()
all_skills = discover_all_skills(
inline_l1,
file_root=DEFAULT_SKILLS_LIBRARY,
external_root=DEFAULT_EXTERNAL_SKILLS,
)
l1_text = "\n".join(
f"{s.get('name', '')}: {s.get('description', '')}" for s in all_skills
)
usage = state.get("token_usage") or {}
usage["l1"] = count_tokens(l1_text)
_log(state, f"发现 {len(all_skills)} 个技能: {[s.get('name') for s in all_skills]}", "discover")
_log(state, f"L1 token: {usage['l1']}", "discover")
return {**state, "l1_skills": all_skills, "token_usage": usage}
def discover_all_skills(
inline_l1: List[Dict[str, str]],
file_root: Optional[Path] = None,
external_root: Optional[Path] = None,
) -> List[Dict[str, str]]:
"""
汇总 Inline、File-based、External 的 L1 元数据。
去重:若 name 重复,以 Inline > File > External 优先保留。
"""
file_root = Path(file_root) if file_root else DEFAULT_SKILLS_LIBRARY
external_root = Path(external_root) if external_root else DEFAULT_EXTERNAL_SKILLS
seen: set[str] = set()
result: List[Dict[str, str]] = []
for meta in inline_l1:
name = meta.get("name", "")
if name and name not in seen:
seen.add(name)
m = dict(meta)
m["_source"] = "inline"
result.append(m)
for meta in _discover_from_dir(file_root, "file"):
name = meta.get("name", "")
if name and name not in seen:
seen.add(name)
result.append(meta)
for meta in _discover_from_dir(external_root, "external"):
name = meta.get("name", "")
if name and name not in seen:
seen.add(name)
result.append(meta)
return result
3.3.4 select_node:技能选择(LLM 语义匹配)
职责 :根据 user_task 从 l1_skills 中选出 1~3 个相关技能名。使用 LLM 语义匹配,解析逗号分隔的响应并校验名称是否在 l1_skills 中。无技能或未配置 API 时返回空列表。
调用链路 :select_node → ChatPromptTemplate.from_template(SELECT_SKILL_PROMPT) → _llm.invoke → 解析并过滤 → selected_skill_names。
verbose 日志:用户任务摘要、无技能/未配置 API 的跳过、LLM 调用、选中技能列表。
select_node 实现:
python
def select_node(state: SkillFactoryState) -> SkillFactoryState:
"""根据 user_task 选出相关技能。"""
skills = state.get("l1_skills") or []
user_task = state.get("user_task") or ""
_log(state, f"用户任务: {user_task[:60]}{'...' if len(user_task) > 60 else ''}", "select")
if not skills:
_log(state, "无可用技能,跳过选择", "select")
return {**state, "selected_skill_names": []}
if not _config.api_key or not user_task.strip():
_log(state, "未配置 API 或任务为空,跳过 LLM 选择", "select")
return {**state, "selected_skill_names": []}
_log(state, "调用 LLM 进行技能语义匹配...", "select")
prompt = ChatPromptTemplate.from_template(SELECT_SKILL_PROMPT)
chain = prompt | _llm
response = chain.invoke({"skills_list": _format_skills_list(skills), "user_task": user_task})
content = (response.content if hasattr(response, "content") else str(response)).strip()
selected = []
for part in content.replace(",", ",").split(","):
name = part.strip().lower().replace(" ", "-")
if any(s.get("name") == name for s in skills):
selected.append(name)
_log(state, f"选中技能: {selected}", "select")
return {**state, "selected_skill_names": selected}
3.3.5 load_l2_node:统一加载 L2
职责 :对 selected_skill_names 中每个技能,调用 load_skill_unified 按 Inline → File → External 顺序加载 L2 正文;累计 L2 token 写入 token_usage["l2"]。
调用链路 :load_l2_node → load_skill_unified(name, get_inline_skill_l2, ...) → skill_loader_ext 内部按形态查找。
verbose 日志:加载的技能列表、每个技能的 token 数、L2 总计。
load_l2_node 实现:
python
def load_l2_node(state: SkillFactoryState) -> SkillFactoryState:
"""加载选中技能的 L2(支持 Inline / File / External)。"""
selected = state.get("selected_skill_names") or []
_log(state, f"加载 L2: {selected}", "load_l2")
l2_content = {}
usage = dict(state.get("token_usage") or {})
for name in selected:
body, _ = load_skill_unified(
name, get_inline_skill_l2,
file_root=DEFAULT_SKILLS_LIBRARY,
external_root=DEFAULT_EXTERNAL_SKILLS,
)
if body:
l2_content[name] = body
_log(state, f" {name}: {count_tokens(body)} tokens", "load_l2")
total_l2 = sum(count_tokens(b) for b in l2_content.values())
usage["l2"] = total_l2
_log(state, f"L2 总计: {total_l2} tokens", "load_l2")
return {**state, "l2_content": l2_content, "token_usage": usage}
3.3.6 execute_node:Agent 工具循环与 final_response
职责 :将 L2 作为 system 上下文,将 load_skill_resource 暴露为 Agent 工具;运行工具循环(LLM 调用 → 若有 tool_calls 则执行 → 追加 ToolMessage → 再次调用),直至无 tool_calls;从工具调用结果统计 L3 token,填充 l3_content 与 final_response。
调用链路 :execute_node → llm.bind_tools([load_skill_resource_tool]) → invoke(messages) 循环 → 工具调用 → count_tokens 统计 L3。
verbose 日志:执行任务与技能列表、每次 LLM 迭代、工具调用(名称与参数)、L3 加载与 token、工具失败、L3 总计与最终回复长度。
execute_node 实现(节选):
python
def execute_node(state: SkillFactoryState) -> SkillFactoryState:
"""执行:L2 + load_skill_resource 工具循环。"""
l2 = state.get("l2_content") or {}
user_task = state.get("user_task") or ""
_log(state, f"执行任务,技能: {list(l2.keys())}", "execute")
# ... 构建 system_content, messages ...
llm_with_tools = _llm.bind_tools(_TOOLS)
l3_content, total_l3 = {}, 0
while iterations < max_iterations:
_log(state, f"LLM 调用 (迭代 {iterations})...", "execute")
response = llm_with_tools.invoke(messages)
if not getattr(response, "tool_calls", None):
_log(state, "LLM 返回最终回复(无工具调用)", "execute")
break
_log(state, f"LLM 请求 {len(response.tool_calls)} 次工具调用", "execute")
for tc in response.tool_calls:
_log(state, f" [Tool] {name}({args})", "execute")
# ... 执行工具 ...
_log(state, f" -> L3 加载 {key}, {tokens} tokens", "execute")
# ...
_log(state, f"L3 总计: {total_l3} tokens, 最终回复: {len(final)} 字符", "execute")
return {**state, "l3_content": l3_content, "token_usage": usage, "final_response": final}
3.3.7 辅助模块
skill_inline.py :INLINE_SKILLS 列表(format-output、concise-response),get_inline_skill_l1()、get_inline_skill_l2(name)、has_inline_skill(name)。
skill_loader_ext.py :discover_all_skills、load_skill_unified、load_skill_resource,支持 Inline / File / External 三形态。
skill_meta.py :run_meta_skill(user_demand, skills_library, config, verbose),加载 skill-creator 的 references、调用 LLM 生成、写入 SKILL.md。
💡 理解要点 :六个图节点(route、meta_skill、discover、select、load_l2、execute)均通过 _log(state, msg, node) 在 verbose=True 时输出日志;main.py -v 与 main.ipynb 中 VERBOSE=True 可观测完整运行流程与工具调用。
4. 运行方式
4.1 环境与依赖
- Python 3.9+
langgraph、langchain-openai、langchain-core、python-dotenv、tiktoken
4.2 配置
在 demo_codes/ 下创建 .env:
OPENAI_API_KEY=sk-...
BASE_URL= # 可选
MODEL=gpt-4o-mini
4.3 运行
shell
cd demo_codes
python main.py
python main.py "写一段关于 LangGraph 的博客开头"
python main.py "帮我创建一个 Python 代码安全审查技能"
python main.py -v "..." # verbose=1 时输出各节点与工具调用日志
Notebook :打开 main.ipynb,设置 VERBOSE = True 可输出各节点与工具调用的详细日志;依次运行:图展示 → 任务执行示例 → 技能创建示例 → 形态对比。
verbose 日志示例 (python main.py -v "写一段关于 LangGraph 的博客开头"):
--- 运行日志 (verbose=1) ---
[route] 用户输入: 写一段关于 LangGraph 的博客开头...
[route] 意图: execute_task
[discover] 汇总 Inline、File-based、External 技能...
[discover] 发现 5 个技能: ['format-output', 'concise-response', 'blog-writer', 'seo-checklist', 'content-research']
[discover] L1 token: 328
[select] 用户任务: 写一段关于 LangGraph 的博客开头...
[select] 调用 LLM 进行技能语义匹配...
[select] 选中技能: ['format-output', 'blog-writer', 'seo-checklist']
[load_l2] 加载 L2: ['format-output', 'blog-writer', 'seo-checklist']
[load_l2] format-output: 89 tokens
[load_l2] blog-writer: 499 tokens
[load_l2] seo-checklist: 499 tokens
[load_l2] L2 总计: 1087 tokens
[execute] 执行任务,技能: ['format-output', 'blog-writer', 'seo-checklist']
[execute] LLM 调用 (迭代 1)...
[execute] LLM 请求 2 次工具调用
[execute] [Tool] load_skill_resource_tool({'skill_name': 'blog-writer', 'resource_path': 'references/style-guide.md'})
[execute] -> L3 加载 blog-writer:references/style-guide.md, 285 tokens
[execute] [Tool] load_skill_resource_tool({'skill_name': 'seo-checklist', 'resource_path': 'references/seo-guidelines.md'})
[execute] -> L3 加载 seo-checklist:references/seo-guidelines.md, 280 tokens
[execute] LLM 调用 (迭代 2)...
[execute] LLM 返回最终回复(无工具调用)
[execute] L3 总计: 565 tokens, 最终回复: 2847 字符
4.4 目录结构
18_skills_3/
├── 18_skills_3.md
└── demo_codes/
├── skill_inline.py # Inline 形态定义
├── skill_loader_ext.py # 多形态统一加载
├── skill_meta.py # Meta 技能运行器
├── skill_factory_graph.py # LangGraph 图
├── skills_library/ # File-based 技能
│ ├── blog-writer/
│ ├── seo-checklist/
│ └── ...
├── external_skills/ # External 技能(模拟社区)
│ └── content-research/
├── skill_creator/ # Meta 技能
│ ├── SKILL.md
│ └── references/
│ ├── skill-spec.md
│ └── example-skill.md
├── main.py, main.ipynb
├── README.md
└── requirements.txt
5. 小结与延伸
5.1 核心结论
- 四种形态各有适用场景:Inline 快速稳定,File-based 可版本控制,External 复用社区,Meta 实现自我扩展;
- skill_loader_ext 统一发现与加载逻辑,使 Agent 无需关心技能来自代码、本地还是外部;
- LangGraph 条件路由清晰表达「任务执行」与「技能创建」两条主流程。
5.2 延伸方向
- External 实际拉取 :集成
git clone或npx skills add,从真实社区仓库拉取技能; - Meta 校验增强 :使用
skills-ref validate校验生成的 SKILL.md; - 与 "Langgraph 17. Skills 三级加载与 Token 优化" 整合:在 execute 分支中暴露 load_skill_resource 工具,L3 按需加载。
5.3 注意事项
- 使用 External 技能前务必审阅 SKILL.md 与 references,技能指令会直接影响 Agent 行为;
- Meta 生成的技能建议先人工复核再投入生产。
参考资料:
- LangGraph 7. 技能 Skills --- 本系列前文,介绍 Skills 的动机、发现→选择→加载→使用流程及 Agent Skills 规范
- Langgraph 17. Skills 三级加载与 Token 优化(含代码示例) --- L1/L2/L3 分层与 load_skill_resource
- Agent Skills Specification (agentskills.io)
- ADK SkillToolset: File-Based & External Skills (Lavi Nigam, Part 2)
- ADK Meta Skills (Lavi Nigam, Part 3)