AI News HubLIVE
站内改写4 分钟阅读

使用 Weaviate MCP 构建编码助手:对代码与文档进行 RAG 检索

本文介绍如何利用 Weaviate 内置的 MCP 服务器为编码助手(如 Claude Code、Cursor 和 VS Code)提供混合搜索能力,无需额外编写胶水代码。通过将代码库与文档分块并索引到 Weaviate,结合 BM25 精确匹配与向量语义检索,LLM 智能代理可以高效获取所需上下文,避免上下文过载与成本浪费。

上周,我让 Claude Code 在我的代码库中实现一个相对简单的功能。三轮对话后,上下文消耗超过 80K token,但 Claude 仍然缺少一些我忘记包含的关键信息。没有检索机制,你就会陷入这样的循环:粘贴太少,代理靠猜测;粘贴太多,又要为代理未使用的上下文付费。

大多数团队通过 RAG 对代码库进行检索来解决这个问题。典型的方案是采用向量数据库加上一个自定义的 MCP 服务器作为桥梁。Weaviate 简化了这一过程:MCP 服务器内建于数据库之中,位于与 REST API 同一端口的 /v1/mcp。仅需一个环境变量即可启用。你可能已经在 Weaviate 中使用的混合检索同样适用于代码检索,其中 BM25 部分可以匹配像 connect_to_local 这样的函数标识符,而向量部分则能发现语义意图,例如“如何初始化客户端”。

本文将指导你基于这一内建 MCP 服务器构建编码助手:包括如何摄取代码库、摄取文档、连接 Claude Code、Cursor 和 VS Code,并运行真实的查询。覆盖以下主题:

  • 为什么你的编码助手需要超越训练数据
  • 为什么 Weaviate MCP 适合这项工作
  • 第一步:运行带 MCP 的 Weaviate
  • 第二步:设计模式
  • 第三步:代码库的分块与摄取
  • 第四步:文档的分块与摄取
  • 第五步:连接 Claude Code、Cursor 和 VS Code
  • 尝试运行
  • 代理运行手册:自动设置

为什么编码助手需要超越训练数据

LLM 具有固定的知识截止期,且对私有代码一无所知。简单的解决方法是直接把文件丢进提示词中。但这带来三个问题:

  1. 成本:上下文中的 token 按轮次计费。一个 200 个文件的 Python 项目无法完全放入提示词,即使部分放入,在代理推理过程中也会持续计费。
  2. 过时的上下文:一旦文件进入提示词,它就被冻结了。如果代理修改了一个函数后又需要重新读取,它必须重新加载整个文件。模型所见的视图与磁盘上的真实情况之间没有实时链接。
  3. 不恰当的粒度:即使文件能放入提示词,模型的注意力也会浪费在无关的部分——导入、模块级样板代码等。代理正在编辑的函数与上百行 from x import y 争夺上下文。

检索解决了这三个问题。只需一次索引代码库,将分块存入向量数据库,让 LLM 客户端按需拉取所需内容。这就是 RAG。编码助手此前缺乏一种干净的方式与这类数据库通信,无需自定义适配层。这就是 MCP 发挥作用的地方。

为什么 Weaviate MCP 适合这项工作

模型上下文协议(MCP)是 Claude Code、Cursor 和 VS Code 等 LLM 客户端调用外部工具的标准方式。Weaviate v1.37.1 将其核心操作作为 MCP 工具暴露在 Streamable HTTP 端点 /v1/mcp 上。共提供四个工具:

  • weaviate-collections-get-config:让 LLM 检查可用的集合及其属性
  • weaviate-tenants-list:在使用多租户时列出租户
  • weaviate-query-hybrid:运行混合(BM25+向量)搜索
  • weaviate-objects-upsert:仅在启用写权限时写入对象

混合搜索是该方案对编码助手最具体的好处。代码是标识符与意图的混合体。BM25 精确匹配标识符,向量捕获意图。像“我们在哪里处理 429 重试?”这样的查询需要两者同时作用:向量找到语义相关的重试代码,BM25 将 429 作为精确词条锚定。纯向量检索会丢失整数匹配,纯 BM25 会遗漏用户未提及的措辞。混合搜索在这种混合意图查询中胜出。

操作简便性是第二个原因。其他方案需要运行一个 MCP 服务器外加向量数据库,相当于在生产中监视两个服务。Weaviate 将 MCP 服务器放在数据库内部,同端口、同认证体系,你只需要监控 Weaviate 本身。

第三个原因是多租户。一个 Weaviate 实例可以承载多个代码库,每个库作为独立的租户隔离。对于拥有多个仓库的组织,一个集群即可,无需为每个团队单独部署。

关于 Weaviate MCP 与函数调用(function calling)的区别:函数调用是针对具体 LLM API 的,而 MCP 是传输层协议——任何支持 MCP 的客户端都可以调用任何支持 MCP 的服务器,无需重写。构建一次检索,即可在 Claude Code、Cursor 和 VS Code 中使用,无需转换。

第一步:运行带 MCP 的 Weaviate

MCP 服务器默认禁用。两个环境变量可启用:

services:
  weaviate:
    image: cr.weaviate.io/semitechnologies/weaviate:1.37.1
    ports:
      - '8080:8080'
      - '50051:50051'
    environment:
      MCP_SERVER_ENABLED: 'true'
      MCP_SERVER_WRITE_ACCESS_ENABLED: 'true'
      AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
      DEFAULT_VECTORIZER_MODULE: 'text2vec-openai'
      ENABLE_MODULES: 'text2vec-openai'
      OPENAI_APIKEY: ${OPENAI_APIKEY}

MCP_SERVER_ENABLED 暴露只读工具(集合查询、租户列表、混合查询)。MCP_SERVER_WRITE_ACCESS_ENABLED 添加 upsert 工具,允许代理写回结果。如果只需要检索,可以跳过写权限。建议先只开启只读模式,因为大多数编码代理的工作都只涉及检索,而且可以避免代理向知识库写入无意义内容的风险。

生产环境认证 本例使用匿名访问以保持聚焦于 MCP 配置。对于任何网络部署,应启用 API 密钥并在客户端配置中添加 Authorization: Bearer——Weaviate 的 MCP 服务器支持标准认证和 RBAC。

启动后,可通过 curl 发送 initialize 握手确认端点是否存活:

docker compose up -d
curl -sf -X POST http://localhost:8080/v1/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'

如果 MCP 服务器存活,会返回一个包含服务器能力的 JSON-RPC 响应并设置 Mcp-Session-Id 头。

第二步:设计模式 创建两个集合:CodeChunksDocChunks,共享同一个 Weaviate 实例。

client.collections.create(
    name="CodeChunks",
    properties=[
        Property(name="content", data_type=DataType.TEXT, tokenization=Tokenization.WORD),
        Property(name="symbol", data_type=DataType.TEXT, tokenization=Tokenization.LOWERCASE),
        Property(name="file_path", data_type=DataType.TEXT, tokenization=Tokenization.FIELD),
        Property(name="language", data_type=DataType.TEXT, tokenization=Tokenization.FIELD),
        Property(name="repo", data_type=DataType.TEXT, tokenization=Tokenization.FIELD),
    ],
    vector_config=Configure.Vectors.text2vec_openai(),
)

symbol 使用小写分词,使 connect_to_local 作为一个 token 而非三个;file_pathlanguagerepo 使用 FIELD 实现精确匹配;contenttitle 使用 WORD

第三步:代码库的分块与摄取 基于行的朴素分块会破坏代码结构。应采用语法边界分块:每个函数、每个类、每个顶级语句一个块。Python 标准库 ast 即可胜任 Python 代码的分块:

import ast
from pathlib import Path

def chunk_python_file(path: Path) -> list[dict]:
    source = path.read_text()
    tree = ast.parse(source)
    lines = source.splitlines()
    chunks = []
    for node in ast.iter_child_nodes(tree):
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
            start = node.lineno - 1
            end = node.end_lineno
            chunks.append({
                "content": "\n".join(lines[start:end]),
                "symbol": node.name,
                "file_path": str(path),
                "language": "python",
                "repo": "my-service",
            })
    return chunks

然后使用 Weaviate 的批量写入模式:

with code_chunks.batch.dynamic() as batch:
    for py_file in Path("./").rglob("*.py"):
        for chunk in chunk_python_file(py_file):
            batch.add_object(properties=chunk)

每个分块在插入时由 text2vec-openai 自动向量化。也可以替换为 text2vec-voyageaitext2vec-cohere

第四步:文档的分块与摄取 文档分块应以标题为边界。推荐按 H2 分割,若某节过长再按 H3 细分:

import re

def chunk_markdown(text: str, max_chars: int = 1500) -> list[str]:
    sections = re.split(r"(?m)^## ", text)
    chunks = []
    for section in sections:
        if len(section) < max_chars:
            chunks.append(section.strip())
        else:
            subsections = re.split(r"(?m)^### ", section)
            for sub in subsections:
                if sub.strip():
                    chunks.append(sub.strip()[:max_chars])
    return chunks

每个块同时保留 titlesource_url 属性。

第五步:连接 Claude Code、Cursor 和 VS Code

  • Claude Code 原生支持 MCP:在 ~/.claude/settings.json 中添加配置指向 Weaviate 端点,混合搜索工具自动可用。
  • Curs 通过 .cursor/mcp.json 配置:原理类似,只需指定 URL 和工具列表。
  • VS Code 需安装 MCP 扩展后配置 mcp.json

代理运行手册:自动设置 提供一个 shell 脚本 setup.sh,包含以下步骤:检查环境变量、拉取 Docker 镜像、启动 Weaviate、等待就绪、验证 MCP 端点,然后运行 ingest.py 摄取数据。脚本具有幂等性,可重复执行。

总之,Weaviate MCP 为编码助手提供了一条极简的路径来实现高效的混合检索。通过将 MCP 服务器内建在数据库内,该方案消除了额外的运维负担,同时提供了强大的多租户支持和开箱即用的混合搜索能力。无论是个人项目还是团队协作,都可以快速上手,让 LLM 代理真正理解私有代码库。