015、自定义 Slash Command:从简单别名到带参数复杂命令的开发方法
015、自定义 Slash Command:从简单别名到带参数复杂命令的开发方法
上周五晚上,我在调试一个微服务链路追踪的配置时,连续敲了十几次claude code /trace-config --service user-svc --env staging。每次都要手动拼参数,烦得不行。突然意识到——我明明可以写个 Slash Command 把这活儿自动化,却还在当人肉脚本机。这大概就是“程序员最擅长用复杂技术解决自己懒得做的简单事”的典型反例。
从“别名”开始:别小看这步
自定义 Slash Command 最基础的形态,其实就是给一段常用 prompt 起个短名字。比如我每天都要让 Claude 分析当前目录的 Python 代码结构:
/debug-py → "分析当前项目所有Python文件的模块依赖关系,输出Mermaid流程图"实现方式很简单,在项目根目录建个.claude/commands.json:
{"debug-py":{"description":"分析Python项目模块依赖","prompt":"分析当前项目所有Python文件的模块依赖关系,输出Mermaid流程图"}}这里踩过坑:description字段不是摆设。Claude Code 的自动补全会根据 description 做模糊匹配,如果你写“分析Python”,敲/ana也能触发。但如果你 description 写“调试工具”,那/debug反而匹配不上——因为补全逻辑是前缀匹配,不是语义匹配。别这样写,老老实实把关键词放前面。
参数化:让命令活起来
别名只能解决“固定需求”,但真实场景里,你经常需要传变量。比如我要查某个服务的日志,服务名、环境、时间范围都是变量。
带参数的 Slash Command 需要用到{{placeholder}}语法。看这个例子:
{"check-log":{"description":"检查服务日志错误","prompt":"查看 {{service}} 服务在 {{env}} 环境的日志,时间范围最近 {{hours}} 小时,重点关注 ERROR 级别日志,统计每种错误类型出现次数"}}当你敲/check-log时,Claude Code 会弹出三个输入框:service、env、hours。填完之后,prompt 里的占位符会被替换。
这里有个容易翻车的地方:占位符命名不要用下划线开头(比如{{_env}}),Claude Code 内部会把下划线开头的占位符当成系统变量,导致替换失败。我因为这个 bug 排查了半小时,最后翻源码才发现的。
复杂命令:当参数需要联动
单层参数替换还不够。比如我有个场景:根据服务类型(Java/Go/Node)自动切换分析工具链。这时候需要参数之间产生逻辑关联。
我的做法是用一个“元命令”来调度:
{"analyze-service":{"description":"深度分析服务性能瓶颈","prompt":"服务名称: {{service_name}}\n服务类型: {{service_type}}\n\n如果服务类型是Java,执行以下分析步骤:\n1. 检查JVM堆内存配置\n2. 分析GC日志模式\n3. 检查线程池配置\n\n如果服务类型是Go,执行:\n1. 检查goroutine泄漏\n2. 分析pprof采样数据\n3. 检查channel使用模式\n\n如果服务类型是Node,执行:\n1. 检查事件循环延迟\n2. 分析内存快照\n3. 检查异步操作链\n\n请根据服务类型执行对应分析流程,输出优化建议。"}}注意看,这里没有用任何条件判断语法,纯粹靠 prompt 里的自然语言分支逻辑。Claude 能理解“如果…则…”这种结构,效果比写死多个命令好得多。
动态参数:从文件或环境变量读取
有些参数不是用户输入的,而是从当前上下文自动获取的。比如我想让命令自动读取.env文件里的PROJECT_ID。
实现方式是利用 Claude Code 的{{file:path}}语法:
{"deploy-check":{"description":"检查部署前环境配置","prompt":"当前项目ID: {{file:.env|PROJECT_ID}}\n部署环境: {{env}}\n\n检查以下内容:\n1. 项目ID对应的云资源是否存在\n2. 环境变量配置是否完整\n3. 依赖服务是否健康\n\n输出检查清单,标记通过/未通过"}}{{file:.env|PROJECT_ID}}的意思是:读取.env文件,提取PROJECT_ID这一行的值。如果文件不存在或格式不对,Claude 会报错提示,不会静默失败——这个设计很良心,避免了“参数没读到但命令继续执行”的坑。
实战:我写的一个“链路追踪调试”命令
回到开头那个让我抓狂的场景。最终我写了个复合命令:
{"trace-config":{"description":"调试服务链路追踪配置","prompt":"服务名称: {{service}}\n部署环境: {{env}}\n追踪采样率: {{sampling_rate:0.1}}\n\n请执行以下操作:\n1. 读取该服务的 tracing 配置文件(路径通常是 config/tracing.yaml 或 application.yml)\n2. 检查采样率设置是否与输入一致\n3. 验证 exporter 端点配置是否正确\n4. 检查 span 标签是否包含必要字段(service.name, env, version)\n5. 如果发现配置错误,直接给出修正后的配置片段\n\n注意:采样率参数有默认值0.1,如果用户不输入则使用默认值。"}}注意{{sampling_rate:0.1}}这个写法——冒号后面是默认值。这是 Claude Code 支持的语法,但文档里没写,我是看 issue 讨论才知道的。如果用户不填这个参数,就自动用 0.1。
调试技巧:如何验证你的命令
写完之后怎么测?别直接在生产项目里试。我习惯在临时目录里建个测试项目:
mkdir/tmp/cmd-test&&cd/tmp/cmd-testecho"test">.env claude code然后敲/你的命令名,看 Claude 是否按预期解析参数、替换占位符。如果命令里有文件读取,确保测试目录里有对应的文件。
另一个技巧:在 prompt 末尾加一句“请先列出你接收到的所有参数值”,这样 Claude 会先输出参数解析结果,方便你确认替换是否正确。
个人经验
- 命令数量控制在5-7个。超过这个数,记忆成本就高了,你反而会忘记自己写过什么命令。我见过有人写了20多个命令,最后自己都记不住,每次还得翻配置文件。
- 参数默认值一定要给。尤其是那些“90%场景都用同一个值”的参数,比如环境名、采样率。少敲一次键盘,就多一分快乐。
- 命令名用连字符,不要用下划线。Claude Code 的自动补全对连字符更友好,敲
/trace能匹配到/trace-config,但敲/trace匹配不到/trace_config。 - 定期清理废弃命令。项目迭代半年后,有些命令对应的流程已经变了,但你还留着旧命令。某天手滑敲了它,Claude 按旧逻辑执行,给你一堆过时建议——这种坑我踩过不止一次。
最后说句实在话:Slash Command 最大的价值不是“自动化”,而是“降低上下文切换成本”。每次你从 IDE 切到浏览器查文档、切到终端跑脚本,都是在消耗注意力。把那些高频操作固化成命令,省下来的不是几秒钟,而是你进入心流状态的那几分钟。
