Files
claude-code/docs/tools/search-and-navigation.mdx
claude-code-best c5edee431f docs: 文档检查/check 20260419 (#296)
* docs: 修复文档巡检发现的 4 处错误

- daemon.md: 反映实际实现状态(supervisor/worker 已实现而非 stub)
- bridge-mode.md: API 操作数量从 7 修正为 9
- web-search-tool.md: 文件路径从 src/tools/ 修正为 packages/builtin-tools/src/tools/
- remote-control-self-hosting.md: 补充缺失的 RCS_WS_IDLE_TIMEOUT 和 RCS_WS_KEEPALIVE_INTERVAL 配置项

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 Safety 和 Context 文档中的代码引用和类型错误

- permission-model: 修正规则来源从"五层"到八层,优先级顺序对齐代码
- permission-model: PermissionUpdate 类型改为实际的 addRules/replaceRules 等
- permission-model: 补充 acceptEdits 和 dontAsk 两种权限模式
- permission-model: DENIAL_LIMITS 字段名对齐实际代码
- plan-mode: 工具路径从 src/tools/ 改为 packages/builtin-tools/src/tools/
- compaction: 修正 COMPACTABLE_TOOLS 和 POST_COMPACT_* 的行号
- project-memory: 修正 ENTRYPOINT_NAME 常量的行号
- system-prompt: 修正 SystemPrompt 类型定义文件路径和多个行号引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修复 introduction 文档中的错误路径和行号引用

- why-this-whitepaper.mdx: BashTool 路径从 src/tools/ 修正为 packages/builtin-tools/src/tools/
- what-is-claude-code.mdx: 移除不存在的 Azure provider,改为实际的 7 种 provider
- architecture-overview.mdx: State 类型行号从 204 修正为 207

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修复 conversation/features 文档中的错误

- streaming.mdx: queryStreamRaw → queryModelWithStreaming 函数名修正
- streaming.mdx: Azure 提供商不存在,替换为实际 7 个提供商
- debug-mode.mdx: --inspect-wait 描述错误,实际使用 BUN_INSPECT 环境变量
- buddy.mdx: 补充缺失的 companionReact.ts、CompanionCard.tsx、index.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修复文档巡检中的源码引用错误

- feature-flags.mdx: 修正 feature() 兜底描述,实际从 bun:bundle 导入而非 cli.tsx:3 内联
- feature-flags.mdx: 修正工具 require 路径为 @claude-code-best/builtin-tools 包路径
- ant-only-world.mdx: 修正 tools.ts 中 require 路径为包路径
- ant-only-world.mdx: 修正 INTERNAL_ONLY_COMMANDS 行号 (267-295) 和数量 (24+)
- skills.mdx: 修正 COMMANDS memoize 行号 258 → 299
- mcp-protocol.mdx: 修正 fetchToolsForClient LRU 缓存上限 20 → 100
- streaming.mdx: 修正流式事件引用
- file-operations.mdx: 修正工具路径引用
- search-and-navigation.mdx: 修正搜索工具引用
- shell-execution.mdx: 修正 shell 工具引用
- buddy.mdx: 补充缺失的 frontmatter 字段
- debug-mode.mdx: 修正调试模式描述

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 tools/agent 文档中的文件路径和行号引用

- 修正 TodoWriteTool、AgentTool、ToolSearchTool 等工具路径
  src/tools/ → packages/builtin-tools/src/tools/
- 更新 Tool.ts、tools.ts、BashTool.tsx 中过时的行号引用
- 修正 WebSearchTool/WebFetchTool/EnterWorktreeTool/ExitWorktreeTool 路径
- 修正 AgentTool.tsx 中多行行号引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature 文档中的文件路径和行号引用

- ultraplan.md: 更新文件行数(525/349/127)
- fork-subagent.md: 路径迁移 src/tools/ → packages/builtin-tools/
- mcp-skills.md: 修正 getMcpSkillCommands 行号 547→604,client.ts 行号 117→129
- kairos.md: 修正 getBriefSection/getProactiveSection 行号
- proactive.md: 修正 getProactiveSection 行号 860→864

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正顶层文档中的路径迁移和行号引用

- auto-updater.md: config.ts 行号 1735→1737,标注未接入启动流程的函数
- external-dependencies.md: WebSearchTool/WebFetchTool 路径迁移到 builtin-tools 包,Vertex 行号修正
- lsp-integration.md: LSPTool 路径从 src/tools/ 迁移到 packages/builtin-tools/
- stub-recovery-design-1-4.md: 修正 Windows 绝对路径链接为标准代码引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 task 文档中的文件扩展名和路径引用

- task-004: AssistantSessionChooser.ts → .tsx, assistant.ts → .tsx
- task-003: cli.tsx 行号 249→272, markdownConfigLoader.ts 行号 29→35
- lan-pipes: SendMessageTool 路径迁移到 packages/builtin-tools/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 补充 computer-use-tools-reference 缺失的 Windows 工具

添加遗漏的 open_terminal 和 activate_window 两个 Windows 专属工具,
修正工具总数 37→39,Windows 工具数 10→12。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 audit/bash-classifier/token-budget/tree-sitter 文档

- feature-flags-audit: ScheduleCronTool 路径迁移、DAEMON 状态更新为 COMPLETE、assistant 文件标记已补全、UDS 标记已实现
- bash-classifier: BashPermissionRequest 文件路径修正、withRetry 行号移除
- token-budget: attachments.ts 行号范围修正
- tree-sitter-bash: bashPermissions.ts 路径迁移到 packages/builtin-tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 langfuse-monitoring AgentTool 路径迁移

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 bridgeApi 行号和 Tool.ts 行号引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 Safety/Extensibility 文档中的工具路径迁移和行号引用

- sandbox.mdx: shouldUseSandbox.ts 和 bashPermissions.ts 路径迁移至 packages/builtin-tools
- why-safety-matters.mdx: bashPermissions.ts 路径迁移(3 处)
- plan-mode.mdx: EnterPlanModeTool/prompt.ts 路径迁移
- auto-mode.mdx: Auto mode 指令行号 3464→3481
- hooks.mdx: AgentTool/runAgent.ts 路径迁移
- skills.mdx: SkillTool.ts 路径迁移
- custom-agents.mdx: Agent built-in 目录和 exploreAgent.ts 路径迁移

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 internals 文档引用计数和路径

- ant-only-world: USER_TYPE 引用计数 465→410+,工具路径迁移到 builtin-tools
- growthbook-ab-testing: growthbook.ts 行数 1156→1258
- hidden-features: 语音模式状态更新(audio-napi 已恢复)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正工具文档中的行号引用

- sub-agents: AgentTool.call 入口行号 340→387
- shell-execution: ShellCommand onTimeout 行号 129→144

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature 文档中的状态、路径和计数

- all-features-guide: 修正 feature flag 启用范围(dev only vs dev+build)
- tier3-stubs: 大量状态修正(stub→已实现),缩减过时条目
- workflow-scripts: 路径迁移到 builtin-tools,状态更新
- web-browser-tool: 工具状态缺失→已实现,路径迁移
- context-collapse: CtxInspectTool 状态缺失→已实现
- computer-use: 行号引用更新,平台分发描述修正
- computer-use-tools-reference: 工具数 39→38
- voice-mode: voiceModeEnabled 行数 55→54

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 更新 the-loop 查询循环行号引用

query.ts 代码变更后终止原因行号整体偏移约 40 行

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 补充 feature-flags-audit 完整 build 默认 feature 列表

添加 ULTRATHINK/LODESTONE/ACP/DAEMON 等 19 个缺失的 build 默认 feature,
修正 dev-only 特征标注(UDS_INBOX/LAN_PIPES/BG_SESSIONS/TEMPLATES)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature-flags-audit ConfigTool 路径迁移

ConfigTool 路径从 src/tools/ 迁移到 packages/builtin-tools/src/tools/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature-flags-audit BashTool 路径迁移

BashTool 路径从 src/tools/ 迁移到 packages/builtin-tools/src/tools/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature-flags-audit SkillTool 路径迁移

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 更新 feature-flags-audit WorkflowTool 状态为已实现

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 09:30:00 +08:00

284 lines
12 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "搜索与导航工具 - 代码库精准定位"
description: "解析 Claude Code 的搜索导航工具Glob 文件匹配、Grep 内容搜索,基于 ripgrep 的高性能代码检索,帮助 AI 在百万行代码中精准定位。"
keywords: ["代码搜索", "Glob", "Grep", "ripgrep", "文件搜索"]
---
## 两种搜索维度
| 维度 | 工具 | 底层实现 | 适用场景 |
|------|------|----------|---------|
| **按名称找文件** | Glob | ripgrep `--files` + glob 过滤 | "找到所有测试文件"、"找 config 开头的文件" |
| **按内容找代码** | Grep | ripgrep 正则搜索 | "哪里定义了这个函数"、"谁在调用这个 API" |
两者共享同一个 ripgrep 引擎,通过不同的参数组合实现不同搜索模式。
## ripgrep 的内嵌方式
Claude Code 不依赖系统安装的 ripgrep——它在 `src/utils/ripgrep.ts` 中实现了三级降级策略:
```
优先级 1: 系统 ripgrep (USE_BUILTIN_RIPGREP=false)
→ 使用 PATH 中的 rg 二进制
→ 安全考虑:只用命令名 'rg',不用完整路径,防止 PATH 劫持
优先级 2: 内嵌模式 (bundled/native build)
→ process.execPath 自身argv0='rg'
→ Bun 将 rg 静态编译进二进制,通过 argv0 分发
优先级 3: vendor 目录 (npm build)
→ vendor/ripgrep/{arch}-{platform}/rg
→ macOS 需要 codesign 签名 + 移除 quarantine xattr
```
平台适配示例:
```
vendor/ripgrep/
├── x86_64-darwin/rg # macOS Intel
├── arm64-darwin/rg # macOS Apple Silicon
├── x86_64-linux/rg # Linux Intel
├── arm64-linux/rg # Linux ARM
└── x86_64-win32/rg.exe # Windows
```
### macOS 代码签名
vendor 模式下的 rg 二进制需要 ad-hoc 签名才能通过 Gatekeeper`codesignRipgrepIfNecessary()`
```typescript
// 首次使用时执行:
// 1. 检查是否已是有效签名
codesign -vv -d <rg-path>
// 2. 如果只是 linker-signed重新签名
codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime <rg-path>
// 3. 移除隔离属性
xattr -d com.apple.quarantine <rg-path>
```
## 搜索结果的设计考量
### head_limit 与 Token 预算
大型项目的搜索结果可能有数十万条。默认最多返回 250 条匹配——这不是随意选择,而是**token 预算**的约束:
- 每条匹配行约 50-100 token
- 250 条 ≈ 12,500-25,000 token
- 这大约占 200k 上下文窗口的 6-12%
- 超过这个比例AI 的推理质量会下降
Grep 工具的 `head_limit` 参数让 AI 可以按需调整——搜索小项目时可以用更大的值。
### 按修改时间排序
Glob 默认把**最近修改的文件排在前面**。这不是默认的文件系统排序,而是刻意的设计决策:
```
设计假设:最近修改的文件最可能与当前任务相关
实际效果AI 优先看到"活"的代码,而不是沉寂的历史文件
```
在 `packages/builtin-tools/src/tools/GlobTool/` 中ripgrep 的输出在返回给 AI 前按 mtime 排序。
### ripgrep 的错误处理
ripgrep 执行有专门的错误恢复链(`src/utils/ripgrep.ts`
| 错误 | 处理 |
|------|------|
| **EAGAIN**(资源不足) | 自动以单线程模式 `-j 1` 重试 |
| **超时**(默认 20sWSL 60s | 返回已有部分结果,丢弃可能不完整的最后一行 |
| **缓冲区溢出** | 截断到 20MB返回已收集的结果 |
| **SIGTERM 失效** | 5 秒后升级为 SIGKILL |
## ToolSearch在 50+ 工具中发现目标
当可用工具超过 50 个时(含 MCP 提供的外部工具AI 可能不知道该用哪个。**ToolSearch**`packages/builtin-tools/src/tools/ToolSearchTool/`)提供了工具发现机制。
### 搜索算法
ToolSearch 实现了基于关键词的加权搜索(`searchToolsWithKeywords()`
```
输入: query = "database connection"
1. 精确匹配: 检查是否有工具名完全匹配(快速路径)
2. MCP 前缀匹配: "mcp__postgres" → 匹配所有 postgres 相关工具
3. 关键词拆分: ["database", "connection"]
4. 工具名解析:
- MCP 工具: "mcp__server__action" → ["server", "action"]
- 普通工具: "FileEditTool" → ["file", "edit", "tool"]
5. 加权评分:
- 工具名精确匹配: 10 分MCP: 12 分)
- 工具名部分匹配: 5 分MCP: 6 分)
- searchHint 匹配: 4 分
- 描述匹配: 2 分
6. 必选词过滤: "+database" 前缀表示必须包含
7. 按分数排序,返回 top-N
```
### `select:` 直接选择
AI 也可以用 `select:ToolName` 精确选择已知工具。这比搜索更快,且支持逗号分隔的批量选择(`select:A,B,C`)。
### 延迟加载Deferred Tools
不是所有工具都常驻内存。MCP 工具和低频工具被标记为 `isDeferredTool`,只有在 ToolSearch 选中后才真正加载。这减少了每次 API 调用的 token 开销(工具描述占用大量 token
### 缓存策略
工具描述的获取是 memoized 的——只在延迟工具集合变化时清除缓存:
```typescript
// 工具名排序后拼接作为缓存 key
function getDeferredToolsCacheKey(deferredTools: Tools): string {
return deferredTools.map(t => t.name).sort().join(',')
}
```
## Web 搜索与抓取
AI 的信息获取不局限于本地代码:
- **WebSearch**`packages/builtin-tools/src/tools/WebSearchTool/`):调用 Anthropic API 的 `web_search_20250305` server tool 搜索互联网
- **WebFetch**`packages/builtin-tools/src/tools/WebFetchTool/`):抓取特定 URL 内容,转换为 Markdown 供 AI 阅读
这让 AI 可以查阅文档、搜索 Stack Overflow、阅读 GitHub issue——和人类开发者的工作方式一致。
### WebSearch 实现机制
WebSearch 通过适配器模式支持三种搜索后端,由 `packages/builtin-tools/src/tools/WebSearchTool/adapters/` 中的工厂函数 `createAdapter()` 选择:
```
适配器架构:
WebSearchTool.call()
→ createAdapter() 选择后端
├─ ApiSearchAdapter — Anthropic API 服务端搜索(需官方 API 密钥)
├─ BingSearchAdapter — 直接抓取 Bing 搜索页面解析(无需 API 密钥)
└─ BraveSearchAdapter — 调用 Brave LLM Context API 解析(需 Brave API 密钥)
→ adapter.search(query, options)
→ 转换为统一 SearchResult[] 格式返回
```
#### 适配器选择逻辑
`adapters/index.ts` 中的工厂函数按以下优先级选择后端:
| 优先级 | 条件 | 适配器 |
|--------|------|--------|
| 1 | 环境变量 `WEB_SEARCH_ADAPTER=api` | `ApiSearchAdapter` |
| 2 | 环境变量 `WEB_SEARCH_ADAPTER=bing` | `BingSearchAdapter` |
| 3 | 环境变量 `WEB_SEARCH_ADAPTER=brave` | `BraveSearchAdapter` |
| 4 | API Base URL 指向 Anthropic 官方 | `ApiSearchAdapter` |
| 5 | 第三方代理 / 非官方端点 | `BingSearchAdapter` |
适配器是无状态的,同一会话内缓存复用。
#### ApiSearchAdapter — API 服务端搜索
将搜索请求委托给 Anthropic API 的 `web_search_20250305` server tool
```
调用链:
ApiSearchAdapter.search(query, options)
→ queryModelWithStreaming() 发起独立的 API 调用
→ 携带 extraToolSchemas: [BetaWebSearchTool20250305]
→ API 服务端执行搜索,返回流式事件
→ server_tool_use / web_search_tool_result / text 交替返回
→ extractSearchResults() 从 content blocks 提取 SearchResult[]
```
| 特性 | 实现 |
|------|------|
| **模型选择** | Feature flag `tengu_plum_vx3` 控制用 Haiku强制 tool_choice还是主模型 |
| **搜索上限** | 每次调用最多 8 次搜索(`max_uses: 8` |
| **域过滤** | 支持 `allowedDomains` / `blockedDomains` |
| **进度追踪** | 流式解析 `input_json_delta` 提取 query实时回调 `onProgress` |
#### BingSearchAdapter — Bing 搜索页面解析
直接抓取 Bing 搜索 HTML 并用正则提取结果,无需 API 密钥:
```
调用链:
BingSearchAdapter.search(query, options)
→ axios.get(bing.com/search?q=...) — 使用浏览器级别 headers 绕过反爬
→ extractBingResults(html)
→ 正则匹配 <li class="b_algo"> 块
→ 提取 <h2><a> 标题和 URL
→ resolveBingUrl() 解码 Bing 重定向链接
→ extractSnippet() 三级降级提取摘要
→ 客户端域过滤 (allowedDomains / blockedDomains)
→ 返回 SearchResult[]
```
**反爬策略**Bing 对非浏览器 UA 返回需要 JS 渲染的空页面。适配器使用完整的 Edge 浏览器请求头(包含 `Sec-Ch-Ua`、`Sec-Fetch-*` 等现代浏览器标头)确保获得完整 HTML。同时使用 `setmkt=en-US` 参数统一市场定位,避免 Bing 基于用户 IP 做区域化定向(如跳转到德语/新加坡市场导致结果不相关)。
**URL 解码**Bing 搜索结果中的 URL 为重定向格式(`bing.com/ck/a?...&u=a1aHR0cHM6Ly9...``resolveBingUrl()` 从 `u` 参数中 base64 解码出真实目标 URL`a1` 前缀 = https`a0` = http
**摘要提取**`extractSnippet()`)按优先级尝试三个来源:
1. `<p class="b_lineclamp...">` — 带行截断的摘要段落
2. `<div class="b_caption">` 内的 `<p>` — 普通摘要段落
3. `<div class="b_caption">` 的直接文本内容 — 兜底方案
| 特性 | 实现 |
|------|------|
| **超时** | 30 秒(`FETCH_TIMEOUT_MS` |
| **域过滤** | 支持 `allowedDomains` / `blockedDomains`,含子域名匹配 |
| **进度追踪** | 发送 query_update 和 search_results_received 回调 |
| **中止支持** | 外部 AbortSignal 传播到 axios 请求 |
### WebSearchTool 统一接口
`WebSearchTool``packages/builtin-tools/src/tools/WebSearchTool/WebSearchTool.ts`)是面向主循环的工具定义,所有 provider 均可使用(`isEnabled()` 始终返回 true。它将适配器返回的 `SearchResult[]` 转换为内部 `Output` 格式,`mapToolResultToToolResultBlockParam` 将搜索结果格式化为带 markdown 超链接的文本,并附加 "REMINDER" 要求主模型在回复中包含 Sources。
### WebFetch 实现机制
WebFetch 是一个完整的 HTTP 客户端 + 内容处理管线:
```
调用链:
WebFetchTool.call({ url, prompt })
→ getURLMarkdownContent(url)
→ validateURL() — 长度≤2000、无用户名密码、公网域名
→ URL_CACHE 命中检查15 分钟 TTL LRU50MB 上限)
→ checkDomainBlocklist() — 调用 api.anthropic.com/api/web/domain_info 预检
→ getWithPermittedRedirects() — axios 请求,自定义重定向处理
→ HTML → Turndown 转 Markdown懒加载单例~1.4MB
→ 非 HTML → 原始文本
→ 二进制PDF 等)→ persistBinaryContent() 保存到磁盘
→ applyPromptToMarkdown()
→ 截断到 100K 字符
→ queryHaiku() 用小模型按 prompt 提取信息
→ 返回处理后的结果
```
安全防护多层设计:
| 层级 | 机制 | 说明 |
|------|------|------|
| **域名预检** | `checkDomainBlocklist()` | 调用 `api.anthropic.com/api/web/domain_info?domain=…`5 分钟缓存 |
| **重定向控制** | `isPermittedRedirect()` | 仅允许同 host±www重定向跨域重定向返回提示让 AI 重新调用 |
| **重定向深度** | `MAX_REDIRECTS = 10` | 防止重定向循环无限挂起 |
| **内容大小** | `MAX_HTTP_CONTENT_LENGTH = 10MB` | 单次响应上限 |
| **请求超时** | `FETCH_TIMEOUT_MS = 60s` | 主请求超时;域名预检 10s |
| **URL 验证** | `validateURL()` | 长度、协议、用户名密码、公网域名检查 |
| **egress 检测** | `X-Proxy-Error: blocked-by-allowlist` | 检测企业代理拦截 |
预批准域名(`packages/builtin-tools/src/tools/WebFetchTool/preapproved.ts`
用户无需手动授权即可抓取的域名列表,包含 ~90 个主流技术文档站点MDN、Python docs、React docs、AWS docs 等)。列表分为 hostname-only 和 path-prefix 两类,查找复杂度 O(1)。
对预批准域名WebFetch 跳过 Haiku 摘要步骤(如果内容是 Markdown 且 < 100K 字符),直接返回原文——因为技术文档本身的结构化程度已经足够好。
权限模型方面WebFetch 按 hostname 生成 `domain:xxx` 规则匹配用户的 allow/deny/ask 规则,支持用户对特定域名配置永久允许或拒绝。
### ripgrep 的流式输出
对于交互式场景(如 QuickOpenripgrep 支持**流式输出**`ripGrepStream()`
```
rg --files → 逐 chunk 到达 → 按行分割 → onLines(lines) 回调
```
不需要等 ripgrep 完成整个搜索——第一批结果在 rg 仍在遍历目录树时就已展示。调用者可以通过 AbortSignal 提前终止搜索(例如找到足够多的结果后)。