accounts/docs/rag-system-design.md

5.9 KiB
Raw Blame History

基于 Go 的 RAG 系统设计

本文档描述一个使用 Go 实现的 Retrieval Augmented Generation (RAG) 系统方案满足多仓库文档同步、Markdown 解析与分块、向量化存储以及问答检索的需求。

1. 数据源同步

  • 多仓库配置:支持在配置文件中声明多个 GitHub 仓库及其关注路径,例如:
    • repoA/docs/
    • repoB/guides/
    • repoC/tutorials/
  • 同步方式:使用 git clone / git pull 将远程仓库同步到本地,定时任务或 Webhook 触发。
  • 增量更新:检测新增或修改的 Markdown 文档,触发后续嵌入流程。

2. Markdown 处理与分块

  • 使用 goldmarkblackfriday 将 Markdown 渲染为纯文本。
  • 对文档按照 500~1000 tokens 分块,保存每块的顺序和位置信息。
  • 每个分块生成唯一 chunk_id 以便回溯源文档位置。

3. 向量化

  • 默认嵌入模型:
  • 统一的 Embed(text string) ([]float32, error) 接口屏蔽具体实现,可在配置中切换模型。

4. 数据库设计

使用 PostgreSQL + pgvector。初始化步骤:

  1. 在目标数据库中启用扩展:

    CREATE EXTENSION IF NOT EXISTS vector;
    
  2. 按以下 SQL 创建存储向量的表及索引:

    CREATE TABLE documents (
        id BIGSERIAL PRIMARY KEY,
        repo TEXT NOT NULL,         -- 来源仓库
        path TEXT NOT NULL,         -- 文件路径
        chunk_id INT NOT NULL,
        content TEXT NOT NULL,
        embedding VECTOR(1024),     -- 向量
        metadata JSONB              -- 额外信息:标签/更新时间等
    );
    
    -- 向量索引
    CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
    
    -- 元数据索引
    CREATE INDEX idx_documents_metadata ON documents USING gin (metadata);
    

连接字符串示例:postgres://user:password@127.0.0.1:5432

5. 检索与问答流程

  1. 用户提出问题,服务端调用 Embed() 对问题生成向量。
  2. documents 表中通过 cosine 相似度检索 Top K 的分块。
  3. 将检索结果拼装为 Prompt调用 GPT/Claude 等大模型生成回答。
  4. 返回答案并附带来源文档信息以便追溯。

5.1 前端 AskAIDialog 调用流程

  1. 用户在 AskAIDialog 中输入问题,handleAsk 会先做去空格、去尾标点等规整并使用防抖避免短时间内重复发送。
  2. 若 10 秒内命中过去问题的缓存,则直接返回缓存答案;否则把规整后的问题与最近对话历史组合为 historyPOST 到 /api/rag/query,请求设置超时并以流式方式返回结果。
  3. 流式结果会实时更新聊天记录,若返回 answerchunks,则通过 SourceHint 展示检索到的来源。
  4. answer 为空或没有检索结果时,会在控制台记录回退原因,并调用 /api/askai 获取普通 AI 回答,同样带有超时限制。
  5. 最终的回答写入缓存并通过 ChatBubble 组件显示给用户,形成完整的 RAG 聊天流程。

6. Go 代码模块划分

rag-server/internal/rag/
├── config/          # 仓库与模型配置
├── sync/            # GitHub 同步逻辑
├── ingest/          # Markdown 解析与分块
├── embed/           # 向量化接口实现
├── store/           # PostgreSQL + pgvector 操作封装
└── api/             # REST/gRPC 接口,提供问答与同步触发

各模块通过 go-pg/pgxgo-git 等库实现,协程与通道用于提升并行处理能力。

7. 未来扩展

  • 支持更多文件格式,如 PDF、HTML。
  • 嵌入向量批量写入以提升效率。
  • 引入缓存与摘要生成,进一步优化响应速度。

以上设计为后续实现提供结构化指导,可在项目中逐步落地。

8. 同步与查询测试

8.1 启动依赖服务

docker run -d --name pgvector \
  -e POSTGRES_PASSWORD=password \
  -p 5432:5432 \
  ankane/pgvector:latest

docker run -d --name redis -p 6379:6379 redis

8.2 配置 rag.yaml

redis:
  addr: "127.0.0.1:6379"
  password: ""
module: "moonshotai/Kimi-K2-Instruct"
vectordb:
  pgurl: "postgres://user:password@127.0.0.1:5432"
datasources:
  - name: Xstream
    repo: https://github.com/svc-design/Xstream
    path: docs
  - name: XControl
    repo: https://github.com/svc-design/XControl
    path: docs
  - name: documents
    repo: https://github.com/svc-design/documents

8.3 运行同步

# 同步并处理所有 Markdown 文件
./xcontrol-cli --config rag.yaml

该命令会克隆或更新数据源仓库,扫描 Markdown 文件,并逐个解析、分块、调用 BGE Embed 并通过 /api/rag/upsert 写入数据库。

8.4 手动测试 Upsert 接口

在同步流程之外,也可以通过 curl 手动向 /api/rag/upsert 写入一条记录:

默认情况下RAG 服务监听 127.0.0.1:8090,因此以下示例均以 http://localhost:8090 为基础地址。

curl -X POST http://localhost:8090/api/rag/upsert \
  -H "Content-Type: application/json" \
  -d '{"docs":[{"repo":"example","path":"doc.md","chunk_id":1,"content":"hello","embedding":[0.1,0.2],"metadata":{},"content_sha":"abc"}]}'

若向量数据库未就绪,接口会返回 error 字段提示连接问题。

8.5 查询接口

同步完成后,可通过 curl 测试 /api/rag/query

curl -X POST http://localhost:8090/api/rag/query \
  -H "Content-Type: application/json" \
  -d '{"question": "What is XControl?"}'

请求体必须包含 question 字段。若数据写入成功,将返回相关的 chunks 列表;若返回 {"chunks":null},请检查同步日志、数据库连接与配置文件是否正确。