本文将剖析 Claude Context Chrome 扩展的技术架构,重点解析其如何将核心的 Milvus 向量数据库能力适配到浏览器环境。核心方案是构建一个基于 RESTful API 的 MilvusRestfulVectorDatabase 轻量实现(milvus-vectordb-stub.ts),并通过 ChromeMilvusAdapter 进行封装。同时,通过 webpack.config.js 中的精细配置,为 Node.js 专有模块提供 Polyfill,确保代码能在浏览器中运行。文章将结合 background.ts 中的 cosSim 函数等关键代码,阐述从嵌入生成、代码分割到向量搜索的完整工作流。

Claude Context Chrome 扩展技术架构:Milvus RESTful 适配与浏览器兼容

Chrome 扩展的沙箱环境与 Node.js 存在根本差异,无法直接使用 @zilliz/claude-context-core 中依赖 Node.js 原生模块(如 grpc)的向量数据库驱动。Claude Context Chrome 扩展的技术挑战,在于将基于 Milvus 的语义搜索能力完整地移植到浏览器中。其解决方案是构建一套纯前端的 Milvus RESTful 适配层,并通过构建工具进行必要的环境兼容。

核心工作流与关键组件

扩展的背景脚本 background.ts 是整个逻辑的枢纽,它协调了从 GitHub 仓库代码获取、代码分割、嵌入生成到 Milvus 存储与查询的全过程。

1. 代码分割与嵌入生成

background.ts 中,splitCode 函数负责将源代码文本分割成适合嵌入的片段。它采用了一种近似于 LangChain RecursiveCharacterTextSplitter 的字符级分割策略,主要依据字符长度(默认 chunkSize = 1000chunkOverlap = 200)而非语法结构。这确保了分割逻辑在浏览器环境中的轻量与一致性。

// background.ts 中的分割函数
function splitCode(content: string, language: string = '', chunkSize: number = 1000, chunkOverlap: number = 200): { content: string; startLine: number; endLine: number }[] {
    // ... 基于行和字符的分割逻辑
}

分割后的代码片段需要转换为向量。EmbeddingModel 类直接在浏览器中调用 OpenAI API,它通过 fetchhttps://api.openai.com/v1/embeddings 端点通信,避免了任何 Node.js 的依赖。该类以批处理方式(EMBEDDING_BATCH_SIZE = 100)发送请求,优化了 API 调用效率。

// background.ts 中的嵌入模型类
class EmbeddingModel {
    // ... 使用 fetch 直接调用 OpenAI API
    static async embedBatch(texts: string[]): Promise<number[][]> {
        const response = await fetch('https://api.openai.com/v1/embeddings', { ... });
        // ...
    }
}

2. 向量相似度计算:cosSim 函数

搜索时,需要计算查询向量与存储向量之间的余弦相似度。background.ts 中定义了一个纯 JavaScript 实现的 cosSim 函数,避免了依赖外部数学库。

// background.ts 中的余弦相似度计算
function cosSim(a: number[], b: number[]): number {
    let dot = 0;
    let normA = 0;
    let normB = 0;
    const len = Math.min(a.length, b.length);
    for (let i = 0; i < len; i++) {
        dot += a[i] * b[i];
        normA += a[i] * a[i];
        normB += b[i] * b[i];
    }
    if (normA === 0 || normB === 0) {
        return 0;
    }
    return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}

此函数虽然在 background.ts 中定义,但其计算逻辑与 milvus-vectordb-stub.ts 中 Milvus 搜索返回距离(distance)到相似度(score)的转换逻辑(score: 1 - distance)保持一致,共同确保了搜索结果的相关性排序准确。关于向量数据库的更多实现细节,可以参考 Claude Context 向量数据库实现:Milvus gRPC 与 RESTful 双引擎

Milvus RESTful 适配层:ChromeMilvusAdaptermilvus-vectordb-stub

这是整个架构的核心创新。为了在浏览器中与 Milvus 交互,项目绕开了 Node.js 的 gRPC 驱动,转而实现了完整的 RESTful API 客户端。

milvus-vectordb-stub.ts 文件提供了一个完整的 MilvusRestfulVectorDatabase 类。它通过浏览器原生的 fetch API 与 Milvus 的 /v2/vectordb 端点通信,支持集合的创建、删除、数据插入和向量搜索。其 search 方法在返回结果前,会确保按相似度得分降序排序。

// milvus-vectordb-stub.ts 中的关键实现
export class MilvusRestfulVectorDatabase {
    private baseUrl: string;
    constructor(config: MilvusRestfulConfig) {
        // 构建基础URL,确保以 /v2/vectordb 结尾
        this.baseUrl = address.replace(/\/$/, '') + '/v2/vectordb';
    }

    async search(collectionName: string, queryVector: number[], options?: SearchOptions): Promise<VectorSearchResult[]> {
        // ... 调用 /entities/search
        // 将返回的 distance 转换为相似度 score
        score: Math.max(0, Math.min(1, 1 - (item.distance || 1)))
        // ... 最终按 score 降序排序
        const sortedResults = filteredResults.sort((a, b) => b.score - a.score);
    }
}

ChromeMilvusAdapter 则是面向 background.ts 的封装层。它将扩展特定的配置管理(MilvusConfigManager)与核心的 MilvusRestfulVectorDatabase 连接起来,提供了更符合扩展上下文的接口,如 insertChunkssearchSimilar。它在搜索后也进行了二次排序,双重保障结果顺序。

// chromeMilvusAdapter.ts 中的适配器
export class ChromeMilvusAdapter {
    private milvusDb: MilvusRestfulVectorDatabase | null = null;
    // ...
    async searchSimilar(queryVector: number[], limit: number = 10, threshold: number = 0.3): Promise<SearchResult[]> {
        const results = await this.milvusDb.search(this.collectionName, queryVector, searchOptions);
        // 转换格式并再次排序
        searchResults.sort((a, b) => b.score - a.score);
        return searchResults;
    }
}

浏览器环境兼容:Webpack Polyfill 配置

即使是使用了 fetch 替代 grpc,扩展的依赖库中可能仍包含对 Node.js 内置模块(如 crypto, path, vm)的引用。webpack.config.js 通过 resolve.fallback 和插件机制,为这些模块提供了浏览器兼容的替代品或空实现。

// webpack.config.js 中的 fallback 配置
resolve: {
    fallback: {
        "crypto": require.resolve("crypto-browserify"),
        "stream": require.resolve("stream-browserify"),
        "buffer": require.resolve("buffer"),
        "path": require.resolve("path-browserify"),
        "vm": false, // 直接禁用 vm 模块
        // ... 其他模块配置
    }
},
plugins: [
    // 将 vm 模块的引用替换为空桩文件
    new webpack.NormalModuleReplacementPlugin(
        /^vm$/,
        require.resolve('./src/vm-stub.js')
    )
]

关键配置包括:

  • "vm": false:直接禁用 vm 模块,这对于某些依赖环境检测的库是必要的。
  • new webpack.NormalModuleReplacementPlugin(... vm ...):通过插件将任何 import vm from 'vm' 的语句重定向到一个空的桩文件 ./src/vm-stub.js,彻底避免运行时错误。
  • 其他模块如 crypto, path, zlib 均通过 crypto-browserify, path-browserify, browserify-zlib 等社区提供的同构库进行填充。

这些配置共同构成了扩展在浏览器中稳定运行的基础。如果你想了解 Claude Context 更广泛的整体架构,包括其核心引擎的设计,可以阅读 Claude Context 核心引擎深度解析:嵌入、向量数据库与代码分割架构

FAQ

Q: 如何验证 Chrome 扩展与 Milvus 服务器的连接是否正常? A: 在扩展的选项页面通常会提供一个“测试连接”按钮。点击后,background.ts 会调用 handleTestMilvusConnection 方法,该方法会实例化一个 ChromeMilvusAdapter 并执行 testConnection 检查,最终向界面返回连接成功或具体的错误信息(如网络问题、认证失败、CORS 限制等)。

Q: 搜索结果的相关性分数(score)是如何计算的? A: 相关性分数基于余弦相似度。首先,background.ts 中的 cosSim 函数用于计算本地向量间的相似度。同时,milvus-vectordb-stub.ts 在从 Milvus REST API 获取搜索结果时,会将返回的“距离”(distance)转换为相似度,公式为 score = 1 - distance。两种方式在数学上是等价的,确保了结果排序的一致性。

Q: 为什么选择 RESTful API 而非 WebSocket 与 Milvus 交互? A: 浏览器环境对原生 TCP/UDP 连接的限制严格,而基于 HTTP 的 RESTful API 兼容性最好,可以无缝使用浏览器的 fetch API。同时,Milvus 官方提供了完整的 RESTful 端点(/v2/vectordb),能够支持扩展所需的所有集合管理和数据操作功能。