首页 › tutorials › Claude Code语义搜索全链路实战

Claude Code语义搜索全链路实战:从Embedding到向量检索

当代码库突破十万行,传统关键词搜索开始力不从心。本文将带你从零构建一套完整的语义搜索系统,让Claude Code真正"理解"你的代码。

引言:为什么Claude Code需要语义搜索?

Claude Code内置了Grep、Glob等文件搜索工具,这些工具基于字符串匹配和文件名模式工作——对于小型项目足够好用,但在大型代码库中存在明显局限:

语义搜索通过将代码转化为向量嵌入(Embedding),在语义空间中计算相似度,从根本上解决了这些问题。

graph LR
    A[自然语言查询] --> B[查询向量化]
    C[代码库] --> D[代码分块 + 向量化]
    D --> E[(向量数据库)]
    B --> F[相似度检索]
    E --> F
    F --> G[语义相关代码]

    style A fill:#e1f5fe
    style G fill:#c8e6c9
    style E fill:#fff3e0

核心概念速览

什么是文本嵌入(Embedding)?

文本嵌入是将文本转换为高维数值向量的过程。语义相近的文本在向量空间中距离更近。例如:

文本A 文本B 语义关系 向量距离
"用户登录验证" "authenticate user" 相似 近
"数据库连接池" "createPool(config)" 相似 近
"发送邮件" "矩阵运算" 无关 远

当前主流的代码嵌入模型包括:

向量数据库选型

数据库 类型 特点 适用场景
ChromaDB 嵌入式 Python原生,零配置 快速原型、本地开发
Milvus/Zilliz 分布式 高性能,支持混合检索 生产级部署
Pinecone 云托管 全托管,免运维 快速上线
Qdrant 独立部署 Rust实现,性能优秀 自托管生产环境
SQLite-VSS 嵌入式 SQLite扩展,轻量 单机轻量场景
graph TD
    subgraph "选型决策树"
        A{项目规模?} -->|个人/小团队| B{是否需要离线?}
        A -->|企业级| C{是否接受云托管?}
        B -->|是| D[ChromaDB / SQLite-VSS]
        B -->|否| E[Pinecone免费层]
        C -->|是| F[Zilliz Cloud / Pinecone]
        C -->|否| G[Milvus自托管 / Qdrant]
    end

    style D fill:#c8e6c9
    style E fill:#c8e6c9
    style F fill:#bbdefb
    style G fill:#bbdefb

实战一:本地语义代码搜索工具

我们先从最实用的场景开始——为Claude Code构建一个本地语义搜索工具。

第一步:安装依赖

# 创建项目目录
mkdir claude-semantic-search && cd claude-semantic-search

# 初始化项目
npm init -y

# 安装核心依赖
npm install chromadb openai ollama-ai-provider @xenova/transformers
npm install -D typescript @types/node tsx

第二步:代码解析与分块

代码分块(Chunking)是语义搜索中最关键的预处理步骤。分块策略直接影响检索质量:

// src/chunker.ts
import * as fs from 'fs';
import * as path from 'path';

interface CodeChunk {
  filePath: string;
  content: string;
  startLine: number;
  endLine: number;
  type: 'function' | 'class' | 'module' | 'block';
  name?: string;
}

// AST级别的代码分块(以TypeScript/JavaScript为例)
export function chunkFile(filePath: string): CodeChunk[] {
  const content = fs.readFileSync(filePath, 'utf-8');
  const lines = content.split('\n');
  const chunks: CodeChunk[] = [];

  // 函数/类级别分块策略
  const functionRegex = /(?:export\s+)?(?:async\s+)?function\s+(\w+)/g;
  const classRegex = /(?:export\s+)?(?:abstract\s+)?class\s+(\w+)/g;
  const arrowRegex = /(?:export\s+)?const\s+(\w+)\s*=\s*(?:async\s+)?\(/g;

  const extractBlock = (regex: RegExp, type: CodeChunk['type']) => {
    let match;
    while ((match = regex.exec(content)) !== null) {
      const startLine = content.substring(0, match.index).split('\n').length;
      const block = extractBlockContent(lines, startLine - 1);
      if (block) {
        chunks.push({
          filePath,
          content: block.content,
          startLine,
          endLine: block.endLine,
          type,
          name: match[1],
        });
      }
    }
  };

  extractBlock(classRegex, 'class');
  extractBlock(functionRegex, 'function');
  extractBlock(arrowRegex, 'function');

  // 如果没有提取到任何块,按固定大小分块
  if (chunks.length === 0) {
    const CHUNK_SIZE = 50; // 行数
    for (let i = 0; i < lines.length; i += CHUNK_SIZE) {
      const endLine = Math.min(i + CHUNK_SIZE, lines.length);
      chunks.push({
        filePath,
        content: lines.slice(i, endLine).join('\n'),
        startLine: i + 1,
        endLine,
        type: 'block',
      });
    }
  }

  return chunks;
}

// 提取花括号匹配的完整块
function extractBlockContent(
  lines: string[],
  startIdx: number
): { content: string; endLine: number } | null {
  let braceCount = 0;
  let foundFirst = false;
  let endIdx = startIdx;

  for (let i = startIdx; i < lines.length; i++) {
    for (const ch of lines[i]) {
      if (ch === '{') {
        braceCount++;
        foundFirst = true;
      } else if (ch === '}') {
        braceCount--;
      }
    }
    endIdx = i;
    if (foundFirst && braceCount === 0) break;
  }

  if (!foundFirst) return null;

  return {
    content: lines.slice(startIdx, endIdx + 1).join('\n'),
    endLine: endIdx + 1,
  };
}

第三步:生成嵌入向量

我们提供两种方案——使用Ollama本地模型(零成本、离线)或Voyage AI API(高质量):

// src/embedder.ts

// 方案A:使用Ollama本地嵌入(推荐用于开发/测试)
export async function embedWithOllama(texts: string[]): Promise<number[][]> {
  const response = await fetch('http://localhost:11434/api/embed', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'nomic-embed-text',
      input: texts,
    }),
  });

  const data = await response.json();
  return data.embeddings;
}

// 方案B:使用Voyage AI(Anthropic推荐,高质量代码嵌入)
export async function embedWithVoyage(
  texts: string[],
  apiKey: string
): Promise<number[][]> {
  const response = await fetch('https://api.voyageai.com/v1/embeddings', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      input: texts,
      model: 'voyage-code-3',
      input_type: 'document',
    }),
  });

  const data = await response.json();
  return data.data.map((item: any) => item.embedding);
}

关于Anthropic嵌入服务的说明:Anthropic的嵌入API底层使用Voyage AI作为提供商。如果你已有Anthropic API密钥,可以通过Anthropic的嵌入端点调用,也可以直接使用Voyage AI的API。两者在代码嵌入场景下效果相当。

第四步:构建向量索引

// src/indexer.ts
import { ChromaClient } from 'chromadb';
import { chunkFile } from './chunker.js';
import { embedWithOllama, embedWithVoyage } from './embedder.js';
import * as fs from 'fs';
import * as path from 'path';

const client = new ChromaClient({ path: 'http://localhost:8000' });

const SUPPORTED_EXTENSIONS = new Set([
  '.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.rs', '.java',
  '.rb', '.php', '.c', '.cpp', '.h', '.hpp', '.cs', '.swift',
]);

export async function indexCodebase(
  rootDir: string,
  collectionName: string = 'codebase'
) {
  // 获取或创建集合
  const collection = await client.getOrCreateCollection({
    name: collectionName,
    metadata: { 'hnsw:space': 'cosine' },
  });

  // 递归收集所有代码文件
  const files = collectFiles(rootDir);
  console.log(`发现 ${files.length} 个代码文件`);

  let totalChunks = 0;

  for (const file of files) {
    const chunks = chunkFile(file);
    if (chunks.length === 0) continue;

    const contents = chunks.map((c) => c.content);
    const embeddings = await embedWithOllama(contents);

    const ids = chunks.map(
      (_, i) => `${path.relative(rootDir, file)}::${i}`
    );
    const metadatas = chunks.map((c) => ({
      filePath: path.relative(rootDir, c.filePath),
      startLine: c.startLine,
      endLine: c.endLine,
      type: c.type,
      name: c.name || '',
    }));

    await collection.add({
      ids,
      embeddings,
      documents: contents,
      metadatas,
    });

    totalChunks += chunks.length;
    console.log(`  索引: ${path.relative(rootDir, file)} (${chunks.length} 块)`);
  }

  console.log(`索引完成!共 ${totalChunks} 个代码块`);
  return { fileCount: files.length, chunkCount: totalChunks };
}

function collectFiles(rootDir: string): string[] {
  const files: string[] = [];
  const ignoreDirs = new Set([
    'node_modules', '.git', 'dist', 'build', '.next', '__pycache__',
    'vendor', '.venv', 'venv',
  ]);

  function walk(dir: string) {
    const entries = fs.readdirSync(dir, { withFileTypes: true });
    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        if (!ignoreDirs.has(entry.name)) walk(fullPath);
      } else if (SUPPORTED_EXTENSIONS.has(path.extname(entry.name))) {
        files.push(fullPath);
      }
    }
  }

  walk(rootDir);
  return files;
}

第五步:语义检索

// src/search.ts
import { ChromaClient } from 'chromadb';
import { embedWithOllama } from './embedder.js';

const client = new ChromaClient({ path: 'http://localhost:8000' });

export interface SearchResult {
  filePath: string;
  startLine: number;
  endLine: number;
  type: string;
  name: string;
  content: string;
  score: number;
}

export async function semanticSearch(
  query: string,
  options: {
    collectionName?: string;
    topK?: number;
    fileFilter?: string;
  } = {}
): Promise<SearchResult[]> {
  const {
    collectionName = 'codebase',
    topK = 10,
    fileFilter,
  } = options;

  const collection = await client.getCollection({ name: collectionName });

  // 查询向量化
  const [queryEmbedding] = await embedWithOllama([query]);

  // 构建过滤条件
  const where = fileFilter
    ? { filePath: { $contains: fileFilter } }
    : undefined;

  // 向量检索
  const results = await collection.query({
    queryEmbeddings: queryEmbedding,
    nResults: topK,
    where,
    include: ['documents', 'metadatas', 'distances'],
  });

  // 格式化结果
  return results.ids[0].map((id, i) => ({
    filePath: (results.metadatas?.[0]?.[i] as any)?.filePath || '',
    startLine: (results.metadatas?.[0]?.[i] as any)?.startLine || 0,
    endLine: (results.metadatas?.[0]?.[i] as any)?.endLine || 0,
    type: (results.metadatas?.[0]?.[i] as any)?.type || '',
    name: (results.metadatas?.[0]?.[i] as any)?.name || '',
    content: results.documents?.[0]?.[i] || '',
    score: 1 - (results.distances?.[0]?.[i] || 0),
  }));
}

// 增量索引更新
export async function updateIndex(
  changedFiles: string[],
  rootDir: string,
  collectionName: string = 'codebase'
) {
  const collection = await client.getCollection({ name: collectionName });

  for (const file of changedFiles) {
    // 删除旧索引
    const prefix = path.relative(rootDir, file);
    await collection.delete({
      where: { filePath: prefix },
    });

    // 重新索引
    const chunks = chunkFile(file);
    if (chunks.length === 0) continue;

    const contents = chunks.map((c) => c.content);
    const embeddings = await embedWithOllama(contents);

    await collection.add({
      ids: chunks.map((_, i) => `${prefix}::${i}`),
      embeddings,
      documents: contents,
      metadatas: chunks.map((c) => ({
        filePath: prefix,
        startLine: c.startLine,
        endLine: c.endLine,
        type: c.type,
        name: c.name || '',
      })),
    });
  }
}

第六步:封装为MCP Server接入Claude Code

为了将语义搜索能力直接集成到Claude Code中,我们构建一个MCP Server:

// src/mcp-server.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { semanticSearch, indexCodebase, updateIndex } from './index.js';

const server = new Server(
  { name: 'semantic-code-search', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

// 注册工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: 'semantic_search',
      description:
        '使用自然语言语义搜索代码。比关键词搜索更智能,能理解代码含义。',
      inputSchema: {
        type: 'object',
        properties: {
          query: {
            type: 'string',
            description: '自然语言查询,描述你想找的代码功能',
          },
          top_k: {
            type: 'number',
            description: '返回结果数量,默认10',
            default: 10,
          },
          file_filter: {
            type: 'string',
            description: '可选,按文件路径过滤',
          },
        },
        required: ['query'],
      },
    },
    {
      name: 'index_codebase',
      description: '为代码库建立语义索引。首次使用或代码大幅变更时调用。',
      inputSchema: {
        type: 'object',
        properties: {
          root_dir: {
            type: 'string',
            description: '代码库根目录路径',
          },
        },
        required: ['root_dir'],
      },
    },
  ],
}));

// 处理工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case 'semantic_search': {
      const results = await semanticSearch(args!.query as string, {
        topK: (args!.top_k as number) || 10,
        fileFilter: args!.file_filter as string,
      });

      const formatted = results
        .map(
          (r, i) =>
            `### 结果 ${i + 1} (${(r.score * 100).toFixed(1)}% 匹配)\n` +
            `文件: ${r.filePath}:${r.startLine}-${r.endLine}\n` +
            `${r.type === 'function' ? '函数' : r.type === 'class' ? '类' : '代码块'}${r.name ? `: ${r.name}` : ''}\n` +
            '```\n' + r.content + '\n```'
        )
        .join('\n\n');

      return {
        content: [{ type: 'text', text: formatted || '未找到相关代码' }],
      };
    }

    case 'index_codebase': {
      const stats = await indexCodebase(args!.root_dir as string);
      return {
        content: [
          {
            type: 'text',
            text: `索引完成:${stats.fileCount} 个文件,${stats.chunkCount} 个代码块`,
          },
        ],
      };
    }

    default:
      throw new Error(`未知工具: ${name}`);
  }
});

// 启动服务
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error('语义代码搜索 MCP Server 已启动');
}

main().catch(console.error);

配置Claude Code使用语义搜索

在.claude/settings.json中添加MCP Server配置:

{
  "mcpServers": {
    "semantic-search": {
      "command": "node",
      "args": ["--experimental-specifier-resolution=node", "dist/mcp-server.js"],
      "env": {
        "CHROMA_URL": "http://localhost:8000",
        "OLLAMA_URL": "http://localhost:11434"
      }
    }
  }
}

配置完成后,在Claude Code中可以直接使用语义搜索:

> 帮我找到处理用户支付回调的所有相关代码

# Claude Code 会调用 semantic_search 工具
# 返回:PaymentService.handleWebhook, verifySignature, processRefund 等
# 这些函数可能不包含"回调"关键词,但语义上高度相关

实战二:混合检索策略——BM25 + 向量搜索

纯向量搜索在某些场景下不如关键词搜索精准(比如搜索特定变量名)。混合检索结合了两者优势:

graph TB
    Q[用户查询] --> V[向量检索]
    Q --> K[BM25关键词检索]
    V --> R1[向量结果 + 相似度分数]
    K --> R2[关键词结果 + BM25分数]
    R1 --> M[RRF互惠排序融合]
    R2 --> M
    M --> F[最终排序结果]

    style Q fill:#e1f5fe
    style M fill:#fff9c4
    style F fill:#c8e6c9
// src/hybrid-search.ts
import { semanticSearch, SearchResult } from './search.js';

interface BM25Result {
  filePath: string;
  startLine: number;
  content: string;
  score: number;
}

// 简易BM25实现
function simpleBM25(
  query: string,
  chunks: { content: string; filePath: string; startLine: number }[]
): BM25Result[] {
  const terms = query.toLowerCase().split(/\s+/);
  const avgDocLen =
    chunks.reduce((sum, c) => sum + c.content.split(/\s+/).length, 0) /
    chunks.length;
  const k1 = 1.5;
  const b = 0.75;

  return chunks
    .map((chunk) => {
      const docTerms = chunk.content.toLowerCase().split(/\s+/);
      const docLen = docTerms.length;
      const tf = terms.map((t) => docTerms.filter((d) => d === t).length);
      const idf = terms.map(
        (t) =>
          Math.log(
            (chunks.length -
              chunks.filter((c) =>
                c.content.toLowerCase().includes(t)
              ).length +
              0.5) /
              (chunks.filter((c) =>
                c.content.toLowerCase().includes(t)
              ).length +
                0.5)
          )
      );
      const score = tf.reduce(
        (sum, f, i) =>
          sum +
          idf[i] *
            ((f * (k1 + 1)) / (f + k1 * (1 - b + b * (docLen / avgDocLen)))),
        0
      );
      return { ...chunk, score };
    })
    .sort((a, b) => b.score - a.score);
}

// RRF(Reciprocal Rank Fusion)融合算法
export function reciprocalRankFusion(
  vectorResults: SearchResult[],
  bm25Results: BM25Result[],
  k: number = 60
): (SearchResult & { fusedScore: number })[] {
  const scoreMap = new Map<string, { vector?: number; bm25?: number; data: any }>();

  vectorResults.forEach((r, i) => {
    const key = `${r.filePath}:${r.startLine}`;
    scoreMap.set(key, { vector: 1 / (k + i + 1), data: r });
  });

  bm25Results.forEach((r, i) => {
    const key = `${r.filePath}:${r.startLine}`;
    const existing = scoreMap.get(key);
    if (existing) {
      existing.bm25 = 1 / (k + i + 1);
    } else {
      scoreMap.set(key, {
        bm25: 1 / (k + i + 1),
        data: {
          filePath: r.filePath,
          startLine: r.startLine,
          endLine: 0,
          content: r.content,
          type: 'block',
          name: '',
          score: 0,
        },
      });
    }
  });

  return Array.from(scoreMap.values())
    .map(({ vector = 0, bm25 = 0, data }) => ({
      ...data,
      fusedScore: vector + bm25,
    }))
    .sort((a, b) => b.fusedScore - a.fusedScore);
}

实战三:利用现有开源工具快速集成

如果你不想从零构建,以下是两个可以直接使用的开源工具:

claude-context(Zilliz出品)

claude-context 是Zilliz团队开发的MCP插件,开箱即用的语义代码搜索工具:

# 使用uvx安装并运行
uvx claude-context --project /path/to/your/project

它支持混合检索(BM25 + 稠密向量),使用Zilliz Cloud作为向量后端。配置方式:

{
  "mcpServers": {
    "claude-context": {
      "command": "uvx",
      "args": ["claude-context", "--project", "/path/to/your/project"],
      "env": {
        "ZILLIZ_CLOUD_URI": "https://your-instance.zillizcloud.com",
        "ZILLIZ_CLOUD_TOKEN": "your-token"
      }
    }
  }
}

GrepAI——本地语义搜索

GrepAI 是一个完全本地的语义代码搜索方案,使用Ollama嵌入模型:

# 安装
pip install grepai

# 首先确保Ollama运行中
ollama pull nomic-embed-text

# 在项目中使用
grepai search "处理HTTP请求的错误重试逻辑" ./src

GrepAI据称可以节省约27%的Claude Code使用成本——因为它让Claude Code更快找到相关代码,减少了来回搜索的Token消耗。

架构设计:生产级语义搜索系统

graph TB
    subgraph "索引管道"
        A[Git Hook / CI触发] --> B[变更文件检测]
        B --> C[增量代码分块]
        C --> D[并行嵌入生成]
        D --> E[向量数据库写入]
    end

    subgraph "查询管道"
        F[Claude Code查询] --> G[MCP Server接收]
        G --> H{查询类型判断}
        H -->|语义查询| I[向量检索]
        H -->|精确匹配| J[BM25检索]
        H -->|混合| K[双路检索 + RRF融合]
        I --> L[结果重排序]
        J --> L
        K --> L
        L --> M[上下文窗口优化]
        M --> N[返回Claude Code]
    end

    subgraph "存储层"
        E --> O[(向量数据库<br/>ChromaDB/Milvus)]
        P[(元数据存储<br/>文件路径/行号/类型)]
    end

    style A fill:#e1f5fe
    style F fill:#e1f5fe
    style N fill:#c8e6c9

Git Hook自动增量索引

将索引更新集成到开发工作流中,确保搜索结果始终最新:

#!/bin/bash
# .git/hooks/post-commit
# 每次提交后自动更新语义索引

CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD | grep -E '\.(ts|tsx|js|jsx|py|go|rs)$')

if [ -n "$CHANGED_FILES" ]; then
  echo "更新语义索引: $CHANGED_FILES"
  node /path/to/claude-semantic-search/dist/update-index.js $CHANGED_FILES
fi

上下文窗口优化策略

当检索结果过多时,需要智能裁剪以适配Claude的上下文窗口:

// src/context-optimizer.ts

const MAX_CONTEXT_TOKENS = 8000; // 预留给代码上下文的Token预算

export function optimizeContext(
  results: SearchResult[],
  maxTokens: number = MAX_CONTEXT_TOKENS
): SearchResult[] {
  let usedTokens = 0;
  const selected: SearchResult[] = [];

  // 按相关度排序后贪心选择
  for (const result of results) {
    const estimatedTokens = Math.ceil(result.content.length / 3.5);
    if (usedTokens + estimatedTokens > maxTokens) {
      // 如果完整块放不下,尝试截断
      const remaining = maxTokens - usedTokens;
      if (remaining > 200) {
        selected.push({
          ...result,
          content: result.content.substring(0, remaining * 3.5) + '\n// ... (截断)',
        });
      }
      break;
    }
    selected.push(result);
    usedTokens += estimatedTokens;
  }

  return selected;
}

性能对比:语义搜索 vs 关键词搜索

场景 关键词搜索 (Grep) 语义搜索 混合检索
查找getUserById 精准命中 精准命中 精准命中
查找"用户认证相关代码" 可能遗漏(需匹配关键词) 命中authenticate、verifyToken等 最全面
查找"类似Redis的缓存逻辑" 无法实现 找到内存缓存实现 找到内存缓存实现
大型代码库速度 快(<100ms) 中等(200-500ms) 稍慢(300-800ms)
索引开销 无 一次性/增量 一次性/增量
Token消耗 需多次搜索 一次精准命中 一次精准命中

完整启动流程

# 1. 启动ChromaDB(Docker方式)
docker run -d -p 8000:8000 chromadb/chroma:latest

# 2. 启动Ollama(如果使用本地嵌入)
ollama serve
ollama pull nomic-embed-text

# 3. 构建项目
cd claude-semantic-search
npm run build

# 4. 初始化索引
node dist/indexer.js /path/to/your/project

# 5. 启动MCP Server(Claude Code会自动连接)
node dist/mcp-server.js

训练营适用性评估

维度 评分 说明
难度曲线 ⭐⭐⭐⭐ 需要理解嵌入/向量概念,但代码实现不算复杂
实用性 ⭐⭐⭐⭐⭐ 直接提升Claude Code在大型项目中的表现
动手占比 ⭐⭐⭐⭐⭐ 100%实操,从编码到部署全覆盖
可扩展性 ⭐⭐⭐⭐⭐ 学员可替换不同嵌入模型/向量数据库
时间投入 ⭐⭐⭐ 完整实现约需3-4小时,可拆分为多个练习
前置知识 ⭐⭐⭐ 需TypeScript基础、了解向量概念、MCP协议

适合人群:有一定编程基础、想深入理解AI代码搜索原理的开发者。

建议课时:2次课,每次2小时。第一次完成索引和检索核心,第二次完成MCP集成和混合搜索。

参考资料

  1. Anthropic Embeddings API文档 - Anthropic官方嵌入服务文档,底层使用Voyage AI
  2. claude-context: Semantic Code Search for Claude Code - Zilliz开源的MCP语义搜索插件,支持混合检索
  3. ChromaDB官方文档 - 开源嵌入式向量数据库,本文核心存储组件
  4. Voyage AI Code Embeddings - 专为代码优化的嵌入模型
  5. Model Context Protocol规范 - MCP协议官方规范

本文为Claude Code实战教程系列第三轮,聚焦语义搜索与向量检索在Claude Code中的完整应用链路。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入