让一个 4B 小模型专门"找代码",主模型省掉 60% token:FastContext 把仓库探索拆出来了

你有没有这种体验:让 coding agent 去修一个 bug,它先 grep 一遍,再 cat 几个文件,又翻了翻测试目录,等真正动手改第一行代码的时候,对话历史已经堆了十几轮无关的文件内容。最要命的是——这些探索性的读取和搜索,全都留在了主模型的上下文里,又烧 token 又分散注意力。

上周读到微软这篇 FastContext,我的第一反应是"对,这事早该有人认真做了"。它的思路简单到一句话能讲清楚:既然探索和求解是两件事,那就别让同一个模型干。专门训一个小模型负责"找代码",找完只把 file path + line range 这种最精炼的证据递给主模型,主模型干净利落地去改。

结果也挺能打——三个基准上端到端解决率最高涨 5.5 个点,主模型 token 消耗最多砍掉 60%。而且负责探索的那个模型只有 4B。


核心摘要

痛点:在主流 coding agent 里,同一个模型既探索仓库又求解任务,探索产生的大量 reading/searching 残留在求解器的上下文里——论文实测这部分占了 56.2% 的工具调用轮次、吃掉 46.5% 的主模型 token,而且求解器平均要熬到第 8.47 轮才开始改第一行代码。

方案:FastContext 是一个只读的探索子智能体,被主模型按需调用。它只用 Read/Glob/Grep 三个语言无关的工具,每轮可以并行发多个工具调用,最后只返回一个紧凑的 <final_answer>(文件路径 + 行范围)。背后是一族 4B–30B 的专门探索模型,先用强参考模型的轨迹做 SFT 冷启动,再用 task-grounded 奖励做 RL 精炼。

效果:集成进 Mini-SWE-Agent 后,在 SWE-bench Multilingual / SWE-bench Pro / SWE-QA 上,端到端解决率最高 +5.5%,主模型 token 最多省 60%,而 4B explorer 自己的 API 成本只占增强总成本的 2.1%。

我的判断:这不是什么颠覆性的新算法,GRPO、子智能体、SFT+RL 都是现成的零件。但它把"仓库探索"这件一直被当成隐性成本的事,明确地立为一个一等的、可训练的组件,而且用一个能本地部署的 4B 小模型就把账算平了——这个工程定位我很认。arXiv 编号 2606.14066,值得做 agent 系统的人细看。


论文信息

  • 标题:FastContext: Training Efficient Repository Explorer for Coding Agents
  • 作者:Shaoqiu Zhang、Maoquan Wang、Yuling Shi、Yuhang Wang、Xiaodong Gu、Yongqiang Yao、Rao Fu、Shengyu Fu
  • 机构:微软(Microsoft)
  • arXiv:2606.14066(cs.SE,2026 年 6 月提交,34 页 7 图)
  • 代码:https://github.com/microsoft/fastcontext

🤔 为什么探索成了瓶颈?先看一组扎心的数字

很多人对 coding agent 的直觉是"它在思考怎么改代码"。但论文拿 GPT-5.4-high + Mini-SWE-Agent 在 SWE-bench Multilingual 全集跑了 300 条轨迹做轨迹分析,发现的真相是——它大部分时间在找代码

  • reading 和 searching 这两类动作,平均每个实例占了 9.96 / 17.72 个工具调用轮次,也就是 56.2% 的全部 tool-use turns
  • 这两类动作消耗了主模型 46.5% 的总 token

换句话说,你花在 GPT-5.4 上的钱,将近一半是在让一个顶级大模型干"在仓库里翻文件"这种粗活。这事怎么看都不划算。

更让我皱眉的是第二个发现——探索是编辑前一段又长又串行的前奏。在 284 条能识别出首次源码编辑的轨迹里,模型平均要到第 8.47 轮才开始改第一行代码。哪怕开了并行工具调用,中位数轨迹仍然要走 6 个串行探索轮次、发 15.5 个探索工具调用,才肯动手。

图1:FastContext 把 coding agent 推向"花更少、得更多"的甜区

图1:SWE-bench Multilingual(左)和 SWE-QA(右)上的"得分 vs 主模型 token"散点图。空心圈是不带探索的基线,加了 FastContext 后(菱形/十字/星形分别是 30B-SFT、4B-SFT、4B-RL),三种主模型(GPT-5.4 蓝、GLM-5.1 橙、Kimi-K2.6 紫)的点都往左上角那块绿色"甜区"移动——得分更高、token 更少。SWE-QA 上的水平箭头尤其夸张,token 直接腰斩还多。

我特别留意了一个细节:未解决的轨迹,编辑前的探索轮次比已解决的更多——8.34(未解决)vs 6.67(已解决)。这说明探索做得越乱、越长,越容易失败。直觉上也对:探索轨迹越长,求解器的上下文被污染得越厉害,真正该聚焦的信息反而被淹没。

图2(右):首次编辑前的探索量,未解决轨迹明显更多

图2(右半部分):首次编辑前的平均探索量。蓝柱是串行探索轮次,橙柱是探索工具调用数。全集(All)要 7.2 轮 / 17.4 次调用;已解决(Resolved)6.7 轮 / 16.2 次;未解决(Unresolved)飙到 8.3 轮 / 20.2 次。探索越多越失败,这个相关性挺说明问题的。

所以分离探索和求解的逻辑就很自然了:把翻文件这件脏活外包给一个便宜的专门模型,让它只把"证据"递回来,主模型的上下文就干净了,token 也省了。


🏗️ FastContext 怎么设计的

一句话讲清核心:主模型只接收证据,不接收探索过程

先看整体架构。主模型(Coding Agent)该改代码改代码,遇到"我得先搞清楚相关代码在哪"的时候,就发一个 Context Query 把探索任务委托给 FastContext。FastContext 自己去 Read/Search 仓库,但它返回的是 file-line 证据,不是补丁

图3:FastContext 总览——左边是端到端 agent 循环,右边是探索子智能体内部

图3:左边,Coding Agent 把探索委托给 Fast Context,后者读写环境(Environment)后只回传"Explore Results"和精炼的 file-line 证据,主模型据此做 Edit and Test。右边是 FastContext 内部:Query 理解 → 并行调用 Read/Glob/Grep → 观察工具输出 → 最终给出 Final Citations(带行号的文件路径,可选附简短代码片段)。注意右下角的输出长这样:/goldmark/images/transform.go:17-22/converter/hooks/hooks.go:51-61——就是这么紧凑。

这里有几个我觉得设计得很克制的点:

只暴露 3 个工具,而且语言无关。Read(读带行号的文件)、Glob(路径发现)、Grep(基于 ripgrep 的正则搜索)。没有花哨的 AST 解析、没有语言专属的索引——就最朴素的三板斧。好处是泛化性强,多语言仓库通吃。

explorer 是只读的。它压根没有编辑文件或提交补丁的能力。这个约束很重要——它从机制上保证了探索和求解的边界,explorer 不会越界去"顺手改一下"。

并行工具调用。每一轮,explorer 要么发一个或多个工具调用,要么停下来给出最终证据。同一轮里的多个调用是并行执行的,这样可以一次性覆盖好几个互补的假设(比如同时按路径模式、按符号名、按入口点去搜),不用一轮一轮串着来。回想图2 里"中位数 6 个串行轮次"的痛点,并行就是冲着这个去的。

输出契约极简。explorer 内部的工具观察、中间推理,全都写进独立的子智能体日志,绝不附加到主模型上下文。主模型只收到那个 <final_answer> 块:

<final_answer>
/src/router.py:42-58 (Router definition)
/tests/test_router.py:101-119
</final_answer>

这就是关键。主模型的上下文不再被探索过程污染,只剩下"相关代码在这几个位置"这一条干净信息。

模型选型:为什么押注 4B

backbone 用的是 Qwen 系列——4B explorer 是 Qwen3-4B-Instruct,30B explorer 是 Qwen3-Coder-30BA3B。

论文的逻辑链是这样的:4B 才是真正的部署目标(探索本来就该足够廉价),30B-SFT 只是作为缩放参考,而 4B-RL 要回答的核心问题是——能不能用 task-grounded 优化让小模型追上大模型,从而省掉昂贵的 30B RL?后面实验会看到,这个赌注赢了。


🔧 训练:先抄好学生的作业,再自己刷题

FastContext 的训练分两阶段,思路很经典:SFT 冷启动 + RL 精炼。

第一阶段:SFT,从 Sonnet 4.6 的轨迹里学三种行为

作者用 Sonnet 4.6 这个强参考模型跑探索,收集轨迹,过滤后得到 2,954 条 SFT 样本。妙的地方在于,这些样本被刻意拆成三类,对应运行时要做的三种动作

数据来源 数量 教会的行为
parallel_toolcalls 990 广泛首轮搜索:给定 query + 顶层目录,要求发出非冗余的并行调用,覆盖路径模式、符号、入口点
multiturn_traj 983 多轮证据收集:保留完整探索轨迹,含工具调用参数和原始观察
linerange 981 精确引用生成:给定文件内容,只输出狭窄的 <final_answer>

我挺喜欢这个拆法。它不是笼统地"学探索",而是把探索拆解成"开局怎么撒网、中盘怎么收集、收官怎么精确定位"三个能力,分别喂数据。损失只算 assistant token(通过掩码保留普通文本和结构化工具调用参数),用 Slime/Megatron 栈、128K 上下文训了 3 个 epoch。

第二阶段:RL,用确定性奖励刷"找得准不准"

SFT 让模型会探索了,但探索得好不好,得靠 RL 校准。作者构建了 400 条 RL prompts(覆盖 395 个仓库),从真实的 issue-resolution 任务和 reference patches 来。

关键一招:把 reference patch 解析成目标 file-and-line ranges 当作探索标签(平均每个 prompt 有 11.07 个目标引用范围)。这样"找得准不准"就有了可计算的 ground truth。explorer 作为真实子智能体跑,用 Read/Glob/Grep,最多 8 轮。

奖励函数是确定性的,长这样:

\[R = \underbrace{F_1(P_f,G_f) + F_1(P_l,G_l)}_{\text{任务结果}} + \underbrace{r_{\text{parallel}}}_{\text{并行奖励}} - \underbrace{r_{\text{format}}}_{\text{格式惩罚}}\]

拆开看:

  • 任务结果:文件级 F1 + 行级 F1。找到的位置和 patch 标注的位置对得越齐,分越高,空集直接 0 分。
  • 并行奖励 \(r_{\text{parallel}}\):当一轮里的最大并行度 \(p_{\max}\) 落在 \(3 < p_{\max} \leq 6\) 这个区间给小奖励——鼓励有节制的并行,既不一根筋串行,也不无脑扇出几十个。
  • 格式惩罚 \(r_{\text{format}}\):拒绝空输出、过长、格式错误,或者引用数量异常(少于 1 个、多于 20 个,或并行度超过 6)的情况。

从 SFT checkpoint 初始化,用 GRPO 优化(每 prompt 采 16 条轨迹)。说到 GRPO,它是 DeepSeek 那套靠组内相对优势省掉 value model 的方法,在这种"奖励可确定性计算、采样多条比好坏"的场景里用着确实顺手——这里没有用熵奖励,clip 上限放到 0.28,跑了 1000 步。

值得一提的是 RL 的增益主要来自更高的 recall,precision 基本不变。这跟奖励设计完全自洽——F1 奖励本质上是在催着模型"把 patch 相关的位置尽量都覆盖到",所以模型学会了找得更全。


📊 实验:4B-RL 居然能压过 30B-SFT

实验跑在三个基准上:SWE-bench Multilingual(300 个多语言实例)、SWE-bench Pro(更难,固定抽 200 实例)、SWE-QA(仓库级问答,用 GPT-5.4 当裁判)。主框架是 Mini-SWE-Agent,三个主模型分别是 GPT-5.4、GLM-5.1、Kimi-K2.6。对比项包括:直接求解(w/o Explore)、用主模型自己探索(same-model)、以及训练好的 FastContext(30B-SFT / 4B-SFT / 4B-RL)。

主表(Table 1):GPT-5.4 这组

Subagent SWE-Multi 分/Token SWE-Pro 分/Token SWE-QA 分/Token
w/o Explore 71.7 / 457k 46.0 / 818k 81.3 / 418k
GPT-5.4(same-model) 73.3 / 379k 51.5 / 703k 81.4 / 166k(省 60.3%)
FC-30B-SFT 75.0 / 356k 49.0 / 688k 82.0 / 206k
FC-4B-SFT 73.3 / 364k 47.0 / 689k 81.9 / 213k
FC-4B-RL 74.7 / 338k 48.5 / 701k 82.0 / 210k

GPT-5.4 在 SWE-QA 上那个 166k token 我盯着看了好几秒——相比基线 418k,省了 60.3%,分数还基本没掉(81.3→81.4)。这就是把探索外包的直接收益。

GLM-5.1 和 Kimi-K2.6 这两组才是亮点

模型 / 基准 w/o Explore FC-4B-RL
GLM-5.1 / SWE-Pro 17.5 / 2692k 22.5(↑5.0) / 2210k(省 17.9%)
Kimi-K2.6 / SWE-Multi 76.3 / 1553k 78.3(↑2.0) / 1384k
Kimi-K2.6 / SWE-Pro 31.0 / 2383k 33.5(↑2.5) / 2158k

最大增益普遍出现在最难的 SWE-bench Pro 上:GPT-5.4 从 46.0→51.5、GLM-5.1 从 17.5→22.5、Kimi-K2.6 从 31.0→33.5。这个规律我觉得很合理——任务越难,越需要精准的代码定位,训练好的 explorer 这时候价值最大。

但真正让我"哦?"了一下的是这个:GLM-5.1 在 SWE-Pro 上,4B-RL(22.5)反超了 30B-SFT(20.0),而且用的 token 还更少。Kimi-K2.6 的 SWE-Multi 和 SWE-Pro 上 4B-RL 也都压过了 30B-SFT。

一个 4B 的 RL 模型,干翻一个比它大七倍多的 SFT 模型。这就是论文最想证明的事——task-grounded 的 RL 优化,能让小模型在专门任务上具备竞争力,省掉训 30B RL 的天价开销。而且 4B-RL 相比 4B-SFT,在全部 9 个端到端设置里得分都是提升或持平,RL 的增益很稳。

独立探索质量(Table 2,SWE-bench Verified)

抛开端到端,单看 explorer 找代码的硬实力。在 SWE-bench Verified 上用 patch-derived 参考位置算 F1:

  • 训练后的 FastContext 拿到 73.71 file-level F1 和 60.35 module-level F1,对比最好的非 FastContext 行(68.57 / 50.88)有明显优势。
  • 训练对 4B explorer 的拉动:SFT 把 file-level F1 从 62.57 提到 70.55,RL 再推到 71.48,module-level 到 56.26,function-level 到 38.45。

Token 都省在哪了?

图5:加了 FC-4B-RL 后,主模型 token 分布整体左移

图5:GPT-5.4 在 SWE-bench Multilingual 上的逐实例主模型总 token 分布。四个面板分别是 Same model、30B-SFT、4B-SFT、4B-RL,灰色是基线、橙色是加了 FastContext。每个面板里橙色分布都明显往左(更低 token)偏移,均值降幅标在右上角:17.1%、22.1%、20.4%、26.0%。4B-RL 这版省得最狠。

成本审计:把账算明白

论文专门做了成本审计(Table 3,GPT-5.4 SWE-Multi),这点我很欣赏,因为很多论文吹省钱但不敢列具体账单:

  • 主模型直接求解成本 $282.47,加 4B-RL 后降到 $208.92,净省 $69.03;
  • 4B-RL explorer 总共消耗 22.58M token,按 Fireworks \(0.20/1M 估算,API 成本只要 **\)4.52**,占增强总成本的 2.1%;
  • 300 个任务里主模型一共调用了 4B-RL explorer 162 次。

而且作者点明:实际部署时 4B 是本地服务,这 $4.52 的 API 成本根本不产生。这账算下来,引入 explorer 几乎是净赚。


💡 我的判断:算法不新,但定位很对

先说我认可的地方。

它解决的是真问题,而且证据扎实。56.2% 的工具轮次、46.5% 的 token 花在探索上——这个量化把"探索是隐性成本"这件事钉死了。很多 agent 系统的优化都在抠 prompt、调 scaffold,但很少有人意识到探索本身值得被单独拎出来当一等组件训练。这个视角我觉得是这篇论文最值钱的地方。

4B-RL 反超 30B-SFT 这个结果很能打。它传递了一个对工程很友好的信号:你不需要一个巨大的探索模型,一个能本地部署的 4B,经过 task-grounded RL,就够用甚至更好。成本审计把这点坐实了。

再说我保留意见的地方。

算法层面其实没什么新东西。子智能体、SFT+RL、GRPO、F1 奖励——零件全是现成的。它的贡献是"把对的零件拼在对的位置上",是一篇优秀的系统/工程论文,但别指望从里面读到什么算法突破。

有个地方我没完全想透:explorer 返回的是静态的 file-line 证据,但求解过程中主模型可能发现需要新的、当初没探索到的代码。这时候是再调一次 FastContext,还是主模型自己临时去找?论文里 162 次/300 任务的调用频率说明主模型确实会多次委托,但探索和求解之间的这种"反复横跳"会不会引入新的协调开销,我觉得还值得再看。

还有个隐忧是泛化。RL 标签是从 reference patch 反推的目标位置,这等于在告诉模型"标准答案改了哪里"。在 SWE-bench 这种有明确 patch 的场景下没问题,但真实开发里很多任务没有干净的 patch 作监督信号,这套训练范式怎么迁移过去,论文没太展开。


🔗 工程启发

如果你也在做 coding agent,FastContext 这套思路至少有两点可以直接借鉴:

  1. 把探索从求解里拆出来。哪怕你不训专门模型,光是用一个独立的 context window 跑探索、只把精炼结果回传主上下文,就能立竿见影地省 token、降污染。这是不需要任何训练就能落地的架构改动。

  2. 小模型 + 任务对齐的 RL,性价比可能远超你的预期。别一上来就想着用最大的模型干所有事。对于"找代码"这种边界清晰、奖励可确定性计算的子任务,一个 4B 模型经过对齐就能打。

说到底,这篇论文真正想说的是一句话:仓库探索不该是单体求解轨迹里被默默吃掉的成本,它应该是一个可以被单独训练、单独优化的一等公民。我觉得这个观点会慢慢变成做 agent 系统的人的共识。

代码和数据都开源了(https://github.com/microsoft/fastcontext),想复现或者改造的可以直接上手。


觉得有启发的话,欢迎点赞、在看、转发。跟进最新 AI 前沿,关注我