Code AI

Guia de Autocomplete Fill-in-the-Middle (FIM): Benchmarks e Arquitetura

Resposta Rápida: Em 2026, o Fill-in-the-Middle (FIM) viabiliza o autocompletar de código em tempo real (ghost text) na IDE ao estruturar prompts com tokens de prefixo, sufixo e meio (ex.: <|fim_prefix|>, <|fim_suffix|>, <|fim_middle|>). Para inferência sub-100ms, o Qwen 2.5 Coder 1.5B lidera em precisão de linha única (84.6% SantaCoder FIM) com 42ms TTFT, enquanto o Qwen 2.5 Coder 7B domina a síntese multilinha (76.8%) a 84ms.


1. Introdução: Exigências de Latência e Precisão no Ghost-Text

O ai code completion (autocompletar de código por IA) e o ai autocomplete em tempo real representam as cargas de trabalho mais sensíveis à latência em toda a IA aplicada. Enquanto agentes conversacionais (como Claude Code, Aider ou OpenCode) podem gastar de 1.5 a 5.0 segundos planejando alterações complexas, as sugestões inline no editor ("ghost text") precisam renderizar em menos de 100 milissegundos para não quebrar o fluxo de raciocínio do desenvolvedor.

+-----------------------------------------------------------------------------------------------+
|                       Orçamento de latência para autocompletar no IDE                         |
+-----------------------------------------------------------------------------------------------+
| Debounce de digitação : 30ms - 50ms                                                           |
| Montagem de contexto  : 10ms - 15ms  (Tree-sitter AST, janelamento de prefixo e sufixo)      |
| Rede / Transporte IPC : 5ms  - 20ms  (vLLM / llama.cpp local ou WebSocket corporativo)        |
| Time-To-First-Token   : 35ms - 55ms  (Teto sub-100ms para o primeiro caractere renderizado)   |
| Streaming de tokens   : 15ms - 25ms  (15-40 tokens a mais de 120 tokens/s para a linha)      |
+-----------------------------------------------------------------------------------------------+
| ORÇAMENTO TOTAL       : 95ms - 145ms (Limiar de percepção humana para sugestão imediata)      |
+-----------------------------------------------------------------------------------------------+

A cada toque no teclado, um evento de edição é disparado. Se a sugestão demorar mais de 150ms, o desenvolvedor já terá digitado a próxima letra, descartando a inferência e gerando lentidão.

Modelos causais convencionais aprendem apenas a prever tokens da esquerda para a direita:

$$P(W) = \prod_{i=1}^{n} P(w_i \mid w_1, w_2, \dots, w_{i-1})$$

No código real, porém, quase sempre existem funções, classes ou fechamentos de chaves situados após o cursor. Se o modelo olhar apenas para trás (Prefix), gerará duplicações de código e conflitos de assinatura.

A arquitetura Fill-in-the-Middle (FIM) resolve isso ao condicionar a previsão tanto no Prefix (código anterior) quanto no Suffix (código posterior), gerando exatamente o conteúdo intermediário (Middle).


2. Arquitetura do Fill-in-the-Middle (FIM)

Pioneirizado por Bavarian et al. (OpenAI) e adotado no StarCoder, DeepSeek Coder e Qwen 2.5 Coder, o FIM converte decodificadores autorregressivos em sistemas bidirecionalmente conscientes sem alterar as matrizes de atenção do Transformer.

+-----------------------------------------------------------------------------------------------+
|                              Transformação Fill-in-the-Middle (FIM)                           |
+-----------------------------------------------------------------------------------------------+
| Arquivo de código original:                                                                   |
| [ CÓDIGO ANTES DO CURSOR (Prefix) ] [ CURSOR (Middle) ] [ CÓDIGO APÓS O CURSOR (Suffix) ]     |
|                                                                                               |
| Formato FIM (Modo PSM):                                                                       |
| <PRE> [ Tokens Prefixo ] <SUF> [ Tokens Sufixo ] <MID> ===> Modelo prevê [ Tokens Middle ]    |
|                                                                                               |
| Formato FIM (Modo SPM):                                                                       |
| <SUF> [ Tokens Sufixo ] <PRE> [ Tokens Prefixo ] <MID> ===> Modelo prevê [ Tokens Middle ]    |
+-----------------------------------------------------------------------------------------------+

Ao expor 50% dos dados de pré-treino ao formato FIM, o modelo atenta para o prefixo e para o sufixo simultaneamente ao gerar o meio.


3. Tabela de Tokens Especiais FIM (2026)

+-------------------------------------------------------------------------------------------------------------+
|                                    Tabela de Tokens Especiais FIM (2026)                                    |
+--------------------+--------------------------+--------------------------+--------------------------+-------+
| Família do Modelo  | Token de Prefixo         | Token de Sufixo          | Início do Middle         | Modo  |
+--------------------+--------------------------+--------------------------+--------------------------+-------+
| Qwen 2.5 Coder     | <|fim_prefix|>           | <|fim_suffix|>           | <|fim_middle|>           | PSM   |
| DeepSeek Coder V1/2| <|fim begin|>          | <|fim hole|>           | <|fim end|>            | SPM   |
| StarCoder / SC2    | <fim_prefix>             | <fim_suffix>             | <fim_middle>             | PSM   |
| Mistral Codestral  | [PREFIX]                 | [SUFFIX]                 | [MIDDLE]                 | PSM   |
| CodeLlama          | <PRE>                    | <SUF>                    | <MID>                    | PSM   |
+--------------------+--------------------------+--------------------------+--------------------------+-------+

4. Benchmarks: Modelos Ghost-Text Sub-100ms

+---------------------------------------------------------------------------------------------------------------+
|                               BENCHMARK COMPARATIVO DE MODELOS GHOST-TEXT SUB-100MS                           |
+-----------------------+--------------------+-------------------+------------------+-------------+-------------+
| Modelo                | Precisão FIM       | Infill Multilinha | Tempo até 1º     | Velocidade  | Consumo     |
|                       | Linha Única(Pass@1)| Precisão(Pass@1)  | Token (TTFT p50) | (Tokens/s)  | VRAM (FP16) |
+-----------------------+--------------------+-------------------+------------------+-------------+-------------+
| Qwen 2.5 Coder 1.5B   | 84.6%              | 64.2%             | 42 ms            | 188 tok/s   | 3.2 GB      |
| Qwen 2.5 Coder 7B     | 89.2%              | 76.8%             | 84 ms            | 112 tok/s   | 15.2 GB     |
| DeepSeek Coder 1.3B   | 78.4%              | 56.1%             | 39 ms            | 196 tok/s   | 2.8 GB      |
| StarCoder2 3B         | 81.1%              | 60.5%             | 58 ms            | 144 tok/s   | 6.4 GB      |
+-----------------------+--------------------+-------------------+------------------+-------------+-------------+

5. Estratégia de Contexto em IDEs

  • Janela Deslizante Assimétrica: 60-70% do orçamento para o prefixo (1.500-3.000 tokens) e 30-40% para o sufixo (500-1.500 tokens).
  • Injeção AST: 300 tokens com declarações de tipos e imports de abas vizinhas via Tree-sitter.

6. Servidor FIM em Python (FastAPI + vLLM)

import os, time
from typing import Optional, List
from fastapi import FastAPI
from pydantic import BaseModel
import httpx

app = FastAPI(title="FIM Engine")
BACKEND_URL = os.getenv("INFERENCE_BACKEND_URL", "http://127.0.0.1:8000/v1/completions")
MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-Coder-1.5B")

class FIMRequest(BaseModel):
    prefix: str
    suffix: str
    max_tokens: int = 48
    temperature: float = 0.1

@app.post("/v1/autocomplete")
async def autocomplete(req: FIMRequest):
    t0 = time.perf_counter()
    prompt = f"<|fim_prefix|>{req.prefix}<|fim_suffix|>{req.suffix}<|fim_middle|>"
    stops = ["<|fim_prefix|>", "<|fim_suffix|>", "<|fim_middle|>", "<|endoftext|>", "\n\n"]
    
    payload = {
        "model": MODEL_NAME, "prompt": prompt, "max_tokens": req.max_tokens,
        "temperature": req.temperature, "stop": stops, "stream": False
    }
    async with httpx.AsyncClient(timeout=1.5) as client:
        resp = await client.post(BACKEND_URL, json=payload)
        data = resp.json()
    return {
        "completion": data["choices"][0]["text"],
        "latency_ms": round((time.perf_counter() - t0) * 1000, 2)
    }

7. Sequências de Parada e Prevenção de Duplicidades

  • Sempre incluir os tokens FIM no array stop.
  • Quebra de linha dupla (\n\n) como delimitador para sugestões de linha única.
  • Filtro no cliente para eliminar fechamento duplicado de } ou ).

8. TCO e Economia de Implantação (100 Desenvolvedores)

  • 100 Desenvolvedores: ~120.000 requisições/dia (2,64M ao mês).
  • Copilot Comercial: $1.900/mês ($19/usuário).
  • API Serverless: ~$115,40/mês ($0,05/$0,15 por 1M de tokens).
  • GPU Dedicada na Nuvem (A10G): $730/mês (100% de privacidade, latência <70ms).
  • Execução Local (Mac M4 / RTX 4090): $0/mês em custos de nuvem.

9. Conclusão e Recomendações

  1. Uso Local no Laptop: Qwen 2.5 Coder 1.5B via llama.cpp (42ms de TTFT e 3.2GB de VRAM).
  2. Servidor Compartilhado de Equipe: Qwen 2.5 Coder 7B com vLLM (76.8% de precisão multilinha).
  3. Limitar Contexto: Menos de 2.000 tokens de prefixo para garantir TTFT sub-100ms.
← Todos os artigos
0 / 4