# Migration to K2 Horizon

This page shows how to move from a K2 V2 model to K2 Horizon, including the differences in the context window, tool-format settings, and multi-turn conversation state.

## What changes

| Area | Required change |
| --- | --- |
| Model name | Replace `MBZUAI-IFM/K2-V2-Instruct` or `MBZUAI-IFM/K2-Think-V2` with `IFM/K2-Horizon-375B-A23B`. |
| Context window | Grows from 128K to 512K tokens. |
| Conversation state | Assistant turns now carry a `reasoning_content` field that must be replayed verbatim. See below. |
| Custom function calling | Set `tool_presentation_format` and `tool_call_format` to `"xml"`; assistant tool turns keep both `tool_calls` and `reasoning`. |
| Sampling parameters | Recommended: `temperature` 1.0 and `top_p` 0.95 for K2 Horizon. |
| Token budget | Replayed reasoning counts as prompt tokens, so long threads consume the daily cap faster than the visible transcript suggests. |

## Multi-turn conversations

K2 Horizon is stateless, like K2 V2: each request carries the full history. The change is what an assistant turn contains. K2 Horizon returns `reasoning_content` alongside `content`, and both must be appended back into `messages` exactly as returned. An empty string `""` is a valid value — keep it rather than dropping the field or sending `null`. Code that rebuilt history from `content` alone will still run, but drops the model's reasoning context between turns.

```
# K2 V2 — content only
messages.append({"role": "assistant", "content": msg.content})

# K2 Horizon — replay reasoning too
msg = resp.choices[0].message
messages.append({
    "role": "assistant",
    "content": msg.content,
    "reasoning_content": msg.reasoning_content,   # keep "" as-is
})
```

Streaming follows the same rule: reasoning and content arrive as separate deltas, so buffer each on its own and append the finished turn when the stream ends. Full patterns, including tool loops, are on [Multi-turn conversations](https://docs.ifm.ai/docs/multi-turn.md).

## Context window

The ceiling moves from 128K to 512K tokens. Existing requests are unaffected, and client-side history trimming written against the old limit can usually be loosened or removed. Per-size context is listed on [K2 Horizon](https://docs.ifm.ai/docs/introduction.md).

## Custom function calling

Existing OpenAI function definitions carry over unchanged. What is new is the two format parameters K2 Horizon adds — set both to `"xml"`, documented on [Custom function calling](https://docs.ifm.ai/docs/custom-function-calling.md).

```
resp = client.chat.completions.create(
    model=os.environ["IFM_MODEL"],
    messages=messages,
    tools=tools,
    extra_body={
        "tool_presentation_format": "xml",
        "tool_call_format": "xml",
    },
)
```

Responses keep the usual OpenAI shape — `tool_calls` with `finish_reason: "tool_calls"` — so parsing code does not change.

## Sampling parameters

Recommended values differ from K2 V2 — the table above lists them. Requests that pass `temperature` and `top_p` explicitly are unaffected; requests that omit them may sample differently, so re-check any output that depended on the K2 V2 behavior.

## Before you switch

- Move the model name into an environment variable so the cutover is a config change, not a code change.
- Re-check any prompt that depended on K2 V2 phrasing — K2 Horizon reasons before answering and may need less instruction scaffolding.
- Set both tool-format parameters to `"xml"` before benchmarking agentic workloads.
- Log `usage` per call during the first week to size the new token profile.
- Retirement dates for the K2 V2 models are on [Deprecation](https://docs.ifm.ai/docs/deprecation.md).

_Last updated: September 2, 2026_
