前面的随笔讨论了工具、任务恢复和执行边界。接下来还有一个日常问题:Agent需要做的事情越来越多,每种工作的步骤、模板和注意事项,应该放在哪里?
把所有流程塞进一份长提示词,修改和查找都会变得费力。Agent Skills把某一类任务的知识与流程放进独立目录,再按任务需要读取。本文从一个虚构的CSV核查技能出发,介绍目录结构与分层加载,并用小程序观察哪些文件被读取。
资料范围:截至2026-09-30核对的Agent Skills官方开放格式说明;该在线规范未在本文引用页面标注语义版本,本文按核对日期说明适用范围。示例使用Python 3.10及以上标准库,不调用模型服务,也不代表某个Agent产品的完整技能实现。
一、一个技能目录,组织一类可重复的工作
Skill 可以包含操作说明、参考材料、模板及脚本。官方格式要求目录内有SKILL.md,其中使用YAML frontmatter提供name和description,再用Markdown描述任务步骤。name需符合命名约束,并与父目录名称一致。见Agent Skills格式规范。
一个教学目录可以这样组织:
text
csv-review/
├── SKILL.md
├── references/
│ └── columns.md
├── scripts/
│ └── check_csv.py
└── assets/
└── report-template.md
SKILL.md写清楚使用场景、输入、执行步骤和完成条件;columns.md放较长的列规则;脚本负责确定性的核查;模板统一报告格式。目录是组织方式,具体读取和执行能力由Agent宿主提供。

图中的目录卡用于判断相关性,展开的操作册对应完整说明。挑选技能后,详细参考材料仍可以等到对应步骤需要时再读取。
二、分层加载,让当前任务只拿到需要的材料
官方把这类方式称为Progressive Disclosure ,即渐进式披露:先发现技能的name与description;任务匹配后读取SKILL.md;执行时按需读取参考文件或使用脚本。见Agent Skills官方概览。

这张图说明加载顺序,箭头不代表网络调用,也没有表示所有宿主使用同一种内部实现。分层目录减少了把所有材料同时放进当前上下文的需要;实际Token开销与任务效果仍应在具体系统中测量。
对CSV核查来说,初始目录只需让Agent知道"这个技能用于检查CSV列与数据"。决定使用后,再读操作步骤;检查具体列时,再读取columns.md。没有进入报告阶段,就无需把报告模板提前展开。
三、把步骤写得可执行,也写清楚完成条件
markdown
---
name: csv-review
description: 检查CSV文件的列名和数据格式。处理CSV核查任务时使用。
---
# CSV核查
1. 确认用户提供的CSV文件与核查范围。
2. 读取references/columns.md,确认列规则。
3. 使用允许的工具检查文件,记录发现的问题。
4. 根据assets/report-template.md整理核查结果。
完成条件:报告包含文件范围、发现的问题与无法判断的项目。
这里的步骤是给Agent使用的流程材料。技能文件不能自行扩大工具权限;发布、删除或访问额外数据等动作,仍要遵守宿主规则与用户授权。scripts目录中的程序也需要先检查来源和执行范围。
description适合描述"做什么、什么时候使用"。把大量细节放在发现阶段,会削弱分层加载的作用;只写"帮助处理数据",又容易让选择范围过宽。
四、完整示例:观察三个加载阶段
下面的程序用内存中的小目录模拟发现阶段,再读取对应文件。为突出加载顺序,metadata直接写在catalog中,没有实现YAML解析、语义选技或模型执行。临时目录里的内容全部由示例创建。
python
from pathlib import Path
from tempfile import TemporaryDirectory
class DemoLoader:
def __init__(self, root, catalog):
self.root = root.resolve()
self.catalog = catalog
self.active = set()
self.loaded = []
def discover(self):
return sorted(self.catalog)
def activate(self, name):
if name not in self.catalog:
raise ValueError("unknown skill")
text = self.read(name, "SKILL.md")
self.active.add(name)
return text
def resource(self, name, relative):
if name not in self.active:
raise ValueError("activate skill first")
return self.read(name, relative)
def read(self, name, relative):
if name not in self.catalog:
raise ValueError("unknown skill")
base = (self.root / name).resolve()
target = (base / relative).resolve()
if not target.is_relative_to(base):
raise ValueError("outside skill directory")
text = target.read_text(encoding="utf-8")
self.loaded.append(f"{name}/{relative}")
return text
with TemporaryDirectory() as folder:
root = Path(folder)
skill = root / "csv-review"
(skill / "references").mkdir(parents=True)
(skill / "SKILL.md").write_text(
"---\nname: csv-review\n"
"description: 检查CSV列名与数据格式。\n---\n"
"先读取references/columns.md,再核查用户提供的文件。\n",
encoding="utf-8",
)
(skill / "references" / "columns.md").write_text(
"必需列:name、amount。amount应为非负数。\n", encoding="utf-8"
)
catalog = {"csv-review": {"description": "检查CSV列名与数据格式。"}}
loader = DemoLoader(root, catalog)
print("discovered:", loader.discover())
print("loaded before activation:", len(loader.loaded))
loader.activate("csv-review")
print("after activation:", loader.loaded)
rule = loader.resource("csv-review", "references/columns.md")
print("rule:", rule.strip())
print("loaded files:", len(loader.loaded))
try:
loader.resource("csv-review", "../outside.md")
except ValueError:
print("outside path: rejected")
else:
raise AssertionError("outside path must be rejected")
保存为skills_loading_demo.py后运行:
shell
python skills_loading_demo.py
输出:
text
discovered: ['csv-review']
loaded before activation: 0
after activation: ['csv-review/SKILL.md']
rule: 必需列:name、amount。amount应为非负数。
loaded files: 2
outside path: rejected
本例已实际执行。它展示了目录发现与文件读取的区别:发现阶段没有读取操作正文,激活后读取SKILL.md,再按请求读取列规则。最后的检查拒绝指向技能目录之外的路径。
路径检查只覆盖这段教学代码的读取边界,没有实现脚本沙箱、并发文件替换防护或完整宿主权限系统。示例也没有核查真实CSV,更没有把文件读取数量当作模型效果评分。
五、与工具接入和长期记忆如何配合
从应用设计上,可以把三类材料分开组织:工具接口 提供执行能力,Skill 提供某类工作的流程与知识,长期记忆提供历史记录或偏好。这是本文的职责划分建议,并非所有产品都采用相同模块结构。
例如CSV核查技能可以指导Agent使用文件读取工具,也可以要求先确认用户关心的列。它无须把所有工具协议写进正文,更不应把某一次任务的私密输入固化到通用技能里。
维护时可以先记录三项信息:说明适用哪些输入,依赖哪些环境,怎样判断完成。规则改动后,用几类代表性任务核对触发范围、缺失输入处理与输出;同一目录能够跨产品复用,也仍需检查各宿主的工具、脚本和发现方式是否兼容。
六、🧠 思维导图
#mermaid-svg-IFUIxjTp4fClHXJW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IFUIxjTp4fClHXJW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IFUIxjTp4fClHXJW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IFUIxjTp4fClHXJW .error-icon{fill:#552222;}#mermaid-svg-IFUIxjTp4fClHXJW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IFUIxjTp4fClHXJW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IFUIxjTp4fClHXJW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IFUIxjTp4fClHXJW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IFUIxjTp4fClHXJW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IFUIxjTp4fClHXJW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IFUIxjTp4fClHXJW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IFUIxjTp4fClHXJW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IFUIxjTp4fClHXJW .marker.cross{stroke:#333333;}#mermaid-svg-IFUIxjTp4fClHXJW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IFUIxjTp4fClHXJW p{margin:0;}#mermaid-svg-IFUIxjTp4fClHXJW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IFUIxjTp4fClHXJW .cluster-label text{fill:#333;}#mermaid-svg-IFUIxjTp4fClHXJW .cluster-label span{color:#333;}#mermaid-svg-IFUIxjTp4fClHXJW .cluster-label span p{background-color:transparent;}#mermaid-svg-IFUIxjTp4fClHXJW .label text,#mermaid-svg-IFUIxjTp4fClHXJW span{fill:#333;color:#333;}#mermaid-svg-IFUIxjTp4fClHXJW .node rect,#mermaid-svg-IFUIxjTp4fClHXJW .node circle,#mermaid-svg-IFUIxjTp4fClHXJW .node ellipse,#mermaid-svg-IFUIxjTp4fClHXJW .node polygon,#mermaid-svg-IFUIxjTp4fClHXJW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IFUIxjTp4fClHXJW .rough-node .label text,#mermaid-svg-IFUIxjTp4fClHXJW .node .label text,#mermaid-svg-IFUIxjTp4fClHXJW .image-shape .label,#mermaid-svg-IFUIxjTp4fClHXJW .icon-shape .label{text-anchor:middle;}#mermaid-svg-IFUIxjTp4fClHXJW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IFUIxjTp4fClHXJW .rough-node .label,#mermaid-svg-IFUIxjTp4fClHXJW .node .label,#mermaid-svg-IFUIxjTp4fClHXJW .image-shape .label,#mermaid-svg-IFUIxjTp4fClHXJW .icon-shape .label{text-align:center;}#mermaid-svg-IFUIxjTp4fClHXJW .node.clickable{cursor:pointer;}#mermaid-svg-IFUIxjTp4fClHXJW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IFUIxjTp4fClHXJW .arrowheadPath{fill:#333333;}#mermaid-svg-IFUIxjTp4fClHXJW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IFUIxjTp4fClHXJW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IFUIxjTp4fClHXJW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IFUIxjTp4fClHXJW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IFUIxjTp4fClHXJW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IFUIxjTp4fClHXJW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IFUIxjTp4fClHXJW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IFUIxjTp4fClHXJW .cluster text{fill:#333;}#mermaid-svg-IFUIxjTp4fClHXJW .cluster span{color:#333;}#mermaid-svg-IFUIxjTp4fClHXJW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IFUIxjTp4fClHXJW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IFUIxjTp4fClHXJW rect.text{fill:none;stroke-width:0;}#mermaid-svg-IFUIxjTp4fClHXJW .icon-shape,#mermaid-svg-IFUIxjTp4fClHXJW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IFUIxjTp4fClHXJW .icon-shape p,#mermaid-svg-IFUIxjTp4fClHXJW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IFUIxjTp4fClHXJW .icon-shape .label rect,#mermaid-svg-IFUIxjTp4fClHXJW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IFUIxjTp4fClHXJW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IFUIxjTp4fClHXJW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IFUIxjTp4fClHXJW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Agent Skills
目录结构
SKILL.md入口
参考脚本与模板
分层加载
先看名称与描述
激活后读取操作说明
执行边界
资源按需读取
宿主权限继续生效
维护验证
清楚的触发范围
环境与完成条件
七、总结
总结要点
技能目录让某类工作的说明、参考材料与模板集中维护。SKILL.md承担入口职责,较长的细节可以拆进对应资源。
分层加载让发现、激活和执行阶段拿到不同深度的信息。任务需要什么,再读取什么,目录结构也应服务这个顺序。
执行与验证边界仍由具体宿主落实。技能说明需要明确输入、环境和完成条件;资源读取成功之后,还要核对任务产物是否满足要求。
下一篇随笔继续关注Agent的知识接入,结合官方资料讨论检索结果如何保留来源并支持回查。
👉 如果你觉得这篇文章对你有所帮助,欢迎点赞、收藏、分享!😊