给 Agent 加能力,最常见的坑是"一个插件需求里混着五种职责":提醒检查清单、读取团队规范、执行发布命令、拦截危险参数、一键安装——如果全塞进一个高权限插件,改一句提示词也要重发代码;全写进 Markdown,真正危险的命令又只能依赖模型"记得不要做"。Pi v0.82.1 把这些职责拆成 Prompt Template、Skill、Tool、Extension 与 Package 五层。选型主线只有一句:用能够形成确定性闭环的最低权限层实现能力;只有缺少执行、生命周期或分发边界时才向上升级。

五种职责拆解

Agent 扩展改变的不是同一个对象:

形态 改变什么
Prompt Template 用户提交的任务文本
Skill 模型按需读取的知识、步骤和配套资源
Tool 具有 Schema、执行器和结果的结构化动作
Extension Runtime 的事件、策略、上下文或界面
Package 安装、锁定、过滤和分发上述资源

这不是功能强弱排行:Package 本身不会凭空增加运行机制;Skill 目录可带脚本,但脚本是否执行仍取决于模型和可用 Tool;Extension 注册的 Tool 则由 Runtime 直接承载。选型前先问五个问题:谁触发?需要什么权限?必须在哪个生命周期生效?正文是否应常驻上下文?能力要不要跨项目安装和更新?

四类机制的边界

Prompt Template:把重复意图做成显式入口

定义是 Markdown 片段,用户输入 /name 后文件内容经参数替换展开成普通 Prompt,再进入 Agent Loop。支持位置参数、默认值、切片以及 description、argument-hint 等元数据。适合"用户明确知道现在要做什么"的任务:审查暂存区、生成变更日志、按固定格式调查故障。

与把所有流程塞进 AGENTS 相比,Template 只在触发时占用上下文,来源容易审查。但它没有强制力:不能在 Tool 执行前检查真实参数,不能监听 Session,也不能保证模型逐项完成检查。若要求是"任何写入生产环境的命令都必须被拦截",继续润色 Prompt 不会获得 Runtime 保证。

Skill:把专业工作流做成渐进披露资源

Skill 是包含 SKILL.md 的目录,可带 scripts、references 与 assets。加载过程:启动时扫描名称与描述,把能力索引放进 System Prompt;任务匹配后模型再读取完整 SKILL.md——几十个低频流程不必全部常驻 Context。适合数据库迁移、PDF 处理、部署诊断等需要详细步骤和资料的工作。

两个容易被忽略的边界:

  • 官方文档明确提醒,模型不一定总会自动读取匹配 Skill;“被发现"不是"被执行”。
  • Skill 可以指示模型运行随附脚本,因此"不是 TypeScript 插件"不等于没有供应链风险。

Skill 的验收至少分四层:发现、正文读取、脚本调用、结果验证——不能只看到它出现在能力列表里就宣称流程已生效。

Tool:当动作需要结构化参数与可控执行

Tool 经常被误认为独立的安装形态——在 Pi 中自定义 Tool 通常由 Extension 通过 registerTool() 注册,但概念上应单独讨论,因为它承担的是动作合同。一个 Tool 至少定义名称、描述、参数 Schema 与执行器,还可处理取消信号、增量更新、结果渲染和 Prompt Guidelines。

它比"让模型拼一条 Shell 命令"多出三种确定性:参数可校验、执行生命周期可观察、结果可结构化返回。如果能力只是"按照这份步骤做代码审查",Skill 足够;如果能力是"用 project、env、revision 三个字段调用部署系统并返回 deployment_id",就应提供 Tool。反过来,不能因为 Tool 更像工程代码就把所有知识压进 Tool 描述——那会重新制造上下文膨胀。

Extension:只有 Runtime 必须介入时才升级

Extension 是 Pi 进程内执行的 TypeScript 模块,可注册 Tool、Command、快捷键、Flag 与 Provider,处理 before_agent_start、context、tool_call、Session 和消息等事件。它能完成 Markdown 无法保证的事情:

  • 在危险 Tool 真正执行前阻断或修改参数;
  • 每次模型调用前裁剪或注入 Context;
  • 对 Session 切换、Fork、Compaction 做决策;
  • 把审计状态显示在 UI,而不塞进模型上下文;
  • 把企业系统封装为结构化 Tool 或 Provider。

代价同样直接:Extension 能改变模型看到的内容,也能在宿主进程中执行代码(Package 中的 Extension 具有完整系统访问能力)。因此"写成 Extension 更可靠"只对确定性成立,不对安全性成立——它必须接受源码审计、权限隔离、事件回归和依赖治理。

Package:解决分发,不替代内部资源的边界

Package 可以从 npm、Git 或本地路径安装,通过 package.json 的 pi 字段或约定目录声明 Extensions、Skills、Prompt Templates 与 Themes;版本或 Git Ref 可固定,Settings 还可过滤实际加载的资源。它解决的是交付问题:来源、版本、依赖、安装位置、启用范围与更新。

Package 不会把 Extension 降权,也不会把 Skill 变成确定执行。过滤某个 Extension 只能减少加载面,不能为已加载代码创建 Sandbox;固定版本只能保证内容一致,不能证明内容可信。团队包可以同时包含发布 Template、操作 Skill、审计 Tool 和拦截 Extension,审核时仍要逐类判断,不能因为它们来自同一个 Package 就共享一条"已安装通过"。

五维选型矩阵

需求 首选 触发主体 需要的确定性 主要风险
重复的审查或发布指令 Prompt Template 用户 低,允许模型解释 提示注入、步骤遗漏
按需专业流程与资料 Skill 模型或用户 中,需单独验执行 恶意指令、脚本供应链
稳定调用业务动作 Tool 模型 高,参数和结果结构化 执行权限、接口副作用
拦截命令或监听生命周期 Extension Runtime 高,必须强制 任意代码、上下文篡改
跨团队安装上述资源 Package 管理员/项目设置 分发确定性 依赖、更新与来源风险

实际决策从最低层向上走:

只是复用任务措辞?                 → Template
需要按需知识和配套文件?           → Skill
需要结构化参数、取消和结果?       → Tool
需要在模型之外强制策略或监听生命周期? → Extension
需要安装、锁版和团队共享?         → 再用 Package 包装

“再用 Package 包装"很重要:Package 与前四项不是互斥选项,它是交付维度。

四个场景如何避免过度设计

  • 固定发布检查清单:从 Template 开始。只有某项检查必须自动采集证据时,再把采集动作做成 Tool;只有所有发布动作都必须经过门禁时,才增加 Extension 拦截。
  • 数据库迁移:通常用 Skill 承载步骤、回滚条件和参考资料,用 Tool 封装迁移系统的只读检查或提交动作。把凭据与执行逻辑直接放进 Skill 脚本,会让模型行动和权限边界难以分开。
  • “禁止修改 .env 和 .git/”:不能只写 Skill——Skill 可以解释原因,真正的强制保护应在 Tool Gate、Extension 或操作系统权限层完成。Extension 也不是最终 Sandbox,敏感凭据和生产网络仍应在宿主层隔离。
  • 团队共享工作流:最后才需要 Package。锁定来源和版本,只启用所需资源,并为每类资源保留独立审核结果。不要让"方便安装"变成"一次信任所有代码、指令和依赖”。

把分层落实为可验证的工程合同

自研 Harness 可以直接借用这套职责分离,但要把对象变成可验收合同:

capability: release
intent:
  type: prompt_template
  owner_triggered: true
knowledge:
  type: skill
  disclosure: on_demand
action:
  type: tool
  schema_version: v2
policy:
  type: extension_hook
  enforced_at: before_tool_execute
distribution:
  type: package
  source: pinned

测试也应拆开:Template 做参数展开快照;Skill 做发现、读取与脚本边界测试;Tool 做 Schema、取消、幂等与副作用测试;Extension 做事件顺序、阻断和 Context Diff;Package 做来源、锁版、过滤与依赖清单验证。更简单的替代方案永远应被保留:如果操作系统只读权限就能阻止写入,就不要先实现复杂 Hook;如果一页模板足以稳定完成任务,就不要引入可执行 Package。最小权限实现通常也是最容易回滚、审计和迁移的实现。

事实边界

本文锁定 Pi v0.82.1(b4f2936);截至 2026-08-11 远端 Tag 已出现 v0.84.1,字段、加载位置和事件集合在使用前需按目标版本刷新。能确认的是固定文档定义的机制与权限边界;不能确认的是某个团队 Package 安全、某个 Skill 一定被触发。把未知项保留下来,恰好也是分层扩展最重要的工程价值:每一层都能用自己的证据证明,而不是靠"插件能运行"替全部对象背书。

原文:武子康《给 Pi 增加能力时,应该写 Prompt、Skill、Tool 还是 Extension?》