Rendering
Rendering 把一组 message 转换成 model 能消费的 token 序列。它和 HuggingFace 的 chat template 类似,但 MinT 的 renderer 覆盖完整训练生命周期:监督学习、强化学习和部署。Renderer 处于两层之间 —— 上层是结构化的对话数据,底层是 model 实际看到的 token。
Concept
Renderer 在两类数据之间转换:结构化的 message 字典(带 user / assistant / system 等 role)和扁平的 token 序列。SFT 阶段用 build_supervised_example() 把 prompt token(不计入 loss)和 completion token(model 学习的部分)分开。RL 和采样阶段用 build_generation_prompt() 构造 prompt,再用 parse_response() 把 model 采样出来的 token 解码回 message。
Renderer 是按 model 家族区分的:Qwen3、Llama 3、DeepSeek V3 等各自有自己的特殊 token 和格式约定。MinT 自带主要家族的 renderer,每一个都会返回正确的 chat template:
Messages(list of dict)--> Renderer --> Token IDs(list of int)
+ loss masks(用于 SFT)
+ stop tokens(用于采样)Pattern
下面是渲染一段对话的标准写法:
import mint
from mint import types
# 初始化 renderer 和 tokenizer
service_client = mint.ServiceClient()
training_client = service_client.create_lora_training_client(
base_model="Qwen/Qwen3-0.6B",
rank=16,
)
tokenizer = training_client.get_tokenizer()
renderer = mint.renderers.get_renderer("qwen3", tokenizer)
# 构造对话
messages = [
{"role": "system", "content": "简洁回答;每条回复最多一句话"},
{"role": "user", "content": "最长寿的啮齿动物是什么?"},
{"role": "assistant", "content": "裸鼹鼠,可以活超过 30 年。"},
{"role": "user", "content": "它们为什么活得这么长?"},
{
"role": "assistant",
"content": "它们进化出了多种保护机制,包括能抑制癌症的特殊透明质酸、稳定性极高的蛋白质,以及高效的 DNA 修复系统。",
},
]
# SFT:得到 token 和 loss weights
model_input, weights = renderer.build_supervised_example(messages)
# 采样:构造一个让 model 续写的 prompt
prompt = renderer.build_generation_prompt(messages[:-1]) # 不包括最后一条 assistant 消息
stop_sequences = renderer.get_stop_sequences() # 采样何时停止
# 把采样到的 token 解码回 message
sampled_tokens = [45, 7741, 34651, 31410] # 实际场景里是 model.sample 的输出
message, success = renderer.parse_response(sampled_tokens)完整源码:https://github.com/MindLab-Research/mint-quickstart/blob/main/concepts/rendering.py
API Surface
| 方法 | 用途 | 返回 |
|---|---|---|
build_supervised_example(messages, train_on_what) | 把 message 转成 SFT 用的 token + loss weights | (ModelInput, weights_array) |
build_generation_prompt(messages) | 把 message 转成 model 续写用的 prompt | ModelInput |
get_stop_sequences() | 表示生成结束的 token | list[int | str] |
parse_response(tokens) | 把采样到的 token 还原成 message | (dict, bool),bool 是成功标志 |
Renderer 列表(用 get_renderer(name, tokenizer) 取)
"qwen3"— Qwen3(默认启用 thinking)"qwen3_disable_thinking"— Qwen3(关闭 thinking)"llama3"— Llama 3"deepseekv3"— DeepSeek V3(non-thinking)"deepseekv3_thinking"— DeepSeek V3(thinking 模式)"nemotron3"— NVIDIA Nemotron 3"kimi_k2"— Kimi K2
Vision renderer(用于 Qwen3-VL 这类 VLM):
from mint.image_processing_utils import get_image_processor
image_processor = get_image_processor("Qwen/Qwen3-VL-235B-A22B-Instruct")
renderer = mint.renderers.get_renderer("qwen3_vl_instruct", tokenizer, image_processor=image_processor)Caveats & Pitfalls
- Renderer 选错家族:调
get_renderer()时务必传对应 model 家族的名字。把 llama3 renderer 用在 Qwen3 的 token 上,会拼出错误的特殊 token。 - Vision 编码:VL model 同时需要 tokenizer 和 image processor。缺 image processor 会让视觉输入的 shape 对不上。
- Loss 掩码:
build_supervised_example()默认只在最后一条 assistant 消息上算 loss。要在所有 assistant 回合上训练,传train_on_what=TrainOnWhat.ALL_ASSISTANT_MESSAGES。 - Stop token:
get_stop_sequences()返回的 token ID 是 model 家族特定的。采样时务必传给SamplingParams(stop=...)。 - 自定义格式:清单里没有的 model 家族,训练前用
register_renderer()注册自己的 renderer。不注册的话会悄悄用错特殊 token,不报错也不正确。