fff 中文教程:先管住索引目录,再谈搜索速度
fff 是常驻本地的文件搜索工具包。它原先叫 fff.nvim,现在既能作为 Neovim 文件选择器,也能通过 MCP 给 Codex、Claude Code 等客户端提供文件名、内容和多模式搜索。它的速度来自预扫描、内存索引和缓存,所以使用前要先想清楚两件事:索引哪个目录,以及愿意给它多少内存。
v0.11.0,发布于 2026-09-21。仓库 main 还有 0.11.1-nightly 构建;生产环境先固定稳定 tag。1. 先选一个入口
只在 Neovim 里找文件,就装官方仓库 dmtrKovalenko/fff;旧名 fff.nvim 已停用。要让 coding agent 调用搜索工具,再装 fff-mcp。首次评估不要同时开插件、MCP 和 SDK,否则很难判断是哪一个进程占用内存或写入数据库。
2. 固定 v0.11.0,并检查下载来源
macOS/Linux 的 MCP 可用仓库内 Homebrew formula;它固定 v0.11.0 和每个平台的 SHA-256。官方 shell 安装脚本也固定相同版本和校验值。不要直接复制管道命令执行:先把脚本下载到本地,读完下载地址、安装目录和校验逻辑,再运行。
curl -fsSLo install-fff-mcp.sh \
https://raw.githubusercontent.com/dmtrKovalenko/fff/v0.11.0/install-mcp.sh
less install-fff-mcp.sh
bash install-fff-mcp.sh
fff-mcp --healthcheck
Neovim 的 download_or_build_binary() 会先取 release 原生库,失败后回退到本地 cargo build --release。离线或受控环境应自己下载 release 资产、核对 SHA-256,再放到插件预期目录。
3. 把项目目录写死
MCP 默认用启动时的当前目录作为索引根。客户端若从错误目录启动,扫描范围会变大。v0.11.0 的 MCP 默认拒绝文件系统根和用户主目录,但配置里仍应把一个仓库的绝对路径直接传给 fff-mcp,不要依赖客户端碰巧给对 cwd。
[mcp_servers.fff]
command = "/absolute/path/to/fff-mcp"
args = ["/absolute/path/to/your-repo", "--no-update-check"]
--no-update-check 关闭启动时对 GitHub releases/latest 的请求。大仓库还可以先加 --no-warmup 或限制 --max-cached-files,用实际数据决定是否开启完整内容缓存。
4. 先跑健康检查,再看搜索结果
MCP 用 --healthcheck;Neovim 用 :FFFHealth。确认二进制、索引、Git 集成和本地数据库都正常。然后准备 10 到 20 条你熟悉答案的查询:精确符号、文件名缩写、一个错字、目录约束和没有结果的词都要覆盖。搜索快但经常把无关文件排在前面,实际会浪费更多阅读时间。
5. 记录内存和本地数据
fff 会把文件树、部分内容和 Git 状态留在长驻进程里。Neovim 默认把 frecency 放在 stdpath('cache')/fff_nvim,查询历史放在 stdpath('data')/fff_queries,日志也写入本机状态目录。共享机器或敏感仓库要核对权限、保留时间和清理命令。
6. 同类对比:fff 与 ripgrep
相比 ripgrep,fff 用常驻索引换取重复查询的低延迟,并额外加入 frecency、Git 状态、定义提示和分页结果;代价是持续占用内存、维护缓存和监听文件变化。编辑器或 agent 会在同一仓库连续搜索很多次时,fff 更值得测;终端里临时查一个字符串,ripgrep 更简单。
7. 用同一组查询做验收
先记录第一次扫描时间和空闲内存,再重复跑同一组查询,统计前五条是否含正确文件、响应时间和进程内存。修改、新增、重命名一个文件后立即再搜,确认 watcher 更新。最后重启进程,检查历史排序是否符合预期。官方 benchmark 是项目方结果,自己的代码库数据才决定是否保留。
8. 验证状态与商业边界
未验证:安装、二进制校验、Neovim 兼容性、搜索召回、速度、内存、watcher、Windows/Android 和具体 MCP 客户端接线。README 有赞助商展示和赞助联系入口,但核心功能没有付费版、托管账户或试用额度限制,因此保留索引;这不等于为赞助商产品背书。
这里仅补原教程没有展开的事实和边界。安装命令与操作步骤仍以前文为准。
先判断这个项目是否适合你
适合谁用
适合在同一个大型代码仓库里反复找文件、查定义和追踪最近修改,也适合为编辑器或 AI coding agent 提供结构化搜索结果。只做一次 shell 搜索、小仓库偶尔检索,或必须保持近零常驻内存时,ripgrep/fd/fzf 更直接。
采用建议
fff 值得在重复搜索很多次的单个代码仓库里试用,先固定 v0.11.0、明确索引根目录,并记录空闲与搜索时内存。它有赞助商展示,但核心是 MIT 本地工具,没有付费服务门槛,未达到商业化隔离条件。一次性搜索或内存紧张的环境继续用 ripgrep 更合适。
原教程未展开的系统信息
核心功能
路径与内容搜索
路径搜索支持错字容忍、smart case、目录和扩展名约束;内容搜索提供 plain、regex、fuzzy 与多模式 OR 查询,并以结构化结果返回行号、上下文和定义提示。
常驻索引与增量更新
首次扫描后把文件树和部分内容索引留在进程内,后台 watcher 追踪文件变化;重复查询省去反复启动进程、遍历目录和读取 ignore 规则的成本。
frecency 与 Git 状态排序
文件访问频率、最近使用时间、最近提交和 modified/staged/untracked 状态会参与排序。Neovim 默认把 frecency 与查询历史写到本地 LMDB 路径。
多种接入层
同一 Rust 核心经 C FFI 提供 Neovim 插件、MCP server、Python、Node/Bun 与 Pi 扩展;不同接入层的安装、持久化和默认参数并不完全相同。
架构与数据流
fff-search、fff-grep 与 fff-query-parser 负责扫描、匹配、内容搜索和查询约束;libfff_c 是语言绑定共用的 C 层,fff-nvim 用 mlua 接到 Neovim,fff-mcp 通过 stdio 暴露 grep、find_files 和 multi_grep。进程启动后以指定目录或当前目录为根建立索引,后台 watcher 更新状态,部分文件内容由 mmap 或内存缓存保留。LMDB 用于 frecency/查询历史,libgit2 负责 Git 状态。
常见问题
fff.nvim 现在应该装哪个仓库名?
官方包名已从 fff.nvim 改成 fff。lazy.nvim 应指向 dmtrKovalenko/fff;旧安装先按插件管理器方式清理 fff.nvim,避免同时加载两份。
fff 会把代码上传到云端吗?
搜索和索引在本机完成,官方源码没有托管搜索账户。MCP 默认会请求 GitHub releases/latest 检查版本;严格离线时加 --no-update-check,并自行控制安装下载。
为什么要显式指定项目目录?
MCP 默认从启动时的当前目录建立索引。cwd 设错会扩大扫描范围;v0.11.0 默认拒绝文件系统根和用户主目录,但最稳妥的做法仍是把仓库绝对路径作为启动参数。
fff 一定比 ripgrep 快吗?
不能这样说。fff 的优势来自常驻索引和缓存,适合一个仓库里的重复查询;只执行一次搜索时,ripgrep 启动即用、结束即释放资源,通常更省事。
安装脚本可以直接管道执行吗?
官方脚本为 v0.11.0 固定了各平台 SHA-256,但管道执行仍会跳过人工审阅。先下载脚本,确认版本、下载地址、校验值和安装目录,再执行更稳妥。