使用 MiniMax 的 thinking 和 reasoning_split
MiniMax 的接入重点是分别处理当前请求的 thinking 开关、推理内容返回形态,以及工具调用后的完整 assistant 消息。MiniMax M3 使用 thinking.type 控制当前请求是否思考,reasoning_split 只控制 thinking 返回在哪里。
区分 thinking 开关和返回形态
MiniMax M3 支持以下 thinking 设置:
- 省略
thinking时,默认开启 adaptive thinking。 - 设置
thinking: {"type": "adaptive"}时,显式开启 adaptive thinking。 - 设置
thinking: {"type": "disabled"}时,关闭思考并直接回答。
MiniMax M2.x 无法关闭 thinking。对 M2.x 传入 thinking.type: "disabled" 时,不要假设 thinking 已关闭。
reasoning_split 不会开启或关闭 thinking,只改变返回形态:
- 设置
reasoning_split: true时,推理内容和最终回答拆分返回。MiniMax M3 的非流式响应可能只包含reasoning_content;流式响应可能同时包含reasoning_content和reasoning_details增量。应用必须允许任一字段缺失。 - 不启用 split 或设置
reasoning_split: false时,推理内容可能出现在content的原生<think>片段中。
如果不向用户展示推理,请在展示层过滤。需要继续多轮对话或工具调用时,保留服务端返回的完整 assistant 消息,不要从历史消息中删除或改写推理字段。
开启 M3 adaptive thinking 并读取 split 响应
以下 Python 示例显式开启 adaptive thinking 和 split 模式。展示推理内容时,优先读取 reasoning_content,并把 reasoning_details 作为兼容回退,避免同时展示两个字段中的重复内容。
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["API_KEY"],
base_url="https://cloud.infini-ai.com/maas/v1",
)
response = client.chat.completions.create(
model="minimax-m3",
messages=[{"role": "user", "content": "What is 17 * 23? Give only the final answer."}],
max_completion_tokens=512,
extra_body={
"thinking": {"type": "adaptive"},
"reasoning_split": True,
},
)
message = response.choices[0].message
reasoning_content = getattr(message, "reasoning_content", None)
reasoning_details = getattr(message, "reasoning_details", None)
if reasoning_content:
print(reasoning_content)
elif reasoning_details:
print(reasoning_details)
print(message.content)如果 reasoning_details 为空,不要立即判定请求失败。先读取 reasoning_content;如果两个字段都为空,再检查本次请求是否关闭了 thinking、这次回复是否只包含最终答案,以及是否使用了 split 模式。
用 curl 验证 M3 请求体
先用 curl 确认 thinking、reasoning_split 和生成长度字段已经传入。运行前先在当前终端设置 API_KEY 环境变量。以下命令适用于 bash/zsh 等 POSIX 风格 Shell(macOS/Linux、WSL、Git Bash)。如果使用 Windows PowerShell 或 CMD,请按对应 Shell 的语法调整命令。
curl --request POST \
--url "https://cloud.infini-ai.com/maas/v1/chat/completions" \
--header "Accept: application/json, text/event-stream" \
--header "Authorization: Bearer $API_KEY" \
--header "Content-Type: application/json" \
--data-raw '{
"model": "minimax-m3",
"messages": [
{
"role": "user",
"content": "What is 17 * 23? Give only the final answer."
}
],
"thinking": {"type": "adaptive"},
"reasoning_split": true,
"max_completion_tokens": 512
}'终端录制
用 curl 验证 MiniMax reasoning_split
适用于验证 MiniMax 推理拆分字段是否按预期传入。
MiniMax M3 新接入建议使用 max_completion_tokens。不要同时设置 max_tokens 和 max_completion_tokens;如果响应以 finish_reason: "length" 结束,应把结果视为不完整输出,并在模型允许范围内提高上限。
关闭 M3 思考
如果业务请求只需要最终答案,可对 MiniMax M3 设置:
extra_body = {
"thinking": {"type": "disabled"},
"reasoning_split": True,
}此时 reasoning_content、reasoning_details 和 <think> 都可能缺失,这是正常结果。reasoning_split 仍只控制返回形态,不会重新开启 thinking。该关闭方式只适用于 MiniMax M3;不要套用到 MiniMax M2.x。
保留 <think> 内容所在的完整 assistant 消息
未启用 split 时,MiniMax 可能把原生 <think> 内容放在 content 中。此时不要在历史消息里删除 <think> 片段后再回传,因为这会改变模型看到的历史。
assistant_message = response.choices[0].message.model_dump(exclude_none=True)
messages.append(assistant_message)如果需要面向用户隐藏 <think>,应在展示层过滤;不要改写要继续传给模型的历史消息。
工具调用后回传完整 assistant 消息
工具调用流程中,MiniMax M3 的非流式 assistant 消息可能包含 reasoning_content 和 tool_calls;流式重建后的消息还可能同时包含 reasoning_details。不要只挑选其中一个推理字段。回传 assistant 消息时保留服务端实际返回的完整结构,再追加 tool 结果。
以下代码假设 tool_call_response 是已经返回 tool_calls 的第一轮响应:
assistant_message = tool_call_response.choices[0].message.model_dump(exclude_none=True)
messages.append(assistant_message)
messages.append(
{
"role": "tool",
"tool_call_id": assistant_message["tool_calls"][0]["id"],
"content": '{"weather": "Sunny"}',
}
)如果应用框架要求把 SDK 对象转成 dict,请确保 content、tool_calls、reasoning_content、reasoning_details 等扩展字段没有被过滤。字段没有返回时保持缺失,不要补写空字符串或空数组。
按增量处理 reasoning_details
reasoning_details 是对象数组,不是纯字符串。流式响应中,同一 id 和 index 可能分多次返回不同的 text 片段。应用应按到达顺序保留对象,或按到达顺序拼接其中的 text;不要按 index 覆盖前一个片段。
stream = client.chat.completions.create(
model="minimax-m3",
messages=[{"role": "user", "content": "What is 17 * 23? Give only the final answer."}],
max_completion_tokens=512,
stream=True,
extra_body={
"thinking": {"type": "adaptive"},
"reasoning_split": True,
},
)
reasoning_detail_parts = []
for chunk in stream:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
for detail in getattr(delta, "reasoning_details", None) or []:
text = detail.get("text") if isinstance(detail, dict) else getattr(detail, "text", None)
if text:
reasoning_detail_parts.append(text)
reasoning_details_text = "".join(reasoning_detail_parts)展示时可优先使用完整的 reasoning_content,仅在该字段缺失时使用拼接后的 reasoning_details。继续工具调用或多轮对话时,应保留并回传模型实际返回的全部字段,而不是只回传展示用文本。