第 3 课
自定义命令、技能与会话管理
写一个用 $1、!`命令`、@文件 的自定义命令并用 mimo run --command 运行,写 SKILL.md 技能并用 mimo debug skill 确认被发现,用 mimo session list、mimo export 查看会话和 token 用量,用 -c、-s、--fork 继续会话,最后用 --format json 让脚本读取结果。
课程目录第 3 / 3 课
学习位置仅保存在当前浏览器,有效期 180 天。
图文教材
本课依据: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,其他配置照用。
本课资料
适用环境
- macOS
- Linux
- Windows
