从零构建Agent(八):Commands

本文是 ZeroAgent 系列第 8 篇。上一篇《Session 管理》中,我们用 /resume 恢复会话,其实已经用到了 Command。本文将拆解如何为 Agent 实现一套可复用的斜杠命令系统。

斜杠命令是来自于Claude Code的经典设计,Command 除了可以控制Agent的行为外,还可以让用户自定义 Prompt 模板。

试想一下,每次想让 Agent "审查代码",你都得手打一遍完整指令:"请审查 xxx 文件,重点关注安全性、性能和代码风格,给出改进建议..."。每次想让 Agent "提交代码",又得输入:"请根据当前改动生成一条符合 Conventional Commits 规范的提交信息..."。

这些高频复用的 Prompt ,能不能像 Shell 别名一样保存起来,用 /review 一个命令就自动展开呢?

1. 什么是 Slash Commands

经常使用Agent的同学,对于这个功能应该不陌生。下图是Hermes Agent的斜杠命令列表,我们可以用这些命令对Agent进行Session管理,上下文压缩等操作。

以下是PI Agent的斜杠命令列表,除了系统自定义的命令之外,opsx 开头的命令,是我们使用OpenSpec init 创建的SDD命令,属于是用户自定义命令,在PI Agent中也叫prompt template

Slash Commands 作为用户自定义的 Prompt 模板 使用时。每个命令是一个 Markdown 文件,包含 YAML frontmatter(元数据)和正文(Prompt 模板)。在交互模式中输入 /命令名 参数1 参数2,CLI 会将参数展开到模板中,生成完整的 Prompt 发送给 Agent。

一个典型的命令文件:

markdown 复制代码
---
name: review
description: Review a file or diff
---
Review the following file and suggest improvements:

File: $1

Focus on: ${2:-correctness, style, and performance}

调用方式:

bash 复制代码
❯ /review src/cli.ts
# 展开后等价于直接发送:
# Review the following file and suggest improvements:
#
# File: src/cli.ts
#
# Focus on: correctness, style, and performance

与 Skills 的关键区别在于:Skills 是给模型看的指令 (模型决定何时加载),Commands 是给用户用的快捷方式(用户决定何时触发)。Skills 影响模型何时、如何加载指令,Commands 影响用户如何发起任务。两者互补:你可以用一个 Command 快速发起任务,Agent 在执行过程中再按需加载 Skill。

维度 Skills Commands
触发者 模型 用户
加载时机 模型按需加载 用户输入时展开
作用对象 模型推理过程 用户输入操作
复用方式 跨任务复用领域知识 跨会话复用 Prompt

需要注意的是,因为Skill本质上也是prompt,有些Agent,比如 Pi Agent,也支持通过 Command 触发 Skill。

2. 实现Command功能

2.1 类型定义

在 src/command/types.ts 中定义命令的数据结构:

typescript 复制代码
export type CommandDefinition = {
    /** 命令名,调用时写作 /name */
    name: string;
    /** 描述,列出可用命令时展示 */
    description: string;
    /** Prompt 模板正文,支持 $1、${2:-default} 占位符 */
    template: string;
};

三个字段:name 是唯一标识,description 用于 /help 或错误提示时展示,template 是带占位符的 Prompt 模板。

占位符约定:$1、$2 表示第 1、2 个位置参数;${2:-default} 表示第 2 个参数缺省时使用 default。模板整体保存为字符串,展开时再做替换------这样命令文件可以原样落盘,便于阅读和版本管理。

2.2 Frontmatter 解析

鉴于命令文件使用与 Skill 文件相同的 frontmatter 格式,我们有必要把解析逻辑抽出来,以便两边可以复用(参考PI Agent也是这么做的),这类微重构可以交给 AI 完成,AI重构后在 src/util/frontmatter.ts 中的新实现如下:

typescript 复制代码
export type Frontmatter = {
    name?: string;
    description?: string;
};

/**
 * Split Markdown content into flat name/description frontmatter and body.
 */
export function splitFrontmatter(content: string, source: string): { frontmatter: Frontmatter; body: string } {
    const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
    if (match === null) {
        throw new Error(`File "${source}" is missing YAML frontmatter. Expected "---" delimited block at the start of the file.`);
    }
    // ...省略
}

解析逻辑很直白:正则匹配 --- 分隔的 frontmatter 块,提取 name 和 description,frontmatter 之后的正文就是模板。缺失必填字段或模板为空都会抛出错误------错误要尽早暴露,不能等到用户调用时才发现命令文件有问题。

2.3 两级加载路径

与 Skills的加载机制一样,Command 支持全局和项目级两个加载路径:

复制代码
~/.zeroagent/commands/*.md           # 全局命令,所有项目可用
{workdir}/.zeroagent/commands/*.md   # 项目命令,仅当前项目可用

项目级命令与全局命令同名时,项目级覆盖全局 (后加载覆盖先加载)。这个设计让你可以为不同项目定制同名命令的行为------比如全局有个通用的 /review,某个项目可以定义一个更具体的 /review 覆盖它。

typescript 复制代码
const dirs = [userCommandsDir(), projectCommandsDir(workdir)];

for (const dir of dirs) {
    const commands = await loadCommandsFromDirectory(dir);
    for (const entry of commands) {
        registry.register(entry.command);
    }
}

加载顺序:全局先、项目后。CommandRegistry 内部是 Map<string, CommandDefinition>,register() 对同名 key 直接覆盖,自然实现了"后写胜出"的优先级。

2.4 热重载

这个功能也是借鉴 PI Agent 的:交互模式中输入 /reload 可以重新加载命令和技能:

typescript 复制代码
async function handleReloadCommand(agent: Agent, registry: CommandRegistry, workdir: string): Promise<void> {
    const loadedCommands = await loadCommands(workdir, registry);
    const loadedSkills = await loadSkills(workdir, agent.skills);
    console.log(`[reload] ${loadedCommands.length} command(s), ${loadedSkills.length} skill(s)\n`);
}

loadCommands 会先 clear() 清空 registry,再从磁盘重新加载。这意味着你在运行中新增、修改、删除命令文件后,不需要重启 Agent------一个 /reload 即可生效。

3. 实际运行

3.1 前置准备

确保已安装依赖,并在 chapter8 目录下启动:

bash 复制代码
pnpm install
pnpm --filter @zero-agent/chapter8 start

启动后,CLI 会扫描全局与项目级命令目录,并打印已加载的命令列表。

3.2 创建命令

在项目目录下创建 .zeroagent/commands/review.md:

markdown 复制代码
---
name: review
description: Review a file and suggest improvements
---
Review the following file and suggest improvements:

File: $1

Focus on: ${2:-correctness, style, and performance}

Provide specific, actionable suggestions with code examples.

再创建 .zeroagent/commands/commit.md:

markdown 复制代码
---
name: commit
description: Generate a conventional commit message
---
Based on the current git diff, generate a commit message following the
Conventional Commits specification (type: scope: description).

Stage: $1

3.3 启动并使用

bash 复制代码
$ pnpm --filter @zero-agent/chapter8 start

[commands] Loaded 2 command(s): review, commit
[session] New session: a1b2c3d4-...
Interactive mode --- type your prompt and press Enter. Ctrl+C to exit.

❯ /review src/cli.ts
[step 1]
[tool_call] read_file({"path":"src/cli.ts"})
[step 2]
Here are my suggestions for src/cli.ts:
1. Extract the session command handlers into a separate module...
[run_end after 2 step(s)]

❯ /commit src/
[step 1]
[tool_call] run_terminal_command({"command":"git diff --cached -- src/"})
[step 2]
feat(chapter8): add slash command support for CLI
[run_end after 2 step(s)]

3.4 热重载

bash 复制代码
❯ /reload
[reload] 3 command(s), 1 skill(s)

新增一个命令文件后,不需要重启 Agent,直接 /reload 即可。

3.5 未知命令

bash 复制代码
❯ /refactor

[error] Unknown command: /refactor
Available commands: /sessions, /resume, /clear, /reload, /review, /commit

列出所有可用命令(内置命令 + 用户定义命令),帮你快速发现是拼写错了还是命令没加载。内置命令(如 /sessions、/resume、/clear、/reload)在启动时注册,用户命令随后合并,同名时以用户命令为准。

4. 总结

本文为 ZeroAgent 构建了 Slash Commands 能力:定义了 CommandDefinition 结构,抽取了可复用的 frontmatter 解析,实现了全局/项目两级加载与同名覆盖,并支持 /reload 热重载。至此,高频 Prompt 可以像 Shell 别名一样被复用。

读者可以在 https://github.com/significantfrank/ZeroAgent 的 chapter8 中获取本文的完整源码。

若觉得本文对你有帮助,请支持我的新书:《Harness 工程实战》。

参考:

Claude code Command: https://code.claude.com/docs/en/commands

PI Prompt Template:https://pi.dev/docs/latest/prompt-templates

相关推荐
瓶瓶持续学习中1 小时前
数字孪生数据模型如何连接空间智能与仿真
人工智能·信息可视化
AI模型调用笔记2 小时前
MiniMax M3.1 Flash 发布
人工智能
该逃避避2 小时前
营销联盟付费模式详解:从佣金结构到落地实践
人工智能
执伞人ONLY2 小时前
AI 知识库多源知识接入:数据接不进来,AI 就是废铁
人工智能
胡家伟++2 小时前
壬子年考:战争与鼎革之轴——干支史考第十三篇
人工智能
2601_962071002 小时前
MiniMax M3 vs DeepSeek V4-Pro实测:同一入口19道题,输出、速度与成本差在哪
人工智能
泽众云测试2 小时前
泽众TestAgent-面向测试的AI智能体
软件测试·人工智能·ai测试
天远Date Lab2 小时前
零信任架构实战:基于天远车辆估值构建自动化品牌二手车置换智能定价与补贴测算网关
运维·人工智能·架构·自动化
wei091302 小时前
哪些ai能自动搜索、整合资料并生成报告?
人工智能