第 3 课

自定义命令、技能与会话管理

写一个用 $1、!`命令`、@文件 的自定义命令并用 mimo run --command 运行,写 SKILL.md 技能并用 mimo debug skill 确认被发现,用 mimo session list、mimo export 查看会话和 token 用量,用 -c、-s、--fork 继续会话,最后用 --format json 让脚本读取结果。

图文22 分钟

课程目录第 3 / 3 课

学习位置仅保存在当前浏览器,有效期 180 天。

01 / 图文教材

图文教材

本课依据:MiMo Code 官方文档「命令」https://mimo.xiaomi.com/zh/mimocode/commands 、「代理技能」https://mimo.xiaomi.com/zh/mimocode/skills 、「会话与上下文」https://mimo.xiaomi.com/zh/mimocode/sessions 、「命令行运行」https://mimo.xiaomi.com/zh/mimocode/cli-options ,官方仓库 README https://github.com/XiaomiMiMo/MiMo-Code (2026-10-29 核对,MiMo Code 0.1.16)。实验接着前两课的 ~/mimo-demo 项目做。

这一课做完你会得到什么

把常用的提示词做成项目里的自定义命令(带参数、自动带上 Git 记录和文件内容),把团队约定写成一个技能让模型按需加载,再学会列出、导出、继续会话,并用 --format json 让脚本读取运行结果。

第 1 步:写一个自定义命令

自定义命令就是存成文件的提示词模板。项目级放在 .mimocode/commands/,全局放在 ~/.config/mimocode/commands/,文件名就是命令名。

cd ~/mimo-demo
mkdir -p .mimocode/commands
cat > .mimocode/commands/review.md <<'EOF2'
---
description: 审查指定文件并给出改进建议
---
最近的提交:
!`git log --oneline -5`

请审查 @$1 ,按「问题 / 建议」两列用表格列出,不超过 5 条。
重点关注:$2
只给建议,不要修改任何文件。
EOF2

模板里用到了官方文档列出的四种写法:

写法作用
$ARGUMENTS整串参数
$1、$2…第 1、2… 个参数
!`命令`先在项目根目录运行这条 shell 命令,把输出放进提示词
@文件把文件内容放进提示词

frontmatter 里的字段:

  • description:TUI 命令列表里显示的说明。
  • agent(本例没写):用哪个模式运行,例如 agent: plan 让审查只读。不写就用当前模式(默认 build),所以模板最后一句明确要求「不要修改任何文件」。实测时我们先写了 agent: plan,2B 小模型在 plan 模式下又像第 2 课那样反复调用子智能体失败、迟迟不出结果,才改成现在这样;用官方 mimo-v2.6 模型时可以放心写 agent: plan。
  • model(本例没写):给这个命令单独指定模型,格式同样是 provider_id/model_id。

官方示例写的是 xiaomi/mimo-v2.5-pro,那是旧型号,照抄时换成 mimo models 实际列出的 ID。

同样的命令也可以写进 mimocode.json 的 command 字段,那时提示词放在必填的 template 里。

第 2 步:运行自定义命令

在 TUI 里输入 /review hello.py 可读性和健壮性 即可。命令行里用 --command 指定命令名,后面的词就是参数:

mimo run --command review hello.py 可读性和健壮性

注意参数不要用引号包成一整串。实测写成 "hello.py 可读性和健壮性" 时,整串都成了 $1,$2 是空的,提示词变成「请审查 @hello.py 可读性和健壮性」「重点关注:」后面什么都没有。分开写才是 $1 = hello.py、$2 = 可读性和健壮性。

用 mimo export 导出这次会话(第 4 步会讲),能看到展开后真正发给模型的提示词:

最近的提交:
bbb010c build step


请审查 @hello.py ,按「问题 / 建议」两列用表格列出,不超过 5 条。
重点关注:可读性和健壮性
只给建议,不要修改任何文件。

!`git log --oneline -5` 已经换成了真实的提交记录,@hello.py 则让 MiMo Code 自动调用 read 工具,把文件内容作为附件一起发给模型。

模型的回复(2B 本地模型实测,约 1 分钟,原样照录):

问题 / 建议描述
可读性函数 greet 非常简洁,对于这种简单的功能,代码是清晰且易于理解的。
健壮性当前代码在处理 name 为空字符串等异常输入时没有明确的防御性编程,但对于当前实现而言,这在范围内是可接受的。
函数签名签名 def greet(name: str) -> str: 已经使用了类型注解,这很好地增强了代码的静态分析和可读性。
主执行块使用 if __name__ == "__main__": 结构是 Python 脚本的标准做法,保持了脚本的清晰入口点。
简洁性对于如此简短的函数,代码完全符合简洁性要求,无需额外的抽象或注释。

小模型把「问题 / 建议」两列合成了一列表头,内容也偏客套,但它确实按 $2 关注了可读性和健壮性,也没有改任何文件(git status --short 只显示我们自己改的 review.md)。这次只用了约 1 分钟,比第 1 课快很多:结束时的统计里 cache.read 为 20,680,说明 llama.cpp 复用了上一轮已经算过的系统提示。

第 3 步:把团队约定写成技能

上一课里 2B 小模型忽略了「写测试」那条规则。规则每次都会塞进上下文,写多了就占地方;技能(Skill)则是按需加载:模型平时只看到技能的名字和描述,需要时才调用 skill 工具读入全文。

mkdir -p .mimocode/skills/py-unittest
cat > .mimocode/skills/py-unittest/SKILL.md <<'EOF2'
---
name: py-unittest
description: 为本项目的 Python 函数编写标准库 unittest 测试
---
## 什么时候用我
新增或修改了 Python 函数、需要补测试时。

## 规则
- 测试文件命名为 test_<模块名>.py,放在项目根目录。
- 只用标准库 unittest,不引入 pytest。
- 每个函数至少一个正常用例和一个边界用例。
- 写完后运行 python3 -m unittest -v 确认全部通过。
EOF2

写技能的要点(官方「代理技能」页):

  • 文件名必须是全大写的 SKILL.md,放在 .mimocode/skills/ 下任意层目录。
  • frontmatter 只认 name(必填)、description(必填)、hidden(可选,设为 true 时能加载但不出现在列表里)。
  • 技能名取自 name 而不是文件夹名。建议用小写字母、数字和连字符;重名时后加载的覆盖先加载的。
  • description 是模型决定要不要加载的唯一依据,要写具体。
  • 也会扫描 .claude、.agents、.codex、.opencode 下的 skills/**/SKILL.md,以及 ~/.config/mimocode/skills/,从别的工具迁移过来的技能可以直接用。

检查技能有没有被发现,不用调模型:

mimo debug skill | python3 -c "
import json, sys
for s in json.load(sys.stdin):
    print(s['name'])"

对照结果(2026-10-29 实测):

arxiv
compose-next
data-analytics
deep-research
docx-official
html-to-video-pipeline
learn-everything
loop
mate
memory-search
mimocode-docs
modern-python-toolchain
pdf-official
playwright
pptx-official
product-design
research-paper-writing
sales
skill-creator
super-research
xlsx-official
py-unittest

前 21 个是 0.1.16 自带的内置技能(论文检索、深度研究、Office 文档、Playwright 等),最后一个就是刚写的 py-unittest。mimo debug skill 输出的是 JSON,每项还有 location(文件位置)和 content(正文),技能没出现时先看这里。

以后让它写代码时,可以在提示里直接点名,例如「新增 farewell 函数,并按 py-unittest 技能补测试」。按官方仓库 README 的说明,TUI 里输入 / 能在补全列表里浏览技能,输入 /py-unittest 可直接调用;一条消息里点名两个以上技能时会一起加载。想限制技能,在 permission.skill 里按名字写 allow / ask / deny,例如 "internal-*": "deny"。

第 4 步:列出、导出和继续会话

MiMo Code 会把每次对话存成会话,按工作目录分组。列出当前项目的会话:

mimo session list

对照结果(实测节选,只保留最近 3 条和第 1 课那条;标题列截短,Updated 是本机时间):

Session ID                      Title                        Updated
ses_ffe5e7c9a304dffe7DIUa0UQCW  hello.py 可读性和健壮性      12:45 AM
ses_ffe5e7c9b800effe4l1mxh6BxU  hello.py 可读性和健壮性      12:43 AM
ses_ffe5e7c9ee682ffeWM1bIk1991  hello.py 可读性和健壮性分析  12:40 AM
……
ses_ffe5e7cb7b03cffeTDvAyg4D8x  用一句中文介绍你自己         12:11 AM

标题是 MiMo Code 用模型自动起的。想给脚本读,加 --format json;只看最近几条,加 -n 5。

导出某个会话为 JSON(不写 ID 会让你从列表里选。mimo export 和 mimo import 目前官方文档页还没写,以 mimo --help 里的说明「export session data as JSON」为准),下面导出第 1 课「用一句中文介绍你自己」那次,看看一次简单问答实际花了多少 token:

mimo export <会话ID> > s1.json
python3 - <<'EOF2'
import json
d = json.load(open("s1.json"))
print(d["info"]["title"], d["info"]["version"])
for m in d["messages"]:
    i = m["info"]
    if i["role"] == "assistant":
        t = i["tokens"]
        print(i["agent"], i["modelID"],
              "input", t["input"], "output", t["output"])
EOF2

对照结果(实测):

用一句中文介绍你自己 0.1.16
build gemma-4-e2b input 20702 output 177

一句话的问题,输入就有 20,702 token,这就是第 1 课要求本地模型至少开 64K 上下文的原因。导出文件可能包含代码、命令输出和路径,分享前先检查;mimo import s1.json 可以把它导回来。

继续或分叉会话(下表按官方「会话与上下文」「命令行参数」两页整理,本课没有实测):

命令作用
mimo -c / mimo run -c "…"继续当前目录最近的会话
mimo -s <ID>继续指定会话
mimo -c --fork复制一份最近的会话再继续,原会话不受影响

TUI 里对应的是 /sessions 切换会话、/new 开新会话、/compact 手动压缩上下文、/undo 和 /redo 撤销或重做上一次修改。

第 5 步:让脚本读取结果

mimo run --format json 把运行过程按 JSON 事件逐行输出,适合放进 CI 或自己的脚本。第 2 步那条命令的 JSON 版:

mimo run --format json --command review \
  hello.py 可读性和健壮性 > review.jsonl

每行是一个事件,都有 type、timestamp、sessionID 和 part 四个字段。这次只有三种事件:step_start(一步开始)、text(模型的文字回复,在 part.text 里)、step_finish(一步结束,part.reason 是结束原因,part.tokens 是用量)。如果模型调用了工具,还会有 tool_use 事件(第 2 课 plan 模式里那些失败的子智能体调用就是这种)。用 Python 把它们读出来:

python3 - <<'EOF2'
import json
for line in open("review.jsonl"):
    e = json.loads(line)
    p = e["part"]
    if e["type"] == "text":
        print("text:", p["text"][:24].replace("\n", " "), "…")
    elif e["type"] == "step_finish":
        t = p["tokens"]
        print(e["type"], p["reason"], "input", t["input"],
              "cache", t["cache"]["read"], "output", t["output"])
    else:
        print(e["type"])
EOF2

对照结果(实测):

step_start
text: | 问题 / 建议 | 描述 | | :---  …
step_finish stop input 338 cache 20680 output 678

reason 为 stop 表示模型正常答完。在 CI 里可以用它判断是否成功,再把 text 写进评论或日志。

另外两个在脚本里常用的参数:

  • -m provider/model:临时换模型,不改配置文件。
  • --dangerously-skip-permissions(别名 --yolo):自动批准所有没被明确 deny 的权限请求。只在一次性的沙箱里用,平时靠第 2 课的 permission 规则放行。

小结

  • 自定义命令:.mimocode/commands/<名字>.md,支持 $ARGUMENTS、$1、!`命令`、@文件;frontmatter 可指定 agent 和 model;命令行用 mimo run --command <名字> 参数1 参数2,参数不要用引号包成一串。
  • 技能:.mimocode/skills/**/SKILL.md,必填 name 和 description,按需加载;mimo debug skill 检查是否被发现。
  • 会话:mimo session list 列出,mimo export 导出 JSON 并能看到每轮 token 用量,-c、-s、--fork 继续或分叉。
  • 自动化:mimo run --format json 输出 JSON 事件,-m 临时换模型。
  • 三课学完,换成官方 mimo-v2.6 模型时只需在 TUI 里 /connect 登录,再把 model 改成 xiaomi/mimo-v2.6-flash 等 ID,其他配置照用。