This release is a pre-release and may not be stable for production use.
MiniCPMO5 SDK
MiniCPMO5 SDK 是面向 MiniCPM-O 系列双工(duplex)训练数据协议的 Python 工具包:把"一通对话"的多轨观测序列化成可训练的 token 流,并提供电子书式的可视化教程。
你写的对话 / 观测
↓ 构造五轨 TrainingData(schema 强校验)
O5DuplexTrainingData
↓ arrange() 把 start_trigger 解到 unit 网格
O5DuplexArrangement
↓ tokenize(tokenizer) 五轨 slot 模板展开
O5TokenizedDuplexData
↓ 可视化(四主视图)
Guidebook / Dataset Viewer
当前版本 0.0.3:只覆盖数据 + token 协议 + 质检 + 可视化。 训练支持在 v0.1,推理支持在 v0.2。详见 CHANGELOG.md。
安装
pip install minicpm-o5-sdk
# 或从源码 editable 安装:
pip install -e .
依赖:python ≥ 3.10、pydantic ≥ 2.11、torch ≥ 2.0、transformers ≥ 5.0、tokenizers ≥ 0.20.4、jsonschema、watchfiles。
查询安装包构建来源
wheel / sdist 构建时会注入只读 build info;查询结果包含 distribution version、完整 Git commit、SDK 子树 Git tree、dirty 标志和 UTC 构建时间:
from minicpm_o5_sdk import O5BuildInfoSource, get_build_info
build_info = get_build_info()
print(build_info.model_dump(mode="json"))
if build_info.source is O5BuildInfoSource.BUILD_ARTIFACT:
assert build_info.git_commit is not None
assert build_info.git_tree is not None
assert build_info.dirty is False # 公开 release 必须成立
直接运行源码或 editable 安装时不会伪造构建来源:
source="editable_fallback",Git、dirty 和构建时间字段均为 None;version
来自已安装 distribution metadata,纯 PYTHONPATH=src 且未安装时为 0+unknown。
构建默认拒绝 dirty SDK release-owned 路径;范围仅包括运行时源码、package config、
README/CHANGELOG 和 release 文档,不受其他模块、测试或 DevMeta state 变化影响。
build/、dist/、*.egg-info/、__pycache__/ 和 *.pyc/*.pyo 属于构建产物,
不参与 dirty 判定,也不会进入 wheel/sdist。
只有内部开发构建可显式设置
MINICPM_O5_INTERNAL_ALLOW_DIRTY_BUILD=1,生成的信息会如实记录 dirty=true;
公开发布必须设置 MINICPM_O5_PUBLIC_RELEASE=1,并且禁止同时使用 dirty 覆盖参数。
快速上手
五轨概览(每个 unit 内严格按此顺序展开 token)
| Track | 类型 | 说明 |
|---|---|---|
user_video |
timed | 用户视频帧(当前 0.0.x 不实现 content tokenize) |
user_audio |
timed | 用户语音 + 可选字级 alignment |
input_event |
text | 外部观测事件:tool_response / tool_created(框架注入)/ standalone event |
ai_spoken |
timed | AI 语音输出,字级 alignment 必填且 schema 校验拼接一致 |
ai_non_spoken |
text | AI 思考 / 工具调用(text + think + tool_call) |
直接加载内置 Case
SDK 随 wheel 分发一组 Guidebook 原子案例,可直接导入为 O5DuplexTrainingData:
from minicpm_o5_sdk import O5CaseID, O5TokenizerID, load_case
training_data = load_case(O5CaseID.CASE_1_02)
result = training_data.tokenize(tokenizer_id=O5TokenizerID.O5)
脚本场景也可以用字符串 ID:
from minicpm_o5_sdk import load_case
training_data = load_case("case_1_02")
可用 ID 通过 list_case_ids() 查看;当前开发线内置 12 个 active case。
Case 可以包含多个按教学顺序演进的 Variant。旧入口继续加载 canonical;需要指定变体时:
from minicpm_o5_sdk import list_case_variants, load_case
print([
variant.variant_id
for variant in list_case_variants("case_1_02")
])
training_data = load_case(
"case_1_02",
variant_id="inter_round_pause",
)
源码仓库中另有 examples/load_builtin_case.ipynb 作为交互式教程;notebook
不随 wheel 打包,pip 用户可直接使用上面的代码片段或启动 Guidebook。
构造一条最小 TrainingData(用户问 → AI 答)
import torch
from minicpm_o5_sdk import (
O5AISpokenSegment, O5AISpokenTrack, O5AINonSpokenTrack,
O5Alignment, O5DuplexTrainingData, O5DuplexTrainingTracks,
O5GlobalTime, O5InputEventTrack, O5MediaSegmentTime,
O5LazyAudio, O5SystemContent, O5SystemTextSegment,
O5StartTrigger, O5UnitPolicy, O5UserAudioSegment,
O5UserAudioTrack, O5WordInterval,
)
def alignment_for(text: str, dur: float) -> O5Alignment:
return O5Alignment(word_intervals=[O5WordInterval(text=text, start_sec=0.0, end_sec=dur)])
training_data = O5DuplexTrainingData(
unit_policy=O5UnitPolicy(
unit_sec=1.0,
non_spoken_budgets_while_listening=[100],
non_spoken_budgets_while_speaking=[100],
),
system=O5SystemContent(segments=[O5SystemTextSegment(text="你是一个友好的中文 AI 助手。")]),
tracks=O5DuplexTrainingTracks(
user_video=None,
user_audio=O5UserAudioTrack(segments=[
O5UserAudioSegment(
audio=O5LazyAudio(
duration_sec=1.2,
get_tensor_fn=lambda: torch.zeros(int(1.2 * 16000), dtype=torch.float32),
),
start_trigger=O5StartTrigger(refs=[O5GlobalTime()]),
transcript="你好",
),
]),
input_event=O5InputEventTrack(segments=[]),
ai_spoken=O5AISpokenTrack(segments=[
O5AISpokenSegment(
audio=O5LazyAudio(
duration_sec=0.8,
get_tensor_fn=lambda: torch.zeros(int(0.8 * 16000), dtype=torch.float32),
),
start_trigger=O5StartTrigger(refs=[
O5MediaSegmentTime(
track="user_audio",
segment_index=0,
at="end",
offset_sec=0.3,
),
]),
text="你好",
alignment=alignment_for("你好", 0.8),
),
]),
ai_non_spoken=O5AINonSpokenTrack(segments=[]),
),
)
Tokenize
from minicpm_o5_sdk import O5TokenizerID
result = training_data.tokenize(tokenizer_id=O5TokenizerID.O5)
assert result.tokenized_data.tokenizer_target == "o5"
for t in result.tokenized_data.token_provenance[:30]:
print(t.token_text, t.track, t.unit_index, t.trainable)
Arrangement 前估计 Token 下限
明显超长样本可先走无需 arrange() 的确定性下限:
from minicpm_o5_sdk import O5TokenizerID
estimate = training_data.estimate_tokenization_lower_bound(
tokenizer_id=O5TokenizerID.O5,
)
print(estimate.total_token_lower_bound)
print(estimate.content_tokens)
print(estimate.omitted_items)
total_token_lower_bound 保证不大于同一 tokenizer/serializer 下最终可成功生成的
input_ids 长度。它不是最终 tokenized length,也不决定训练最大长度;
Trigger/budget/Unit 落点等无法在编排前证明的增量会列在 omitted_items。
需要函数式组合时,可从顶层导入
estimate_tokenization_lower_bound(training_data, tokenizer=...)。
调用方已经完成 Layer1 Arrangement 时,可通过显式 keyword-only 参数复用,避免
tokenize() 再次 arrange:
from minicpm_o5_sdk import O5TokenizerID, load_builtin_tokenizer
tokenizer = load_builtin_tokenizer(O5TokenizerID.O5)
arrangement = training_data.arrange(tokenizer=tokenizer)
result = training_data.tokenize(
tokenizer=tokenizer,
arrangement=arrangement,
)
arrangement 只接受 arrange() 的直接输出,不接受 result.arrangement 这类已经附加
token slices 的派生产物。SDK 会 fail-closed 校验 TrainingData 语义 SHA-256、tokenizer
target/完整 fingerprint、tool serializer、Arrangement 载荷 SHA-256、phase 和 Layer1
validation report;任一错配都拒绝。省略 arrangement 时,默认行为与原 API 完全一致。
Tokenizer target:O5 和 O45_FC 是当前 active line;O45 仅作为 deprecated shim 保留。两者基础词表和 token id 不可互换,调用方必须显式选 target:
from minicpm_o5_sdk import O5TokenizerID
result = training_data.tokenize(tokenizer_id=O5TokenizerID.O45_FC)
推理代码指导示例
如果你要在推理代码里拼 system/tool prefill、解析 tool_call、写回 tool_response,
可参考源码仓库中的 examples/inference_runtime_guide.ipynb;该 notebook 不随 wheel
打包。
用户可见流式文本必须通过 SDK ordinary text decode stream 增量解码,不能逐
token 调用 decode_ordinary([token_id]):
from minicpm_o5_sdk import O5TokenizerID, load_builtin_tokenizer
tokenizer = load_builtin_tokenizer(O5TokenizerID.O5)
stream = tokenizer.create_ordinary_text_decode_stream()
for token_id in generated_ordinary_token_ids:
text_delta = stream.step(token_id)
if text_delta is not None:
emit_text_delta(text_delta)
每条连续文本流使用独立 stream;control token 不进入 stream。完整接入边界见
docs/engineering-practices/runtime-integration.md。
Token 查表与资料卡
如果你要确认当前 tokenizer target 下某个 token 的 id、语义 key、track、loss
或 hf_added_special,可参考源码仓库中的 examples/token_lookup_guide.ipynb;该
notebook 不随 wheel 打包。
它演示:
tok.token_to_id("<|speak|>")
tok.id_to_token(248103)
tok.tokens_to_ids(["<ai_spoken_slot>", "<|speak|>"])
tok.ids_to_tokens([248159, 248103])
tok.token_info("<tool_call>")
tok.list_special_tokens(track="ai_non_spoken")
0.0.5 起,24 个 SDK extension token 已连续排列:O45_FC 为
151748..151771(模型至少 151772 行),O5 为 248144..248167
(模型至少 248168 行)。0.0.5a0/a1 的旧 tokenized artifact 与 checkpoint
不兼容新布局,必须重新 tokenize 或重新训练;SDK 不提供旧 ID remap/alias。
启动 Guidebook(电子书式教程,随 wheel 分发)
python -m minicpm_o5_sdk.visualizers.duplex.guidebook \
--host 0.0.0.0 --port 10035 \
--tokenizer-id o5
推荐并默认使用 --tokenizer-id o5。Guidebook 正文中的 token 数、budget 边界和 Unit
切分均以 O5 tokenizer 为发布基准。o45_fc 使用不同的 base tokenizer/BPE,只用于
兼容性验证;结果仍应 valid,但精确数量不保证与正文一致。
浏览器打开 http://localhost:10035。涵盖:
- Ch1 为什么需要双工
- Ch2 Token 协议
- Ch3 TrainingData 五轨
- Ch5 原子案例(当前 12 个 active case,含真实 TTS+CTC alignment)
启动 Dataset Viewer(任意数据集浏览)
python -m minicpm_o5_sdk.visualizers.duplex.dataset_viewer \
/path/to/your/cases \
--port 10036 --tokenizer-id o5 \
--case-cache-size 100
每个 case 提供四个主视图:Interaction Timeline / Unit Grid / Causal Graph /
Trace Replay。Raw TrainingData、tokenized/provenance 与 issues 仍可在 Raw Sources、
详情和 fail-loud 告警中审计。--tokenizer-id 默认是 o5;如需按 O45_FC token id
查看,改为 --tokenizer-id o45_fc。
协议要点
unit_sec协议自由度:协议层允许任意值,默认 timing/budget profile 只保证 O5 训练规范主线 1s;改用 0.5s 等其它值时必须同时提供匹配的 timing/budget。- start_trigger 时序声明:每个 segment 用
O5StartTrigger(refs=[...])表达启动条件; 多 ref 是 AND 语义。AI target 在离散(unit, phase, position)Gate 上解析,用户媒体 target 保留精确用户时间,input_event 同时保留 raw user time 与 perceived Gate。 - alignment 必填:
ai_spoken.alignment是 schema 强 invariant,且"".join(wi.text for wi in word_intervals) == text严格相等(中文天然字级,英文把空格放进wi.text)。 - ai_spoken 采用 composite turn:同 output unit,或 activation Gate 仍落在当前 waveform output span 内的 source segment,保留 provenance 并顺延合并为一个 turn; prelook 不得跨 source activation Gate 泄漏未来文本。source 独立 encode 与 merged text 整体 encode 必须 BPE 等价,否则 fail-fast。
- 末 output unit 不丢失:即使 prelook 后没有正文,仍生成
<|speak|> <|spoken_turn_eos|> <|spoken_slot_eos|>;只有中间空 unit 使用<|tts_pad|>。 - AI non-spoken 使用 unit-local decode cursor:EOS 占 decode budget;
O5NoBudgetLimit不施加隐藏 token cap,timing 超窗会独立 fail-fast。 - token 模板每 unit 五轨 slot 固定顺序:
user_video → user_audio → input_event → ai_spoken → ai_non_spoken。AI 两个输出 slot 必出现(空时分别走<|listen|>/<|no_action|>)。
开发(贡献者)
PYTHONPATH=omni_agent_research/minicpm_o5_sdk/src \
.venv/minicpmo5/bin/python -m pytest \
omni_agent_research/minicpm_o5_sdk/tests/protocols/duplex -q
# 624 passed(0.0.6a0,2026-07-28)
PYTHONPATH=omni_agent_research/minicpm_o5_sdk/src \
.venv/minicpmo5/bin/python -m mypy \
omni_agent_research/minicpm_o5_sdk/src/minicpm_o5_sdk/
# Arranger 50/100/200/500 segment 扩展性基准
PYTHONPATH=omni_agent_research/minicpm_o5_sdk/src \
.venv/minicpmo5/bin/python \
omni_agent_research/minicpm_o5_sdk/scripts/benchmark_arranger_scalability.py \
--scenario append --sizes 50,100,200,500 --repeats 3
# Trigger 因果链与 spoken dirty-suffix 基准
PYTHONPATH=omni_agent_research/minicpm_o5_sdk/src \
.venv/minicpmo5/bin/python \
omni_agent_research/minicpm_o5_sdk/scripts/benchmark_arranger_scalability.py \
--scenario spoken_reflow --sizes 50,100,200,500 --repeats 3
# 真正受 spoken occupancy 影响的 non-spoken 局部后缀
PYTHONPATH=omni_agent_research/minicpm_o5_sdk/src \
.venv/minicpmo5/bin/python \
omni_agent_research/minicpm_o5_sdk/scripts/benchmark_arranger_scalability.py \
--scenario spoken_dirty_suffix --sizes 50,100,200,500 --repeats 3
.venv/minicpmo5/bin/python -m build \
--wheel --outdir omni_agent_research/minicpm_o5_sdk/dist \
omni_agent_research/minicpm_o5_sdk
Arranger benchmark 的工作量指标、父提交对照与 profiler 结论见 docs/engineering-practices/arranger-performance.md。
发版前检查:docs/before_release_checklist.md。
当前源码与 package metadata 均为 0.0.6a0;该 alpha wheel / sdist 只用于
0.0.6 发布前验证,不作为 PyPI 或飞书公开推荐版本。构建说明见
docs/releases/0.0.6a0.md。
0.0.5 状态路由:docs/0.0.5-milestone.md(仅索引;
实时状态查询 DevMeta Release Manifest / Issue)。
0.0.5 历史 Milestone:
docs/archive/0.0.5-milestone.md(只读,不再是状态源)。
内部 0.0.5 wheel 交接:docs/0.0.5-local-wheel-handoff.md。
飞书 latest 使用入口本地源:docs/feishu/latest_usage_entry.md。
0.0.1 历史里程碑:docs/0.0.1-milestone.md。
变更日志:CHANGELOG.md。
v0.0.1 之后的剩余 follow-up:docs/future-work.md。
当前不支持
- 多模态 event content(音频/图像)序列化:当前 0.0.x 入口抛
NotImplementedError。 - 用户音频 tensor 合成:
O5DuplexTrainingData.build_user_audio_tensor()返回按全局 unit timeline 补 0 后的O5UserAudioTensor,供训练 adapter 从同一 canonical waveform 中切 unit/window。 - 训练 / 推理脚本:分别在 v0.1 / v0.2 引入。
- abort(pending lifecycle):当前 0.0.x 保留
<|non_spoken_abort|>token 和abort_triggerschema,但暂不在 arranger/tokenization 中生产 abort token。
类型提示
wheel 内包含 py.typed,IDE / pyright / mypy 可以识别 SDK 自带的 inline type hints。常用 public API 推荐从顶层导入,例如 from minicpm_o5_sdk import O5DuplexTrainingData, load_case;内部实现路径后续重构时会通过顶层 facade 保持用户侧 import 稳定。
版权与许可
Author / maintainer: Weiyue Sun sunweiyue@modelbest.cn.
Copyright (c) 2026 ModelBest Inc.
本 SDK 使用 MIT License 发布。详见 LICENSE。
Release files for minicpm-o5-sdk 0.0.6a0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| minicpm_o5_sdk-0.0.6a0.tar.gz | 8.4 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| minicpm_o5_sdk-0.0.6a0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.3 MB
Release files / minicpm_o5_sdk-0.0.6a0.tar.gz
| Download URL | minicpm_o5_sdk-0.0.6a0.tar.gz |
|---|---|
| Size | 8.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a296bf3f68872e58b12da03f481992907cd5d564773665b1290c24fa250cefc2
|
|
BLAKE2b-256 checksum How to use checksums |
9c7d4a49e9d5c9465f7d87afb721ca4ecc22e266479d036dafd5c6896a2bf274
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Release files / minicpm_o5_sdk-0.0.6a0-py3-none-any.whl
| Download URL | minicpm_o5_sdk-0.0.6a0-py3-none-any.whl |
|---|---|
| Size | 8.8 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f5ad5399871ec3fafc84acf50af189f5418c3407f66435922e270882e6252780
|
|
BLAKE2b-256 checksum How to use checksums |
ecea981a8c174f0aed68937fa8ff1e945049f3e1ced76e90c65d1e704241e9b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|