Skip to content

总览

环境搭建与配置

问题排查与维护

1. RAG 管道概览

1.1 系统架构

  • 目标:网站集成 RAG 聊天机器人,基于 Cloudflare Workers
  • 核心组件:数据摄取管道 → 向量存储 → 查询处理 → 答案生成
  • 数据来源:Hugo 网站 Markdown 文件(content/ 目录)
  • 后端模型:Gemini 与通义千问(Qwen)可切换
  • 基础设施:Cloudflare Workers + Vectorize + 边缘计算

1.2 高层工作流程

  1. 内容摄取:Markdown 文件 → 文本分块 → 嵌入向量 → 向量存储
  2. 查询处理:用户问题 → 查询嵌入 → 向量相似度检索
  3. 上下文检索:Top-K 相似分块 → 元数据过滤 → 来源汇总
  4. 答案生成:检索上下文 + 用户问题 → LLM → 结构化回复

1.3 关键特性

  • 📁 目录递归处理:批量处理 Hugo 内容目录,智能草稿过滤
  • 🌐 多语言支持:中英文内容,语言专属处理
  • ⚡ 高性能:简化查询逻辑,无 fallback 延迟
  • 🛡️ 草稿感知:兼容 Hugo 草稿过滤及级联继承

2. 实体关系图

2.1 数据流架构

flowchart TD
  A(["Markdown 文件 (.md)\ncontent"]) -->|"matter.js + markdownToPlain()"| B(["纯文本"])
  B -->|"chunkText 中文感知"| C(["文本分块,最多 800 字"])
  C -->|"Embedding text-embedding-v4 或 text-embedding-004"| D(["向量嵌入,1024 或 768 维"])
  D -->|"generateShortId 和元数据"| E(["向量记录"])
  E -->|"Cloudflare Vectorize upsert"| F(["向量索引"])

  subgraph 检索
    Q(["用户查询"]) -->|"Embed"| QV(["查询向量"])
    QV -->|"相似度与过滤"| F
    F -->|"Top-K 匹配"| R(["检索上下文与来源"])
    R -->|"Prompt 与上下文"| L(["LLM: qwen-turbo-latest 或 gemini-2.5-flash-lite"])
    L -->|"答案与来源"| O(["生成答案与来源"])
  end

  style A fill:#fff5e6,stroke:#f5a623,rx:10,ry:10
  style B fill:#fff,stroke:#ccc,rx:10,ry:10
  style C fill:#e6f7ff,stroke:#1890ff,rx:10,ry:10
  style D fill:#f0e6ff,stroke:#722ed1,rx:10,ry:10
  style E fill:#fff,stroke:#ccc,rx:10,ry:10
  style F fill:#e8ffe6,stroke:#52c41a,rx:10,ry:10
  style Q fill:#fff,stroke:#ccc,rx:10,ry:10
  style QV fill:#fff,stroke:#ccc,rx:10,ry:10
  style R fill:#fff,stroke:#ccc,rx:10,ry:10
  style L fill:#fff0f6,stroke:#eb2f96,rx:10,ry:10
  style O fill:#f6ffed,stroke:#389e0d,rx:10,ry:10

2.2 核心实体

erDiagram
  MARKDOWN_FILE ||--o{ TEXT_CHUNK : "包含"
  TEXT_CHUNK ||--|| VECTOR_EMBEDDING : "嵌入为"
  TEXT_CHUNK ||--|| METADATA : "由...描述"
  QUERY ||--o{ QUERY_RESULT : "产生"
  VECTOR_EMBEDDING ||--o{ QUERY_RESULT : "匹配"

  MARKDOWN_FILE {
    string path
    string title
    string language
    string frontmatter
  }
  TEXT_CHUNK {
    string id
    string text
    int index
    string sourcePath
  }
  METADATA {
    string title
    string url
    string language
    string source
  }
  VECTOR_EMBEDDING {
    string id
    float[] values
    int dimension
  }
  QUERY {
    string id
    string text
    string language
  }
  QUERY_RESULT {
    string vectorId
    float score
  }

2.3 实体说明

  • Markdown 文件:原始 Hugo 内容(frontmatter + 正文)
  • 文本分块:按标题与句子分割的片段
  • 向量嵌入:数值表示(依赖模型维度)
  • 元数据:附加于每个分块,用于过滤与归属
  • 查询结果:相似度匹配列表

3. 详细数据格式

3.1 TypeScript 接口

向量元数据结构

export type MatchMeta = {
  text?: string;           // 分块实际文本内容
  source?: string;         // 相对 content 目录的文件路径
  title?: string;          // frontmatter 中的文档标题
  url?: string;            // 生成的网站 URL
  language?: string;       // 文档语言('zh' | 'en')
};

环境配置

export interface Env {
  VECTORIZE: VectorizeIndex;
  PROVIDER: 'gemini' | 'qwen';
  GOOGLE_API_KEY?: string;
  QWEN_API_KEY?: string;
  QWEN_BASE?: string;
  QWEN_EMBED_MODEL?: string;
  LLM_MODEL?: string;
  ADMIN_TOKEN: string;
  EMBED_DIM: string;
}

向量索引操作

export interface VectorizeIndex {
  upsert(items: {
    id: string;
    values: number[];
    metadata?: Record<string, any>
  }[]): Promise<void>;

  query(vector: number[], opts: {
    topK: number;
    returnValues?: boolean;
    includeMetadata?: boolean;
    returnMetadata?: string;
    filter?: { metadata: Record<string, any> };
  }): Promise<{
    matches: { id: string; score: number; metadata?: MatchMeta }[];
  }>;
}

3.2 JSON 数据示例

Upsert 请求体

{
  "items": [
    {
      "id": "a1b2c3d4e5f6-0",
      "vector": [0.123, -0.456, 0.789, ...],
      "text": "Kubernetes 是一个开源的容器编排平台...",
      "source": "zh/blog/kubernetes-intro/index.md",
      "title": "Kubernetes 入门指南",
      "url": "https://jimmysong.io/blog/kubernetes-intro/",
      "language": "zh"
    }
  ]
}

聊天请求/响应

// 请求
{
  "message": "什么是 Kubernetes?",
  "history": [
    {"type": "user", "content": "之前的问题"},
    {"type": "bot", "content": "之前的回答"}
  ],
  "language": "zh"
}

// 响应
{
  "answer": "Kubernetes 是一个开源的容器编排平台...",
  "sources": [
    {
      "id": "a1b2c3d4e5f6-0",
      "url": "https://jimmysong.io/blog/kubernetes-intro/",
      "title": "Kubernetes 入门指南",
      "source": "zh/blog/kubernetes-intro/index.md"
    }
  ]
}

4. 代码流程:端到端管道

4.1 摄取管道(scripts/fast-ingest.ts

  1. 文件发现globby() 扫描 content 目录下 .md 文件
  2. 并行处理:同时处理 MAX_CONCURRENT_FILES 个文件
  3. 内容提取matter.js 解析 frontmatter,markdownToPlain() 转为纯文本
  4. 中文分块chunkText() 按标题与句子边界分割
  5. 批量嵌入getBatchEmbeddings() 高效批量处理分块
  6. 元数据生成toUrlFromPath() 生成 URL,generateShortId() 生成唯一 ID
  7. 向量上传:每批 300 条 upsert 到 Cloudflare Vectorize

4.2 嵌入生成(src/providers/embeddings.ts

// 通义千问嵌入(批量处理)
{
  model: "text-embedding-v4",
  input: ["text1", "text2", ...] // 每次最多 10 条
}

// Gemini 嵌入(单条处理)
{
  model: "models/text-embedding-004",
  content: { parts: [{ text: "单条文本" }] },
  outputDimensionality: 1024
}

4.3 向量存储与上传(src/worker.ts

  • 鉴权:管理操作需 Bearer ${ADMIN_TOKEN}
  • 数据校验:向量维度校验(EMBED_DIM
  • 批量操作:每次最多 300 条向量
  • 元数据保存:完整元数据与向量一同存储

4.4 查询处理(src/rag/retriever.ts

  1. 查询嵌入:用户问题 → 嵌入向量
  2. 直接检索:全量向量查询,无语言过滤
  3. 元数据处理:提取文本上下文和来源信息
  4. URL 转换:根据语言偏好转换 URL(如需)
  5. 来源去重:按 URL 去除重复来源

4.5 答案生成(src/providers/llm.ts

// 通义千问聊天生成
{
  model: "qwen-turbo-latest",
  messages: [
    { role: "system", content: "请用中文回答,并在末尾列出来源路径。" },
    { role: "user", content: "构建的提示词包含上下文和问题" }
  ]
}

// Gemini 内容生成
{
  contents: [
    { parts: [{ text: "完整的提示词" }] }
  ]
}

5. 模型角色与能力

5.1 text-embedding-v4(通义千问嵌入模型)

  • 主要功能:文本转 1024 维向量
  • 批量处理:每次最多 10 条(高效)
  • 语言支持:优化中英文
  • 应用场景
  • 摄取时文档分块
  • 检索时查询向量化
  • API 地址https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings

5.2 qwen-turbo-latest(通义千问聊天模型)

  • 主要功能:根据检索文档生成上下文答案
  • 输入处理:系统提示 + 用户问题 + 检索上下文
  • 输出生成:结构化中文回复,附来源
  • 能力
  • 多轮对话
  • 上下文感知
  • 来源归属
  • 语言专属回复
  • API 地址https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions

5.3 备选:Gemini 模型

  • 嵌入text-embedding-004(768/1024 维)
  • 生成gemini-2.5-flash-lite
  • 限制:嵌入不支持批量
  • 应用:Qwen 不可用地区的备选方案

6. 端到端示例会话

6.1 完整摄取示例

# 环境变量设置
PROVIDER=qwen
QWEN_API_KEY=sk-xxx
ADMIN_TOKEN=your-admin-token
WORKER_URL=https://your-worker.workers.dev
CONTENT_DIR=../website/content
EMBED_DIM=1024

# 摄取流程
npm run ingest

处理流程

  1. 发现:../website/content/zh/blog/kubernetes/index.md
  2. 提取:title: "Kubernetes 容器编排",内容:Kubernetes是...
  3. 分块:约 800 字分 3 块
  4. 嵌入:批量请求 → 3 个 1024 维向量
  5. 上传:{"id": "a1b2c3d4e5f6-0", "vector": [...], "metadata": {...}}

6.2 完整查询示例

// 用户查询
const query = "Kubernetes 是什么?";

// 1. 查询嵌入
const queryVector = await embedder.embed([query]); // [0.123, -0.456, ...]

// 2. 向量检索
const results = await VECTORIZE.query(queryVector, {
  topK: 8,
  filter: { metadata: { language: 'zh' } }
});

// 3. 上下文组装
const contexts = results.matches
  .map(m => m.metadata.text)
  .join('\n---\n');

// 4. Prompt 构建
const prompt = `
基于以下上下文回答用户问题:
${contexts}

用户问题:${query}
请用中文回答,并在末尾列出参考来源。
`;

// 5. LLM 生成
const answer = await llmGenerate(env, prompt);

// 6. 响应组装
return {
  answer: "Kubernetes 是一个开源的容器编排平台...",
  sources: [
    {
      url: "https://jimmysong.io/blog/kubernetes-intro/",
      title: "Kubernetes 入门指南"
    }
  ]
};

6.3 小部件集成示例

<!-- 网站集成 -->
<script
  src="/path/to/widget.js"
  data-endpoint="https://your-worker.workers.dev"
  defer
></script>
<div id="ai-chatbot"></div>

用户交互流程

  1. 用户打开聊天窗口
  2. 输入:"什么是微服务架构?"
  3. 小部件 POST 到 /chat 接口
  4. RAG 管道处理查询
  5. 返回结构化答案与来源链接
  6. 小部件展示答案并支持复制

6.4 性能特性

  • 摄取速度:约 1000 文档/分钟(Qwen 批量处理)
  • 查询延迟:端到端约 3-5 秒(简化后速度提升)
  • 向量存储:每 1 万文档约 50MB
  • 并发用户:Cloudflare Workers 边缘网络可扩展
  • 语言支持:中英文自动检测与切换(无过滤延迟)

可用文档

核心功能

  • 目录递归处理 - 批量目录处理功能详解
  • 🎯 递归文件发现与处理
  • 🛡️ 智能草稿过滤机制
  • 📊 进度跟踪与性能监控
  • 🔧 最佳实践与故障排查

技术深度

高级主题

详细文档下一步

  1. 搭建与部署指南 - 步骤化安装说明
  2. API 参考 - 完整接口文档
  3. 配置指南 - 环境变量与自定义
  4. 故障排查 - 常见问题与解决方案
  5. 性能优化 - 大规模部署调优
  6. 集成示例 - 更多前端集成模式