parrot.nvim
parrot.nvim 是一款专为 Neovim 打造的 AI 辅助插件,旨在将大语言模型(LLM)的能力无缝融入你的文本编辑工作流。它专注于提供按需的代码补全、内容生成及对话式交互,所有操作均在原生的 Neovim 缓冲区中进行,让开发者能像在聊天一样与 AI 协作编写和修改代码。
这款工具主要解决了传统 AI 编程助手“黑盒化”的问题。不同于自动扫描文件或在后台静默发送数据的智能体,parrot.nvim 坚持透明与隐私优先的原则:用户完全掌控发送给 API 的内容,绝无隐藏的后台请求或自动分析行为。这意味着你可以放心地在敏感项目中使用它,而无需担心代码泄露风险。
parrot.nvim 特别适合注重隐私、希望精确控制 AI 交互过程的资深开发者和技术研究人员。其技术亮点在于强大的兼容性,支持 OpenAI、Anthropic、Google Gemini 等主流云服务,也能通过 Ollama 连接本地离线模型;同时提供灵活的凭证管理和基于 Markdown 的持久化对话存储。无论是修复 Bug、重写代码段还是添加注释,它都能让你在不离开编辑器的情况下,安全高效地完成各类编程任务。
使用场景
资深后端工程师小李正在 Neovim 中重构一个遗留的 Python 微服务模块,需要快速修复逻辑漏洞并补充缺失的文档注释。
没有 parrot.nvim 时
- 上下文切换频繁:遇到复杂 Bug 或需要生成代码时,必须手动复制代码片段切换到浏览器,在多个 AI 网页标签页间粘贴提问,打断心流。
- 隐私与安全顾虑:担心将包含内部业务逻辑或敏感配置的代码上传至不明云端服务,缺乏对发送内容的完全掌控权。
- 工作流割裂:AI 返回的代码需要手动复制回编辑器,再仔细对齐缩进和格式,容易引入人为错误且效率低下。
- 模型切换困难:想对比不同大模型(如本地 Ollama 与云端 Claude)的输出效果时,需重新配置环境变量或更换工具,过程繁琐。
使用 parrot.nvim 后
- 原生无缝交互:直接在 Neovim 缓冲区选中代码,通过
PrtRewrite或PrtAppend命令即可让 AI 基于当前上下文修复 Bug 或续写代码,无需离开编辑器。 - 数据主权在握:所有发送给 LLM 的内容均由用户显式触发且完全可控,支持调用本地部署的 Ollama 模型,确保敏感代码绝不流出内网。
- 指令驱动编辑:利用预定义的系统提示词(System Prompts),一键为函数添加符合团队规范的文档注释(
PrtPrepend),自动保持代码风格一致。 - 灵活模型调度:通过统一接口随时在 OpenAI、Anthropic 或本地模型间切换,针对不同任务选择最优模型,且凭据管理安全透明。
parrot.nvim 通过将大模型能力深度融入 Neovim 原生工作流,让开发者在享有极致编码效率的同时,牢牢掌握数据隐私与操作控制权。
运行环境要求
- Linux
- macOS
- Windows
未说明 (插件本身无 GPU 需求,若使用本地 Ollama 部署模型则取决于所选模型)
未说明

快速开始
parrot.nvim 🦜
这是 parrot.nvim,一款终极的 随机鹦鹉模型,旨在支持你在 Neovim 中进行文本编辑。
功能 • 演示 • 快速入门 • 命令 • 配置 • 路线图 • 常见问题
功能
parrot.nvim 提供开箱即用的无缝体验,将当前的 LLM API 与你的 Neovim 工作流紧密集成,专注于文本生成。精选的核心功能包括 按需文本补全和编辑,以及在原生 Neovim 缓冲区 中进行的 类聊天会话。
此插件面向那些真正知道自己在做什么,并且重视 隐私与透明度 的用户。用户始终完全掌控将发送到 LLM API 端点的内容,因此该插件完全 排除 了诸如 codex、claude-code 和 gemini-cli 等工具所提供的代理概念。
代码的很大一部分基于 Tibor Schmidt 华丽作品 gp.nvim 的早期分支。
- 持久对话以 Markdown 文件形式存储在 Neovim 的标准路径或用户定义的位置
- 基于用户指令和带有预设系统提示的聊天的自定义钩子,用于内联文本编辑
- 统一的提供者系统,支持任何兼容 OpenAI 的 API:
- OpenAI API
- Anthropic API
- Google Gemini API
- xAI API
- 通过 ollama 进行本地和离线服务
- 任何可配置函数的自定义 OpenAI 兼容端点;还支持 Perplexity.ai API、Mistral API、Groq API、DeepSeek API、GitHub Models 和 NVIDIA API
- 来自不同来源的灵活 API 凭证管理:
- 环境变量
- Bash 命令
- 密码管理器 CLI(惰性求值)
- 使用
.parrot.md文件通过PrtContext命令实现仓库特定的指令 - 无 自动补全,无 在后台隐藏请求来分析你的文件
演示
无缝切换提供商和模型。
https://github.com/user-attachments/assets/0df0348f-85c0-4a2d-ba1f-ede2738c6d02
根据注释触发代码补全。
https://github.com/user-attachments/assets/197f99ac-9854-4fe9-bddb-394c1b64f6b6
让鹦鹉帮你修复 bug。
https://github.com/user-attachments/assets/d3a0b261-a9dd-45e6-b508-dc5280594b06
使用 `PrtRewrite` 重写可视选区。
https://github.com/user-attachments/assets/c3d38702-7558-4e9e-96a3-c43312a543d0
使用 `PrtAppend` 将可视选区作为上下文追加到代码中。
https://github.com/user-attachments/assets/80af02fa-cd88-4023-8a55-f2d3c0a2f28e
使用 `PrtPrepend` 向函数添加注释。
https://github.com/user-attachments/assets/9a6bfe66-4bc7-4b63-8694-67bf9c23c064
使用 `PrtRetry` 重试你最近的一次重写、追加或插入操作。
https://github.com/user-attachments/assets/03442f34-687b-482e-b7f1-7812f70739cc
快速入门
依赖项
此插件需要最新版本的 Neovim,并依赖于一组精心挑选的成熟插件。
neovim 0.10+plenaryripgrep(可选)fzf(可选,需要 ripgrep)telescope(可选)
安装
lazy.nvim
{
"frankroeder/parrot.nvim",
dependencies = { "ibhagwan/fzf-lua", "nvim-lua/plenary.nvim" },
opts = {}
}
Packer
require("packer").startup(function()
use({
"frankroeder/parrot.nvim",
requires = { 'ibhagwan/fzf-lua', 'nvim-lua/plenary.nvim'},
config = function()
require("parrot").setup()
end,
})
end)
Neovim 原生包
git clone --depth=1 https://github.com/frankroeder/parrot.nvim.git \
"${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/pack/parrot/start/parrot.nvim
设置
最低要求是至少设置一个提供者,例如下面提供的那个,或者从 提供者配置示例 中选择一个。
{
"frankroeder/parrot.nvim",
dependencies = { 'ibhagwan/fzf-lua', 'nvim-lua/plenary.nvim' },
-- 可选地包含 "folke/noice.nvim" 或 "rcarriga/nvim-notify" 以获得精美的通知
config = function()
require("parrot").setup {
-- 必须显式设置提供者才能使其可用。
providers = {
openai = {
name = "openai",
api_key = os.getenv "OPENAI_API_KEY",
endpoint = "https://api.openai.com/v1/chat/completions",
params = {
chat = { temperature = 1.1, top_p = 1 },
command = { temperature = 1.1, top_p = 1 },
},
topic = {
model = "gpt-4.1-nano",
params = { max_completion_tokens = 64 },
},
models ={
"gpt-4o",
"o4-mini",
"gpt-4.1-nano",
}
},
},
}
end,
}
使用
聊天基础
parrot.nvim 中的聊天本质上是标准的 Markdown 缓冲区。
工作原理:
- 打开聊天:使用
:PrtChatNew打开一个新的聊天缓冲区(或使用:PrtChatToggle切换最近的一个)。 - 输入提示:在用户前缀
🗨:后直接在缓冲区中写下你的问题或指令。 - 触发 LLM:按下触发键映射(默认为插入模式下的
<C-g><C-g>)或使用:PrtChatRespond命令。 - 接收响应:LLM 会将响应流式传输到光标所在位置。
- 停止生成:随时按下
<C-g>s可以停止生成。
关键概念:
- 上下文:整个缓冲区内容都会作为上下文发送(除非使用了隐藏注释)。
- 系统提示:你可以为每个聊天或全局设置独特的系统提示。
- 持久化:聊天会以
.md文件的形式保存在你配置的目录中。
命令模式(交互式命令)
命令模式允许你在不离开当前缓冲区的情况下,直接对代码与 LLM 进行交互。
可用命令:
:PrtRewrite– 根据你的提示重写可视选区。:PrtAppend– 在选区后追加生成的文本。:PrtPrepend– 在选区前插入生成的文本。:PrtRetry– 重试上次的重写/追加/插入操作。:PrtEdit– 编辑并重新运行上一条命令,同时修改提示。
工作流程:
- 使用可视化模式选择需要修改的代码。
- 运行上述命令之一(例如
:PrtRewrite fix the bug)。 - LLM 处理你的选区,并将结果流式传输过来,或者显示一个差异视图。
独立的模型选择:
parrot.nvim 维持 两套独立的模型选择:
- 聊天模型:用于聊天缓冲区。可在聊天缓冲区内部使用
:PrtModel进行切换。 - 命令模型:用于交互式命令(如
PrtRewrite等)。可在任何非聊天缓冲区中使用:PrtModel进行切换。
这使得你可以为快速的内联编辑使用速度快、成本低的模型,而为深入的对话交流则使用功能更强大的模型。
命令
以下是可配置为快捷键的可用命令。这些命令已包含在默认配置中。此外,还有一些有用的命令通过钩子实现(见下文)。
通用
| 命令 | 描述 |
|---|---|
PrtChatNew <target> |
打开一个新的聊天 |
PrtChatToggle <target> |
切换聊天(打开最近一次聊天或新建一个) |
PrtChatPaste <target> |
将可视选区粘贴到最近的聊天中 |
PrtInfo |
打印插件配置 |
PrtContext <target> |
编辑本地上下文文件 |
PrtChatFinder |
使用 fzf 模糊搜索聊天文件 |
PrtChatDelete |
删除当前的聊天文件 |
PrtChatRespond |
触发聊天响应(在聊天文件中) |
PrtStop |
中断正在进行的 Parrot 生成任务(在任何地方都有效) |
PrtProvider <provider> |
切换提供商(参数为空时会触发 fzf) |
PrtModel <model> |
切换交互式命令使用的模型(参数为空时会触发 fzf)。注意:聊天模型必须在聊天缓冲区内部更改。 |
PrtStatus |
打印当前的提供商和模型选择 |
PrtReloadCache <optional provider> |
为所有或特定提供商重新加载缓存的模型 |
PrtCmd <optional prompt> |
直接生成可执行的 Neovim 命令(需明确确认后执行) |
| 交互式 | |
PrtRewrite <optional prompt> |
根据提供的提示重写可视选区(直接输入、输入对话框或从集合中选择) |
PrtEdit |
类似于 PrtRewrite,但可以修改上次的提示 |
PrtAppend <optional prompt> |
根据提供的提示将文本追加到可视选区(直接输入、输入对话框或从集合中选择) |
PrtPrepend <optional prompt> |
根据提供的提示将文本插入到可视选区之前(直接输入、输入对话框或从集合中选择) |
PrtRetry |
重复上次的重写/追加/插入操作 |
| 示例钩子 | |
PrtImplement |
将可视选区作为提示来生成代码 |
PrtAsk |
向模型提问 |
其中 <target> 表示在以下目标位置之一打开聊天的命令(默认为 toggle_target):
popup:打开一个弹出窗口,可通过下方提供的选项进行配置。split:在水平分割窗口中打开聊天。vsplit:在垂直分割窗口中打开聊天。tabnew:在新标签页中打开聊天。
所有聊天相关命令(PrtChatNew, PrtChatToggle)以及自定义钩子都支持在触发时将可视选区显示在聊天中。而交互式命令则要求用户利用 模板占位符,以便在 API 请求中考虑可视选区。
配置
选项
{
-- 提供商定义包括端点、API密钥、默认参数,
-- 以及用于聊天摘要的主题模型参数。你可以为你的提供商使用任意名称,
-- 并通过自定义函数进行配置。
providers = {
openai = {
name = "openai",
endpoint = "https://api.openai.com/v1/chat/completions",
-- 用于在线查询可用模型的端点
model_endpoint = "https://api.openai.com/v1/models",
api_key = os.getenv("OPENAI_API_KEY"),
-- 可选:获取API密钥的替代方法
-- 使用GPG解密:
-- api_key = { "gpg", "--decrypt", vim.fn.expand("$HOME") .. "/my_api_key.txt.gpg" },
-- 使用macOS Keychain:
-- api_key = { "/usr/bin/security", "find-generic-password", "-s my-api-key", "-w" },
--- 用于聊天和交互式命令的默认模型参数
params = {
chat = { temperature = 1.1, top_p = 1 },
command = { temperature = 1.1, top_p = 1 },
},
-- 用于总结聊天的主题模型参数
topic = {
model = "gpt-4.1-nano",
params = { max_completion_tokens = 64 },
},
-- Parrot可以在会话间记住的一组模型
-- 注意:在未来的版本中,这将得到更智能的处理
models = {
"gpt-4.1",
"o4-mini",
"gpt-4.1-mini",
"gpt-4.1-nano",
},
},
...
}
-- 聊天会话和命令流程中使用的默认系统提示
system_prompt = {
chat = ...,
command = ...
},
-- 所有命令使用的前缀
cmd_prefix = "Prt",
-- curl 的可选参数
curl_params = {},
-- 存储持久化状态信息的目录,例如
-- 当前提供商和所选模型
state_dir = vim.fn.stdpath("data"):gsub("/$", "") .. "/parrot/persisted",
-- 存储聊天记录的目录(可通过 PrtChatFinder 搜索)
chat_dir = vim.fn.stdpath("data"):gsub("/$", "") .. "/parrot/chats",
-- 聊天用户提示前缀
chat_user_prefix = "🗨:",
-- LLM 提示前缀
llm_prefix = "🦜:",
-- 明确确认删除聊天文件
chat_confirm_delete = true,
-- 本地聊天缓冲区快捷键
chat_shortcut_respond = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g><C-g>" },
chat_shortcut_delete = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g>d" },
chat_shortcut_stop = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g>s" },
chat_shortcut_new = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g>c" },
-- 完成回复后将光标移动到文件末尾的选项
chat_free_cursor = false,
-- PrtChatToggle、PrtChatNew、PrtContext 以及从 ChatFinder 打开的聊天的默认目标
-- 取值:popup / split / vsplit / tabnew
toggle_target = "vsplit",
-- 交互式用户输入的方式可以是“原生”的
-- 对于 vim.ui.input,也可以是“缓冲区”,即在原生 nvim 缓冲区中查询输入
-- (见下方视频演示)
user_input_ui = "native",
-- 弹出窗口布局
-- 边框样式:single、double、rounded、solid、shadow、none
style_popup_border = "single",
-- 边距以字符或行数表示
style_popup_margin_bottom = 8,
style_popup_margin_left = 1,
style_popup_margin_right = 2,
style_popup_margin_top = 2,
style_popup_max_width = 160
-- 用于交互式 LLM 调用的提示模板,例如 PrtRewrite,其中 {{llm}} 是
-- LLM 名称的占位符
command_prompt_prefix_template = "🤖 {{llm}} ~ ",
-- 自动选择命令响应(便于命令链式调用)
-- 如果设置为 false,则会释放缓冲区光标以便在其他地方继续编辑
command_auto_select_response = true,
-- 模型缓存刷新的时间间隔(小时)
-- 设置为 0 可禁用模型缓存
model_cache_expiry_hours = 48,
-- 安装插件时,PrtModel 和 PrtChatFinder 使用的 fzf_lua 选项
fzf_lua_opts = {
["--ansi"] = true,
["--sort"] = "",
["--info"] = "inline",
["--layout"] = "reverse",
["--preview-window"] = "nohidden:right:75%",
},
-- 启用查询加载动画
enable_spinner = true,
-- 加载时显示的动画类型
-- 可选:dots、line、star、bouncing_bar、bouncing_ball
spinner_type = "star",
-- 显示通过 @file、@buffer 或 @directory 补全添加的上下文提示
show_context_hints = true
-- 在应用重写/追加/前置更改之前显示差异预览
enable_preview_mode = true,
preview_auto_apply = false, -- 如果为真,预览超时后会自动应用更改
preview_timeout = 10000, -- 自动应用前的等待时间(毫秒)
preview_border = "rounded",
preview_max_width = 120,
preview_max_height = 30,
}
演示
当 user_input_ui = "native" 时,使用 vim.ui.input 作为简洁的输入界面。
https://github.com/user-attachments/assets/c2fe3bde-a35a-4f2a-957b-687e4f6f2e5c
当 user_input_ui = "buffer" 时,你的输入就是一个普通的缓冲区。关闭时,所有内容都会传递给 API。
https://github.com/user-attachments/assets/63e6e1c4-a2ab-4c60-9b43-332e4b581360
加载动画对于响应时间较长的提供商来说是一个有用的指示器。
https://github.com/user-attachments/assets/ebcd27cb-da00-4150-a0f8-1d2e1afa0acb
键位绑定
该插件提供了以下默认键映射:
| 键位 | 描述 |
|---|---|
<C-g>c |
通过 PrtChatNew 打开一个新的聊天 |
<C-g><C-g> |
通过 PrtChatRespond 触发 API 生成回复 |
<C-g>s |
通过 PrtStop 停止任何正在进行的 Parrot 生成过程 |
<C-g>d |
通过 PrtChatDelete 删除当前的聊天文件 |
提供商配置示例
统一的提供商系统允许你配置任何兼容 OpenAI 的 API 提供商。以下是几个流行提供商的示例:
Anthropic Claude
providers = {
perplexity = {
name = "perplexity",
endpoint = "https://api.perplexity.ai/chat/completions",
model_endpoint = "https://api.perplexity.ai/models",
api_key = os.getenv "PERPLEXITY_API_KEY",
params = {
chat = { temperature = 1.0, top_p = 1 },
command = { temperature = 1.0, top_p = 1 },
},
topic = {
model = "pplx-70b-chat",
params = { max_tokens = 32 },
},
headers = function(self)
return {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. self.api_key,
}
end,
models = {
"pplx-70b-chat",
"pplx-70b-instruct",
"pplx-40b-chat",
"pplx-40b-instruct",
"pplx-22b-chat",
"pplx-22b-instruct",
},
preprocess_payload = function(payload)
for _, message in ipairs(payload.messages) do
message.content = message.content:gsub("^%s*(.-)%s*$", "%1")
end
if payload.messages[1] and payload.messages[1].role == "system" then
-- 移除作为系统提示的第一条消息,因为 Perplexity 要求系统提示应包含在 API 请求体中,而非消息列表中
payload.system = payload.messages[1].content
table.remove(payload.messages, 1)
end
return payload
end,
},
}
Meta Llama
providers = {
llama = {
name = "llama",
endpoint = "https://api.llama-api.com/v1/chat/completions",
model_endpoint = "https://api.llama-api.com/v1/models",
api_key = os.getenv "LLAMA_API_KEY",
params = {
chat = { temperature = 1.0, top_p = 1 },
command = { temperature = 1.0, top_p = 1 },
},
topic = {
model = "Llama-3.1-8B-Instruct",
params = { max_tokens = 32 },
},
headers = function(self)
return {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. self.api_key,
}
end,
models = {
"Llama-3.1-8B-Instruct",
"Llama-3.1-70B-Instruct",
"Llama-3.1-405B-Instruct",
},
preprocess_payload = function(payload)
for _, message in ipairs(payload.messages) do
message.content = message.content:gsub("^%s*(.-)%s*$", "%1")
end
if payload.messages[1] and payload.messages[1].role == "system" then
-- 移除作为系统提示的第一条消息,因为 Llama API 要求系统提示应包含在请求体中
payload.system = payload.messages[1].content
table.remove(payload.messages, 1)
end
return payload
end,
},
}
Qwen
providers = {
qwen = {
name = "qwen",
endpoint = "https://dashscope.aliyuncs.com/compatible/oss/api/v1/chat/completions",
model_endpoint = "https://dashscope.aliyuncs.com/compatible/oss/api/v1/models",
api_key = os.getenv "QWEN_API_KEY",
params = {
chat = { temperature = 1.0, top_p = 1 },
command = { temperature = 1.0, top_p = 1 },
},
topic = {
model = "Qwen-Max",
params = { max_tokens = 32 },
},
headers = function(self)
return {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. self.api_key,
}
end,
models = {
"Qwen-Max",
"Qwen-Turbo",
"Qwen-Long",
"Qwen-Plus",
},
preprocess_payload = function(payload)
for _, message in ipairs(payload.messages) do
message.content = message.content:gsub("^%s*(.-)%s*$", "%1")
end
if payload.messages[1] and payload.messages[1].role == "system" then
-- 移除作为系统提示的第一条消息,因为 Qwen API 要求系统提示应包含在请求体中
payload.system = payload.messages[1].content
table.remove(payload.messages, 1)
end
return payload
end,
},
}
DeepSeek
providers = {
deepseek = {
name = "deepseek",
endpoint = "https://api.deepseek.com/v1/chat/completions",
model_endpoint = "https://api.deepseek.com/v1/models",
api_key = os.getenv "DEEPSEEK_API_KEY",
params = {
chat = { temperature = 1.0, top_p = 1 },
command = { temperature = 1.0, top_p = 1 },
},
topic = {
model = "DeepSeek-V2-Lite",
params = { max_tokens = 32 },
},
headers = function(self)
return {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. self.api_key,
}
end,
models = {
"DeepSeek-V2-Lite",
"DeepSeek-V2-Pro",
"DeepSeek-V2.5-Lite",
"DeepSeek-V2.5-Pro",
},
preprocess_payload = function(payload)
for _, message in ipairs(payload.messages) do
message.content = message.content:gsub("^%s*(.-)%s*$", "%1")
end
if payload.messages[1] and payload.messages[1].role == "system" then
-- 移除作为系统提示的第一条消息,因为 DeepSeek API 要求系统提示应包含在请求体中
payload.system = payload.messages[1].content
table.remove(payload.messages, 1)
end
return payload
end,
},
}
Yandex GigaChat
providers = {
gigachat = {
name = "gigachat",
endpoint = "https://gigachat.app/api/v1/chat/completions",
model_endpoint = "https://gigachat.app/api/v1/models",
api_key = os.getenv "GIGACHAT_API_KEY",
params = {
chat = { temperature = 1.0, top_p = 1 },
command = { temperature = 1.0, top_p = 1 },
},
topic = {
model = "GigaChat Pro",
params = { max_tokens = 32 },
},
headers = function(self)
return {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. self.api_key,
}
end,
models = {
"GigaChat Pro",
"GigaChat Lite",
"GigaChat Turbo",
},
preprocess_payload = function(payload)
for _, message in ipairs(payload.messages) do
message.content = message.content:gsub("^%s*(.-)%s*$", "%1")
end
if payload.messages[1] and payload.messages[1].role == "system" then
-- 移除作为系统提示的第一条消息,因为 Yandex GigaChat 要求系统提示应包含在请求体中
payload.system = payload.messages[1].content
table.remove(payload.messages, 1)
end
return payload
end,
},
}
providers = {
perplexity = {
name = "perplexity",
api_key = os.getenv("PERPLEXITY_API_KEY"),
endpoint = "https://api.perplexity.ai/chat/completions",
headers = function(self)
return {
["Content-Type"] = "application/json",
["Accept"] = "application/json",
["Authorization"] = "Bearer " .. self.api_key,
}
end,
topic = {
model = "r1-1776",
params = {
max_tokens = 64,
},
},
models = {
"sonar",
"sonar-pro",
"sonar-deep-research",
"sonar-reasoning",
"sonar-reasoning-pro",
"r1-1776",
},
}
}
添加新命令
提问并以弹出窗口形式接收答案
require("parrot").setup {
-- ...
hooks = {
Ask = function(parrot, params)
local template = [[
根据你现有的知识库,请生成一个简洁明了、直接回答问题的回复。在回答中优先考虑准确性和相关性,尽量利用你所掌握的最新信息。力求用简练的语言,抓住问题的核心要点。
问题: {{command}}
]]
local model_obj = parrot.get_model("command")
parrot.logger.info("正在调用模型: " .. model_obj.name)
parrot.Prompt(params, parrot.ui.Target.popup, model_obj, "🤖 询问 ~ ", template)
end,
}
-- ...
}
使用预设聊天提示开始对话,检查拼写
require("parrot").setup {
-- ...
hooks = {
SpellCheck = function(prt, params)
local chat_prompt = [[
你的任务是将提供的文本改写成清晰、语法正确的版本,同时尽可能保留原文的意思。请纠正其中的拼写错误、标点符号错误、动词时态问题、用词不当以及其他语法错误。
]]
prt.ChatNew(params, chat_prompt)
end,
}
-- ...
}
更多钩子和键绑定可以参考我的 个人 lazy.nvim 配置 或者 其他用户的配置。
提示语集合
如果你在使用 PrtRewrite、PrtAppend 或 PrtPrepend 时,反复输入相同的提示语,那么可以考虑一种更轻量级的方式——直接定义提示语,而不是通过用户命令(即钩子)来实现:
require("parrot").setup {
-- ...
prompts = {
["Spell"] = "我希望你校对所提供的文本,并修正其中的错误。" -- 例如::'<,'>PrtRewrite Spell
["Comment"] = "请添加注释,解释这段代码的作用。" -- 例如::'<,'>PrtPrepend Comment
["Complete"] = "请继续完成文件 {{filename}} 中提供的代码片段。" -- 例如::'<,'>PrtAppend Complete
}
-- ...
}
这些提示语可以直接作为上述交互式命令的参数使用,也可以与 模板占位符 结合使用。
模板占位符
用户可以在钩子和系统模板中使用以下占位符,以注入额外的上下文信息:
| 占位符 | 含义 |
|---|---|
{{selection}} |
当前可视选区 |
{{filetype}} |
当前缓冲区的文件类型 |
{{filepath}} |
当前文件的完整路径 |
{{filecontent}} |
当前缓冲区的全部内容 |
{{multifilecontent}} |
所有打开缓冲区的全部内容 |
下面是一个如何在补全钩子中使用这些占位符的示例,该钩子会接收整个文件上下文和选中的代码片段作为输入。
require("parrot").setup {
-- ...
hooks = {
CompleteFullContext = function(prt, params)
local template = [[
我有来自 {{filename}} 的如下代码:
```{{filetype}}
{{filecontent}}
```
请特别关注以下部分:
```{{filetype}}
{{selection}}
```
请仔细且逻辑严谨地完成上述代码。请仅回复应插入的代码片段。
]]
local model_obj = prt.get_model("command")
prt.Prompt(params, prt.ui.Target.append, model_obj, nil, template)
end,
}
-- ...
}
此外,{{filetype}} 和 {{filecontent}} 占位符也可以用于自定义钩子中调用 prt.ChatNew(params, chat_prompt) 时,直接注入整个文件的内容。
require("parrot").setup {
-- ...
CodeConsultant = function(prt, params)
local chat_prompt = [[
你的任务是分析提供的 {{filetype}} 代码,并提出优化建议以提升其性能。找出代码中可以变得更高效、更快或更节省资源的地方。提供具体的优化方案,并说明这些改动将如何提升代码性能。优化后的代码应保持与原代码相同的功能,同时展现出更高的效率。
这里是代码:
```{{filetype}}
{{filecontent}}
```
]]
prt.ChatNew(params, chat_prompt)
end,
}
-- ...
}
补全功能
除了使用 模板占位符 外,parrot.nvim 还支持通过 nvim-cmp 和 blink.cmp 实现内联补全,从而提供更多上下文信息:
@buffer:foo.txt- 包含名为foo.txt的打开缓冲区的内容@file:test.lua- 包含名为test.lua的文件内容@directory:src/- 包含目录src/下的所有文件内容
提示:启用
show_context_hints选项后,你可以直观地看到请求所考虑的实际文件内容提示。补全文本(如@file)需要放在 新行 上!
配置 nvim-cmp
要启用 parrot.nvim 的补全功能,只需将该源添加到你的 nvim-cmp 配置中:
...
sources = cmp.config.sources({
{ name = "parrot" },
}),
...
配置 blink.cmp
对于 blink.cmp,你需要将 "parrot" 添加到默认的源列表中,并按以下方式配置提供者:
...
parrot = {
module = "parrot.completion.blink",
name = "parrot",
score_offset = 20,
opts = {
show_hidden_files = false,
max_items = 50,
}
},
...
状态栏支持
使用您最喜欢的状态栏插件,可以显示当前的聊天或命令模式。下面我们提供一个针对 lualine 的示例:
-- 定义函数及信息格式化
local function parrot_status()
local status_info = require("parrot.config").get_status_info()
local status = ""
if status_info.is_chat then
status = status_info.prov.chat.name
else
status = status_info.prov.command.name
end
return string.format("%s(%s)", status, status_info.model)
end
-- 添加到 lueline 区域
require('lualine').setup {
sections = {
lualine_a = { parrot_status }
}
添加自定义提供者
如果默认提供者不可用,您可以根据需要定义任意数量的自定义提供者。这使您可以自定义各种方面,例如端点、可用模型、默认参数、头部以及处理 LLM 响应的函数。 请注意,以这种方式配置提供者是为高级用户设计的。如果您需要帮助或对改进提供者支持有任何建议,请随时提交问题或讨论。
providers = {
my_custom_provider = {
name = "my_custom_provider",
api_key = os.getenv("MY_API_KEY"),
endpoint = "https://api.example.com/v1/chat/completions",
model = { "model-1", "model-2" },
-- 提供者特定的 curl 参数(可选)
curl_params = { "--insecure", "--max-time", "30", "--proxy", "http://proxy:8080" },
-- 自定义头部函数
headers = function(api_key)
return {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. api_key,
["X-Custom-Header"] = "custom-value",
}
end,
-- 自定义负载预处理
preprocess_payload = function(payload)
-- 根据您的 API 格式修改负载
return payload
end,
-- 自定义响应处理
process_stdout = function(response)
-- 解析来自您的 API 的流式响应
local success, decoded = pcall(vim.json.decode, response)
if success and decoded.content then
return decoded.content
end
end,
},
}
取消操作
您可以随时使用多种方法停止正在进行的 Parrot 生成:
方法
- 快捷键:
<C-g>s(可通过chat_shortcut_stop配置) - 命令:
:PrtStop(在任何地方都有效)
行为
当您取消生成时:
- 立即终止:API 请求会立即停止
- 保留已生成文本:目前为止生成的文本仍保留在缓冲区中
- 视觉反馈:您会收到确认取消的通知
- 预览模式:如果在流式传输过程中取消,则不会显示预览
- 多任务处理:如果有多个生成任务正在运行,所有任务都会被停止
自动命令事件
当生成被取消时,会触发 User PrtCancelled 事件,允许您创建自定义钩子:
vim.api.nvim_create_autocmd("User", {
pattern = "PrtCancelled",
callback = function()
-- 您的自定义逻辑在此处
print("Parrot 生成已被取消")
end,
})
高级用法
对于自定义代码中的特定缓冲区取消操作:
-- 仅停止当前缓冲区的任务
local chat_handler = require("parrot").chat_handler
chat_handler:stop({ buffer = vim.api.nvim_get_current_buf() })
-- 不发送通知地停止
chat_handler:stop({ notify = false })
附赠
可以直接从终端访问 parrot.nvim:
command nvim -c "PrtChatNew"
也可以将内容直接通过管道输入到聊天中:
ls -l | command nvim - -c "normal ggVGy" -c ":PrtChatNew" -c "normal p"
路线图
- 添加状态栏集成/通知功能,用于总结使用的 token 数量或花费金额
- 改进文档
- 制作教程视频
- 降低整体代码复杂度并提高健壮性
常见问题解答
- 我遇到了与状态相关的错误。
如果状态损坏,只需删除文件
~/.local/share/nvim/parrot/persisted/state.json即可。 - 补全功能无法正常工作,并且出现了错误。
请确保您有足够的 API 余额,并检查日志文件
~/.local/state/nvim/parrot.nvim.log中是否有任何错误。 - 聊天和交互式命令的模型选择是如何工作的?
聊天和交互式命令的模型选择是分开的。要更改聊天模型,您必须位于使用
PrtChatNew启动的聊天窗口中。在聊天窗口之外切换模型只会影响交互式命令的模型(例如PrtRewrite、PrtAppend)。一旦设置,这些选择就会保持不变。 - 我发现了一个 bug,有一个功能建议,或者有一个总体的想法来改进这个项目。
欢迎所有人参与该项目!如果您有任何建议、想法或 bug 报告,请随时提交问题。
相关项目
- parrot.nvim 是早期版本 robitx/gp.nvim 的分支,于 2024 年 1 月从提交
607f94d361f36b8eabb148d95993604fdd74d901分支出来。此后,原始代码的很大一部分已被移除或重写,这一努力将持续进行,直到parrot.nvim发展成为其独立的版本。原始的MIT许可证已被保留并将继续维持。 - huynle/ogpt.nvim
PrtCmd的想法受到 exit.nvim 的启发。
星标历史
版本历史
v2.5.12025/11/17v2.5.02025/10/05v2.4.02025/09/30v2.3.02025/07/15v2.2.02025/07/11v2.1.02025/05/31v2.0.02025/05/29v1.8.02025/05/29v1.7.02025/04/10v1.6.02025/03/31v1.5.02025/03/15v1.4.02025/03/11v1.3.02025/03/06v1.2.22025/01/26v1.2.12024/11/21v1.2.02024/10/21v1.1.02024/10/17v1.0.02024/10/15v0.7.02024/09/13v0.6.02024/08/22常见问题
相似工具推荐
stable-diffusion-webui
stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。
everything-claude-code
everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上
ComfyUI
ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。
NextChat
NextChat 是一款轻量且极速的 AI 助手,旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性,以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发,NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。 这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言,它也提供了便捷的自托管方案,支持一键部署到 Vercel 或 Zeabur 等平台。 NextChat 的核心亮点在于其广泛的模型兼容性,原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型,让用户在一个界面即可自由切换不同 AI 能力。此外,它还率先支持 MCP(Model Context Protocol)协议,增强了上下文处理能力。针对企业用户,NextChat 提供专业版解决方案,具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能,满足公司对数据隐私和个性化管理的高标准要求。
ML-For-Beginners
ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程,旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周,包含 26 节精炼课程和 52 道配套测验,内容涵盖从基础概念到实际应用的完整流程,有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。 无论是希望转型的开发者、需要补充算法背景的研究人员,还是对人工智能充满好奇的普通爱好者,都能从中受益。课程不仅提供了清晰的理论讲解,还强调动手实践,让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持,通过自动化机制提供了包括简体中文在内的 50 多种语言版本,极大地降低了全球不同背景用户的学习门槛。此外,项目采用开源协作模式,社区活跃且内容持续更新,确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路,ML-For-Beginners 将是理想的起点。
ragflow
RAGFlow 是一款领先的开源检索增强生成(RAG)引擎,旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体(Agent)能力相结合,不仅支持从各类文档中高效提取知识,还能让模型基于这些知识进行逻辑推理和任务执行。 在大模型应用中,幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构(如表格、图表及混合排版),显著提升了信息检索的准确度,从而有效减少模型“胡编乱造”的现象,确保回答既有据可依又具备时效性。其内置的智能体机制更进一步,使系统不仅能回答问题,还能自主规划步骤解决复杂问题。 这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统,还是致力于探索大模型在垂直领域落地的创新者,都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口,既降低了非算法背景用户的上手门槛,也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目,它正成为连接通用大模型与行业专有知识之间的重要桥梁。
