Loading...

文章背景图

minuet-ai.nvim:在 Neovim 里随敲随补的 AI 代码补全(支持 DeepSeek/Ollama/Gemini)

2026-10-07
0
- 字
- 分钟
|

minuet-ai.nvim 补全界面

官方信息

项目名称minuet-ai.nvim(小步舞曲)
仓库地址https://github.com/milanglacier/minuet-ai.nvim
官方网站GitHub README 文档
最新更新时间2026-10-07
项目定位Neovim 上"随敲随补"的 AI 代码补全插件,支持 OpenAI、Claude、Gemini、Codestral、Ollama、Llama.cpp 与任意 OpenAI 兼容服务,无需后台专有二进制

项目背景

Minuet(小步舞曲)的口号是 "Dance with Intelligence in Your Code 💃"——像小步舞曲一样,让 AI 补全跟着你的敲键节奏优雅地流动在代码里。它由开发者 milanglacier 维护,目标是做一个不绑定任何模型厂商、不依赖后台专有进程的 Neovim 补全方案。

和 llm.nvim 不同,Minuet 干脆连后端二进制都不要了——它只通过 curl 直接向你选定的 LLM 服务商发 HTTP 请求。这意味着:你用 DeepSeek 官方 API 就填 DeepSeek 的 Key,用本地 Ollama 就填 localhost:11434,用 OpenRouter 聚合就填 OpenRouter 的地址,插件本身不抽成、不缓存、不启动守护进程。

它的另一个特点是"前端兼容":既能作为 nvim-cmp / blink.cmp 的一个补全源,也能以独立的 virtual-text 幽灵文本前端工作,还能当 Neovim 0.11+ 的内置 LSP 补全服务器。最近版本还加入了"Duet 下一行预测"实验特性,以及对 DeepSeek V4、Qwen2.5-Coder 等 FIM 模型的专门适配。

核心特性

  • 双补全模式:既支持基于 chat 模型的补全(专门优化的提示词),也支持 FIM(Fill-in-the-Middle)中插补全,适配 DeepSeek、Codestral、Qwen 等模型。
  • 多 Provider 支持:OpenAI、Claude、Gemini、Codestral、Ollama、Llama.cpp,以及任何 OpenAI 兼容接口(DeepSeek 官方、OpenRouter、Opencode 等)。
  • 无需后台二进制:只用 vim.system 调 curl,不再依赖 plenary.nvim,进程干净、易排查。
  • 多前端可选:virtual-text(幽灵文本)、nvim-cmp、blink.cmp、Neovim 内置补全、mini.completion。
  • 流式输出:补全可以边生成边显示,慢模型也不卡。
  • 逐行接受:长建议可以一行一行增量接受,按自己的节奏拉取。
  • 输入同步:当你继续输入的内容和建议开头匹配时,Minuet 会保持补全同步而不是丢弃,减少重复请求。
  • Duet 下一行预测:实验性地预测你接下来要编辑的位置(next-edit prediction)。

环境要求

  • Neovim:0.10+(内置补全需 0.11+,inline_completion 需 0.12+)。
  • 插件管理器:lazy.nvim 推荐;也支持 Rocks.nvim(Rocks install minuet-ai.nvim)。
  • 可选补全前端:nvim-cmp 或 blink.cmp(用 virtual-text 前端则不需要)。
  • API Key:至少一个支持的 LLM 服务商的 Key(DeepSeek / OpenRouter / Gemini 等)。
  • 本地模型(可选):Ollama 或 llama.cpp 服务。

详细部署步骤

第一步:安装插件

lazy.nvim 用户新建 ~/.config/nvim/lua/plugins/minuet.lua:

return {
  'milanglacier/minuet-ai.nvim',
  config = function()
    require('minuet').setup {
      -- 配置见下方
    }
  end,
  -- 可选:用 nvim-cmp / blink.cmp 作为前端时再加
  -- { 'hrsh7th/nvim-cmp' },
  -- { 'Saghen/blink.cmp' },
}

Rocks.nvim 用户直接在 Nvim 里执行:

:Rocks install minuet-ai.nvim

第二步:配置 virtual-text 幽灵文本前端(最省事,推荐)

下面这套配置不依赖 nvim-cmp,直接在光标后显示灰色建议:

require('minuet').setup {
  virtualtext = {
    auto_trigger_ft = {},          -- 想自动触发就填 { 'python', 'lua', 'rust' }
    keymap = {
      accept          = '<A-A>',   -- 接受整段补全
      accept_line     = '<A-a>',   -- 只接受一行
      accept_n_lines   = '<A-z>',   -- 接受 N 行(再按数字+回车)
      prev            = '<A-[>',   -- 上一条建议 / 手动触发
      next            = '<A-]>',   -- 下一条建议 / 手动触发
      dismiss         = '<A-e>',   -- 忽略
    },
  },
}

第三步:配置 Provider(以 DeepSeek 为例)

Minuet 的核心是 provider。下面给出三个最常用方案。

方案 A:DeepSeek 官方 FIM 接口(便宜、快,推荐)

# 先设置环境变量
export DEEPSEEK_API_KEY="sk-xxxxxxxxxxxxxxxx"
require('minuet').setup {
  provider = 'openai_fim_compatible',
  provider_options = {
    openai_fim_compatible = {
      api_key = 'DEEPSEEK_API_KEY',     -- 填环境变量名,不要硬写 Key
      name = 'deepseek',
      optional = {
        max_tokens = 256,
        top_p = 0.9,
      },
    },
  },
}

方案 B:OpenRouter 聚合(可白嫖 Gemini 免费额度)

export OPENROUTER_API_KEY="sk-or-xxxxxxxx"
require('minuet').setup {
  provider = 'openai_compatible',
  request_timeout = 2.5,
  throttle = 1500,        -- 调大省钱、防限流
  debounce = 600,
  provider_options = {
    openai_compatible = {
      api_key = 'OPENROUTER_API_KEY',
      end_point = 'https://openrouter.ai/api/v1/chat/completions',
      model = 'deepseek/deepseek-v4-flash',
      name = 'Openrouter',
      optional = {
        max_tokens = 56,
        top_p = 0.9,
        provider = { sort = 'throughput' },
        reasoning_effort = 'none',   -- 关闭思考,降低首 token 延迟
      },
    },
  },
}

方案 C:本地 Ollama(完全离线)

ollama pull qwen2.5-coder:7b
require('minuet').setup {
  provider = 'openai_fim_compatible',
  n_completions = 1,               -- 本地模型省资源只出 1 条
  context_window = 512,              -- 先从小上下文试起
  provider_options = {
    openai_fim_compatible = {
      api_key = 'TERM',
      name = 'Ollama',
      end_point = 'http://localhost:11434/v1/completions',
      model = 'qwen2.5-coder:7b',
      optional = { max_tokens = 56, top_p = 0.9 },
    },
  },
}

第四步:(可选)接入 nvim-cmp / blink.cmp

如果你用 nvim-cmp,把 minuet 加进 sources 并调大超时:

require('cmp').setup {
  sources = {
    { name = 'minuet' },
    -- 其他原有 source
  },
  performance = {
    fetching_timeout = 2000,        -- LLM 比 LSP 慢,要调大
  },
  mapping = {
    ['<A-y>'] = require('minuet').make_cmp_map(),  -- 手动触发补全
  },
}

blink.cmp 用户在 sources.default 里加 'minuet',并在 providers.minuet 里把 score_offset = 50 调高优先级即可。

第五步:启动验证

重启 Nvim,新建一个 test.py,输入:

def is_prime(n):
    # 光标停在这里,按 <A-[> 手动触发补全

按 <A-[> 手动召唤建议,灰色 ghost-text 出现后按 <A-A> 接受。常用命令:

  • :Minuet change_provider —— 切换 Provider。
  • :Minuet change_model —— 切换模型。
  • :Minuet virtualtext —— 开关 virtual-text 前端。
  • :Minuet duet —— 实验性下一行预测。

常见坑与解决办法

  • 补全半天出不来:LLM 首 token 延迟高。把 request_timeout 调到 2.5s 以上;chat 模型记得关闭 thinking(reasoning_effort='none')。
  • nvim-cmp 里输入有明显卡顿:把 fetching_timeout 调到 2000,并把 minuet 设为手动触发(从自动 sources 移除)。
  • 401 / 认证失败:api_key 字段填的是环境变量名而不是 Key 本身,确认 export 生效。
  • 本地模型补全质量差:从 context_window = 512 起步,确认显存能跑得动 qwen2.5-coder:7b。
  • 缩进错乱:Neovim 0.11 内置补全有上游 bug,对 Python 这类缩进敏感语言建议只用 virtual-text 前端。

使用方法示例

日常写代码时,敲完函数名和注释后停顿,<A-]> 召唤下一条建议,<A-a> 一行行接受,不合适按 <A-e> 丢掉。需要在多个模型间横评时,用 :Minuet change_provider 一键在 DeepSeek 与 Gemini 之间切换,对比哪个补全更合手。

常见问题 FAQ

Q1:它和 Copilot 哪个便宜?
A:用 DeepSeek FIM 或 OpenRouter 免费模型时成本接近零,且可本地跑;Copilot 需月订阅。

Q2:需要后台常驻一个服务吗?
A:不需要。Minuet 每次补全才发一次 curl 请求,进程退出即停止,不占内存。

Q3:支持中文注释补全吗?
A:支持,chat 模型对中文注释理解很好;FIM 模型则更依赖上下文代码。

Q4:能接公司自建的 OpenAI 网关吗?
A:能。把 end_point 改成公司网关的 /v1/chat/completions 地址即可。

跳转链接

评论交流

文章目录