【免费下载链接】Kimi-K2-Thinking-BF16
Kimi-K2-Thinking-BF16 是 Moonshot AI 开源推理大模型Kimi K2 Thinking的 BF16 权重镜像(1T 总参 / 32B 激活、256K 上下文)。仓库里的 chat_template.jinja 聊天模板只有 96 行,却决定了模型如何"思考"与"调用工具"。本文逐行拆解它的思考块(think block)与工具调用区块设计,帮你一次看懂 prompt 的拼装逻辑。
一、先看全貌:96 行模板如何分工
整个模板由3 个 Jinja 宏 + 1 段主流程组成,像流水线一样把messages数组逐条渲染成特殊 token:
| 区块 | 行号 | 职责 |
|---|---|---|
render_content宏 | L1-L14 | 统一渲染文本 / 图片内容 |
set_roles宏 | L16-L25 | 把角色映射成<|im_user|>等特殊 token |
render_toolcalls宏 | L28-L35 | 拼装工具调用区块 |
| 消息切分主流程 | L38-L49 | 找出"最后一个无工具调用的 assistant 消息",据此切分历史/后缀 |
| 历史 + 后缀双循环 | L55-L91 | 分别渲染,保留后缀的思考块 |
| 生成提示 | L94-L96 | 需要时追加 assistant 起始 token |
理解这套模板前,先认识两个关键文件:
- 特殊 token 清单:tokenizer_config.json —— 模板里出现的
<|im_user|>、<|think|>等都来自这里。 - 分词器实现:tokenization_kimi.py —— 基于 tiktoken 的
TikTokenTokenizer,词表见 tiktoken.model。
💡 一句话总结:历史消息抹掉思考、后缀消息保留思考,这是 K2 Thinking "深度推理 + 稳定工具调用"的底层钥匙。下面逐块拆解。
二、render_content 宏:文本与图片的统一渲染
{%- macro render_content(msg) -%} {%- set c = msg.get('content') -%} {%- if c is string -%} {{ c }} {%- elif c is not none -%} {% for content in c -%} {% if content['type'] == 'image' ... -%} <|media_start|>image<|media_content|><|media_pad|><|media_end|> {% else -%} {{ content['text'] }} {%- endif -%} {%- endfor -%} {%- endif -%} {%- endmacro -%}- 纯字符串:直接输出,最常见场景。
- 多模态列表:遍历
content数组,遇到image类型就输出一串图片占位 token(<|media_start|>image<|media_content|><|media_pad|><|media_end|>),文本项则原样输出content['text']。
这解释了 README.md 里"content 可以是 list"的写法——模板天然兼容多模态消息,无需额外处理。
三、set_roles 宏:角色到特殊 token 的映射
{%- macro set_roles(message) -%} {%- set role_name = message.get('name') or message['role'] -%} {%- if message['role'] == 'user' -%} <|im_user|>{{role_name}}<|im_middle|> {%- elif message['role'] == 'assistant' -%} <|im_assistant|>{{role_name}}<|im_middle|> {%- else -%} <|im_system|>{{role_name}}<|im_middle|> {%- endif -%} {%- endmacro -%}设计要点:
role_name优先取name字段,否则回退到role,让"带名字的多智能体"对话也能正确渲染。<|im_middle|>是分隔符:角色标签 + 名字 + <|im_middle|>构成消息头,其后才是正文。这三个 token(<|im_user|>、<|im_assistant|>、<|im_system|>、<|im_middle|>)都在 tokenizer_config.json 里注册为独立 token,因此不会被分词器切碎,模型能精准识别消息边界。
四、render_toolcalls 宏:工具调用区块的结构
{%- macro render_toolcalls(message) -%} <|tool_calls_section_begin|> {%- for tool_call in message['tool_calls'] -%} <|tool_call_begin|>{{ tool_call['id'] }}<|tool_call_argument_begin|>{{ 参数 }}<|tool_call_end|> {%- endfor -%} <|tool_calls_section_end|> {%- endmacro -%}它用四层特殊 token把每次函数调用框成结构化区块:
| Token | 作用 |
|---|---|
<\|tool_calls_section_begin\|>/end | 包裹"一次回复里的全部工具调用" |
<\|tool_call_begin\|> | 标记单条调用的开始,后接调用id |
<\|tool_call_argument_begin\|> | 标记参数起点,参数以 JSON 输出 |
<\|tool_call_end\|> | 单条调用结束 |
参数渲染很贴心:若arguments已是字符串就直接输出,否则用tojson序列化(见 L32),保证两种输入格式都能正确落盘。这套结构对应 README.md 里的"调用天气工具"示例——模型自主决定何时、以什么参数发起get_weather调用。
五、核心亮点:history 与 suffix 的双段渲染
这是全模板最精妙的部分,也是标题里"思考块设计"的关键。
第一步:定位"最后一个无工具调用的 assistant 消息"
{%- set ns = namespace(last_non_tool_call_assistant_msg=-1) -%} {%- for idx in range(messages|length-1, -1, -1) -%} {%- if messages[idx]['role'] == 'assistant' and not messages[idx].get('tool_calls') -%} {%- set ns.last_non_tool_call_assistant_msg = idx -%} {%- break -%} {%- endif -%} {%- endfor -%}注意它用了 Jinja 的namespace对象——因为普通set在循环里无法跨迭代修改值。代码从后往前遍历,找到第一个"是 assistant 且没有tool_calls"的消息下标。
第二步:以此为界切分
{%- set hist_msgs = messages[:ns.last_non_tool_call_assistant_msg+1] -%} {%- set suffix_msgs = messages[ns.last_non_tool_call_assistant_msg+1:] -%}第三步:两段循环,区别对待思考块
- 历史段
hist_msgs(L55-L73):assistant 消息渲染成<think></think>{{内容}}——思考块被清空。 - 后缀段
suffix_msgs(L75-L91):assistant 消息渲染成<think>{{reasoning_content}}</think>{{内容}}——真实思考内容被保留。
{# 后缀段:保留思考 #} {%- set rc = message.get('reasoning_content', '') -%} <think>{{rc}}</think>{{render_content(message)}}🧠为什么这么设计?推理模型在长对话里会产生海量思考 token。历史轮次的思考对当前决策价值有限,清空它能显著节省上下文(256K 窗口尤为宝贵);而最近几轮(后缀)的思考必须保留,否则模型"丢失思路"。这种"旧思考丢弃、新思考保留"的分级策略,正是 K2 Thinking 能稳定跑完200–300 次连续工具调用而不跑偏的模板层保障(见 README.md 的"Stable Long-Horizon Agency")。
此外,tool角色的消息被渲染成## Return of {tool_call_id}加结果正文(L67 / L85),用tool_call_id把"返回结果"与"发起调用"一一对应,让模型清楚哪次调用拿到了什么数据。
六、system prompt 默认注入与工具声明
{%- if tools -%} <|im_system|>tool_declare<|im_middle|>{{ tools | tojson(separators=(',', ':')) }} {%- endif -%} {%- for message in hist_msgs -%} {%- if loop.first and messages[0]['role'] != 'system' -%} <|im_system|>system<|im_middle|>You are Kimi, an AI assistant created by Moonshot AI. {%- endif -%}两个细节值得注意:
- 工具声明:当请求传入
tools,模板会在最前面插入一条 system 消息,用tool_declare作为名字,内容是紧凑 JSON(separators=(',', ':')去掉多余空格,省 token)。 - 默认 system 兜底:若第一条消息不是
system,模板自动补一句官方默认身份"你是 Kimi,Moonshot AI 打造的 AI 助手"。这与 README.md 的提示一致——"无需特殊指令时,上面这句 system prompt 是个好默认值"。
七、add_generation_prompt:为下一轮生成开门
{%- if add_generation_prompt -%} <|im_assistant|>assistant<|im_middle|> {%- endif -%}这是 Hugging Face 聊天模板的通用约定:当add_generation_prompt=True,模板末尾追加 assistant 起始 token,相当于告诉模型"轮到你了,请开始输出",模型随即从assistant头开始续写(思考块或正文)。推理引擎(vLLM/SGLang)在预填充阶段通常靠它触发解码。
八、部署与调用要点:温度、reasoning_content 与引擎
理解了模板,调用时牢记几点即可:
- 温度:官方推荐
temperature = 1.0(见 README.md)。 - 两个输出字段:
message.content(正文)与message.reasoning_content(思考块内容)分开返回,对应模板里的content与reasoning_content两个来源。 - 工具循环:
finish_reason == "tool_calls"时执行工具、把role: "tool"结果追加回messages再请求,直到得到正文为止(完整流程见 README.md)。 - 推荐引擎:vLLM、SGLang、KTransformers(README.md)。模板中的特殊 token 解析依赖引擎对 K2 原生工具解析逻辑的支持。
模型整体规格与生成参数分别在 config.json(deepseek_v3架构、384 专家、YARN 262144 上下文)与 generation_config.json 中定义;架构配置类为 configuration_deepseek.py 的DeepseekV3Config,527 个分片权重由 model.safetensors.index.json 索引。
九、关键文件速查表
| 文件 | 作用 |
|---|---|
| chat_template.jinja | 本文主角:对话 → prompt 的渲染模板 |
| tokenizer_config.json | 特殊 token(<\|im_*\|>、<\|tool_*\|>、<\|think\|>)注册表 |
| tokenization_kimi.py | 基于 tiktoken 的分词器实现 |
| config.json | MoE / MLA / YARN 等架构超参 |
| generation_config.json | max_length: 262144、EOS 等生成参数 |
| README.md | 模型介绍、调用示例、部署指南 |
| configuration_deepseek.py | DeepseekV3Config配置类 |
小结
chat_template.jinja 用 96 行代码完成了三件大事:统一多模态渲染、用特殊 token 精准划分角色与工具调用、通过 history/suffix 双段渲染保留新鲜思考并清理历史思考。读懂它,就掌握了 Kimi K2 Thinking 这类"深度推理 + 工具编排"模型的 prompt 骨架,也能为你自研推理模型的聊天模板设计提供参考。
【免费下载链接】Kimi-K2-Thinking-BF16
相关推荐
chat_template.jinja揭秘:Kimi-K2-Thinking-NVFP4如何实现深度思考链与工具调用
chat_template.jinja揭秘:Kimi K2 Thinking NVFP4如何实现深度思考链与工具调用 Kimi K2 Thinking NVFP
深入Kimi-K2-Thinking-Pruning对话模板:chat_template.jinja中thinking标签与工具声明的设计原理
深入Kimi K2 Thinking Pruning对话模板:chat_template.jinja中thinking标签与工具声明的设计原理 这篇文章带你深入
大模型推理模型模型量化K2-Horizon-3.7B-4bit 聊天模板全解:chat_template.jinja 中工具调用格式与容错渲染机制
K2 Horizon 3.7B 4bit 聊天模板全解:chat_template.jinja 中工具调用格式与容错渲染机制 本文带你彻底搞懂 K2 Horiz
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考