Kimi K3.1 Pro is a “3T-class” mixture-of-experts model from Moonshot AI, a Chinese lab, launched on October 23, and you cannot download its weights today. Moonshot’s launch post says only that “The full model weights will be released by Nov 4”, and it names no license. What you can do right now is call it through an API at $2 per million input tokens and $10 per million output tokens, with the model id kimi-k3.1-pro.
In this post I cover what is shipped versus promised, whether anybody can run a model this size at home, what benchmarks and critics say (including the paid-promotion allegation), and then the part I care about most as a CTO: calling it with the Anthropic Python SDK, feature by feature, and what breaks when you swap the base URL. Clearly, once: the examples follow Moonshot’s docs, and we did not run them against the live API, because I have no Moonshot key. My verdict: a strong model at a fair price, “open weights” is only a date until November 4, and the Anthropic-compatible endpoint is real but narrower than “compatible” suggests.
What did Moonshot actually release?
Two things, and people mix them up. The older model, Kimi K3, is a real download: its Hugging Face card says 2.8T total parameters, 104B active per token, a 1,048,576-token context, and MXFP4 weights. Kimi K3.1 Pro is “a post-trained version of Kimi K3”, in Moonshot’s own quickstart words, with a Highspeed variant that is 2 to 3 times faster.
The parameter count is where sources disagree. VentureBeat calls it a 3-trillion parameter model. Moonshot says “3T-class” and gives no exact figure. The Artificial Analysis page says 2.8 trillion, which is the K3 number, and lists the model as proprietary because nothing is public. If it is a post-trained K3, 2.8T and 104B active is my guess. I would not print “3T” as a spec until the model card exists.

Prices from Moonshot’s pricing page: K3.1 Pro is $2.00 input, $10.00 output, $0.20 cached input. Highspeed is $4 and $20. K3 is $3 and $15, so the new model is one third cheaper than the one it came from. Context is 1M tokens, and K3.1 Pro unlocks after a $1 top-up.
Two catches. Moonshot says it aims “not to release open weights that would extend the absolute frontier of cyber capability”, and that it removed cyber-related data from both training stages, so the November 4 weights are trimmed on purpose. And the license is unknown. The K3 one is on GitHub and is not MIT: you may use, modify and sell the weights, but if you run a “Model as a Service” business above $20 million in 12-month revenue you need a separate deal, and a product over 100 million monthly users or $20 million monthly revenue must display “Kimi K3”. Internal use, and use through Moonshot’s own products or certified partners, are exempt. I am not a lawyer, and I read it as fine for a startup that embeds a model in features. Same exercise as my Muse Spark license post.
Can you run Kimi K3.1 Pro at home?
No. Here is the arithmetic. The K3 repository on Hugging Face adds up to about 1,561 GB for 2.78T parameters, so roughly 0.56 bytes per parameter, vision encoder included. Scale that to 3T and you need about 1.7 TB just to hold the weights, before any KV cache for a long context. Native MXFP4 is already a 4-bit format, so there is no big squeeze left in the official checkpoint.
The 104B active parameters help with speed, not with memory. All 896 experts have to be somewhere, and each token reads about 58 GB of them (104B times 0.56 bytes). Mettons your memory does 100 GB/s: that caps you under 2 tokens per second, and I made up the bandwidth but not the division. A server with 400 GB/s gets you to around 7, if you own 1.7 TB of RAM, which you do not.
The community answer is aggressive quantization of K3, not K3.1 Pro. Unsloth’s K3 GGUF repo lists these sizes (I summed the files through the Hugging Face API): 466 GB for the smallest 1-bit-class file, 594 GB for IQ1_S, 861 GB for Q2_K_XL, and 1,509 GB for the 4-bit one. Even the smallest wants a 512 GB machine, and nobody has quality numbers for K3.1 Pro quants because the weights do not exist. I looked for r/LocalLLaMA threads, but Reddit returns a 403 to my scripts, so no Reddit quotes here. I would rather say that than paste a summary of a summary.
For a smaller MoE on a gaming GPU, see my post on expert offloading. For this one, “home” means a rented node or the API.
What are people saying about it?
Independent numbers first. Artificial Analysis gives K3.1 Pro an Intelligence Index of 55, fourth of 221 models, behind Opus 5.5 at 58. The same page says it is “notably slow” at 41.4 output tokens per second (188th of 192) and “very verbose”: 150M output tokens to run the index, against a median of 81M, which is 1.85 times more. Average cost per index task is $2.11. Per Latent Space’s roundup, Arena put it 8th in Code Arena WebDev at 1,692 points, up 37 points over K3. Simon Willison called it the first soon-to-be open-weight model to score this close to the frontier.
Moonshot’s own claims, not independent: 65.7% on Terminal-Bench 4.0 against 66.4% for Opus 5.5, and a claim-level hallucination rate down from 23.4% to 8.3% on an internal stress test that Moonshot itself says does not represent daily error rates. The quickstart page still had template placeholders like “[xx.x%]” when I read it, so the docs shipped in a hurry.
Opinions split on the one decision Moonshot made on purpose, removing cyber data. One commenter quoted that passage and answered with one word: “Lame.” Another wrote that they were “glad that at least one Chinese company seems to be listening to AI cybersecurity concerns”. On quality, a third pointed to the AA-Omniscience benchmark, which “puts K3.1 about 6 months behind the frontier”, and said that matched their gut feeling on trickier problems. A fourth said Kimi models often score higher than DeepSeek, Qwen or GLM but perform worse for them, though they had not tried this one. Those are single experiences, and I list them because they are what I would test first.
What is the paid-promotion allegation?
VentureBeat reports that an X user posted screenshots of influencer instructions saying “Please DO NOT put on the paid partnership label”. The document “has not been independently authenticated”, and as of October 25 there was no confirmed Moonshot response. VentureBeat also says the screenshots do not by themselves invalidate the independent benchmarks. I agree. It is a marketing story, and it tells me to trust the benchmark pages more than the launch hype.
How do I call Kimi K3.1 Pro with the Anthropic SDK?
This is the section you can copy. Per Moonshot’s Messages API docs, the base URL is https://api.moonshot.ai/anthropic, the endpoint is POST /anthropic/v1/messages, and the model ids accepted there are kimi-k3.1-pro, kimi-k3.1-pro-highspeed and kimi-k3. I installed anthropic 2.3.0 in a clean virtualenv and checked each snippet with python -m py_compile and the SDK signatures. That proves syntax and parameter names, not Moonshot’s server behaviour.
Setup first. The docs use a Bearer token, so I pass auth_token, not api_key (which sends an x-api-key header the docs never mention).
python -m venv .venv
source .venv/bin/activate
pip install anthropic requests
export MOONSHOT_API_KEY="your-key-here"
unset ANTHROPIC_API_KEY
A basic call with a system prompt. My first sketch printed response.content[0].text. The docs list content blocks in the order thinking, text, tool_use, and K3.1 Pro always reasons, so block zero is probably a thinking block with no .text. I filter by type. The default reasoning effort is max, so I set low here and give a big max_tokens.
import os
from anthropic import Anthropic
client = Anthropic(
auth_token=os.environ["MOONSHOT_API_KEY"],
base_url="https://api.moonshot.ai/anthropic",
)
MODEL = "kimi-k3.1-pro"
def text_of(response):
return "".join(b.text for b in response.content if b.type == "text")
response = client.messages.create(
model=MODEL,
max_tokens=4096,
system="You are a terse assistant for Amazon sellers.",
output_config={"effort": "low"},
messages=[{"role": "user", "content": "In two sentences, what is the buy box?"}],
)
print(text_of(response))
print(response.usage.output_tokens)
Streaming uses the normal SDK helper. Expect a pause first, because the model thinks.
with client.messages.stream(
model=MODEL,
max_tokens=4096,
output_config={"effort": "low"},
messages=[{"role": "user", "content": "Explain MXFP4 in two sentences."}],
) as stream:
for piece in stream.text_stream:
print(piece, end="", flush=True)
How does tool use work on Kimi K3.1 Pro?
Now the tool loop, the reason I wanted to test this at all. The tool is a product lookup, the kind of thing a Trellis-style assistant would call, with fake data. The docs say tool results go back as tool_result blocks matched by tool_use_id, and that thinking blocks must be passed back unchanged with their signature in multi-turn chats. Appending response.content as-is does that.
import json
PRODUCTS = {"B0EXAMPLE01": {"price_usd": 24.99, "units_in_stock": 112}} # fake
def lookup_product(asin):
return PRODUCTS.get(asin, {"error": "unknown asin"})
tools = [{
"name": "lookup_product",
"description": "Current price in USD and units in stock for one ASIN.",
"input_schema": {
"type": "object",
"properties": {"asin": {"type": "string"}},
"required": ["asin"],
},
}]
messages = [{"role": "user", "content": "Is B0EXAMPLE01 in stock, and at what price?"}]
for _ in range(5):
response = client.messages.create(
model=MODEL, max_tokens=4096, tools=tools,
output_config={"effort": "low"}, messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
break
results = []
for block in response.content:
if block.type == "tool_use":
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(lookup_product(**block.input)),
})
messages.append({"role": "user", "content": results})
print(text_of(response))
Five rounds is my cap, so a confused model cannot loop forever.
How do I replace Anthropic’s web fetch tool on Kimi?
Anthropic’s server tools (web_search, web_fetch, code_execution) run on Anthropic’s machines. Moonshot’s tool schema only accepts the custom type, so I treat all three as unavailable. What Moonshot offers instead is REST endpoints: /v1/tools/search and /v1/tools/fetch, billed at $0.002 per successful call per its pricing page. The older $web_search built-in is chat-completions only and marked as going away. So web fetch becomes a client tool you add to the loop above.
import requests
def fetch_page(url):
r = requests.post(
"https://api.moonshot.ai/v1/tools/fetch",
headers={"Authorization": "Bearer " + os.environ["MOONSHOT_API_KEY"]},
json={"url": url},
timeout=30,
)
r.raise_for_status()
return r.json().get("markdown", "")[:20000]
tools.append({
"name": "fetch_page",
"description": "Fetch a web page and return its text as Markdown.",
"input_schema": {
"type": "object",
"properties": {"url": {"type": "string"}},
"required": ["url"],
},
})
# in the loop, route block.name == "fetch_page" to fetch_page(**block.input)
Does structured output, caching and image input work?
For code generation I would use structured output rather than parsing prose. The docs describe output_config.format with a JSON Schema, and the SDK has the same field. For “write code, then run it”, give the model a run_python client tool, and run that code in a throwaway container with a timeout. Never in your own process.
schema = {
"type": "object",
"properties": {
"listing_ok": {"type": "boolean"},
"problems": {"type": "array", "items": {"type": "string"}},
},
"required": ["listing_ok", "problems"],
"additionalProperties": False,
}
response = client.messages.create(
model=MODEL,
max_tokens=4096,
output_config={"effort": "low", "format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": "Check this title: 'Steel bottle 750ml BPA free'"}],
)
print(json.loads(text_of(response)))
Caching and images, in one call. Caching is a top-level cache_control field, and the SDK has that parameter. Images go in as base64 with a jpeg, png, gif or webp media type.
import base64
with open("label.png", "rb") as f:
img = base64.b64encode(f.read()).decode()
response = client.messages.create(
model=MODEL,
max_tokens=4096,
cache_control={"type": "ephemeral", "ttl": "1h"},
output_config={"effort": "low"},
messages=[{"role": "user", "content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img}},
{"type": "text", "text": "Read the ingredients on this label."},
]}],
)
print(text_of(response))
print(response.usage.cache_read_input_tokens, response.usage.cache_creation_input_tokens)
For Claude Code, Moonshot’s guide sets ANTHROPIC_BASE_URL to the same URL and ANTHROPIC_AUTH_TOKEN to your key, and then needs the model variables (opus, sonnet, haiku, subagent) set too, or those tiers “fail silently”. The guide lists kimi-k3[1m] as the model, not K3.1 Pro, so swapping the id is my guess.
Which Anthropic features does Moonshot document?
Here is the table, with each status read from Moonshot’s docs.
| Feature | Status | Source |
|---|---|---|
| Messages call, system prompt, streaming | Documented as supported | Messages API page |
| Client tools (tool_use, tool_result) | Documented as supported; tool_choice is auto, any or none only | Messages API page |
| Anthropic server tools (web_search, web_fetch, code_execution) | Not documented, tool type is custom only. Assume no | Messages API schema |
| Structured output (output_config.format) | Documented as supported | Messages API page |
| Reasoning effort (low, high, max) | Documented as supported | Messages API page |
| thinking with budget_tokens | Documented as not supported for K3.1 Pro (always thinks; do not pass thinking). That guide covers the OpenAI-format endpoint, so test | Thinking models guide |
Images, PDFs, caching, token counting, batches and Claude Code are in the second half.
| Feature | Status | Source |
|---|---|---|
| Images | Documented as supported: base64 or an uploaded ms:// file id, not a web URL | Messages API schema |
| PDF document blocks | Not documented, test first. Moonshot has a separate file upload and extraction API | Messages API schema |
| Prompt caching | Documented as supported, top-level cache_control only | Messages API page |
| Token counting (count_tokens) | Not documented, test first. Moonshot has its own estimate endpoint in the OpenAI format | Estimate Tokens page |
| Message Batches | Not documented. Moonshot’s Batch API uses chat completions JSONL and lists K2 models, not K3 | Batch API guide |
| Claude Code | Documented as supported, with kimi-k3[1m] | Claude Code guide |
What breaks when you swap the base URL?
Seven things, in the order I would hit them.
response.content[0].textcan crash, because block zero is thinking.max_tokensis required, and reasoning counts as output. A small limit gets cut off mid-thought with amax_tokensstop reason and no answer.- Per-block
cache_controlmarkers insidemessagesare ignored. Only the top-level field works. If your bill depends on caching, checkcache_read_input_tokenson the second call before you move traffic. usage.input_tokensexcludes cache reads and writes here. Total input is the three fields added together, so a dashboard that reads onlyinput_tokenswill show a drop in usage that is not real.- The SDK accepts effort values such as
mediumandxhigh. Moonshot’s documented list islow,high,max. Pass only those. - Tool schemas must follow Moonshot’s MFJS spec, a stricter JSON Schema flavour. Tool names are limited to letters, digits, underscore and hyphen.
- There is a
refusalstop reason when content review triggers. Handle it, or your loop will treat an empty answer as success.
Bon, and the ones I cannot confirm: server tools, PDFs, count_tokens and batches all need a test call, with the exact error text, before you build on them.
What does this mean for a startup like Trellis?
Cost first, with made-up traffic and real prices. A call with 3,000 tokens in and 500 out costs $0.006 plus $0.005, so $0.011 at $2 and $10. If 2,500 of those input tokens are a cached prefix at $0.20, the call costs $0.0005 plus $0.001 plus $0.005, so $0.0065. That is 41% less, and the whole saving comes from the cache. The catch is the output side. A model that writes 1.85 times the median tokens can eat the saving before you notice, and output is the expensive half of the bill. I have no real Trellis numbers here, and nothing at Trellis runs on Kimi.
Lock-in is where I land on the optimistic side. Moving between an Anthropic model and this one is a base URL, a key, a model string and the seven items above. I would budget a day for it, so I can keep a second vendor warm for the day my main provider changes a price or a policy. I would not move production on a promise, though. Wait for November 4, and see if the license and the checkpoint show up.
What I will do this week is simple. Take 20 real seller tasks, run them through my current model and through kimi-k3.1-pro at low effort, and count cost, output tokens and mistakes a seller would catch. The first thing I check is whether cache_read_input_tokens is above zero on call number two.