Skip to main content

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
# 543 passed(2026-07-26)

PYTHONPATH=omni_agent_research/minicpm_o5_sdk/src \
  .venv/minicpmo5/bin/python -m mypy \
  omni_agent_research/minicpm_o5_sdk/src/minicpm_o5_sdk/

.venv/minicpmo5/bin/python -m build \
  --wheel --outdir omni_agent_research/minicpm_o5_sdk/dist \
  omni_agent_research/minicpm_o5_sdk

发版前检查:docs/before_release_checklist.md。 当前源码与 package metadata 均为 0.0.5;本地 wheel 只用于内部验证,尚未上传 PyPI。最近正式版 0.0.4 发布说明: docs/releases/0.0.4.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_trigger schema,但暂不在 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.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for minicpm-o5-sdk 0.0.5
File Size Uploaded
minicpm_o5_sdk-0.0.5.tar.gz 8.4 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for minicpm-o5-sdk 0.0.5
File Interpreter ABI Platform
minicpm_o5_sdk-0.0.5-py3-none-any.whl Python 3 none any Details

Total release size: 21.3 MB

Release files / minicpm_o5_sdk-0.0.5.tar.gz

Download URL minicpm_o5_sdk-0.0.5.tar.gz
Size 8.4 MB
Tags Source
SHA-256 checksum
How to use checksums
d5b2ca405915179d517b3ca46c4fb6d26f10f924fc8bc29332c2b1993205e563
BLAKE2b-256 checksum
How to use checksums
0309be27327a6b602e491478c74f9edb1c53aa8263b956ad5c16b16e545e2718
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.5-py3-none-any.whl

Download URL minicpm_o5_sdk-0.0.5-py3-none-any.whl
Size 12.9 MB
Tags Python 3
SHA-256 checksum
How to use checksums
e4eac03d23357dafff768fd28ab221d104739dc602afc40dc9154825929bfd4a
BLAKE2b-256 checksum
How to use checksums
e520be6046558233eb81a9e0f38ce2f1e52bb207d4a097b95dba9955e5938353
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page