一、为什么要单独理解 Slash Command
用 Agent 做事时,经常会遇到以 / 开头的输入:
text
/help
/new
/model
/skill markdown-to-wechat-richtext
这类输入就是 Slash Command。
它看起来像一句聊天消息,但本质上更接近"命令"。普通消息通常会进入大模型推理流程,由模型理解意图,再决定是否使用工具;Slash Command 则会先被 Agent 的命令系统拦截和解析,然后按命令名触发固定逻辑。
这也是我觉得它值得单独讲清楚的原因:Slash Command 不是 Prompt 的另一种写法,而是 Agent 系统里的一个控制入口。
理解这个入口后,很多问题就容易解释了:
- 为什么
/help不需要模型推理,也能直接显示帮助信息? - 为什么
/new可以直接开启新会话? - 为什么有些开源项目安装后,会在 Claude Code、Gemini CLI、Hermes 这类 Agent 里多出自己的命令?
- 为什么 Hermes 可以通过配置新增
/greet、/wechat-gzh这样的自定义命令?
这篇文章围绕这些问题展开,重点放在 Slash Command 本身,而不是 Skill 的基础概念。
二、Slash Command 到底是什么
Slash Command 是 Agent 会话中的一种"命令式输入"。它通常以 / 开头,后面跟命令名和可选参数。
例如:
text
/help
/model gpt-5.1
/skill markdown-to-wechat-richtext
/wechat-gzh abc/def.md
一条 Slash Command 通常可以拆成两部分:
text
/wechat-gzh abc/def.md
└─────────┘ └────────┘
命令名 参数
也就是:
text
命令名:/wechat-gzh
参数:abc/def.md
Agent 收到这类输入后,一般不会马上把整句话当作自然语言丢给模型,而是先执行类似下面的流程:
text
用户输入一条以 / 开头的消息
↓
Agent 判断这是 Slash Command
↓
解析命令名和参数
↓
查找命令注册表、Quick Command、插件命令或 Skill 命令
↓
执行对应逻辑
↓
返回结果,或者改变当前会话状态
所以 Slash Command 的关键点不是"让模型理解得更好",而是"让系统更确定地触发一个动作"。
举个简单例子:
text
帮我开一个新会话
这是自然语言,Agent 需要理解你的意图。
而:
text
/new
这是命令,系统可以直接把它识别为"开启新会话"。
三、Slash Command 解决了什么问题
Slash Command 的价值,是把常用操作变成短小、稳定、可重复的入口。
在 Agent 使用过程中,有些事情不适合每次都用自然语言描述。比如:
- 查看帮助
- 新建会话
- 清理上下文
- 切换模型
- 加载 Skill
- 执行固定脚本
- 给已有能力起一个短别名
- 在聊天平台里触发运维检查
如果每次都用自然语言表达,容易出现两个问题。
第一个问题是啰嗦。比如"帮我重新开启一个新的上下文,并且不要继承当前对话历史",不如 /new 直接。
第二个问题是歧义。自然语言要经过模型理解,模型可能会解释、追问、或者做出和预期不一致的判断;Slash Command 的命令名和参数结构更固定,适合控制类动作。
我通常把 Slash Command 分成四类来看。
会话控制命令
这类命令改变当前会话状态,例如:
text
/new
/clear
/retry
/undo
/compress
/quit
它们不是用来完成业务任务的,而是用来管理会话本身。
配置和状态命令
这类命令用于查看或修改 Agent 运行状态,例如:
text
/model
/config
/tools
/status
/usage
它们的特点是:用户希望得到一个确定的系统行为,而不是一段开放式回答。
能力加载命令
这类命令用于加载某种能力或工作流,例如 Hermes 中的:
text
/skill markdown-to-wechat-richtext
也可以是某个 Skill 被注册成动态命令后直接调用:
text
/markdown-to-wechat-richtext abc/def.md
这里的重点是:Slash Command 只是入口,真正执行任务的可能是 Skill、工具、插件或 Agent 工作流。
用户自定义命令
用户自定义命令是本文后面重点讨论的部分。比如希望输入:
text
/greet
直接输出:
text
Hello, nice to meet you!
或者希望输入:
text
/wechat-gzh abc/def.md
实际调用本地已有的:
text
/markdown-to-wechat-richtext abc/def.md
这就是 Slash Command 作为"快捷入口"的典型用法。
四、开源项目为什么安装后能提供自己的命令
很多开源项目安装后,可以在某个 Agent 里使用自己的 Slash Command。这里容易产生一个误解:好像所有 Agent 都有一套统一的 Slash Command 插件标准。
实际情况不是这样。
不同 Agent 的实现方式差别很大。一个项目能提供命令,通常是因为它适配了某个 Agent 的扩展机制。
常见方式有几种。
文件型命令
有些 Agent 会约定一个命令目录。项目只要把 Markdown 文件放进去,Agent 就会把这些文件识别成命令。
典型形式类似:
text
.claude/commands/xxx.md
~/.claude/commands/xxx.md
这种模式下,Markdown 文件往往不是普通文档,而是一个 Prompt 模板。用户输入 /xxx 后,Agent 加载对应模板,再把参数拼进去执行。
这种方式很适合开源项目分发自己的工作流,例如:
text
/spec-create
/spec-implement
/spec-review
但要注意:这是某些 Agent 的约定,不代表所有 Agent 都支持同样的目录结构。
注册表型命令
有些 Agent 在源码里维护一张命令注册表。每个命令都有名字、说明、参数、handler。
用户输入 /help、/model、/new 时,系统会查注册表,然后调用对应处理函数。
Hermes 的内置 Slash Command 就属于这种思路。命令注册表是核心入口之一,CLI、自动补全、帮助信息、部分平台映射都可以基于这张表生成。
这种方式更适合系统级命令,因为它需要修改 Agent 本身的代码。
插件型命令
插件型命令介于"用户配置"和"修改源码"之间。
项目提供一个插件,插件安装后向 Agent 注册新的 Slash Command。用户不需要改 Agent 源码,但命令仍然可以拥有比较完整的逻辑。
这类方式适合可分发、可复用、功能较完整的扩展。
MCP 或工具型入口
还有一些项目并不直接提供 Slash Command,而是提供 CLI、MCP Server 或工具集。Agent 通过工具发现机制拿到这些能力后,再用某种命令或自然语言触发。
这种情况下,用户看到的可能像 Slash Command,但底层并不一定是命令文件或命令注册表,而是工具调用。
所以判断一个项目为什么能提供命令,不能只看"有没有 /xxx",还要看它适配的是哪一种扩展机制。
五、Hermes 里自定义 Slash Command 的几种方式
在 Hermes 中,自定义 Slash Command 可以从简单到复杂分成几层。
Quick Command
最简单的是 Quick Command。
它写在 Hermes 配置文件里:
text
~/.hermes/config.yaml
Quick Command 支持两种类型:
text
exec
alias
exec 用来执行本地 shell 命令,适合固定输出、系统检查、脚本执行。
alias 用来把一个短命令改写到另一个 Slash Command,适合给已有命令、Skill 命令或复杂命令起别名。
官方文档里的表达也很直接:Quick Commands 可以把一个短 Slash Command 映射到 shell 命令,或者映射到另一个 Slash Command。
内置 Slash Command
如果要做系统级命令,就需要改 Hermes 源码。
大体思路是:
- 在命令注册表里增加命令定义。
- 在 CLI 或 Gateway 的命令处理逻辑里增加 handler。
- 如有必要,补充帮助信息、自动补全、平台映射和测试。
这种方式适合真正属于 Hermes 核心能力的命令,例如会话控制、配置管理、工具管理等。
普通用户只是想加一个快捷命令时,不建议直接走这条路。
插件命令
插件命令适合可分发扩展。
如果一个能力不应该进入 Hermes 核心,但又希望安装后自动多出命令,就可以做成插件。
插件方式比 Quick Command 更重,但比直接改核心源码更适合分发。
Skill 动态命令
Hermes 还支持把已安装 Skill 当作动态命令来调用。
例如本地有一个 Skill:
text
markdown-to-wechat-richtext
它可以用于把 Markdown 文章转换成微信公众号编辑器友好的富文本 HTML 片段。
如果这个 Skill 可以作为动态命令调用,那么原始调用可能是:
text
/markdown-to-wechat-richtext abc/def.md
这里 /markdown-to-wechat-richtext 是入口,abc/def.md 是传给这个 Skill 的文件路径参数。
后面要做的 /wechat-gzh,本质上就是给这条较长的 Skill 命令起一个短别名。
六、实践一:用 Quick Command 实现 /greet
先从最简单的例子开始:实现一个 /greet 命令。
目标效果是:
text
/greet
输出:
text
Hello, nice to meet you!
这个命令不需要读取文件,不需要调用 Skill,也不需要让大模型参与推理。它只是返回一句固定文本,所以最适合用 Quick Command 的 exec 类型。
配置写法
打开 Hermes 配置文件:
text
~/.hermes/config.yaml
加入下面配置:
yaml
quick_commands:
greet:
type: exec
command: "printf 'Hello, nice to meet you!\n'"
这里有几个细节需要注意。
greet 是命令名,不需要写成 /greet。用户输入时带 /,配置里只写命令名。
type: exec 表示这是一个执行 shell 命令的 Quick Command。
command 里的内容是实际执行的 shell 命令。这里用 printf 输出固定文本。
保存配置后,在 Hermes 会话里输入:
text
/greet
预期看到:
text
Hello, nice to meet you!
如果当前会话没有立即生效,可以重启 Hermes CLI,或者开启一个新会话再测试。
为什么这里不用 Skill
/greet 这种命令没有复杂流程,也没有可复用的任务经验。为了输出一句固定文本去写 Skill,会把问题复杂化。
这里用 exec 的好处是:
- 不调用 LLM
- 不消耗 token
- 配置简单
- 行为稳定
- 很适合做系统检查、固定脚本、状态查询
比如下面这些命令也适合 exec:
yaml
quick_commands:
disk:
type: exec
command: "df -h /"
uptime:
type: exec
command: "uptime"
exec 的边界也很清楚:它适合执行明确的 shell 命令,不适合承载复杂的 Agent 工作流。
七、实践二:用 /wechat-gzh abc/def.md 调用本地 Skill
第二个例子更接近真实工作流。
本地已经有一个 Skill:
text
markdown-to-wechat-richtext
它的用途是把 Markdown 文章转换成微信公众号编辑器友好的富文本 HTML 片段。
原始调用可以写得比较完整:
text
/markdown-to-wechat-richtext abc/def.md
但这个命令名偏长。日常写文章时,更希望输入一个短命令:
text
/wechat-gzh abc/def.md
达到同样效果。
目标映射关系是:
text
/wechat-gzh abc/def.md
↓
/markdown-to-wechat-richtext abc/def.md
这里推荐使用全小写字母和连字符的命令名:
text
wechat-gzh
这种命名方式更符合 Slash Command 的使用习惯,也更不容易遇到大小写匹配带来的困扰。
配置写法
在 ~/.hermes/config.yaml 中配置:
yaml
quick_commands:
wechat-gzh:
type: alias
target: /markdown-to-wechat-richtext
如果已经有前面的 /greet,可以放在同一个 quick_commands 下:
yaml
quick_commands:
greet:
type: exec
command: "printf 'Hello, nice to meet you!\n'"
wechat-gzh:
type: alias
target: /markdown-to-wechat-richtext
注意这里用的是 alias,不是 exec。
原因很简单:/wechat-gzh 不是要执行一条本地 shell 命令,而是要转发到另一个 Slash Command,让 Hermes 继续按 Skill 命令处理。
参数到底是怎么传过去的
这一段最容易困惑。
用户输入的是:
text
/wechat-gzh abc/def.md
Hermes 先把它拆成两部分:
text
/wechat-gzh abc/def.md
└─────────┘ └────────┘
命令名 参数文本
也就是:
text
命令名:/wechat-gzh
参数文本:abc/def.md
然后 Hermes 查 quick_commands,发现配置里有:
yaml
wechat-gzh:
type: alias
target: /markdown-to-wechat-richtext
接下来,alias 会把原命令后面的参数文本追加到 target 后面:
text
/markdown-to-wechat-richtext + 空格 + abc/def.md
最终得到:
text
/markdown-to-wechat-richtext abc/def.md
也就是说,abc/def.md 不是写死在配置里的,也不需要在配置里写 ${1}、$ARGUMENTS 这类占位符。
它来自用户实际输入中跟在命令名后面的剩余文本。
Hermes CLI 的处理逻辑也能印证这一点。alias 分支里会取出原始命令中 base_cmd 后面的内容:
python
user_args = cmd_original[len(base_cmd):].strip()
aliased_command = f"{target} {user_args}".strip()
return self.process_command(aliased_command)
这段逻辑表达的意思就是:
text
目标命令 + 原命令参数 = 改写后的新命令
所以不同输入会得到不同的改写结果:
| 用户输入 | Hermes 改写后 |
|---|---|
/wechat-gzh abc/def.md |
/markdown-to-wechat-richtext abc/def.md |
/wechat-gzh posts/a.md |
/markdown-to-wechat-richtext posts/a.md |
/wechat-gzh /home/sharpcj/blog/a.md |
/markdown-to-wechat-richtext /home/sharpcj/blog/a.md |
target 是固定的:
text
/markdown-to-wechat-richtext
参数是动态的:
text
abc/def.md
posts/a.md
/home/sharpcj/blog/a.md
这就是带参数 alias 的核心。
Skill 接收到的是什么
alias 只负责改写命令,不负责解释参数含义。
当 /wechat-gzh abc/def.md 被改写成:
text
/markdown-to-wechat-richtext abc/def.md
后面的处理就交给 markdown-to-wechat-richtext 这个 Skill 命令。
这个 Skill 需要理解:
text
abc/def.md
是一个 Markdown 文件路径,然后按自己的工作流去读取文件、转换内容,并生成微信公众号可复制使用的 HTML fragment。
所以职责边界是:
| 角色 | 负责什么 |
|---|---|
/wechat-gzh |
提供短命令入口 |
| Quick Command alias | 把短命令改写成长命令,并保留参数 |
/markdown-to-wechat-richtext |
加载并执行本地 Skill 工作流 |
| Skill | 理解文件路径,完成 Markdown 到微信富文本 HTML 的转换 |
这个边界很重要。不要期待 alias 自己去读文件、转换 HTML、处理 Mermaid 或输出结果文件。alias 只做"转发"。真正的任务执行在 Skill 里。
没有传参数会怎样
如果只输入:
text
/wechat-gzh
alias 改写后会变成:
text
/markdown-to-wechat-richtext
这时 Skill 没有拿到文件路径,就无法知道要转换哪篇文章。比较合理的结果是提示用户补充 Markdown 文件路径。
所以这个命令的推荐用法应该始终带上文件路径:
text
/wechat-gzh path/to/article.md
如果路径里包含空格,最好避免这种路径命名;如果确实需要使用,建议先按当前 Hermes 命令解析行为测试引号是否符合预期。技术文章和工程文件里,我更建议直接使用不含空格的路径。
八、exec 和 alias 怎么选
理解 /greet 和 /wechat-gzh 后,Quick Command 的两种类型就比较清楚了。
| 类型 | 做什么 | 是否调用 Agent 工作流 | 适合场景 |
|---|---|---|---|
exec |
执行本地 shell 命令 | 通常不调用 | 固定输出、系统检查、脚本执行 |
alias |
改写到另一个 Slash Command | 取决于目标命令 | 缩短命令名、包装 Skill、复用已有命令 |
判断时可以问一个问题:这个命令最终要做的事情,是一条 shell 命令能完成,还是应该交给 Agent/Skill 继续处理?
如果是一条 shell 命令能完成,用 exec。
例如:
yaml
quick_commands:
disk:
type: exec
command: "df -h /"
如果是调用另一个 Slash Command,用 alias。
例如:
yaml
quick_commands:
wechat-gzh:
type: alias
target: /markdown-to-wechat-richtext
我不建议把复杂 Prompt 直接塞进 Quick Command。Hermes 文档也明确提到,string-only prompt shortcut 不是有效的 Quick Command。可复用 Prompt 工作流应该放进 Skill,再用 alias 指向这个 Skill 命令。
这也是 /wechat-gzh 这个例子的设计思路:
text
复杂工作流放 Skill
短入口用 alias
九、排查命令不生效的问题
配置完 Slash Command 后,如果输入命令没有得到预期结果,可以从下面几个方向排查。
配置文件位置是否正确
Quick Command 写在:
text
~/.hermes/config.yaml
不要写到项目目录里的普通 YAML 文件,也不要写到其他 profile 的配置里。
如果使用 Hermes profile,需要确认当前会话使用的是哪个 profile。不同 profile 有不同的配置、Skill 和记忆目录。
YAML 缩进是否正确
YAML 对缩进敏感。下面是正确写法:
yaml
quick_commands:
greet:
type: exec
command: "printf 'Hello, nice to meet you!\n'"
wechat-gzh:
type: alias
target: /markdown-to-wechat-richtext
常见错误是缩进错位,例如把 type 写到和 greet 同一层,或者把第二个命令写到 greet 里面。
命令名不要带斜杠
配置 key 不写 /:
yaml
wechat-gzh:
type: alias
target: /markdown-to-wechat-richtext
用户输入时才写 /:
text
/wechat-gzh abc/def.md
这是很多人第一次配置时容易写错的地方。
修改配置后是否需要重启
有些配置在当前会话里不会立刻重新加载。稳妥做法是保存配置后重启 Hermes CLI,或者开启新会话再测试。
如果是在 Gateway 场景,比如 Telegram、Discord、Slack 里使用,也可能需要重启 Gateway。
Skill 是否真的存在
如果 /wechat-gzh 最终指向:
text
/markdown-to-wechat-richtext
那本地就必须真的有这个 Skill,并且 Hermes 能识别到它。
可以用 Hermes 的 Skill 管理命令检查,或者在会话里直接测试原始命令:
text
/markdown-to-wechat-richtext abc/def.md
如果原始命令都不工作,/wechat-gzh 这个 alias 也不会工作。alias 只是改写命令,不会修复目标命令本身的问题。
十、什么时候需要更正式的 Slash Command
Quick Command 很方便,但它不是万能的。
如果只是给常用命令起别名、执行脚本、包装已有 Skill,Quick Command 足够好。
但如果需要下面这些能力,就应该考虑更正式的实现方式:
- 命令需要复杂参数解析
- 命令需要交互式确认
- 命令要出现在完整帮助和自动补全体系里
- 命令要跨平台稳定分发给很多用户
- 命令需要访问 Hermes 内部状态
- 命令需要完整测试和权限控制
这时更适合做内置命令或插件命令。
可以这样选择:
| 需求 | 推荐方式 |
|---|---|
| 自己用的短命令 | Quick Command |
| 执行一条固定脚本 | Quick Command exec |
| 给已有 Slash Command 起别名 | Quick Command alias |
| 包装已有 Skill | Skill + Quick Command alias |
| 给团队分发完整扩展 | 插件命令 |
| 进入 Hermes 核心能力 | 内置 Slash Command |
对大多数个人工作流来说,最实用的组合是:
text
Skill 承载复杂流程
Quick Command 提供短入口
/wechat-gzh 就是这个组合的例子。
十一、总结
Slash Command 是 Agent 里的命令入口,不是普通 Prompt。
它的作用是把常用动作变成明确、短小、可重复的输入。命令系统会先解析命令名和参数,再决定调用内置逻辑、Quick Command、插件命令、Skill 命令或其他扩展能力。
在 Hermes 中,普通用户自定义命令最适合从 Quick Command 开始。
固定输出或脚本执行,用 exec:
yaml
quick_commands:
greet:
type: exec
command: "printf 'Hello, nice to meet you!\n'"
给已有 Skill 命令起短别名,用 alias:
yaml
quick_commands:
wechat-gzh:
type: alias
target: /markdown-to-wechat-richtext
输入:
text
/wechat-gzh abc/def.md
实际等价于:
text
/markdown-to-wechat-richtext abc/def.md
这里最关键的是参数传递机制:abc/def.md 不写在配置里,而是来自用户输入中跟在命令名后面的剩余文本。alias 会把这段文本追加到目标命令后面。
理解这一点后,Slash Command 就不再只是一个"以斜杠开头的神秘命令",而是可以被设计、组合和复用的 Agent 交互入口。