sábado, 1 de agosto de 2026

Autocompletado con IA local en Neovim: cómo saqué a Ollama del error de la API key

Desde hace un tiempo tengo montado un flujo de trabajo con Neovim para programar en Python, C/C++ y para el desarrollo de firmware en microcontroladores de 8 bits (PIC, AVR) y en plataformas de 32 bits como STM32 y el ESP32 con MicroPython. Quería sumarle autocompletado inteligente, pero sin depender de servicios en la nube: todo corriendo local, en mi propia laptop.

El punto de partida

El hardware con el que trabajo no es una bestia de IA, pero da para lo que necesito:

  • GPU dedicada NVIDIA GTX 1650
  • CPU Intel i5 de 10ma generación
  • 16 GB de RAM
  • Ubuntu 26.04 LTS con drivers NVIDIA al día

Sobre eso tengo Ollama corriendo dos modelos locales: qwen2.5-coder:7b para código y minicpm-v:8b para tareas con visión. Para conectar Ollama con Neovim elegí el plugin minuet-ai.nvim, usando el motor FIM (Fill-In-The-Middle), pensado justo para autocompletar código a mitad de una línea o función, no solo al final del archivo.

El error que no me dejaba avanzar

Al abrir Neovim con un archivo .py me aparecía este mensaje:

"The API key has not been provided as an environment variable..."

Lo curioso es que el autocompletado sí funcionaba, aunque de forma breve e inconsistente — lo cual hacía más confuso el diagnóstico.

La causa resultó ser un detalle fácil de pasar por alto en la configuración del plugin:

provider_options = {
  openai_fim_compatible = {
    api_key = "OLLAMA", -- esto NO es lo que Minuet espera
    ...
  },
},

minuet-ai.nvim no toma ese campo como el valor de la clave, sino como el nombre de una variable de entorno que va a buscar con os.getenv(). Como en mi sistema no existía ninguna variable llamada OLLAMA, el plugin fallaba al intentar leerla — aunque Ollama, de por sí, no valida ninguna clave real.

La solución

  1. Crear una variable de entorno placeholder en ~/.bashrc:
    export OLLAMA_API_KEY="ollama"
  2. Recargar la shell:
    source ~/.bashrc
  3. Apuntar el plugin al nombre de la variable, no a un valor literal:
    provider_options = {
      openai_fim_compatible = {
        api_key = "OLLAMA_API_KEY", -- nombre de la variable de entorno
        name = "Ollama",
        end_point = "http://127.0.0.1:11434/v1/completions",
        model = "qwen2.5-coder:7b",
        optional = {
          max_tokens = 128,
          top_p = 0.9,
        },
      },
    },
  4. Abrir Neovim desde una terminal que haya cargado esa variable. Si Neovim se lanza desde un acceso directo gráfico o una shell distinta, nunca va a heredar la variable y el error va a reaparecer. Confirmar con:
    echo $OLLAMA_API_KEY

Sobre el tamaño del modelo y el hardware

Un detalle que vale la pena tener presente: una GTX 1650 típicamente trae 4 GB de VRAM, y qwen2.5-coder:7b en su versión cuantizada ya pesa 4.7 GB solo en los pesos del modelo. Es muy probable que Ollama esté descargando parte del procesamiento a la CPU, lo que explicaría respuestas lentas o cortadas.

Para autocompletado tipo FIM —que necesita ser rápido más que profundo— probablemente convenga bajar a una versión más ligera:

ollama pull qwen2.5-coder:1.5b-base
# o
ollama pull qwen2.5-coder:3b-base

La pérdida de calidad para completar líneas en Python o C/C++ es mínima, pero la latencia baja notablemente, que es justo lo que uno busca cuando el autocompletado tiene que aparecer mientras se sigue escribiendo.

Configuración final

return {
  "milanglacier/minuet-ai.nvim",
  dependencies = {
    "nvim-lua/plenary.nvim",
  },
  config = function()
    require("minuet").setup({
      provider = "openai_fim_compatible",
      n_completions = 1,
      context_window = 1024,
      provider_options = {
        openai_fim_compatible = {
          api_key = "OLLAMA_API_KEY",
          name = "Ollama",
          end_point = "http://127.0.0.1:11434/v1/completions",
          model = "qwen2.5-coder:7b",
          optional = {
            max_tokens = 128,
            top_p = 0.9,
            stop = { "\n\n" },
          },
        },
      },
      virtualtext = {
        auto_trigger_ft = { "c", "cpp", "python", "lua" },
        keymap = {
          accept = "<A-y>",
          accept_line = "<A-l>",
          prev = "<A-[>",
          next = "<A-]>",
          dismiss = "<A-e>",
        },
      },
    })
  end,
}

Cierre

Al final, el problema no era de Ollama ni de la GPU, sino de una confusión de conceptos en la configuración del plugin: nombre de variable de entorno vs. valor de la clave. Con esto resuelto, el flujo de autocompletado local en Neovim queda funcionando para el trabajo diario en Python, C/C++ y embebidos — sin mandar una sola línea de código a la nube.

Próximo paso: confirmar que Ollama esté usando realmente la GPU (nvidia-smi mientras genera completions) y afinar el tamaño de modelo según la latencia real que se sienta al escribir.