Agent Engineering 101|11|Skills

Skills 把任务知识、约束和可复用流程包装成运行时资源。mini-agent-harness 通过 SKILL.md 发现并注入 system prompt。

Agent Engineering 101|11|Skills

核心结论

配套代码仓库: github.com/llm-101/mini-agent-harness

读完本文,你应该能回答

  • Skill 和普通 prompt 有什么区别?
  • 什么时候应该把经验沉淀为 Skill?
  • Skill 如何影响 Context Builder 和 Agent Loop?
  • Skill、Memory、Tool、Prompt Template 的边界是什么?

本篇在系列中的位置

  • 上一篇:10 Compaction 解决长上下文压力。
  • 本篇:本文说明可复用任务知识如何进入 Harness,而不是每次靠用户重讲。
  • 下一篇:12 Prompt Templates 会讨论用户主动触发的工作流入口。

贯穿例子

本系列会反复使用同一个任务来连接各章:

用户说:“帮我修复这个 repo 里的 failing tests。”

在这个任务里,Skills 可以注入“修 failing tests 的调试顺序、验证要求、不要跳过测试”等任务知识。读者要关注的是:Skill 保存的是可复用流程,不是这一次任务的临时日志。

  • Skill 是可发现、可加载、可注入的任务能力包。在当前教学实现里,一个 Skill 由目录和 SKILL.md 表示,并被格式化为XML block。
  • 把所有任务知识都写进一个巨大 system prompt,会导致上下文臃肿、知识难维护、不同任务的流程互相干扰。
  • mini-agent-harness 中,Skills 被当作运行时资源加载,而不是写死在 core prompt 里。

定义

Skill 是可发现、可加载、可注入的任务能力包。在当前教学实现里,一个 Skill 由目录和 SKILL.md 表示,并被格式化为XML block。

为什么要单独看这一层?

任务知识如果只靠用户每次重讲,会不稳定;如果全部塞进 system prompt,又会臃肿。Skills 让可复用知识按任务类型进入上下文。

Skills as Runtime Resources

边界

这一层的职责可以拆成几个稳定部分:

  • discover:扫描 skillsDir 下的 SKILL.md
  • Frontmatter:解析 name 与 description
  • loadAll:读取完整内容
  • formatSkills:包装为
  • Harness.load:启动时追加到 system prompt
  • Runtime Resource:不是 core feature,而是可组合资源

这一层的边界可以用一个问题检验:如果它的内部实现变化,模型适配、工具执行、状态存储和产品外壳是否都不需要跟着重写?如果答案是否定的,说明这个边界还没有真正收束变化。

代码锚点

本篇主要对应这些模块:

  • src/skills/skill-loader.ts
  • src/core/harness.ts

阅读代码时建议先看类型,再看运行路径。

类型定义告诉你这一层暴露什么 contract;运行路径告诉你这个 contract 在 Agent 执行中何时被消费、何时被写回、何时被产品层看见。

运行流程

Skill Loading Path

一次典型执行可以概括为:

  1. Directory:skillsDir
  2. Discover:parse frontmatter
  3. Load:read SKILL.md
  4. Format:XML blocks
  5. Inject:system prompt suffix
  • Instructions:任务规则
  • References:领域知识
  • Workflows:可复用步骤

这里最容易被忽略的是“中间态”。生产级 Agent 不是只关心最终答案;它还要在运行过程中展示进度、捕获错误、记录 usage、允许取消,并把可恢复状态写回 session。

读者抓手:Skill、Memory、Tool、Prompt Template 的边界

能力 保存什么 何时使用 不该承担什么
Skill 可复用流程和约束 任务类型匹配时注入上下文 不保存临时任务进度
Memory 长期稳定事实 未来会反复有用时 不保存操作步骤和日志
Tool 对外部世界的动作能力 模型需要读取、写入、执行、查询时 不携带大量写作策略
Prompt Template 用户触发的起始结构 重复工作流的入口 不替代 loop 和 runtime

一个简单判断:知识放 Skill,事实放 Memory,动作放 Tool,入口放 Prompt Template。

可迁移伪实现:Skill 注入

下面的伪代码是机制抽象,不对应真实 API 或文件结构。它只用来说明这一层的控制点:

const loader = new SkillLoader(skillsDir);
const skills = await loader.loadAll();
systemPrompt += formatSkillsForSystemPrompt(skills);

这个草图的价值在于说明控制点,而不是提供可复制的库代码。

真正的工程实现还要处理错误、取消、并发、token 预算、日志、权限、序列化和 provider 差异。

工程原则

将这一层从 Agent 系统中拆出来,通常带来四个直接收益。

第一,可替换。

外部系统、模型 provider、工具集合或产品外壳变化时,核心运行时不必整体重写。

第二,可观测。

边界清晰后,事件、trace、usage、错误和状态迁移都有稳定落点。

第三,可恢复。

只要状态写入 session,运行时就可以在进程重启、工具失败或长任务中断后继续推理。

第四,可治理。

权限、脱敏、审批、路径保护和执行策略可以放在稳定 hook 或 runtime boundary 上,而不是只靠 prompt 约束。

和 Agent Harness 的关系

Agent = Model + Harness 这个公式的重点,不是把模型之外的所有东西都称为“工程杂活”。

相反,它提示我们:模型之外存在一套必须被设计的运行时系统。

Skills 就是这套系统中的一个切面。它不替代模型能力,也不替代产品体验;它让模型能力可以被组织成可执行、可观察、可恢复、可治理的任务流程。

小结

Skills 的核心价值,是把一类容易扩散的复杂性收束到明确边界中。

mini-agent-harness 中,这个边界被刻意写得较小,方便阅读和教学。但它对应的问题并不小:只要一个 Agent 要长期运行、调用工具、管理上下文、支持 UI、保存状态并处理失败,这个边界就会出现。

下一步可以继续沿着系列计划,把这些边界组合成完整 Agent Harness:模型边界、工具边界、状态边界、上下文边界、扩展边界和产品外壳边界。

参考资料

  • OpenAI Agents / Responses API 文档:用于理解现代模型调用、工具调用和结构化响应的运行时边界。
  • Anthropic Claude Messages / Tool Use / Agent Skills 文档:用于理解 content blocks、tool_use/tool_result、stop reason、Skills 与长任务上下文管理。
  • Model Context Protocol Specification:用于理解工具、资源和 prompts 的连接层边界。
  • Martin Fowler, “Agent = Model + Harness”:用于理解模型之外的 harness 概念。