# index1 vs Claude Code 原生工具 — 搜索性能基准测试

> 测试日期：2026-02-06
> 测试环境：macOS (Apple Silicon M2), 48GB RAM, Python 3.14, Ollama nomic-embed-text
> 项目规模：19 个 Python 文件, 45 个文档, 17,725 个 chunks
> 数据库：`~/.claude-index1/knowledge.db`

## 一、测试方法

在 index1 项目自身代码库上，对比三种搜索方式：

- **原生工具** (`Grep` / `Glob`)：Claude Code 内置工具（底层 ripgrep + globset）
- **index1 CLI** (`index1 search`)：命令行调用，含 Python 启动开销
- **index1 MCP** (`docs_search`)：MCP Server 常驻进程，通过 stdio 通信

每组测试覆盖精确关键词和语义查询两类场景。

## 二、速度对比

### 2.1 原始数据

| 查询 | 类型 | Grep/Glob | index1 CLI | index1 MCP |
|------|------|-----------|------------|------------|
| `CJK` | 关键词 | 4 ms | 326 ms | ~200 ms |
| `embedding` | 关键词 | 4 ms | 236 ms | ~100 ms |
| `搜索是怎么工作的` | 语义（中文） | 4 ms* | 232 ms | 99 ms |
| `how to configure watch paths` | 语义（英文） | 4 ms* | 335 ms | ~150 ms |

> \*Grep 只能做字面匹配，无法理解语义。此处仅对比响应时间。

### 2.2 有 Ollama vs 无 Ollama

| 查询 | Hybrid（有 Ollama） | BM25-only（无 Ollama） | 降级幅度 |
|------|---------------------|----------------------|---------|
| `CJK` | 79 ms, 5 条结果 | 1,064 ms, 5 条结果 | **慢 13 倍** |
| `embedding` | 38 ms, 5 条结果 | 1,061 ms, 5 条结果 | **慢 28 倍** |
| `搜索是怎么工作的` | 41 ms, **5 条结果** | 1,045 ms, **0 条结果** | **100% 丢失** |
| `how to configure watch paths` | 181 ms, 5 条结果 | 1,198 ms, 5 条结果 | **慢 7 倍** |

核心发现：
- **无 Ollama 首次查询慢 7–28 倍**：需要尝试连接 Ollama 并等待超时
- 后续查询很快（~35 ms）— 失败状态缓存 60 秒（v0.1.1+）
- **中文语义查询直接归零**：没有向量 embedding，BM25 无法匹配中文到英文代码
- 缓存预热后，两种模式都能 < 1 ms 返回

### 2.3 延迟分解

```
原生 Grep:      [  4ms  ]  ← ripgrep 全文扫描
                ━━━━━━━━

index1 CLI:     [ ~150ms Python 启动 ][ ~50ms BM25 ][ ~100ms 向量 ][ ~30ms RRF ]
                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

index1 MCP:     [ ~50ms BM25 ][ ~100ms 向量 ][ ~30ms RRF ]
                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                （常驻进程，无启动开销）
```

- **Python 启动**：CLI 每次调用 ~150ms（模块导入 + 初始化）
- **BM25 查询**：FTS5 全文索引 ~50ms
- **向量查询**：Ollama embedding API + sqlite-vec 余弦相似度 ~100ms
- **RRF 融合**：Reciprocal Rank Fusion 合并排序 ~30ms

### 2.4 缓存性能

同一进程内连续查询：

| 轮次 | `CJK` | `embedding` | `搜索是怎么工作的` | `how to configure watch paths` |
|------|-------|-------------|-------------------|-------------------------------|
| 冷启动 | 79 ms | 38 ms | 41 ms | 181 ms |
| 热缓存 | < 1 ms | < 1 ms | < 1 ms | < 1 ms |

L1 缓存（10 分钟 TTL）完全消除重复查询开销。

## 三、上下文窗口占用分析

AI Agent（如 Claude Code）搜索代码时，搜索工具在**本地免费运行** — 但搜索结果会作为 `tool_result` 消息发送回 LLM API。这些结果占用**上下文窗口 tokens**：

- **上下文被更快填满** → 更早触发对话压缩，丢失之前的消息
- **响应变慢** → 输入上下文越大，LLM 推理越慢
- **API Key 用户花更多钱** → 输入 tokens 按量计费

> **注意**：这里说的不是本地搜索的费用（那是零）。是搜索结果返回给 LLM 时占用的上下文窗口大小。

### 3.1 Grep 上下文开销（全项目扫描）

| 查询 | 匹配行数 | 字符数 | 估算 Tokens |
|------|---------|--------|------------|
| `CJK` | 24 | 2,490 | ~622 |
| `embedding` | 217 | 23,214 | ~5,803 |
| `search` | 881 | 143,583 | ~35,895 |
| `watch` | 457 | 140,590 | ~35,147 |

> Grep 返回整个项目中**所有匹配行**，无排序。

### 3.2 index1 上下文开销（top-5 结果）

| 查询 | 结果数 | 字符数 | 估算 Tokens |
|------|-------|--------|------------|
| `CJK` | 5 | 1,840 | ~460 |
| `embedding` | 5 | 2,056 | ~514 |
| `搜索是怎么工作的` | 5 | 1,644 | ~411 |
| `how to configure watch paths` | 5 | 1,868 | ~467 |

> index1 返回**预排序的 top-k 结果**，附带相关度评分。

### 3.3 上下文节省对比

| 查询 | Grep（上下文 tokens） | index1（上下文 tokens） | 节省比例 |
|------|---------------------|----------------------|---------|
| `CJK` | ~622 | ~460 | 26% |
| `embedding` | ~5,803 | ~514 | **91%** |
| `search` | ~35,895 | ~411 | **99%** |
| `watch` | ~35,147 | ~467 | **99%** |

常见查询下，index1 节省 **90–99% 的上下文窗口**：
- **对话空间更充裕** — 上下文填充更慢，更少触发压缩
- **LLM 响应更快** — 输入越小，推理越快
- **API Key 用户省钱** — 更少的输入 tokens 计费

### 3.4 大规模场景的上下文预算

典型 Agent 会话（20 次搜索，200k 上下文窗口）：

| 策略 | 每次查询上下文（均值） | 总上下文消耗 | 占 200k 窗口比例 |
|------|---------------------|------------|-----------------|
| 纯 Grep | ~15,000 tokens | 300,000 | **150%**（触发压缩） |
| 纯 index1 | ~460 tokens | 9,200 | **5%**（绰绰有余） |
| 混合使用（推荐） | ~5,000 tokens | 100,000 | 50% |

> 混合 = 50% Grep（精确查找）+ 50% index1（语义查询）。
>
> 纯 Grep 策略下，20 次宽泛搜索就能**撑爆整个上下文窗口**，导致 Agent 丢失之前的对话历史。

## 四、搜索质量对比

### 4.1 精确关键词：`CJK`

**Grep** 结果（`src/` 内 5 行匹配）：
```
src/index1/search.py:52:  def _has_cjk(text: str) -> bool:
src/index1/search.py:54:  return bool(_CJK_PATTERN.search(text))
tests/test_search.py:    class TestHasCJK
```
精确，零噪声，每行都包含 "CJK" 字面量。

**index1** 结果（top 5）：
```
1. [high] tests/test_search.py — TestHasCJK
2. [high] README.md — License（噪声）
3. [high] tests/test_search.py — 重复
4. [high] CLAUDE-MEM-DEEP-ANALYSIS.md —（噪声）
5. [high] src/index1/search.py — _has_cjk
```
命中核心代码，但混入不相关结果。

**胜者**：Grep — 精确搜索零噪声。

### 4.2 语义查询：`搜索是怎么工作的`

**Grep** 结果（匹配 "search"，41 行）：
```
src/index1/cli.py: 4 处
src/index1/mcp_server.py: 6 处
src/index1/search.py: 4 处
src/index1/web.py: 22 处
... 共 41 行，无排序
```
返回所有包含 "search" 的行。无法理解中文语义。

**index1** 结果（top 5）：
```
1. [high] CLAUDE-MEM-DEEP-ANALYSIS.md — 搜索优化策略
2. [high] README.md — 项目简介
3. [high] CLAUDE-MEM-DEEP-ANALYSIS.md — 系统总结
4. [high] CLAUDE-MEM-DEEP-ANALYSIS.md — 系统架构
5. [high] src/index1/indexer.py — SkipFile
```
理解中文查询语义，找到相关文档。

**无 Ollama 时**：**0 条结果** — BM25 无法将中文查询匹配到英文代码。

**胜者**：index1 — 唯一支持跨语言语义搜索的工具。

### 4.3 语义查询：`how to configure watch paths`

**Grep** 结果（需要分别搜 "watch" + "config" + "path"）：
```
需要 2-3 次独立搜索 + 人工交叉筛选
```

**index1** 结果（top 5）：
```
1. [high] src/index1/mcp_server.py — docs_reindex
2. [high] src/index1/cli.py — watch 命令
3. [medium] ...
```
一次查询覆盖多个概念（"configure" + "watch" + "paths"）。

**胜者**：index1 — 跨概念查询，一步到位。

## 五、优劣势分析

### 5.1 原生工具（Grep / Glob）

| 维度 | 评分 | 说明 |
|------|------|------|
| 速度 | 5/5 | 4ms，近乎瞬间 |
| 精确性 | 5/5 | 正则匹配，零误判 |
| 语义理解 | 1/5 | 只能字面匹配 |
| 依赖 | 5/5 | 零依赖，Claude Code 内置 |
| 实时性 | 5/5 | 文件改了立刻搜到 |
| 结果排序 | 2/5 | 按文件/行号排列，无相关度 |
| 跨语言 | 1/5 | 中文查不到英文代码 |
| 资源占用 | 5/5 | 无额外内存/磁盘 |
| **上下文开销** | **2/5** | **返回所有匹配行 → 撑爆 LLM 上下文窗口** |

**最佳场景**：已知标识符、正则模式、小型项目。

### 5.2 index1（BM25 + 向量混合搜索）

| 维度 | 评分 | 说明 |
|------|------|------|
| 速度 | 3/5 | 冷启动 40–180ms，缓存命中 < 1ms |
| 精确性 | 3/5 | 近似匹配，偶有噪声 |
| 语义理解 | 4/5 | 理解查询意图，跨概念匹配 |
| 依赖 | 2/5 | 需要 Ollama + 预索引 |
| 实时性 | 3/5 | 需 reindex 或 watch 模式 |
| 结果排序 | 4/5 | RRF 融合排序，相关度优先 |
| 跨语言 | 4/5 | CJK 动态调权，中英互查 |
| 资源占用 | 2/5 | Ollama ~500MB，DB ~10MB |
| **上下文开销** | **5/5** | **仅返回 top-k → ~400–500 tokens，极低上下文占用** |

**最佳场景**：探索性查询、跨语言搜索、大型项目、AI Agent 自动化。

## 六、使用建议

### AI Agent 搜索决策流程

```
收到查询
    |
    +-- 包含具体标识符？（函数名/类名/文件名）
    |   └── 是 → Grep/Glob（4ms，精确匹配）
    |
    +-- 探索性/理解性问题？
    |   └── 是 → index1 MCP（40-180ms，语义搜索）
    |
    +-- 跨语言查询？（中文问英文代码）
    |   └── 是 → index1 MCP（CJK 动态调权）
    |
    +-- 预计返回大量结果？（常见关键词如 "search"）
    |   └── 是 → index1 MCP（节省 99% 上下文）
    |
    └── 不确定？
        └── 先试 Grep，没结果再用 index1
```

### 总结对比

| 指标 | 原生工具 | index1（Hybrid） | index1（BM25-only） |
|------|---------|-----------------|-------------------|
| 冷启动速度 | **4 ms** | 40–180 ms | 1,000–1,200 ms |
| 缓存速度 | 不适用 | **< 1 ms** | **< 1 ms** |
| 精确搜索 | **最优** | 良好 | 良好 |
| 语义搜索 | 无 | **最优** | 无 |
| 中文查询 | 无 | **最优** | **无（0 条结果）** |
| 上下文开销 | 高（全部匹配） | **低（top-k）** | **低（top-k）** |
| 外部依赖 | **无** | Ollama + 索引 | 仅索引 |

### 结论

**两者互补，不是替代关系。** Grep 是"精确制导导弹"，index1 是"语义雷达"。组合使用让 AI Agent 兼具快速精确查找和智能语义理解 — 同时在宽泛查询上节省 90% 以上的上下文窗口。

**请安装 Ollama。** 没有它，语义搜索完全失效，中文查询直接归零，且每次查询都要付出 1 秒超时代价。

## 附录：Ollama 安装与配置

### 安装

```bash
# macOS
brew install ollama && ollama pull nomic-embed-text

# Linux
curl -fsSL https://ollama.ai/install.sh | sh && ollama pull nomic-embed-text

# Windows — 从 https://ollama.ai/download 下载安装后：
ollama pull nomic-embed-text
```

### 验证

```bash
ollama list                    # 应显示 nomic-embed-text
curl http://localhost:11434    # 应返回 "Ollama is running"
index1 status                  # 应显示 vec_loaded: true
```

### 按内存选择模型

| 内存 | 模型 | 向量维度 | 安装命令 |
|------|------|---------|---------|
| 8 GB | `all-minilm` | 384 | `ollama pull all-minilm` |
| 16 GB+ | `nomic-embed-text`（默认） | 768 | `ollama pull nomic-embed-text` |
| 32 GB+ | `nomic-embed-text-v2-moe` | 768 | `ollama pull nomic-embed-text-v2-moe` |

### 自定义端口

Ollama 默认运行在 `11434` 端口。如需更改：

```bash
OLLAMA_HOST=0.0.0.0:11435 ollama serve
index1 config ollama_url http://localhost:11435
```

### 切换模型后重建索引

```bash
index1 config embedding_model <model-name>
index1 config embedding_dim <dim>
index1 index --force ./docs ./src
```

### Claude Code 集成

项目根目录添加 `.mcp.json`：

```json
{
  "mcpServers": {
    "index1": {
      "type": "stdio",
      "command": "index1",
      "args": ["serve"]
    }
  }
}
```

> 如果 `index1` 不在 PATH 中，使用完整路径：
> - macOS/Linux: `which index1`
> - Windows: `where.exe index1`

重启 Claude Code 后，即可使用 `docs_search`、`docs_get`、`docs_status`、`docs_reindex`、`docs_config` 五个工具。
