外观
搜索工具精通指南
通过组合使用正确的工具,精通代码搜索与文档导航,实现最高效率
作者:Florian BRUNIAUX | 贡献者:Claude(Anthropic)阅读时间:约 25 分钟最后更新:2026 年 5 月
目录
- 快速参考矩阵
- 工具对比
- 决策树
- 组合工作流
- 真实场景案例
- 性能优化
- 常见陷阱
- 扩展工具集:scip-search 与 lilmd
快速参考矩阵
| 我需要… | 使用这个工具 | 命令示例 |
|---|---|---|
| 查找精确文本 | rg(搜索工具) | rg "authenticate" --type ts |
| 按含义查找 | grepai | grepai search "user login flow" |
| 查找函数定义 | Serena | serena find_symbol --name "login" |
| 查找结构模式 | ast-grep | ast-grep "async function $F" |
| 查看函数调用者 | grepai | grepai trace callers "login" |
| 获取文件结构 | Serena | serena get_symbols_overview |
| 跨文件重构 | Serena + ast-grep | 组合工作流 |
| 探索未知代码库 | grepai → Serena | 发现模式 |
| 无 MCP 时查找符号引用(工作树安全) | scip-search | scip-search refs AuthService.login |
| 导航大型 Markdown 文档 | lilmd | lilmd read docs/arch.md "Authentication" |
工具对比
完整功能矩阵
| 功能 | rg(ripgrep) | grepai | Serena | ast-grep |
|---|---|---|---|---|
| 搜索类型 | 正则/文本 | 语义(含义) | 符号感知 | AST 结构 |
| 技术原理 | 模式匹配 | 嵌入向量(Ollama) | 符号解析 | 抽象语法树 |
| 速度 | ⚡ ~20ms | 🐢 ~500ms | ⚡ ~100ms | 🕐 ~200ms |
| 安装配置 | ✅ 无需(内置) | ⚠️ Ollama + 安装 | ⚠️ MCP 配置 | ⚠️ npm install |
| 集成方式 | ✅ 原生(Grep) | ⚠️ MCP 服务器 | ⚠️ MCP 服务器 | ⚠️ 插件 |
| 隐私保护 | ✅ 100% 本地 | ✅ 100% 本地 | ✅ 100% 本地 | ✅ 100% 本地 |
| 所需上下文 | 无 | 无 | 项目索引 | 无 |
| 支持语言 | 所有(文本) | 所有 | TS/JS/Py/Rust/Go | TS/JS/Py/Rust/Go/C++ |
| 调用图 | ❌ 不支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| 符号追踪 | ❌ 不支持 | ❌ 不支持 | ✅ 支持 | ❌ 不支持 |
| 会话记忆 | ❌ 不支持 | ❌ 不支持 | ✅ 支持 | ❌ 不支持 |
| 误报率 | 中 | 低 | 极低 | 极低 |
| 学习曲线 | 低 | 中 | 低 | 高 |
Token 消耗对比
| 工具 | 典型查询 | 消耗 Token | 返回结果 |
|---|---|---|---|
| rg | "authenticate" | ~500 | 仅精确匹配 |
| grepai | "auth flow" | ~2000 | 基于意图的匹配 |
| Serena | find_symbol | ~1000 | 符号 + 上下文 |
| ast-grep | AST 模式 | ~1500 | 结构性匹配 |
核心洞察:rg 的 Token 效率是语义工具的 4 倍,但智能度低约 10 倍。
扩展工具参考
以下两款工具填补了核心工具栈的空白,详见§ 扩展工具集:
| 工具 | 类别 | 与现有工具栈对比 |
|---|---|---|
| scip-search | 符号索引搜索(SCIP) | 类似 Serena,但无状态、无需 MCP、工作树安全 |
| lilmd | Markdown 章节导航 | 工具栈中无对等工具(专注文档,非代码) |
决策树
第一层:你知道什么?
Plain
你知道确切的文本/模式吗?
│
├─ 知道 → 使用 rg(ripgrep)
│ ├─ 已知函数名:rg "createSession"
│ ├─ 已知导入:rg "import.*React"
│ └─ 已知模式:rg "async function"
│
└─ 不知道 → 进入第二层第二层:你在找什么?
Plain
你的搜索意图是什么?
│
├─ "按含义/概念查找"
│ → 使用 grepai
│ └─ 示例:grepai search "payment validation logic"
│
├─ "查找函数/类定义"
│ → 使用 Serena
│ └─ 示例:serena find_symbol --name "UserController"
│
├─ "按代码结构查找"
│ → 使用 ast-grep
│ └─ 示例:没有错误处理的 async 函数
│
└─ "理解依赖关系"
→ 使用 grepai trace
└─ 示例:grepai trace callers "validatePayment"第二层(工作树 / 无 MCP 环境)
在 CI 环境、git 工作树或任何 MCP 服务器不可用的场景下:
Plain
已知符号名,但无 MCP 可用?
│
└─ 使用 scip-search(预构建的 SCIP 索引,毫秒级冷启动)
└─ scip-search refs "AuthService.login" --format json第三层:优化
Plain
结果太多?
│
├─ rg → 添加 --type 过滤器或缩小路径范围
├─ grepai → 添加 --path 过滤器或使用 trace
├─ Serena → 按符号类型过滤(function/class)
└─ ast-grep → 为模式添加约束条件组合工作流
工作流 1:探索未知代码库
目标:快速理解一个新项目
步骤说明:
Bash
# 1. 语义发现(grepai)
# 查找与认证相关的文件
grepai search "user authentication and session management"
# → 输出:auth.service.ts, session.middleware.ts, user.controller.ts
# 2. 结构概览(Serena)
# 了解每个文件的结构
serena get_symbols_overview --file auth.service.ts
# → 输出:
# - class AuthService
# - login(email, password)
# - logout(sessionId)
# - validateSession(token)
# 3. 依赖关系映射(grepai trace)
# 查看 login 的使用情况
grepai trace callers "login"
# → 输出:被 UserController、ApiGateway、AdminPanel 调用
# 4. 精确搜索(rg)
# 查找具体实现细节
rg "validateSession" --type ts -A 5
# → 输出:完整函数及 5 行上下文结果:4 条命令完成全面理解(相比读取 30+ 个文件)
工作流 2:大规模重构
目标:将 createSession 重命名为 initializeUserSession,涉及 50+ 个文件
步骤说明:
Bash
# 1. 影响分析(grepai trace)
# 了解全部范围
grepai trace callers "createSession"
# → 输出:23 个文件中有 47 处调用
grepai trace callees "createSession"
# → 输出:调用了 validateUser、createToken、storeSession
# 2. 结构验证(ast-grep)
# 确保使用模式一致
ast-grep "createSession($$$ARGS)"
# → 输出:所有调用及其参数模式
# 3. 符号感知重构(Serena)
# 精确重命名
serena find_symbol --name "createSession" --include-body true
# → 获取精确定义 + 所有引用
serena replace_symbol_body \
--name "createSession" \
--new-name "initializeUserSession"
# → 跨所有文件重命名,保持结构完整
# 4. 验证(rg)
# 确认没有旧引用残留
rg "createSession" --type ts
# → 应返回 0 个结果结果:在完全了解依赖关系的前提下安全重构
工作流 3:安全审计
目标:查找安全漏洞
步骤说明:
Bash
# 1. 语义发现(grepai)
# 查找安全敏感代码
grepai search "SQL query construction"
grepai search "user input validation"
grepai search "password handling"
# 2. 结构模式(ast-grep)
# 查找特定漏洞模式
# SQL 注入风险
ast-grep 'db.query(`${$VAR}`)'
# XSS 风险
ast-grep 'innerHTML = $VAR'
# 缺少错误处理
ast-grep -p 'async function $F($$) { $$BODY }' \
--without 'try { $$$TRY } catch'
# 3. 依赖追踪(grepai)
# 查看漏洞代码的调用位置
grepai trace callers "executeQuery"
# → 识别所有入口点
# 4. 精确验证(rg)
# 确认发现的问题
rg "innerHTML\s*=" --type ts
rg "password" --type ts | rg -v "hashed"结果:在数分钟内完成全面的安全审计
真实基准测试
grepai vs grep(2026 年 1 月)
背景:在 Excalidraw(15.5 万行 TypeScript)上进行基准测试作者:YoanDev(grepai 维护者 — 存在潜在偏差)方法:5 个相同的代码发现问题
| 指标 | grep | grepai | 差异 |
|---|---|---|---|
| 工具调用次数 | 139 | 62 | -55% |
| 输入 Token 数 | 51k | 1.3k | -97% |
要点:语义搜索通过首次尝试即定位相关文件,避免了迭代探索,从而大幅减少 Token 消耗。
局限性:
- 由工具维护者进行的基准测试
- 单一项目验证(仅 TypeScript)
- 目前尚无独立验证
来源:yoandev.co/grepai-benchmark
注意:本基准测试反映的是 2026 年 1 月的状态,随着 Claude Code 和 grepai 的更新,性能可能有所变化。
工作流 4:框架迁移
目标:将 React 类组件迁移至 Hooks
步骤说明:
Bash
# 1. 清单(ast-grep)
# 查找所有类组件
ast-grep 'class $C extends React.Component'
# → 输出:34 个待迁移组件
# 2. 依赖分析(grepai)
# 了解组件间关系
for component in $(ast-grep 'class $C extends' --json | jq -r '.[].name'); do
grepai trace callers "$component"
done
# → 确定迁移顺序(叶子组件优先)
# 3. 模式检测(ast-grep)
# 识别所使用的生命周期方法
ast-grep 'componentDidMount() { $$BODY }'
ast-grep 'componentWillReceiveProps($$) { $$$BODY }'
# → 映射到等效的 Hooks
# 4. 增量迁移(Serena + ast-grep)
# 逐个组件迁移
serena find_symbol --name "UserProfile" --include-body true
# → 获取完整组件代码
# 使用 ast-grep 进行转换
ast-grep --rewrite \
--from 'class $C extends React.Component' \
--to 'const $C = () => { }'
# 5. 验证(rg + grepai)
# 确认迁移成功
rg "React.Component" --type tsx # 数量应减少
grepai search "component lifecycle methods" # 查找遗漏项结果:系统性迁移,破坏性最小
工作流 5:性能优化
目标:识别并修复性能瓶颈
步骤说明:
Bash
# 1. 热点发现(grepai)
# 查找性能关键代码
grepai search "heavy computation or loops"
grepai search "database queries in loops"
# 2. 模式检测(ast-grep)
# 查找 N+1 查询模式
ast-grep 'for ($$) { await db.query($$) }'
# 查找缺少 memoization 的情况
ast-grep 'useMemo' --invert-match \
--in 'const $VAR = $$$'
# 3. 调用图分析(grepai trace)
# 查找热点路径
grepai trace graph "renderUserList" --depth 3
# → 可视化依赖树
# 4. 符号追踪(Serena)
# 追踪函数变化
serena write_memory "perf_baseline" \
"renderUserList: 450ms avg"
# 优化后
serena write_memory "perf_optimized" \
"renderUserList: 45ms avg (10x improvement)"
# 5. 验证(rg)
# 确认优化已应用
rg "useMemo|useCallback" --type tsx结果:数据驱动的性能改进
真实场景案例
场景 1:"我不知道我在找什么"
问题:新项目,没有文档,需要添加功能
解决方案:以语义搜索为先的发现策略
Bash
# 从宽泛的含义开始
grepai search "user profile management"
# → 发现相关文件
# 再通过结构缩小范围
serena get_symbols_overview --file user-profile.service.ts
# → 了解可用函数
# 最后精确搜索细节
rg "updateProfile" --type ts -C 3场景 2:"这个函数到处都在调用"
问题:需要修改某个函数,但担心破坏其他地方
解决方案:先进行依赖关系映射
Bash
# 1. 查看所有调用者
grepai trace callers "calculateTotal"
# → 发现 47 处调用
# 2. 分析调用上下文
for file in $(grepai trace callers "calculateTotal" --json | jq -r '.[].file'); do
serena get_symbols_overview --file "$file"
done
# 3. 识别安全与风险调用点
ast-grep 'calculateTotal($ARGS)' --json
# → 按参数模式分组
# 4. 有把握地进行修改
# 现在你已了解所有影响点场景 3:"查找所有做 X 的代码"
问题:需要在代码库中应用统一的模式
解决方案:结合语义搜索 + 结构搜索
Bash
# 示例:查找所有错误处理代码
# 1. 语义发现
grepai search "error handling and exception management"
# 2. 结构模式
ast-grep 'try { $$$TRY } catch ($ERR) { $$$CATCH }'
ast-grep 'throw new Error($MSG)'
# 3. 验证一致性
rg "catch\s*\(" --type ts | wc -l
# 与 ast-grep 的计数对比,找出异常情况场景 4:"我需要理解这个模块"
问题:复杂模块,职责不清晰
解决方案:多工具综合分析
Bash
# 1. 获取符号概览(Serena)
serena get_symbols_overview --file payment.module.ts
# → 查看所有导出、类、函数
# 2. 理解依赖关系(grepai)
grepai trace callees "PaymentModule"
# → 该模块依赖什么?
grepai trace callers "PaymentModule"
# → 谁使用了该模块?
# 3. 查找实现模式(ast-grep)
ast-grep 'export class $C' --file payment.module.ts
ast-grep 'async $METHOD($$$)' --file payment.module.ts
# 4. 读取具体实现(rg)
rg "processPayment" --type ts -A 20性能优化
选择最快的工具
通用原则:
- 已知精确文本 → 始终优先使用 rg
- 不知道精确文本 → 使用 grepai,然后用 rg 验证
- 重构 → 使用 Serena 确保符号安全
- 大规模迁移 → 使用 ast-grep 确保结构精确
性能基准测试
测试:在 50 万行代码库中查找认证代码
| 策略 | 耗时 | 结果质量 |
|---|---|---|
| 仅用 rg "auth" | 0.2s | 5000+ 误报 |
| 仅用 grepai "auth" | 2.5s | 50 个相关结果 |
| grepai → rg(组合) | 2.7s | 50 个相关且已验证 |
| 仅用 Serena 符号 | 1.5s | 12 个认证函数 |
| ast-grep 模式 | 3.0s | 8 个认证流程 |
最优方案:对已知函数名使用 Serena 符号(最快 + 高质量)
并行化策略
针对大型代码库(> 10 万行):
Bash
# 并行运行搜索
# 终端 1:语义发现
grepai search "authentication flow" > /tmp/grepai-results.json &
# 终端 2:符号索引
serena get_symbols_overview --file src/**/*.ts > /tmp/symbols.json &
# 终端 3:模式检测
ast-grep 'async function $F' --json > /tmp/ast-results.json &
# 等待全部完成,然后合并结果
wait
jq -s '.[0] + .[1] + .[2]' \
/tmp/grepai-results.json \
/tmp/symbols.json \
/tmp/ast-results.json常见陷阱
陷阱 1:用语义搜索查找精确匹配
❌ 错误做法:
Bash
grepai search "createSession" # 慢,大材小用✅ 正确做法:
Bash
rg "createSession" --type ts # 快速、精确原则:如果你知道精确文本,永远不要用语义搜索。
陷阱 2:用 rg 进行概念性搜索
❌ 错误做法:
Bash
rg "auth.*login.*session" --type ts # 会遗漏变体✅ 正确做法:
Bash
grepai search "authentication and session management"原则:正则表达式不理解含义,请使用语义工具。
陷阱 3:重构前忽略调用图
❌ 错误做法:
Bash
# 不检查调用者,直接重构
rg "oldFunction" --type ts | sed 's/oldFunction/newFunction/g'✅ 正确做法:
Bash
# 先检查影响范围
grepai trace callers "oldFunction"
# 发现 23 个文件中有 47 处调用
# 然后制定重构策略原则:修改共享代码前,始终先追踪依赖关系。
陷阱 4:不组合使用工具
❌ 错误做法:
Bash
# 复杂任务只用一种工具
ast-grep 'async function $F' --json | jq '.[].file' | xargs -I {} vim {}
# 不了解上下文,盲目编辑✅ 正确做法:
Bash
# 组合使用,全面理解
ast-grep 'async function $F' --json > /tmp/async.json
for file in $(jq -r '.[].file' /tmp/async.json); do
serena get_symbols_overview --file "$file" # 上下文
grepai trace callers "$(jq -r '.[].name' /tmp/async.json)" # 使用情况
done原则:复杂任务需要多角度视角。
陷阱 5:简单搜索过度工程化
❌ 错误做法:
Bash
# 仅为了找 TODO 注释而配置 grepai + Ollama
grepai search "TODO comments in the code"✅ 正确做法:
Bash
rg "TODO" --type ts原则:使用能解决问题的最简单工具。
工具选择速查表
快速决策矩阵
| 你的情况 | 使用这个 | 不要用这个 |
|---|---|---|
"查找函数 login" | rg "login" | grepai search "login" |
| "查找与登录相关的代码" | grepai "login flow" | rg "login.*" |
| "安全地重命名函数" | Serena find_symbol | rg + sed |
| "谁调用了这个函数?" | grepai trace callers | rg + grep |
| "获取文件结构" | Serena overview | rg "class |
| "查找没有 try/catch 的 async" | ast-grep | rg "async.*{" |
| "迁移 React 类" | ast-grep | rg + 手动操作 |
| "查找 TODO" | rg "TODO" | 其他任何工具 |
扩展工具集:scip-search 与 lilmd
这两款 CLI 工具填补了 rg/grepai/Serena 工具栈的空白。
scip-search
scip-search 查询预构建的 SCIP(Sourcegraph 代码智能协议)符号索引。grepai 按语义含义搜索,Serena 需要实时的 MCP 连接,而 scip-search 则基于静态二进制索引运行,冷启动时间仅需毫秒。
| 属性 | 详情 |
|---|---|
| 来源 | github.com/liza-mas/scip-search |
| 安装 | `curl -fsSL https://raw.githubusercontent.com/liza-mas/scip-search/main/install.sh |
| 索引格式 | SCIP(Go、TypeScript、Python、Java、Rust 等) |
| 输出格式 | 单行文本、JSON 或仅位置信息 |
工作流:scip-search 可替代符号发现时典型的 5-10 次 rg/读取往返操作。
Bash
# 步骤 1:每种语言生成一次 SCIP 索引
scip-typescript index --output index.scip
# 步骤 2:查找符号定义
scip-search find AuthService
# 步骤 3:获取所有引用及行号
scip-search refs AuthService.login --format json
# 步骤 4:仅读取返回的行范围与 Serena 的对比:Serena 连接到语言服务器并具有会话记忆。scip-search 是无状态的,基于快照运行:无需 MCP,无需持久进程。这使其在工作树和临时 CI 环境中可靠运行,而 Serena 的 LSP 后端在这些环境中可能不可用。
与 grepai 的对比:grepai 按语义意图查找("支付验证逻辑")。scip-search 按精确或近似精确的符号标识符查找。两者可顺序配合使用:grepai 发现概念,scip-search 确认符号。
工作树兼容性:索引是每个仓库的文件,无共享状态。在工作树内运行 scip-typescript index 会为该工作树生成本地索引。
lilmd
lilmd 将 Markdown 文件视为数据库。它返回带有行范围的目录,并支持定向章节读取。智能体读取一篇 2000 行的指南时,只需一次调用即可获取某个章节,而不必读取整个文件。
| 属性 | 详情 |
|---|---|
| 来源 | github.com/molefrog/lilmd |
| 安装 | npm install -g lilmd |
| 运行时 | Node 或 Bun |
核心命令:
Bash
# 带行范围的目录(含头尾,1 为起始行)
lilmd docs/architecture.md
# 按名称读取章节(默认模糊匹配)
lilmd read docs/architecture.md "Authentication"
# 读取嵌套章节
lilmd read docs/architecture.md "Security > JWT"
# 精确匹配(以 = 开头)
lilmd read docs/architecture.md "=Authentication Flow"对智能体的特殊价值:目录输出包含每个标题的行范围。智能体解析这些信息后,只请求相关章节,而不是加载整个文件。自然的处理流程是:rg(找到哪个文件)→ lilmd(获取带范围的目录)→ Read lines:N-M(加载特定章节)。这同样适用于 CHANGELOG.md、大型 README 文件和知识库文档。
工作树兼容性:无状态,无索引,按文件运行。适用于任何环境。
安装优先级
推荐安装顺序:
- 起步:rg(已内置于搜索工具)✅
- 下一步:Serena MCP(符号感知,会话记忆)
- 然后:grepai(语义搜索 + 调用图)
- 如果工作流涉及工作树:scip-search(无状态符号查找,无需 MCP)
- 针对大型文档:lilmd(定向 Markdown 章节读取,无需配置)
- 最后:ast-grep(结构模式,大规模重构)
理由:90% 的搜索用 rg + Serena 即可完成。语义需求时添加 grepai。工作树或 MCP 不可用的 CI 环境时添加 scip-search。仅在大规模重构时才添加 ast-grep。
总结:六工具工具箱
Plain
┌─────────────────────────────────────────────────────────┐
│ 搜索工具精通 │
├─────────────────────────────────────────────────────────┤
│ │
│ rg(ripgrep) → 快速、精确的文本匹配 │
│ ├─ 适用:90% 的搜索场景 │
│ └─ 速度:~20ms │
│ │
│ grepai → 语义搜索 + 调用图 │
│ ├─ 适用:概念发现、依赖追踪 │
│ └─ 速度:~500ms(能找到 rg 找不到的内容) │
│ │
│ Serena → 符号感知 + 会话记忆 │
│ ├─ 适用:重构、结构理解 │
│ └─ 速度:~100ms │
│ │
│ ast-grep → AST 结构模式 │
│ ├─ 适用:大规模迁移、复杂模式 │
│ └─ 速度:~200ms │
│ │
│ scip-search → 符号索引(无状态,SCIP) │
│ ├─ 适用:CI / 工作树 / 无 MCP 环境 │
│ └─ 速度:~5ms 冷启动 │
│ │
│ lilmd → Markdown 章节导航 │
│ ├─ 适用:大型文档,带行范围的目录 │
│ └─ 速度:即时,无需索引 │
│ │
│ ═══════════════════════════════════════════════════ │
│ │
│ 掌握工具组合,而非单一工具。 │
│ 每种工具都有其最适合的场景,选对工具才是关键。 │
│ │
└─────────────────────────────────────────────────────────┘延伸阅读
- Serena MCP 指南
- grepai 文档
- 「ast-grep 模式技能」
- 「架构:Grep 与 RAG 的历史演变」
- scip-search GitHub
- lilmd GitHub
最后更新:2026 年 5 月兼容版本:Claude Code 2.1.7+
来源:飞书 · AI Spark 知识库 | 原文(最新版):https://lcnniolukk80.feishu.cn/wiki/EKWqwKydcirCzDk3WpOcKnjHnFg | 归档:2026-06-04