在 AI 代码助手日益普及的今天,如何在赋予 AI 强大能力的同时,保障代码库的安全与开发者的工作流不被侵扰,成为了一个核心议题。由 ThePrimeagen 开发的 Neovim AI 代理项目 99,正是针对这一痛点进行的深度探索。它不仅仅是一个简单的代码补全插件,更是一套旨在 “精简请求并将其限制在受限区域” 的权限控制流与执行沙箱体系。本文将深入剖析 99 的设计架构,解析其如何通过规则引擎、上下文捕获与显式确认流来实现细粒度的安全操作隔离。
1. 设计理念:从 “全知全能” 到 “受限专家”
99 的核心设计哲学在项目 README 中被明确阐述:“This is meant to streamline the requests to AI and limit them to restricted areas”。这与当前大多数 “全能型” AI 编程助手(如 OpenCode、Copilot Workspace)形成了鲜明对比。传统的 AI 代理往往被赋予极高的权限,可以自由浏览整个代码库并生成跨文件的改动,这在带来便利的同时也埋下了巨大的安全隐患 ——AI 可能会误解项目结构,生成破坏性的修改。
99 采取了相反的策略:限制即安全。它不试图让 AI 理解整个仓库,而是将 AI 的视线聚焦于当前上下文和开发者定义的特定 “规则区域”。这种设计思路天然地将 AI 置于一个 “沙箱” 之中:AI 只能看到被允许看到的规则和文件,执行被明确限定的操作。
2. 权限系统的核心:规则引擎与配置
99 的权限控制并非通过硬编码实现,而是构建在一个灵活的规则引擎之上。这个引擎主要由两部分组成:配置层和规则定义层。
2.1 配置层的受限区域定义
在 99.setup() 函数中,用户可以通过 md_files 和 custom_rules 两个配置项来划定 AI 的活动范围。
- md_files (代理规则文件):通过
md_files选项,99 会自动扫描当前文件所在目录及其父目录,查找名为AGENT.md的文件。这意味着,对于不同的项目或模块,你可以定义不同的代理行为准则。例如,在/project/utils/下的AGENT.md可以规定:“该模块下的代码生成必须遵循严格的函数式编程风格”。 - custom_rules (技能规则目录):
custom_rules允许用户指定一个路径,该路径下的每一个子目录都被视为一个独立的 “技能”(Skill),并期望在子目录中发现SKILL.md文件。这提供了一种极为精细的能力授权机制。你可以创建一个debug技能,定义如何自动添加printf语句;创建一个test技能,定义如何生成单元测试。AI 只有在用户显式激活(通过@符号引用)特定技能时,才会获得该技能对应的权限。
2.2 规则引擎的加载与刷新
代码中的 Agents.rules(self) 负责解析这些规则。值得注意的是,99 实现了 refresh_rules 机制。虽然当前版本为了性能简化了实现,但这一设计预留了动态更新规则的能力 —— 即规则文件可以在不重启 Neovim 的情况下被修改并即时生效。这种 “热更新” 特性对于快速迭代开发流程中的权限配置至关重要。
3. 执行沙箱:操作流与用户确认
即使有了规则限制,如何触发操作也是权限控制的关键环节。99 区分了两种核心操作模式:隐式填充(fill_in_function)和显式确认(fill_in_function_prompt / visual_prompt)。后者构成了其 “执行沙箱” 的核心交互层。
3.1 隐式填充:快速但受限
fill_in_function 是一种直接的操作方式。它根据当前光标上下文和预定义的规则,直接调用 AI 生成代码。这种方式假设用户已经通过其他途径(如之前的对话或全局配置)设定了意图,因此不进行额外的用户输入捕获。它的权限控制完全依赖于 99_state 中加载的静态规则和上下文文件。
3.2 显式确认:动态权限赋予
fill_in_function_prompt 和 visual_prompt 则展示了 99 在细粒度权限控制上的深度思考。以 fill_in_function_prompt 为例,其工作流如下:
- 输入捕获:首先通过
Window.capture_input打开一个输入窗口,等待用户输入 Prompt。 - 动态规则匹配:在用户输入完成后,系统调用
Agents.by_name(_99_state.rules, response)。这里的response是用户的 Prompt。如果用户在其中使用了@符号(例如:@debug 在这个函数开头添加日志),系统会自动解析该符号,匹配对应的技能规则(Skill Rules),并将这些规则动态添加到本次请求的additional_rules列表中。 - 规则绑定与执行:匹配到的规则和用户的原始 Prompt 一起被传递给
ops.fill_in_function执行。
这种设计实现了一个精妙的沙箱模型:默认状态下 AI 权限最低(只有全局 md_files 规则);随着用户在 Prompt 中 @ 指定特定技能,AI 的权限边界随之扩展。这不仅防止了 AI 的 “越权” 行为,也使得功能的复用(如 “调试”、“测试”)变得标准化且可控。
4. 安全操作隔离:状态管理与回滚
一个缺乏监控和回滚能力的系统是危险的。99 在这一方面也提供了基础但关键的保障机制。
- 活跃请求追踪:
_99_state维护了一个_active_requests列表,记录所有当前正在运行的 AI 请求。这使得系统能够感知并管理并发的 AI 操作。 - 停止所有请求:
stop_all_requests函数允许用户在 AI 行为异常或耗时过长时,立即终止所有正在进行的请求。这为用户提供了一个可靠的 “紧急切断” 开关,防止 AI 在错误的道路上走得太远。 - 日志审计:通过 Logger 模块,所有请求的上下文、规则匹配结果和 AI 的响应(如果启用)都会被记录到
/tmp/{project}.99.debug文件中。这不仅便于调试,也是发生安全事件后的重要审计依据。
5. 总结与工程建议
99 项目代表了一种务实的 AI 代理安全架构。它没有追求绝对的容器化隔离(那是更底层的操作系统或容器范畴的工作),而是在应用层通过规则引擎和显式确认流构建了一道智能的 “权限防火墙”。对于希望在 Neovim 中安全使用 AI 的开发者,我们建议:
- 严格定义 SKILL.md:不要将所有权限都开放给默认规则,而是创建具体的、可复用的技能(如
refactor,optimize,test)。 - 优先使用 Prompt 模式:尽量使用
<leader>9f触发的 Prompt 模式而非直接填充模式,以利用@规则匹配机制进行动态授权。 - 善用停止功能:当 AI 的输出偏离预期时,养成使用
<leader>9s立即停止的习惯,并检查日志。
资料来源:
- GitHub - ThePrimeagen/99: https://github.com/ThePrimeagen/99