02. 知识篇:构建高并发 RAG 系统
RAG (检索增强生成) 是目前 AI 落地最成熟的模式。对于 Go 开发者,我们的战场不在模型训练,而在高性能数据管道 (Data Pipeline) 和 检索服务 (Retrieval Service)。
1. 为什么用 Go 做 RAG 数据处理?
一个生产级 RAG 系统往往需要处理数百万份文档。
- Python: 单线程处理慢,多进程消耗大。
- Go: 启动 1000 个 Goroutine 并发读取、切分、Embedding,速度是 Python 的 10-50 倍。
2. 高并发 ETL 管道设计
我们使用 Producer-Consumer 模式构建数据入库管道。
go
// 伪代码架构
func ETLPipeline() {
filesChan := make(chan string, 1000)
docsChan := make(chan Document, 1000)
vectorsChan := make(chan Vector, 1000)
// Stage 1: 扫描文件 (Producer)
go ScanFiles("/data", filesChan)
// Stage 2: 并发加载与切分 (Workers)
for i := 0; i < 50; i++ {
go func() {
for file := range filesChan {
doc := LoadAndSplit(file)
docsChan <- doc
}
}()
}
// Stage 3: 并发 Embedding (Workers)
// 注意:要控制并发度,避免触发 LLM API Rate Limit
for i := 0; i < 20; i++ {
go func() {
for doc := range docsChan {
vec := OpenAIEmbedding(doc) // 耗时 IO
vectorsChan <- vec
}
}()
}
// Stage 4: 批量入库 (Consumer)
BatchInsertToMilvus(vectorsChan)
}3. 向量数据库:Milvus Go SDK 实战
Milvus 是 Go 编写的云原生向量库,与 Go 应用结合最紧密。
3.1 连接与 Schema 定义
go
package main
import (
"context"
"log"
"github.com/milvus-io/milvus-sdk-go/v2/client"
"github.com/milvus-io/milvus-sdk-go/v2/entity"
)
func main() {
ctx := context.Background()
// 连接 Milvus
c, err := client.NewClient(ctx, client.Config{Address: "localhost:19530"})
if err != nil {
log.Fatal(err)
}
defer c.Close()
// 定义 Schema
schema := &entity.Schema{
CollectionName: "enterprise_knowledge",
Fields: []*entity.Field{
{
Name: "id",
DataType: entity.FieldTypeInt64,
PrimaryKey: true,
AutoID: true,
},
{
Name: "vector",
DataType: entity.FieldTypeFloatVector,
TypeParams: map[string]string{
"dim": "1536", // OpenAI Embedding 维度
},
},
{
Name: "text",
DataType: entity.FieldTypeVarChar,
TypeParams: map[string]string{
"max_length": "65535",
},
},
},
}
// ... 创建 Collection 代码 ...
}4. 检索优化策略
仅仅靠向量检索(Vector Search)往往不够准确。
4.1 混合检索 (Hybrid Search)
公式: Score = α * VectorScore + (1-α) * BM25Score
- 向量检索: 擅长语义匹配("苹果" <-> "水果")。
- 关键词检索 (BM25): 擅长精确匹配("iPhone 15 Pro Max")。
- Go 实现: Milvus 和 Weaviate 都支持 Hybrid Search。
4.2 重排序 (Rerank)
检索出的 Top 100 文档,再经过一个精排模型(如 BGE-Reranker)打分,选出 Top 5 给 LLM。 这通常是一个 HTTP 调用:
go
func Rerank(query string, docs []string) []string {
// 调用 Rerank 模型 API
// 返回相关性最高的文档
}5. 进阶作业
- 实现一个带有
Semaphore(信号量) 的 Embedding Worker 池,确保每秒请求数不超过 OpenAI 限制 (RPM)。 - 对比纯向量检索和混合检索在特定数据集上的准确率。
