← K3 overview

Kimi K3 Quickstart

This guide summarises the official Kimi K3 quickstart so you can get kimi-k3 running fast. The API is OpenAI-compatible — if you already use the OpenAI SDK, you only need to change the base URL, key and model name. All credit for the underlying content goes to the official Kimi documentation; see the references at the end.

1. Get started

Grab an API key from the Kimi platform (there is also a hosted playground if you want to try the model without code). The examples require Python 3.9+ and the OpenAI SDK. Install the SDK and initialise the client once — later examples reuse client.

Install
python3 -m pip install --upgrade 'openai>=1.0'
Initialise the client
import os

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["MOONSHOT_API_KEY"],
    base_url="https://api.moonshot.ai/v1",
)

2. Basic call

Python
completion = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Introduce Kimi K3 in one sentence."}],
)

print(completion.choices[0].message.content)
cURL
curl https://api.moonshot.ai/v1/chat/completions \
  --header "Authorization: Bearer $MOONSHOT_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "kimi-k3",
    "messages": [{"role": "user", "content": "Introduce Kimi K3 in one sentence."}]
  }'

3. Thinking effort

K3 always has thinking mode enabled, and you configure it with the top-level reasoning_effort field. Do not use the K2.x thinking parameter. Thinking effort currently supports only the max level (the default); more levels are coming.

completion = client.chat.completions.create(
    model="kimi-k3",
    reasoning_effort="max",
    messages=[{"role": "user", "content": "Prove that the square root of 2 is irrational."}],
)

print(completion.choices[0].message.content)
For multi-turn conversations and tool calls, add the complete assistant message returned by the API to the next request — do not keep only content.

4. Streaming

Streaming responses provide separate reasoning_content and final-answer content deltas.

stream = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Explain why the sky is blue."}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta
    reasoning = getattr(delta, "reasoning_content", None)
    if reasoning:
        print(reasoning, end="", flush=True)
    if delta.content:
        print(delta.content, end="", flush=True)

5. Vision input

For vision messages, content must be an array of objects, not a serialized string. Public image URLs are not supported — use base64 or an ms://<file-id> upload.

Local image
import base64
from pathlib import Path

image_data: str = base64.b64encode(Path("image.png").read_bytes()).decode()
completion = client.chat.completions.create(
    model="kimi-k3",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/png;base64,{image_data}"},
                },
                {"type": "text", "text": "Describe this image."},
            ],
        }
    ],
)

print(completion.choices[0].message.content)
Video file
from pathlib import Path

video = client.files.create(file=Path("video.mp4"), purpose="video")
try:
    completion = client.chat.completions.create(
        model="kimi-k3",
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "video_url",
                        "video_url": {"url": f"ms://{video.id}"},
                    },
                    {"type": "text", "text": "Summarize this video."},
                ],
            }
        ],
    )
    print(completion.choices[0].message.content)
finally:
    client.files.delete(video.id)

6. Structured output

Use json_schema with strict: true to constrain the final message.content. Parse only that field — not reasoning_content.

import json

completion = client.chat.completions.create(
    model="kimi-k3",
    messages=[
        {"role": "user", "content": "Lin is 28 years old. Extract the name and age."}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                },
                "required": ["name", "age"],
                "additionalProperties": False,
            },
        },
    },
)

person: dict[str, object] = json.loads(
    completion.choices[0].message.content or "{}"
)
print(person)

7. Partial mode

Add an assistant message with partial=True at the end of messages to continue from a text prefix. Prepend that prefix when displaying the final result.

prefix: str = "Conclusion: "
completion = client.chat.completions.create(
    model="kimi-k3",
    messages=[
        {"role": "user", "content": "In one sentence, explain why API compatibility matters."},
        {"role": "assistant", "content": prefix, "partial": True},
    ],
)

print(prefix + (completion.choices[0].message.content or ""))

8. Custom tools and tool_choice

Use tool_choice="required" on the first turn to require at least one tool call. After executing every call, return the complete assistant message and append one tool result with the matching tool_call_id for each call.

Minimal weather agent loop
import json
from typing import Any

tools: list[dict[str, Any]] = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the weather for a city",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
            },
        },
    }
]
messages: list[Any] = [
    {"role": "user", "content": "What is the weather in San Francisco today?"}
]

first = client.chat.completions.create(
    model="kimi-k3",
    messages=messages,
    tools=tools,
    tool_choice="required",
)
assistant_message = first.choices[0].message
messages.append(assistant_message)

for tool_call in assistant_message.tool_calls or []:
    arguments: dict[str, str] = json.loads(tool_call.function.arguments)
    result: str = json.dumps(
        {"city": arguments["city"], "weather": "sunny", "temperature_c": 24}
    )
    messages.append(
        {"role": "tool", "tool_call_id": tool_call.id, "content": result}
    )

final = client.chat.completions.create(
    model="kimi-k3",
    messages=messages,
    tools=tools,
)
print(final.choices[0].message.content)

9. Dynamic tool loading

Place a complete tool definition in a system message without content. The tool becomes available from that message onward.

from typing import Any

dynamic_messages: list[dict[str, Any]] = [
    {"role": "user", "content": "Calculate 23 times 47."},
    {
        "role": "system",
        "tools": [
            {
                "type": "function",
                "function": {
                    "name": "calculate",
                    "description": "Evaluate an arithmetic expression",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "expression": {
                                "type": "string",
                                "description": "The arithmetic expression to evaluate",
                            }
                        },
                        "required": ["expression"],
                    },
                },
            }
        ],
    },
]
completion = client.chat.completions.create(
    model="kimi-k3",
    messages=dynamic_messages,
)

print(completion.choices[0].message.tool_calls)

10. 1M context and automatic caching

Context caching is automatic for regular model requests — no cache ID, TTL or extra parameter is required. Keep the long prefix unchanged so later requests can automatically attempt a cache hit.

from pathlib import Path

knowledge: str = Path("knowledge-base.md").read_text(encoding="utf-8")

for question in ["Summarize the key conclusions.", "List three implementation risks."]:
    completion = client.chat.completions.create(
        model="kimi-k3",
        messages=[
            {"role": "system", "content": knowledge},
            {"role": "user", "content": question},
        ],
    )
    print(completion.choices[0].message.content)

11. Official tools

Official tools are integrated through Formula:

  1. Fetch tool definitions from the Formula /tools endpoint.
  2. Add those definitions to the Chat Completions tools field.
  3. When the model returns tool_calls, submit each function name and arguments to the Formula /fibers endpoint.
  4. Add the complete assistant message and Fiber output as the corresponding tool message.
  5. Call Chat Completions again until the model returns a final answer.
Web search is being updated and is not recommended for production workflows in the near term.

12. Important limits

13. FAQ and pricing

How is Kimi K3 billed?

Kimi K3 offers a 1M-token context and uses flat pay-as-you-go pricing — there is no tiering by context length. Input (with separate rates for cache hits and misses) and output are billed at uniform per-token prices. See the Kimi K3 pricing page for current rates.

References

  1. Kimi API Platform — Kimi K3 Quickstart (primary source for this page): https://platform.kimi.ai/docs/guide/kimi-k3-quickstart
    Retrieved 17 July 2026. Code examples reproduced for educational purposes with attribution.
  2. Kimi API Platform — playground and API keys: https://platform.kimi.ai/
  3. Kimi API Platform — model pricing: https://platform.kimi.ai/docs/pricing