How to Use the Mistral Large 4 API: Reasoning Effort, Tools, JSON Output, Caching and Batch

Mistral Large 4 is Mistral’s biggest model so far, and you can call it today through the Mistral API even though the open weights aren’t out yet. If you build agents, coding tools or document pipelines, this guide gets you from an API key to a working request in a few minutes, then walks through the parameters that matter most for this model: reasoning_effort, tool calling, schema-locked JSON, prompt caching and the Batch API. Every snippet below comes from Mistral’s official documentation, and we checked the Python method signatures against the current mistralai SDK (3.3.0).

Key facts (from Mistral’s launch post and model page, checked October 22, 2026):

  • Status: public preview since October 6, 2026. Mistral says the weights will be released “by the end of the month.”
  • Size: granular Mixture-of-Experts, 1.05T total parameters, 52B active, plus a 1.6B vision encoder.
  • Context window: 1M tokens.
  • API names: mistral-large-4 and mistral-large-4-0 (version 26.10).
  • Price (USD per 1M tokens): $1.36 input, $0.14 cached input, $4.18 output.
  • Supported features: chat completions, structured outputs, function calling, document Q&A, prefix, batching, and Agents & Conversations with built-in tools.

New to the site? The 7minai homepage lists our other step-by-step model guides, including Mistral’s much smaller open models like the Timestral forecasting models and the Shieldstral moderation model.

What Mistral Large 4 is, and when to pick it

Mistral calls ML4 “our largest and most capable model to date.” It was trained from scratch on 3,800 NVIDIA Grace Blackwell GPUs in Mistral’s own European datacenters, and the preview API runs on that same infrastructure. Mistral says a significant share of the training data covered more than 160 languages, including every official EU language.

The launch post focuses on four areas.

Agentic coding. Mistral reports 61.7% on DeepSWE v1.1, 59.4% on SWE-Atlas-QnA and 28.3% on Terminal-Bench 4, for a combined Coding Agent Index score of 49.8%. In a blind human evaluation run with Surge AI, professional annotators scored ML4 Preview 3.74 out of 5 for coding quality. That put it second of five models, behind only Claude Opus 5 (4.22).

General agents. On AutomationBench, 657 business workflows across apps like Gmail, Google Sheets, Slack and Salesforce, Mistral reports 59.9%.

Cybersecurity. Mistral says ML4 solves 93% of the 40 Cybench challenges and scores 82% on a test that asks the model to reproduce and then patch a real open-source vulnerability. It also reports that ML4 resists 93.3% of attacks on Lakera’s B3 prompt-injection benchmark.

Vision and documents. The model is natively multimodal, and Mistral highlights visual grounding, charts and PDF retrieval.

All of these numbers are Mistral’s own published results for a preview model. Treat them as a reason to run your own evals, not as a guarantee. Mistral itself says the model “continues to improve rapidly as we refine it.”

Pick ML4 when you need long context (1M tokens), strong tool use, or a model you’ll later be able to self-host once the weights ship. For short, cheap, high-volume calls, a smaller model is usually the better deal. For example, Mistral Medium 3.5 lists at $1.5 input and $7.5 output per 1M tokens, as we covered in our Vibe remote agents news post.

Step 1: Create an API key

Mistral’s first-request quickstart lays out the steps:

  1. Open Studio › API keys in the Mistral console.
  2. Click Create new key, give it a name (for example quickstart) and click Create.
  3. Copy the key right away. It’s shown only once, so if you lose it you have to generate a new one.

Then put the key in an environment variable so it never ends up in your code:

# macOS / Linux
export MISTRAL_API_KEY="your_api_key_here"

On Windows PowerShell, use $env:MISTRAL_API_KEY="your_api_key_here".

The account also needs a payment method. Without one, requests fail with 402 Payment Required (see the troubleshooting table below).

Step 2: Install the SDK

Python:

pip install mistralai

TypeScript / Node:

npm install @mistralai/mistralai

The Python examples in this guide use the current import path, from mistralai.client import Mistral. We installed mistralai 3.3.0 (the latest release on PyPI when we checked) and confirmed that client.chat.complete accepts every parameter used below: reasoning_effort, tools, tool_choice, parallel_tool_calls, response_format, prompt_cache_key and service_tier. If your code still does from mistralai import Mistral and a parameter is rejected, upgrade the package first.

Step 3: Send your first request

This is the example from the Large 4 model page. It uses the mistral-large-4 model name and turns reasoning up to high:

# ml4_quickstart.py
import os
from mistralai.client import Mistral

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

response = client.chat.complete(
    model="mistral-large-4",
    messages=[
        {
            "role": "user",
            "content": "Write a Python function to merge two sorted linked lists into one sorted list.",
        }
    ],
    reasoning_effort="high",
)

print(response.choices[0].message.content)

Run it with python ml4_quickstart.py.

The same request with curl:

curl https://api.mistral.ai/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MISTRAL_API_KEY" \
  -d '{
    "model": "mistral-large-4",
    "messages": [
      {
        "role": "user",
        "content": "Write a Python function to merge two sorted linked lists into one sorted list."
      }
    ],
    "reasoning_effort": "high"
  }'

And in TypeScript:

import { Mistral } from '@mistralai/mistralai';

const client = new Mistral({ apiKey: process.env.MISTRAL_API_KEY });

const response = await client.chat.complete({
  model: 'mistral-large-4',
  messages: [
    {
      role: 'user',
      content: 'Write a Python function to merge two sorted linked lists into one sorted list.',
    },
  ],
  reasoning_effort: 'high',
});

console.log(response.choices[0].message.content);

Which model name should you use? The model page lists two names: mistral-large-4 and mistral-large-4-0. In production, pin the versioned name (mistral-large-4-0) so the model doesn’t change under you. Don’t assume mistral-large-latest points to Large 4. Several of Mistral’s docs pages, including the function calling page, still describe mistral-large-latest as Mistral Large 3.

Step 4: Choose a reasoning effort

reasoning_effort is the most important parameter on this model. Mistral’s reasoning docs say mistral-large-4-0 “supports adjustable reasoning via the reasoning_effort parameter” with no extra configuration.

The Chat Completions API reference accepts these values: "none", "minimal", "low", "medium", "high" and "xhigh". The reasoning guide documents the two ends of that range:

  • "high": the response includes a full thinking chunk before the final answer, and you pay for the extra tokens.
  • "none": the model thinks minimally, the thinking chunk is left out, and message.content is a plain string.

A practical way to choose:

WorkloadStarting point
Classification, extraction, short rewrites"none"
Chat assistants, summaries"low" or "medium"
Agentic coding, multi-step tool use, math"high"
Your hardest offline tasks, where cost matters lesstry "xhigh" and compare

This table is our suggestion, not Mistral’s. Measure quality and output tokens on your own prompts, because reasoning tokens are billed at the $4.18 output rate.

Handle thinking chunks in the response

This is where most first integrations break. With reasoning_effort="high", message.content is a list of chunks, not a string. There are two chunk types:

  • ThinkChunk (type: "thinking") holds the reasoning trace. Its thinking field is itself a list of TextChunk objects.
  • TextChunk (type: "text") holds the final answer.

If you call .strip() or concatenate content as if it were a string, your code will crash. Mistral’s documented parser handles both shapes:

from mistralai.client.models import TextChunk, ThinkChunk

content = response.choices[0].message.content

# reasoning_effort="none" returns a plain string
if isinstance(content, str):
    print(content)
else:
    for chunk in content:
        if isinstance(chunk, ThinkChunk):
            print("--- thinking ---")
            for inner in chunk.thinking:
                if isinstance(inner, TextChunk):
                    print(inner.text)
            print("--- /thinking ---")
        elif isinstance(chunk, TextChunk):
            print(chunk.text)

If you only want the answer, keep the TextChunk branch and skip the thinking trace. Don’t show raw thinking to end users unless you’ve decided that’s appropriate for your product.

Streaming with reasoning

When you stream (client.chat.stream(...)), the docs say delta.content changes shape partway through:

  1. Thinking phase: delta.content is a list containing a ThinkChunk.
  2. Transition: a single list containing both a closing ThinkChunk and the first TextChunk.
  3. Answer phase: delta.content is a plain string.

So your stream handler has to check isinstance(delta, str) on every event and fall back to iterating chunks otherwise. The full streaming example is in the reasoning docs.

Step 5: Call your own functions (tool calling)

The model page lists function calling for both /v1/chat/completions and /v1/conversations. The flow from Mistral’s function calling guide has five steps: you define tools, the user asks, the model returns tool arguments, you run the function, and the model answers using the result.

Define a tool as JSON Schema:

tools = [
    {
        "type": "function",
        "function": {
            "name": "retrieve_payment_status",
            "description": "Get payment status of a transaction",
            "parameters": {
                "type": "object",
                "properties": {
                    "transaction_id": {
                        "type": "string",
                        "description": "The transaction id.",
                    }
                },
                "required": ["transaction_id"],
            },
        },
    }
]

Pass it with the request:

response = client.chat.complete(
    model="mistral-large-4-0",
    messages=messages,
    tools=tools,
    tool_choice="any",          # "auto" (default), "any"/"required", or "none"
    parallel_tool_calls=False,  # default is True
)

Run the function and send its result back as a tool message tied to the call’s ID:

import json

tool_call = response.choices[0].message.tool_calls[0]
function_name = tool_call.function.name
function_params = json.loads(tool_call.function.arguments)
function_result = names_to_functions[function_name](**function_params)

messages.append(response.choices[0].message)
messages.append({
    "role": "tool",
    "name": function_name,
    "content": function_result,
    "tool_call_id": tool_call.id,
})

response = client.chat.complete(model="mistral-large-4-0", messages=messages)

Here names_to_functions is a dict that maps tool names to your Python functions, as in Mistral’s guide.

Three things to get right:

  • Loop until there are no more tool calls. The docs note that the model may follow one tool call with another, so call the model again after each result until it returns a plain answer.
  • Parallel calls are on by default. With parallel_tool_calls=True you can get several tool calls in one message. Answer every one of them, each with its own tool_call_id.
  • tool_choice values: "auto" lets the model decide, "any" or "required" forces at least one tool call, "none" blocks tools, and {"type": "function", "function": {"name": "..."}} forces a specific tool.

Step 6: Get schema-locked JSON output

For extraction jobs, use custom structured outputs. With the Python SDK, define a Pydantic model and call client.chat.parse:

from pydantic import BaseModel

class Book(BaseModel):
    name: str
    authors: list[str]

chat_response = client.chat.parse(
    model="mistral-large-4-0",
    messages=[
        {"role": "system", "content": "Extract the books information."},
        {"role": "user", "content": "I recently read 'To Kill a Mockingbird' by Harper Lee."},
    ],
    response_format=Book,
    max_tokens=256,
    temperature=0,
)

print(chat_response.choices[0].message.content)  # raw JSON string

Mistral’s example uses ministral-8b-latest. We swapped in the Large 4 name because the model page lists structured outputs as supported, but run a quick check on your own account.

If you call the REST API directly, the API reference describes two modes for response_format:

  • { "type": "json_object" } (JSON mode) guarantees valid JSON, but you must also tell the model to produce JSON in a system or user message.
  • { "type": "json_schema" } guarantees the output is JSON that follows the schema you send.

Use schema mode whenever you can. It’s the difference between “valid JSON” and “JSON your code can actually rely on.”

Step 7: Send images and documents

ML4 has a 1.6B-parameter vision encoder, and Mistral highlights charts, technical drawings and PDFs. The vision docs show the message format: content becomes a list that mixes text parts and image_url parts.

messages = [
    {
        "role": "user",
        "content": [
            {"type": "text", "text": "What's in this image?"},
            {"type": "image_url", "image_url": "https://docs.mistral.ai/img/eiffel-tower-paris.jpg"},
        ],
    }
]

chat_response = client.chat.complete(model="mistral-large-4-0", messages=messages)

You can also pass a base64-encoded image instead of a public URL. When we checked, the vision page’s list of “recommended models with vision capabilities” still stopped at Mistral Large 3 (mistral-large-2512) and hadn’t been updated for Large 4. The Large 4 model page does describe it as natively multimodal, so test image input on your account before you build on it.

Step 8: Cut costs with prompt caching

ML4’s cached input price ($0.14 per 1M tokens) is about 10% of the normal input price ($1.36). That matches Mistral’s prompt caching docs, which say cached prompt tokens are billed at 10% of the standard input price. With a 1M-token context window, that matters a lot: an agent that resends a large system prompt, tool list or document on every turn can pay a fraction of the full price for the repeated part.

To make cache hits more likely, set the same prompt_cache_key on requests that share a prefix:

curl https://api.mistral.ai/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MISTRAL_API_KEY" \
  -d '{
    "model": "mistral-large-4-0",
    "prompt_cache_key": "support-session-42",
    "messages": [
      {"role": "system", "content": "You are a support assistant. Answer with concise troubleshooting steps."},
      {"role": "user", "content": "My API request returns a 401 error. What should I check?"}
    ]
  }'

Rules from the docs:

  • Keep the prefix identical. Caching only reuses the beginning of the prompt, so put stable content (system prompt, tool definitions, reference documents) first and the changing user message last.
  • Use a stable ID such as a conversation, session or workflow ID. Don’t put secrets, API keys or sensitive user data in the key.
  • A key isn’t a guarantee. It raises the chance of a hit but doesn’t promise one.
  • 64-token blocks. cached_tokens is always a multiple of 64, and prompts shorter than 64 tokens never hit the cache.
  • Check the result in usage.prompt_tokens_details.cached_tokens. Billable uncached input is prompt_tokens - cached_tokens.

A rough example with list prices: a 100,000-token prompt with a 5,000-token answer costs about 100,000 × $1.36/1M + 5,000 × $4.18/1M ≈ $0.157 without caching. If 90,000 of those prompt tokens come from the cache on the next turn, the input part drops to about 10,000 × $1.36/1M + 90,000 × $0.14/1M ≈ $0.026.

Step 9: Run big offline jobs with the Batch API

For evals, backfills and bulk document processing, the Batch API runs requests asynchronously “at a 50% discount.” Each line of a .jsonl file is one request, with a custom_id and a body in the same shape as a normal chat completion request:

{"custom_id": "0", "body": {"max_tokens": 128, "messages": [{"role": "user", "content": "What is the best French cheese?"}]}}
{"custom_id": "1", "body": {"max_tokens": 512, "temperature": 0.2, "messages": [{"role": "user", "content": "What is the best French wine?"}]}}

Upload the file, create a job, then download the results:

batch_data = client.files.upload(
    file={"file_name": "test.jsonl", "content": open("test.jsonl", "rb")},
    purpose="batch",
)

created_job = client.batch.jobs.create(
    input_files=[batch_data.id],
    model="mistral-large-4-0",
    endpoint="/v1/chat/completions",
    metadata={"job_type": "testing"},
)

retrieved_job = client.batch.jobs.get(job_id=created_job.id)
# when the job has finished:
output_file_stream = client.files.download(file_id=retrieved_job.output_file)
with open("batch_results.jsonl", "wb") as f:
    f.write(output_file_stream.read())

Details from the docs: a batch can hold up to 1M requests, each batch uses one model, and for fewer than 10,000 requests you can skip the file and pass them inline with requests=. Job statuses include QUEUED, RUNNING, SUCCESS, FAILED, TIMEOUT_EXCEEDED, CANCELLATION_REQUESTED and CANCELLED. Mistral’s tier comparison says batch requests are processed over a 24-hour period, so don’t use batch for anything a user is waiting on.

Optional: Priority Tier

If you’re on an enterprise contract, the service_tier parameter controls routing. "auto" uses Priority Tier when your request is eligible and falls back to Standard Tier otherwise, while "standard_only" (the default) never uses Priority Tier. According to the Priority Tier docs, it requires account setup with Mistral and comes with a 99.5% uptime SLA. Standard and Batch have no SLA. Most developers can ignore this.

Troubleshooting

SymptomLikely causeFix
401 UnauthorizedKey missing or wrongRun echo $MISTRAL_API_KEY in the same shell that runs your code. Regenerate the key if you lost it, since it’s shown only once.
402 Payment RequiredNo payment method on the accountAdd one under Admin Panel › Subscriptions › Billing.
429 Too Many RequestsRate limit hitRetry with exponential backoff, and move bulk work to the Batch API.
TypeError / AttributeError on .contentreasoning_effort above "none" returns a list of chunksUse the chunk parser from Step 4.
Unknown parameter reasoning_effort or prompt_cache_keyOld SDK versionRun pip install -U mistralai and use from mistralai.client import Mistral.
cached_tokens is always 0Prefix changes between calls, or the prompt is under 64 tokensMove stable content to the top and keep it byte-for-byte identical. Reuse the same prompt_cache_key.
Model loops on tool callsTool results not appended, or missing tool_call_idAppend the assistant message and one tool message per call, each with the matching tool_call_id.
Outputs changed without a code changeFloating model namePin mistral-large-4-0 instead of an alias.

FAQ

Can I download and self-host Mistral Large 4 today? Not yet. The launch post says the weights will be released “by the end of the month,” and that until then Mistral is red-teaming the model with cybersecurity leaders, vetted partners and state authorities. The model page already links a Hugging Face repo, mistralai/Mistral-Large-4-1T-A52B, but it wasn’t publicly available when we checked on October 22, 2026. Mistral hasn’t published the license terms for the weights yet, so check them before you plan on-prem use.

How much does it cost? $1.36 per 1M input tokens, $0.14 per 1M cached input tokens and $4.18 per 1M output tokens (USD list prices on the model page). Batch jobs are billed at a 50% discount.

How long is the context window? 1M tokens, according to the model page.

Is reasoning_effort required? No. The model page’s example sets it to "high". For simple tasks, "none" returns a plain string and uses fewer tokens.

Does it work with the Agents and Conversations APIs? Yes. The model page lists /v1/agents and /v1/conversations, including built-in tools. On those endpoints, reasoning_effort goes inside the completion_args field.

Will the preview change? Probably. Mistral calls this a public preview and says it “continues to improve rapidly.” Pin the versioned model name and re-run your evals when Mistral ships a new version.

Sources