1. 项目简介

Claude Context 是一个为 Claude Code、Cursor、Gemini CLI 等 AI 编码助手(以及 VSCode、Chrome 浏览器)提供代码库语义检索能力的工具集。它用向量数据库(Milvus / Zilliz Cloud)把代码切分后的片段索引起来,再通过 MCP(Model Context Protocol) 协议暴露 index_codebase / search_code 等工具,让 AI Agent 可以用自然语言快速定位到代码库中相关的代码片段,显著降低 token 消耗。

核心功能列表

  • 索引代码库:将整个仓库按语言切块、向量化后写入 Milvus。
  • 语义搜索(Hybrid Search):结合 BM25 稀疏检索 + Dense Vector(稠密向量)检索,支持 RRF 重排。
  • 增量同步:基于 Merkle DAG + 文件哈希检测变更,只重建动过的文件(后台定时 5 分钟跑一次)。
  • 多端接入:MCP Server(stdio)、VSCode 扩展(Sidebar + 命令)、Chrome 扩展(在 GitHub 等页面直接搜索)。
  • 多嵌入提供商:OpenAI、VoyageAI、Gemini、Ollama(本地)、OpenRouter。
  • 两种切分策略:基于 tree-sitter 的 AST 切分(首选)+ LangChain 字符切分(兜底)。

技术栈总览

类别选型备注
语言TypeScript 5.8全栈 TS,严格模式
运行时Node.js ≥ 20见根 package.json > engines
包管理pnpm ≥ 10(workspace)pnpm-workspace.yaml 配置
MCP SDK@modelcontextprotocol/sdk ^1.12.1stdio 传输
向量库@zilliz/milvus2-sdk-node ^2.5.10(gRPC)+ 自研 REST 客户端packages/core/src/vectordb
AST 切分tree-sitter + 11 种语言 grammarJS/TS/PY/Java/Cpp/Go/Rust/C#/Scala
字符切分langchain ^0.3.27RecursiveCharacterTextSplitter兜底方案
Embeddingopenai ^5.1.1voyageai@google/genaiollama统一抽象在 base-embedding.ts
哈希/差异自实现 MerkleDAG + sha256packages/core/src/sync
VSCode 扩展vscode ^1.74webpack 5web-tree-sitter浏览器化打包
Chrome 扩展webpack + manifest v3gRPC stub 掉 Milvus,走 REST
评测Python + uv + 自研 server/retrievalevaluation/ 目录

2. 目录结构说明

claude-context/
├── packages/                                   # monorepo 核心:4 个子包
│   ├── core/                                   # ⭐️ @zilliz/claude-context-core:核心引擎,被其它包依赖
│   │   └── src/
│   │       ├── context.ts                      # 【门面类 Context】索引/搜索主入口,1300+ 行,最重要的文件
│   │       ├── types.ts                        # SemanticSearchResult 等顶层类型
│   │       ├── index.ts                        # 统一 re-export 入口
│   │       ├── embedding/                      # Embedding 抽象与多提供商实现
│   │       │   ├── base-embedding.ts           # 抽象基类 Embedding(embed/embedBatch/detectDimension)
│   │       │   ├── openai-embedding.ts         # OpenAI 实现
│   │       │   ├── voyageai-embedding.ts       # VoyageAI 实现(voyage-code-3 默认)
│   │       │   ├── gemini-embedding.ts         # Gemini 实现(支持 Matryoshka 维度)
│   │       │   └── ollama-embedding.ts         # 本地 Ollama 实现
│   │       ├── vectordb/                       # 向量数据库抽象
│   │       │   ├── types.ts                    # VectorDatabase 接口 + HybridSearch 类型
│   │       │   ├── milvus-vectordb.ts          # gRPC 实现(生产首选)
│   │       │   ├── milvus-restful-vectordb.ts  # REST 实现(VSCode Web / Chrome 用)
│   │       │   └── zilliz-utils.ts             # Personal API Key → endpoint 解析
│   │       ├── splitter/                       # 代码切块
│   │       │   ├── ast-splitter.ts             # tree-sitter AST 切分 + 自动降级
│   │       │   └── langchain-splitter.ts       # 字符级兜底
│   │       ├── sync/                           # 增量同步
│   │       │   ├── merkle.ts                   # MerkleDAG:用 sha256 做内容指纹的 DAG
│   │       │   └── synchronizer.ts             # FileSynchronizer:快照 + 变更检测
│   │       └── utils/env-manager.ts            # 统一 env 读取 + ~/.context/.env 加载
│   │
│   ├── mcp/                                    # ⭐️ @zilliz/claude-context-mcp:MCP stdio server
│   │   └── src/
│   │       ├── index.ts                        # MCP 服务入口,注册 4 个 tools
│   │       ├── config.ts                       # 从 env 构建 ContextMcpConfig;CodebaseSnapshot v1/v2
│   │       ├── handlers.ts                     # 4 个工具的实现(最重量级,1000+ 行)
│   │       ├── snapshot.ts                     # ~/.context/mcp-codebase-snapshot.json 读写
│   │       ├── sync.ts                         # SyncManager:5 分钟定时增量同步
│   │       ├── embedding.ts                    # createEmbeddingInstance 工厂
│   │       └── utils.ts                        # 路径归一化、内容截断
│   │
│   ├── vscode-extension/                       # VSCode 扩展(商店名 semanticcodesearch)
│   │   └── src/
│   │       ├── extension.ts                    # 激活入口,注册命令 + webview
│   │       ├── config/configManager.ts         # 读取 workspace 配置,生产 Context 实例
│   │       ├── commands/{index,search,sync}Command.ts
│   │       ├── webview/                        # Sidebar 面板(HTML + JS + CSS 三件套)
│   │       └── stubs/                          # gRPC 桩,强制走 REST
│   │
│   └── chrome-extension/                       # 浏览器里对 GitHub 等仓库做搜索
│       └── src/
│           ├── background.ts / content.ts / options.ts
│           ├── manifest.json                   # MV3
│           ├── milvus/chromeMilvusAdapter.ts   # 浏览器端 Milvus 适配
│           └── stubs/                          # 同样用 stub 屏蔽 Node gRPC

├── examples/basic-usage/                        # 最小可运行示例(直接用 core 包)
│   └── index.ts                                # Context/Milvus/Embedding 组合调用样板

├── evaluation/                                  # Python 离线评测套件
│   ├── run_evaluation.py                       # 主入口:对比原始检索 vs Claude Context
│   ├── retrieval/                              # 基类 + 自定义检索器
│   ├── servers/                                # grep/read/edit 三个 MCP 评测 server
│   ├── analyze_and_plot_mcp_efficiency.py      # 生成 token 节省图表
│   └── pyproject.toml

├── docs/                                        # 用户文档
│   ├── getting-started/{prerequisites,quick-start,environment-variables}.md
│   ├── dive-deep/{asynchronous-indexing-workflow,file-inclusion-rules}.md
│   └── troubleshooting/{faq,troubleshooting-guide}.md

├── scripts/build-benchmark.js                   # 构建性能统计
├── .env.example                                 # 环境变量模板(要复制到 ~/.context/.env)
├── pnpm-workspace.yaml                          # workspace 声明:packages/*、examples/*
├── package.json                                 # 根脚本(pnpm -r build 等)
└── README.md                                    # 项目总纲(250 行+,含所有客户端接入方式)

3. 架构设计

3.1 整体架构模式

Claude Context 采用 Monorepo + 分层(Hexagonal 风格) 的设计:

  • 领域核心(core):把「索引一个代码库」「对代码库做语义搜索」抽象成 Context 这个门面类,只依赖 3 个接口:EmbeddingVectorDatabaseSplitter
  • 适配层(mcp / vscode-extension / chrome-extension):各自实现一种 UI/协议壳子,调用 core 提供的 API,不关心向量化和切分细节。
  • 驱动实现(multiple providers)OpenAI/Voyage/Gemini/Ollama 各自是 Embedding 的实现;MilvusVectorDatabase(gRPC)与 MilvusRestfulVectorDatabase(REST)是 VectorDatabase 的两种实现。

这让「把 Milvus 换成别的向量库」或「把 OpenAI 换成本地 Ollama」这类替换只改一处实例化代码。

3.2 核心模块划分

模块职责关键类/文件
门面协调切分→向量化→入库;暴露 indexCodebase/semanticSearchContext (packages/core/src/context.ts)
切分把源代码文件切成可向量化的 chunkAstCodeSplitter / LangChainCodeSplitter
向量化文本 → 向量Embedding 抽象 + 4 个实现
存储Collection 管理、Dense + Sparse 双字段、Hybrid SearchVectorDatabase 接口 + MilvusVectorDatabase
增量检测文件增/删/改MerkleDAG + FileSynchronizer
快照记录”哪些 codebase 已索引/正在索引”SnapshotManager(MCP 独有)
适配层MCP / VSCode / Chrome 各自的 UI 壳3 个独立包

3.3 数据流向

索引阶段(index):

codebasePath
  → getCodeFiles()          // 按扩展名 + ignore 过滤
  → codeSplitter.split()    // AST 或 LangChain,产出 CodeChunk[]
  → 按 EMBEDDING_BATCH_SIZE(100) 累积 chunk
  → embedding.embedBatch()  // 得到 Dense vector
  → 构造 VectorDocument(含 BM25 文本 + dense vector + metadata)
  → vectorDatabase.insertHybrid(collectionName, documents)
  → FileSynchronizer 写入 ~/.context/merkle/<md5>.json(文件哈希 + Merkle DAG)

搜索阶段(search):

query(string)
  → embedding.embed(query)  // 得到 query dense vector
  → 组装 2 个 HybridSearchRequest:
      - { anns_field: 'vector', data: queryVec }          // Dense
      - { anns_field: 'sparse_vector', data: query }      // BM25
  → vectorDatabase.hybridSearch(..., { rerank: { strategy: 'rrf' } })
  → 归一化为 SemanticSearchResult[]
  → 返回给 AI Agent

增量同步(5 分钟一次):

FileSynchronizer.initialize()
  → 从 ~/.context/merkle/<hash>.json 加载旧快照
  → 重新扫描目录生成新的文件哈希 + 新 MerkleDAG
  → MerkleDAG.compare(old, new) 发现根哈希变化 → 逐文件对比
  → 输出 { added, removed, modified }
  → context.reindexByChange() 删除旧 chunks、重新 embed+insert 增量部分

4. 核心流程解析

4.1 MCP Server 启动流程

入口:packages/mcp/src/index.ts

// packages/mcp/src/index.ts(节选)
async function main() {
  const config = createMcpConfig() // ① 从 env 读配置,支持 ~/.context/.env
  logConfigurationSummary(config)
  const server = new ContextMcpServer(config) // ② 实例化服务
  await server.start() // ③ 启动 stdio
}

ContextMcpServer 构造函数做了四件事(见上面 index.ts 节选):

  1. 新建 @modelcontextprotocol/sdkServer,声明 capabilities.tools
  2. createEmbeddingInstance(config) 生产 Embedding 实例(根据 EMBEDDING_PROVIDER)。
  3. new MilvusVectorDatabase({ address, token }) 建立向量库连接。
  4. 把二者注入 new Context({...}),然后初始化 SnapshotManager(读 ~/.context/mcp-codebase-snapshot.json)、SyncManagerToolHandlers

server.start() 中有一个细节值得留意:

// 修复 Issue #295:老版本 MCP 会留下 "0 files / 0 chunks + completed" 这样的伪记录
// 会让客户端误判为"未索引",进而触发强制重索引 → 删数据 → 循环。所以启动时做一次愈合。
await this.toolHandlers.validateLegacyZeroEntries()
const transport = new StdioServerTransport()
await this.server.connect(transport)
this.syncManager.startBackgroundSync() // 5 秒后启动首轮同步,之后每 5 分钟一次

关键点:MCP 协议只能用 stdout 传 JSON-RPC,所以文件顶端把 console.log/console.warn 重定向到了 stderr(packages/mcp/src/index.ts 前 15 行),避免污染协议流。

4.2 index_codebase 工具执行链路

  1. Agent 调用 MCP index_codebasesetRequestHandler(CallToolRequestSchema, ...) 派发到 toolHandlers.handleIndexCodebase
  2. handleIndexCodebase 做参数校验(必须是绝对路径)、检查快照是否已索引、决定 force/非 force,然后立即返回一个”indexing started”响应(不阻塞 Agent)。
  3. 真正的重活由后台 Promise 跑:
    • Context.prepareCollection(codebasePath):创建 Milvus collection(含 dense vector + sparse_vector 两个字段)。
    • getCodeFiles() 扫描全部符合扩展名且不匹配 ignore 规则的文件。
    • processFileList() 流式读文件 → codeSplitter.split() → 按 100 条/批累积 → 调用 processChunkBatch()
  4. processChunkBatch() 核心逻辑:
// packages/core/src/context.ts
const chunkContents = chunks.map((c) => c.content)
const embeddings = await this.embedding.embedBatch(chunkContents) // 批量向量化
const documents: VectorDocument[] = chunks.map((chunk, index) => ({
  id: this.generateId(relativePath, start, end, chunk.content), // sha256 前 16 位
  content: chunk.content, // 作为 BM25 原文存储
  vector: embeddings[index].vector, // Dense
  relativePath,
  startLine,
  endLine,
  fileExtension,
  metadata: { ...rest, codebasePath, language, chunkIndex: index },
}))
await this.vectorDatabase.insertHybrid(collectionName, documents)
  1. 过程中 SnapshotManager 把百分比进度写入 ~/.context/mcp-codebase-snapshot.json,Agent 随时可以 get_indexing_status 查。

4.3 search_code 工具执行链路

// 简化自 context.ts → semanticSearch()
const queryEmbedding = await this.embedding.embed(query);
const requests: HybridSearchRequest[] = [
  { data: queryEmbedding.vector, anns_field: 'vector', param: {...}, limit: topK * 2 },
  { data: query,                 anns_field: 'sparse_vector', param: {...}, limit: topK * 2 },
];
const hits = await this.vectorDatabase.hybridSearch(
  collectionName,
  requests,
  { rerank: { strategy: 'rrf' }, limit: topK, filterExpr }
);
return hits.map(h => ({ content, relativePath, startLine, endLine, language, score }));

为什么是 Hybrid? Dense 向量擅长语义相似(“用户登录逻辑” → authenticateUser),BM25 擅长关键字命中(“UserService.login”),RRF 重排能兼得两者。

4.4 增量同步流程(5 分钟/次)

SyncManager.startBackgroundSync

  • 启动 5 秒后跑首次 → 然后 setInterval(handleSyncIndex, 5 * 60 * 1000)
  • handleSyncIndex 遍历 snapshot 里所有 indexed 状态的 codebase,调 context.reindexByChange(path)
  • reindexByChange 内部用 FileSynchronizer.checkForChanges()
// packages/core/src/sync/synchronizer.ts
public async checkForChanges() {
    const newFileHashes = await this.generateFileHashes(this.rootDir);  // 全量扫 + sha256
    const newMerkleDAG = this.buildMerkleDAG(newFileHashes);
    const changes = MerkleDAG.compare(this.merkleDAG, newMerkleDAG);    // 先比根
    if (changes.added.length || changes.removed.length) {
        const fileChanges = this.compareStates(oldHashes, newHashes);   // 再比文件
        await this.saveSnapshot();
        return fileChanges;
    }
    return { added: [], removed: [], modified: [] };                    // 大多数情况走这里
}

精妙处MerkleDAG 的根节点数据是”所有文件哈希拼接”再 sha256,根节点没变意味着一个字节都没动,整个 O(N) 的文件对比就可以跳过。

4.5 VSCode 扩展启动流程

packages/vscode-extension/src/extension.tsactivate()

configManager = new ConfigManager(context) // 读 workspace 配置
codeContext = createContextWithConfig(configManager) // 用 REST 版 Milvus
searchCommand = new SearchCommand(codeContext) /* index/sync 同理 */
// 注册 Webview 视图 + 3 个命令 + 状态栏
setupAutoSync() // 默认每 5 分钟
runInitialSync() // 启动时跑一次

VSCode 扩展强制使用 REST 版 MilvusRestfulVectorDatabase,因为 @zilliz/milvus2-sdk-node 的 gRPC 依赖无法在 webpack 打包的扩展环境中工作(src/stubs/ 里也能看出:把 milvus-vectordb.jsast-splitter.js 全替换成了 stub)。


5. 关键设计与实现

5.1 使用的设计模式

  • 门面(Facade)Context 把切分/向量化/入库/同步四个子系统封装成 indexCodebasesemanticSearchreindexByChange 三个方法。
  • 策略(Strategy)Splitter 接口有 AST / LangChain 两种策略;AstCodeSplitter 内部还会根据语言是否支持自动降级到 LangChain。
  • 抽象工厂createEmbeddingInstance(config)(MCP)、ConfigManager.createEmbeddingInstance(VSCode)根据字符串生产实现。
  • 模板方法Embedding 抽象类提供 preprocessTextpreprocessTexts,子类只填 embed/embedBatch
  • 观察者/回调indexCodebase(path, onProgress) 的进度回调。
  • 适配器chromeMilvusAdapter.ts 把浏览器 fetch 适配成 Milvus REST 调用。

5.2 数据模型

Milvus Collection Schema(Hybrid):packages/core/src/vectordb/milvus-vectordb.ts,关键字段:

字段类型说明
idVarChar PKchunk_<sha256[:16]>,由 relativePath + lines + content 生成
vectorFloatVector(dim)Dense embedding
sparse_vectorSparseFloatVector由 Milvus 内置 BM25 function 从 content 生成
contentVarChar(65535)原文,BM25 的输入 & 搜索返回字段
relativePathVarChar相对 codebase 根
startLine / endLineInt64便于定位
fileExtensionVarChar过滤用
metadataJSONcodebasePathlanguagechunkIndex

Collection 命名:由 Context.getCollectionName(codebasePath) 生成,默认 hybrid_code_chunks_<md5(codebasePath)>,长度受限于 MAX_COLLECTION_NAME_LENGTH = 255。可通过 CODE_CHUNKS_COLLECTION_NAME_OVERRIDE 环境变量覆盖。

快照结构(V2)~/.context/mcp-codebase-snapshot.json

// packages/mcp/src/config.ts
type CodebaseInfo =
  | { status: 'indexing'; indexingPercentage: number; lastUpdated: string }
  | {
      status: 'indexed'
      indexedFiles: number
      totalChunks: number
      indexStatus: 'completed' | 'limit_reached'
      lastUpdated: string
    }
  | { status: 'indexfailed'; errorMessage: string; lastAttemptedPercentage?: number; lastUpdated: string }

Merkle 快照~/.context/merkle/<md5(codebasePath)>.json —— 文件哈希 Map + 序列化的 DAG。

5.3 错误处理与日志策略

  • MCP 服务内:把 console.log/warn 改写到 stderr(保证 stdout 纯净),大量带前缀的结构化日志如 [Context][SYNC-DEBUG][SNAPSHOT-VALIDATE]
  • Hard-fail vs Soft-fail
    • 单个文件读不到 → console.warn 跳过,不中断整体索引(见 processFileList 的 try/catch)。
    • VectorDB 瞬态错误 → 清 buffer 继续下一批;集群无响应 → 抛出由上层 handler 捕获并写入 indexfailed 状态。
  • 集合数量超限:用特殊常量 COLLECTION_LIMIT_MESSAGE 做 message 匹配,避免平台差异导致误判(见 vectordb/types.ts)。
  • 快照自愈:启动时 validateLegacyZeroEntries() 会用 Milvus getCollectionRowCount() 校正历史遗留的 0/0+completed 条目(详见 Issue #295 的注释,保留了很高的可读性)。

5.4 安全机制

  • API Key 与 Token:全部走环境变量 (OPENAI_API_KEYVOYAGEAI_API_KEYGEMINI_API_KEYMILVUS_TOKEN),envManager 支持 ~/.context/.env,避免把密钥写入项目根。
  • 路径隔离Context 要求绝对路径,避免”相对路径在不同 CWD 下定位到不同 collection”引起数据污染(文档 asynchronous-indexing-workflow.md 明确说明)。
  • 隐藏文件永远排除matchesIgnorePatternFileSynchronizer.shouldIgnore 都硬编码了「任何以 . 开头的路径段都忽略」,保护 .env.ssh 等不被索引。
  • Chunk 数硬上限CHUNK_LIMIT = 450000,超大仓库会触发 limit_reached 状态,防止无限膨胀。

6. 环境搭建与运行

6.1 前置条件

  • Node.js ≥ 20.x(22.x 也支持)
  • pnpm ≥ 10(npm install -g pnpm
  • Milvus / Zilliz Cloud 账号(或本地 docker run -p 19530:19530 milvusdb/milvus:latest
  • 一个 Embedding 服务(最简单是 OpenAI API Key;想纯本地就装 Ollama + nomic-embed-text

6.2 安装与构建

# 1. 克隆
git clone https://github.com/zilliztech/claude-context.git
cd claude-context

# 2. 装依赖(会为所有 workspace 子包装依赖)
pnpm install

# 3. 构建全部包
pnpm build
# 也可以只构建某一个
pnpm build:core      # @zilliz/claude-context-core
pnpm build:mcp       # @zilliz/claude-context-mcp
pnpm build:vscode    # semanticcodesearch(VSCode 扩展)

# 4. 开发模式(多包 watch)
pnpm dev

6.3 运行方式

A. 直接跑示例(最快看到效果)

# 1. 配置全局 env(一次即可)
cp .env.example ~/.context/.env
# 编辑 ~/.context/.env,至少填:
#   OPENAI_API_KEY=sk-...
#   MILVUS_ADDRESS=your-zilliz-endpoint
#   MILVUS_TOKEN=your-zilliz-key

# 2. 运行 basic example(会索引整个项目并做几次搜索)
pnpm example:basic

B. 作为 MCP Server(给 Claude Code/Cursor/Gemini 用)

# 直接用已发布的包
npx @zilliz/claude-context-mcp@latest

# 或者用本地构建版本
node packages/mcp/dist/index.js

Cursor 里在 ~/.cursor/mcp.json 加:

{
  "mcpServers": {
    "claude-context": {
      "command": "npx",
      "args": ["-y", "@zilliz/claude-context-mcp@latest"],
      "env": {
        "OPENAI_API_KEY": "sk-xxx",
        "MILVUS_ADDRESS": "https://xxx.zilliz.com",
        "MILVUS_TOKEN": "xxx"
      }
    }
  }
}

C. VSCode 扩展

pnpm build:vscode
cd packages/vscode-extension
pnpm package           # 产出 .vsix
# 或者:F5 启动 Extension Development Host 调试

6.4 关键环境变量(完整列表见 .env.example

变量作用默认
EMBEDDING_PROVIDEROpenAI / VoyageAI / Gemini / OllamaOpenAI
EMBEDDING_MODEL对应 provider 的模型名text-embedding-3-small
EMBEDDING_BATCH_SIZE一次嵌入多少 chunk100
OPENAI_API_KEYOpenAI key
MILVUS_ADDRESSMilvus/Zilliz endpoint
MILVUS_TOKENZilliz personal key
SPLITTER_TYPEast / langchainast
HYBRID_MODEtrue 开启 BM25+Densetrue
CUSTOM_EXTENSIONS追加后缀名(.vue,.svelte
CUSTOM_IGNORE_PATTERNS追加忽略规则(temp/**
CODE_CHUNKS_COLLECTION_NAME_OVERRIDE覆盖 collection 命名

7. 推荐学习路线

第一阶段 · 入门(0.5 ~ 1 天)

目标:搞懂”什么是语义代码检索”,能跑起 basic example。

  1. README.md 前半部分(到 Architecture 图为止),理解整体定位。
  2. docs/getting-started/quick-start.md + docs/dive-deep/asynchronous-indexing-workflow.md,理解”异步索引 + 后台同步”的用户视角状态机。
  3. 6.3 A 节跑通 pnpm example:basic,打开 Zilliz Cloud 控制台肉眼看到生成的 collection。
  4. examples/basic-usage/index.ts:这是 Context 最小用法样板,30 行左右就能看完。

第二阶段 · 进阶(2 ~ 3 天)

目标:掌握核心引擎的每个环节。

  1. 门面 - 精读 packages/core/src/context.ts(1300 行,分 4 次读):
    • 构造函数 + 默认 ignore/extension 表
    • indexCodebase()prepareCollection()processFileList()processChunkBatch()
    • semanticSearch() 的 Hybrid 请求构造
    • reindexByChange() 如何调 FileSynchronizer
  2. 切分 - 精读 packages/core/src/splitter/ast-splitter.ts,重点看 SPLITTABLE_NODE_TYPESextractChunksrefineChunks(大块二次切分)+ 兜底到 LangChain 的条件。
  3. 向量化 - 通读 packages/core/src/embedding/base-embedding.ts + openai-embedding.ts,理解 detectDimensionpreprocessText 的”按字符截断”近似。
  4. 存储 - 挑 packages/core/src/vectordb/milvus-vectordb.ts 中三个方法精读:createHybridCollectioninsertHybridhybridSearch;对照 vectordb/types.ts 接口。
  5. 增量 - 精读 sync/merkle.ts(只有 89 行)+ sync/synchronizer.tscheckForChanges / buildMerkleDAG。画一张小图:一次文件改动如何传导到 DAG 根 → 触发 context.reindexByChange
  6. MCP 层 - 读 packages/mcp/src/index.ts + handlers.tshandleIndexCodebase / handleSearchCode。重点看”立即返回 + 后台 Promise”的模式,和 SnapshotManager 的 v1→v2 迁移。

第三阶段 · 实践(验证理解)

挑 1~2 个小任务练手:

  1. 加一种语言:在 SPLITTABLE_NODE_TYPESgetLanguageConfig 里接入 tree-sitter-ruby(仓库当前没有 Ruby grammar,Ruby 当前只能走 LangChain)。
  2. 加一个 Embedding 提供商:模仿 openai-embedding.ts 写一个 Cohere / Jina 实现,注册到 packages/mcp/src/embedding.ts 的工厂里。
  3. 加一个 MCP 工具:实现 list_indexed_codebases,读 SnapshotManager 返回当前已索引的 codebase 列表(目前需要看日志才能知道)。
  4. 换一种向量库:写一个 QdrantVectorDatabase implements VectorDatabase,实测 indexCodebase 是否完全不用改(验证抽象是否真的干净)。
  5. 做一次评测:进 evaluation/ 目录,按 README.mdrun_evaluation.py,观察 token 节省效果。

8. 常见问题与注意事项

8.1 容易踩的坑

  • MCP 必须用 stdout 传协议:任何 console.log 都会污染,所以 packages/mcp/src/index.ts 顶部做了重定向。如果你自己加新的依赖库打印到 stdout,整个 MCP 会话会直接崩。
  • .env 要放 ~/.context/.env,不要放在被索引的仓库里.env.example 开头明确警告,否则和被索引项目的 env 冲突,且 .env 又会被默认忽略规则排除。
  • 绝对路径强约束:Agent 传相对路径给 MCP 会被拒。索引”同一仓库的不同软链路径”会被当成两个 codebase 创建两份 collection,浪费额度。
  • Chunk 上限 450000:超级大仓库会看到 status: 'limit_reached';这是保护措施,不要以为是 bug。
  • VSCode 扩展被迫走 REST:因为 @zilliz/milvus2-sdk-node 含 Node 原生模块,webpack 无法打入浏览器化的扩展;如果你想在扩展里直连 gRPC Milvus,不可行。
  • Hybrid Search 要求 Milvus ≥ 2.4:老版本 Milvus 没有 sparse_vector + BM25 function,会建 collection 失败。
  • Merkle 快照位于 ~/.context/merkle/<md5>.json:如果你手动删了 Milvus collection 但忘了删这个文件,下次 sync 会误以为”所有文件都没变”什么也不做。SyncManager 里有一段启发式恢复:error.message.includes('Failed to query Milvus')FileSynchronizer.deleteSnapshot
  • Ollama 走本地时 EMBEDDING_MODELOLLAMA_MODEL 优先级不同config.ts 里 Ollama 优先读 OLLAMA_MODEL,其他 provider 优先读 EMBEDDING_MODEL,写配置时要注意。

8.2 代码中的特殊约定

  • 日志前缀即模块名[Context][Synchronizer][SYNC-DEBUG][SNAPSHOT-VALIDATE][EMBEDDING] 等,方便 grep 定位;新加模块时请沿用。
  • 路径用斜杠归一化ignorePattern 匹配前一律把 \\ 换成 /,跨平台一致。
  • ID 生成规则:chunk id = chunk_<sha256(relativePath:startLine:endLine:content)[:16]>,因此只要内容和行号没变,重复索引也不会重复入库(Milvus PK 去重)。
  • 生产/VSCode/Chrome 三套 VectorDatabase 实现,但共用一个接口 (packages/core/src/vectordb/types.ts):新增方法时务必同步三个实现,否则某个适配层会编译挂。

8.3 值得注意的 TODO / 技术债务

  • roadmap 中未完成项README.md 末尾):Agent-based interactive search mode、Search result ranking optimization、Robust Chrome Extension 尚未实现。
  • V1 快照兼容代码packages/mcp/src/snapshot.tsloadV1Format 把历史 v1 数据里的 indexedFiles/totalChunks 填成 0,加之 Issue #295 的自愈逻辑,说明这块曾踩过坑;后续可能会彻底废弃 v1 格式,自定义扩展快照结构时需要小心。
  • rowCount 被同时用作 indexedFilestotalChunkshandlers.ts 注释明确承认”imprecise”):目前没有便宜的元数据查询能拿到真实 file count,后续如果 Milvus 支持 group-by count 应该替换。
  • AstCodeSplitter 未覆盖 Ruby/Swift/Kotlin/PHP 等常用语言,只在 LangChain 分支兜底,切分质量有改进空间。
  • Chrome 扩展比 VSCode 扩展粗糙一些(README.md 明说”Robust Chrome Extension”还在 roadmap),依赖 stub 较多,阅读时别把它当生产级参考。
  • CHUNK_LIMIT = 450000 是硬编码,对超大 monorepo 不友好,未来可能会改成配置项。