Flint 把 39.8B 的编码 Agent 压在 2.5B 激活参数后面,一个副本只要一张 GPU
💡 工具推荐: AI Token 计数、JSON 格式化、代码差异对比
Recursive 在 10 月 21 日把 Flint 传上 Hugging Face,Apache 2.0,权重直接可下。它的定位很明确:不是通用聊天模型,而是给编码 Agent 用的。这句话在参数表里能看出来——总量 39.8B,但每个 token 只激活约 2.5B(不含输入嵌入矩阵的「本体」约 2.2B),官方把这种规格写作 40B-A2.5B。整个模型 49 层,前两层是稠密层,后面 47 层全是 MoE;每层 256 个路由专家、每个 token 选 6 个,外加一个常驻的共享专家。这套结构的直接后果是:推理成本按 2.5B 算,表达能力按 40B 算,于是「跑在自己机器上」这件事第一次对编码 Agent 变得现实。
35 层滑窗只往前看 513 个 token,14 层全注意力负责长程。
一、规格表里真正影响你的那几行
注意力部分是这份规格表里最值得读的地方。49 层中,35 层是滑动窗口,窗口 513 个 token(当前 token 加前 512 个),另外 14 层是全注意力;32 个 query 头对 4 个 key/value 头,头维度 128;滑动层用 RoPE 位置编码,全注意力层不做位置编码,改成可学习的分头 attention sink。这组设计的意图是省 KV 缓存:绝大部分层只看最近 512 个 token,长程依赖交给少数全注意力层。上下文标称 262,144 token,官方特别注明提示词和生成内容共用这个预算;词表 150,144,知识截止 2026 年 6 月。对写 harness 的人来说,最后那条「共用预算」比 26 万这个数字重要得多——它不是「输入 26 万再加输出」,而是一起分。
# Serve one replica on a single B300 (or H200). The SGLang kit ships
# in the repo; Transformers modeling code is not included yet.
pip install -U huggingface_hub openai
hf download RecursiveSI/flint --local-dir flint # about 80 GB, BF16
cd flint
docker build -t flint-sglang sglang
docker run -d --name flint --gpus '"device=0"' --ipc=host \
-p 127.0.0.1:30000:30000 \
-v "$PWD:/model" -e MODEL=/model \
flint-sglang bash /model/sglang/serve_b300.sh # H200: serve_h200.sh
# Readiness, not sleep(60).
until curl -sf localhost:30000/health_generate >/dev/null; do sleep 15; done
# The server is OpenAI-compatible on /v1.
python3 sglang/example_client.py --base-url http://localhost:30000/v1二、起服务:一个副本一张卡,先跑通再谈集群
官方给的部署方式很干脆:每个副本一张 B300 或 H200。仓库里带 SGLang 的 serving kit(sglang/ 目录),BF16 权重约 80GB,下载之后 docker build、按卡型选 serve_b300.sh 或 serve_h200.sh,服务在 /v1 上暴露 OpenAI 兼容接口。要注意两点。第一,官方明确说目前还没有提供 Transformers 的建模代码,所以别指望 from_pretrained 一把梭,走 SGLang 是现阶段唯一的正路。第二,就绪判断用 health_generate 端点轮询,不要用固定 sleep——80GB 权重加载加上图编译,时间随磁盘和卡型浮动,睡 60 秒经常不够,睡 300 秒又太浪费。
# Sampling is part of the model contract, not a preference.
# Flint documents temperature 1.0, top-p 0.95, top-k 20, and an output
# budget of at least 32768 tokens INCLUDING reasoning.
from openai import OpenAI
client = OpenAI(base_url="http://localhost:30000/v1", api_key="unused")
SAMPLING = {"temperature": 1.0, "top_p": 0.95, "extra_body": {"top_k": 20}}
messages = [{"role": "user", "content": "Fix the failing test in tests/test_dispatch.py"}]
first = client.chat.completions.create(
model="flint",
messages=messages,
max_tokens=32768,
**SAMPLING,
)
msg = first.choices[0].message
# Keep reasoning_content in history. Dropping it breaks multi-turn tool use.
messages.append({
"role": "assistant",
"content": msg.content or "",
"reasoning_content": getattr(msg, "reasoning_content", "") or "",
**({"tool_calls": msg.tool_calls} if msg.tool_calls else {}),
})
# Temperature 0 is the reflex from other coding models. Here it flattens
# the distribution the model was tuned around, and long tool loops stall.三、采样参数是契约的一部分,不是偏好
模型卡里写得很清楚:温度 1.0、top-p 0.95、top-k 20,难任务的输出预算至少 32768 个 token,而且明确说这个预算包含推理内容。这三行建议直接当契约处理。常见的坑有两个:一是把别家编码模型的经验搬过来,温度设成 0 或 0.2,结果在多轮工具循环里反复打转——温度 0 会把模型调优时依赖的分布压平,长链推理反而更容易卡死;二是只给 8k 或 16k 的输出预算,推理链还没走完就被截断,模型吐出一个「看起来像补丁」的半成品。因为激活参数只有 2.5B,推理本身便宜,真正贵的是被截断后重试的那几轮。
一个副本一张 B300 或 H200,BF16 权重约 80GB。
// Bundle the sampling contract with the checkpoint name so nobody
// silently inherits another model's defaults in a shared harness.
{
"model": "flint",
"context_window": 262144,
"context_note": "prompt and generated output share this budget",
"sampling": { "temperature": 1.0, "top_p": 0.95, "top_k": 20 },
"max_output_tokens": 32768,
"output_budget_note": "counts reasoning tokens, not just visible text",
"tool_calls": { "style": "openai", "parallel": true },
"history": { "preserve_reasoning_content": true },
"stop_when": ["tests_pass", "patch_applied", "max_turns:24"]
}
// Why the output budget matters: at 2.5B active parameters inference is
// cheap, but a reasoning trace that gets truncated mid-plan produces a
// confident half-patch. Budget the trace, not the answer.四、工具循环里必须保住 reasoning_content
Flint 支持 OpenAI 风格的工具调用,但有一个细节必须照做:把返回的 reasoning_content 保留在对话历史里。这不是可选优化,而是多轮工具调用的正确性要求——推理链一旦从历史里消失,模型下一轮就得从零重新推断当前进度,表现为重复调用同一个工具,或者在第 6 轮之后开始改自己刚写的代码。第二个细节是上下文预算的算术:262,144 是提示词加输出的总和,如果一轮里工具返回了一个 4000 行的日志,再留 32768 给输出,剩下的空间就不多了。可行的做法是给工具返回做摘要、把大文件落到磁盘只回传路径和行号,以及在循环里显式设置最大轮次(实测 24 轮是个合理的上限)。
# Laptop-side serving. Unsloth publishes quantised GGUFs; pick by memory,
# then verify the quant against the BF16 reference before trusting it.
pip install -U "huggingface_hub[hf_transfer]"
export HF_HUB_ENABLE_HF_TRANSFER=1
# Q4_K_XL is the usual first stop for 64GB unified memory machines.
hf download unsloth/flint-GGUF --include "*Q4_K_XL*" --local-dir flint-gguf
llama-server -m flint-gguf/*Q4_K_XL*.gguf \
--ctx-size 65536 \
--temp 1.0 --top-p 0.95 --top-k 20 \
--jinja \
--port 8080
# Notes that cost us an afternoon:
# 1. --jinja is required for the chat template and tool calls.
# 2. Start at 64k context, not 262k. KV cache scales; unified memory does not.
# 3. Quantisation changes the distribution. Re-check tool-call validity
# on your own repo before switching a harness over.五、怎么读那三个 benchmark 数字
官方给的三组数字是:Terminal-Bench 2.1 54.9%、SWE-bench Pro v2 89.7%、SWE-bench Verified 74.2%。三组都在温度 1.0、top-p 0.95、top-k 20 下跑,Terminal-Bench 用 Terminus 2 作为 harness,SWE-bench 用 mini-swe-agent,成绩是至少五次尝试的平均 pass@1。这里有两个必须注意的脚注。第一,Terminal-Bench 的分数把「通过网页检索拿到的解」记为不成功,而同一张表里其他模型的分数由各自开发者提供,未必做了同样的扣除——跨行比较要打折。第二,SWE-bench Pro v2 的 89.7% 和 Verified 的 74.2% 差得很远,这不是模型不稳定,而是两套任务集的难度分布不同,选型时应该拿你自己仓库的 issue 去测,而不是看排行榜换模型。
pass@1 平均五次以上,且通过网页检索拿到的解算失败。
# Reading an agentic benchmark honestly: pass@1 over at least five
# attempts, and know what the harness counts as a failure.
import statistics
def pass_at_1(run_task, tasks, attempts=5):
scores = []
for task in tasks:
outcomes = []
for _ in range(attempts):
result = run_task(task)
# Flint's Terminal-Bench number excludes solutions that reached
# the answer through web retrieval. Apply the same rule or you
# are not comparing the same thing.
ok = result["tests_passed"] and not result.get("used_web_retrieval")
outcomes.append(1 if ok else 0)
scores.append(sum(outcomes) / attempts)
return {
"pass@1": round(statistics.mean(scores) * 100, 1),
"tasks": len(tasks),
"attempts": attempts,
}
# Published by Recursive: 54.9% Terminal-Bench 2.1 (Terminus 2 harness),
# 89.7% SWE-bench Pro v2, 74.2% SWE-bench Verified (mini-swe-agent).
# Comparison rows in the same table are developer-reported and may not
# apply the web-retrieval adjustment.📌 常见问题 FAQ
Flint 是谁做的,什么时候发布的?
由 Recursive 发布,Hugging Face 仓库 RecursiveSI/flint 的上传时间是 2026 年 10 月 21 日,采用 Apache 2.0 许可。官方博客和本地推理引擎的开源仓库都在模型卡里给出链接。
39.8B 总量、2.5B 激活是什么意思?
它是 MoE 结构:总参数 39.8B,但每个 token 只走 256 个路由专家中的 6 个,加上一个常驻共享专家,所以实际计算量约等于 2.5B 参数的稠密模型(这个约定包含输出头、不含完整输入嵌入矩阵,本体约 2.2B)。
能在笔记本上跑吗?
官方给的参考部署是每副本一张 B300 或 H200(BF16 约 80GB)。社区已经有量化 GGUF 版本(unsloth/flint-GGUF),量化后可以走 llama.cpp / Ollama 这类运行时,但量化会改变分布,工具调用正确性需要在你自己仓库上重新验证。
为什么温度不能设 0?
模型卡公布的评测配置是温度 1.0、top-p 0.95、top-k 20。温度 0 会压平模型调优时依赖的分布,在多轮工具调用中更容易陷入重复动作;这不是绝对的禁令,但如果你要设 0,先在自己的任务上做 A/B。
262,144 上下文是不是可以塞满?
不建议。官方注明提示词和生成内容共享这个预算,而难任务的输出预算至少要留 32768 个 token(含推理)。把上下文塞满等于把推理链截断,正确的做法是压缩工具返回、大文件只回传路径,并在 harness 里限制循环轮次。