本文涉及的 FIM 推理实现已开源RWKV-Server https://github.com/AUXStar/RWKV-Server —— 基于 RWKV7 的高性能批量推理引擎单卡 RTX 4090 峰值 11,081 tok/s支持 FIM 代码补全。从一个场景说起程序员在编辑器中写代码时光标往往不在文件末尾——它在函数体中间、在两行已有代码之间、在 import 语句和函数签名之后。此时代码补全面临一个根本问题模型需要同时理解光标前的代码和光标后的代码才能生成正确的填充内容。传统的自回归语言模型只能从左到右生成。它们看到 prefix 后就开始逐 token 输出对 suffix 一无所知。这在文件末尾续写时没问题但在文件中间编辑时丢失了半数上下文。Fill In the MiddleFIM正是为解决这个问题而生的技术。它的核心思想极其简洁不改模型架构只改训练数据的排列方式就让因果语言模型同时利用前后文信息。一、FIM 的原理1.1 核心变换FIM 的做法是将一篇文档在随机位置切分为三段——prefix、middle、suffix——然后把 middle 移到末尾用特殊 token 拼接原始文档: [prefix] [middle] [suffix] FIM 变换后: [prefix] [suffix] [middle] ↑ ↑ ↑ fim_prefix fim_suffix fim_middle模型仍然从左到右自回归生成但此时它已经看到了 suffix。当生成到fim_middle之后的内容时模型同时拥有 prefix 和 suffix 的信息可以生成连贯的中间填充。推理时只需将用户提供的 prefix 和 suffix 按相同格式拼接模型就会在fim_middle之后输出填充内容输入: fim_prefix{prefix}fim_suffix{suffix}fim_middle 输出: {模型在此生成中间内容}1.2 SPM 与 PSM原始论文定义了两种排列变体[1]PSMPrefix-Suffix-Middlepre{prefix}/presuf{suffix}/sufmid{middle}/midSPMSuffix-Prefix-Middlesuf{suffix}/sufpre{prefix}/premid{middle}/mid区别在于 suffix 和 prefix 的先后顺序。SPM 把 suffix 放在 prefix 前面使 suffix 离生成位置更近模型更容易利用 suffix 信息。论文实验表明 SPM 在 FIM 任务上表现更好但联合训练 PSMSPM各 50%是最佳实践。1.3 “FIM-for-free”——零代价获得新能力FIM 最优雅的属性在于在预训练阶段混合 FIM 数据不会损害模型原有的从左到右生成能力[1]。论文作者训练了从 50M 到 6.9B 参数的 16 个模型进行对照实验。结果表明以 50% 的 FIM 变换概率混合训练后模型在 perplexity、PIQA、Winograd、DROP、HellaSwag、LAMBADA、HumanEval 等标准基准上的表现与纯自回归模型完全一致。FIM 能力是免费附赠的。反过来如果留到微调阶段才学 FIM则需要大量额外算力才能达到同等效果。这意味着 FIM 应该在预训练阶段就引入。二、主流实现2.1 各模型的 FIM 格式几乎所有主流代码模型都在预训练中采用了 FIM。它们的特殊 token 命名不同但原理完全一致模型FIM Token 格式训练策略OpenAI Codex|fim_prefix|...|fim_suffix|...|fim_middle|PSM 为主StarCoder (BigCode)fim_prefix...fim_suffix...fim_middlePSMSPM 混合50% FIM rateDeepSeek-Coderfim▁begin...fim▁hole...fim▁end三片段输入Qwen2.5-Coder|fim_prefix|...|fim_suffix|...|fim_middle||fim_pad|PSMSPM 混合CodeLlama (Meta)类似 Codex 格式FIM 训练SantaCoderfim_prefix...fim_suffix...fim_middlePSMSPM 混合RWKV (rwkv_lightning / RWKV-Server)✿prefix✿✿suffix✿{suffix}✿middle✿{prefix}Unicode 字符标记无需特殊 token2.2 推理示例以 Qwen2.5-Coder 为例[5]fromtransformersimportAutoTokenizer,AutoModelForCausalLM tokenizerAutoTokenizer.from_pretrained(qwen/qwen2.5-coder-7b)modelAutoModelForCausalLM.from_pretrained(qwen/qwen2.5-coder-7b)prefixdef hello_world():suffix\n print(result)promptf|fim_prefix|{prefix}|fim_suffix|{suffix}|fim_middle|inputstokenizer(prompt,return_tensorspt)outputsmodel.generate(**inputs,max_new_tokens100)以 DeepSeek API 为例[4]responseclient.fim_completions.create(modeldeepseek-fim,prefixdef factorial(n):\n if n 0:\n return 1\n ____,suffix\n print(factorial(5)) # 输出120)三、FIM vs 其他双向方案FIM 并非让语言模型看到两边的唯一方案但它是最简洁、最实用的一种。3.1 方案对比方案代表模型架构修改训练开销生成质量工业采用FIM (Infilling)Codex, StarCoder, DeepSeek-Coder无零额外高广泛Permutation LMXLNet[12]双流注意力中等中高XLNetSpan CorruptionT5, SpanBERTEncoder / Enc-Dec中等中T5Masked LMBERTEncoder-only中等低生成BERT 系列3.2 为什么 FIM 胜出Permutation Language ModelingXLNet对输入 token 序列做随机排列通过双流自注意力让每个 token 看到所有位置。理论上更通用但需要修改模型架构双流注意力计算开销更大且在代码生成任务上没有明显优势。Span CorruptionT5、SpanBERT随机遮蔽文本中的连续片段让模型预测被遮蔽的内容。通常用于 encoder 或 encoder-decoder 架构可以腐蚀多个 span但训练目标是 denoising 而非自回归在开放式生成任务上表现不如因果模型。FIM的优势在于不改变模型架构、不增加推理开销、不损失原有能力、实现极其简单只需数据变换。它是一个免费的午餐。四、适用场景FIM 并非在所有场景下都优于传统的从左到右生成。选择取决于上下文的可用性场景推荐方式原因代码续写文件末尾L2Rsuffix 为空FIM 退化为 L2R代码中间补全FIM光标前后都有代码函数体生成FIM有函数签名prefix和返回语句suffiximport 语句生成FIM后续代码作为 suffix 约束类型docstring 生成FIM函数体作为 suffix 提供类型信息对话 / 问答L2R天然顺序生成文本编辑 / 修改FIM替换段落时前后文都存在实际应用中代码编辑器如 rwkv-code-completion[9]会根据光标位置自动切换光标后有代码时走 FIM光标在文件末尾时走普通续写。RWKV-Server 的 FIM 端点同样遵循这一策略——suffix 为空时自动退化为普通续写无需额外适配。五、RWKV 生态中的 FIM5.1 rwkv_lightning 的实现rwkv_lightning[8]使用 Unicode 字符✿U273F作为 FIM 标记而非传统的fim_prefix格式✿prefix✿✿suffix✿{suffix}✿middle✿{prefix}这种设计的好处是✿是普通 Unicode 字符不需要在 tokenizer 中添加特殊 token任何 RWKV 模型都可以直接使用。rwkv_lightning 的 FIM 接口支持批量推理prefix 和 suffix 为列表一次请求处理多组不同的 FIM 任务充分利用 RWKV 的批量推理能力。5.2 RWKV-Server 的 FIMRWKV-Server 在 rwkv_lightning 的基础上进一步简化了接口。POST /v1/tasks/fim接收单个 prefix suffix内部构造相同的 FIM prompt 后复用现有的 Task 调度器和批量推理引擎curl-XPOST http://localhost:8000/v1/tasks/fim\-HContent-Type: application/json\-d{ prefix: def hello_world():\n print(, suffix: )\n return True, max_tokens: 50, stream: false }整个 FIM 功能只改了两个文件——schemas.py新增请求模型routers.py新增端点——核心 prompt 构造只有一行。FIM 的实现完全复用了 RWKV-Server 的现有基础设施——Task 调度器、动态扩缩容、SSE 流式输出——零侵入底层。5.3 RWKV 架构对 FIM 的天然适配RWKV 的 O(1) 线性注意力和固定大小 state 使其天然适合高并发 FIM 场景state 不随序列长度膨胀长 prefix suffix 不会像 Transformer 的 KV Cache 那样消耗大量显存批量吞吐线性增长batch_size 越大GPU 利用率越高单卡可以支撑数百并发 FIM 请求状态复用同一文件的多次编辑可以复用 prefix 部分的 state避免重复 prefill在 RTX 4090 上RWKV-Server 使用 RWKV7 2.9B 模型可达到峰值 11,081 tok/s256 并发7.2B 模型峰值 6,373 tok/s。六、关键超参数原始论文的消融实验揭示了几个关键超参数[1]FIM Rate变换概率推荐 50%即一半训练数据做 FIM 变换一半保持原始顺序。低于 50% 会削弱 FIM 能力高于 50% 会轻微影响 L2R 能力。Span 选择策略推荐在 context 级别而非 document 级别做 FIM并使用均匀的 span 长度分布。对于代码优先在行/段落边界分割效果更好。SPM vs PSM 比例联合训练 SPMPSM各 50%是最佳实践单一格式的效果略逊。评估方式论文特别指出仅看 test loss 会误导——不同超参数下 FIM test loss 差异很小但在采样基准pass rate上差异巨大。评估 FIM 能力必须用采样而非 perplexity。SourcesBavarian et al., Efficient Training of Language Models to Fill in the Middle, arXiv:2207.14255, 2022.https://arxiv.org/abs/2207.14255Li et al., SantaCoder: Training Open-Source Code LLMs with 1 Trillion Tokens, BigCode, 2023.https://blog.csdn.net/gitblog_02761/article/details/144662538Ray et al., StarCoder: May the Source Be with You!, BigCode, 2023.https://hub.baai.ac.cn/view/26590DeepSeek FIM 功能解析, CSDN, 2024.https://blog.csdn.net/qinzhenyan/article/details/154409461Qwen2.5-Coder 技术报告, CSDN, 2024.https://blog.csdn.net/jinselizhi/article/details/143759611Seed-Coder FIMSPM 训练策略, 2025.https://www.dodgeindustrial.com.cn/dy/article/20250508796423665.shtmltiktoken FIM 特殊 token 定义, OpenAI.https://blog.csdn.net/gitblog_00536/article/details/151175018rwkv_lightning 项目 Albatross 推理引擎, RWKV-Vibe.https://juejin.cn/post/7597641580104581174rwkv-code-completion VS Code 插件, xun082.https://juejin.cn/post/7597641580104581174RWKV7-G1c 系列模型发布, RWKV 社区, 2025.https://juejin.cn/post/7600888960106070052Yang et al., XLNet: Generalized Autoregressive Pretraining for Language Understanding, 2019.https://blog.csdn.net/DarrenXf/article/details/96449450