背景
我當前有一個業務系統,希望能添加一個機器人助手。直接使用大模型,由于缺少相關的業務數據,效果并不理想,了解一下 RAG
。
什么是 RAG
RAG(Retrieval Augmented Generation),搜索引擎 + 大模型。
簡單來說就是從一個數據源中先撈出一部分數據,有個前置的篩選操作(通常是向量數據庫),然后將搜索出的數據組成 prompt
喂給大模型,最終獲取大模型的返回值,進行過濾輸出。
什么時候要用到 RAG
其實大多數的業務系統可以不上 RAG
,通常情況下的業務系統都是通過數據庫記錄數據,很少有需要做數據推理、解釋、總結的相關功能,如果真遇到了需要語義匹配(例如:任務表中有任務描述)等剛需場景再考慮上。
- 數據規模大:需要參考的知識庫太大,超過了模型上下文限制。
- 時效性與準確性:數據經常更新,每次更新都要重新訓練模型,成本就太高了。
- 多租戶/版本數據隔離:非公開數據(例:常見的SaaS系統都有用戶角色控制權限,數據僅某些角色可見)。
- 長尾:出現頻率低、種類多的一些罕見任務或小眾需求。
題外話:發現了一個開源庫 vanna 可以直接和數據庫進行對話。
這個我也測試了一下,其原理簡單說就是
- 訓練:數據庫結構(DDL)、字段說明、示例 SQL 等扔進向量庫,建成私有知識庫。
- 提問:用自然語言問問題時,系統先檢索最相關的上下文,再喂給 LLM 生成可直接執行的 SQL,本地運行并返回結果/圖表。整個過程數據不出本地,且每次成功查詢會自動回注向量庫,持續自我優化。
CODE SHOW
使用 AI
編程簡單做了一個小 demo
,github源碼
技術架構
核心特性
- 完全本地化:使用本地嵌入模型和LLM,無需依賴外部API
- 權限控制:基于用戶角色和單位的多級權限管理
- 向量檢索:使用Qdrant向量數據庫進行語義搜索
- 智能問答:結合檢索到的上下文進行個性化回答
核心實現
RAG服務核心邏輯
// 處理用戶查詢的核心流程
func (r *RAGService) Query(userID int, question string) (string, error) {// 1. 獲取用戶信息和權限user, err := r.authSvc.GetUserByID(userID)userAccess := r.getUserAccessContext(user)// 2. 個性化查詢重寫personalizedQuery := r.personalizeQuery(question, user)// 3. 向量檢索(帶權限過濾)apkIDs, contexts, err := r.retrieveAPKs(personalizedQuery, userAccess)// 4. 構建提示詞并生成答案prompt := r.buildPrompt(user, question, contexts)return r.generateAnswer(prompt)
}// 個性化查詢處理
func (r *RAGService) personalizeQuery(query string, user *User) string {if strings.Contains(query, "我") || strings.Contains(query, "我的") {return fmt.Sprintf("%s 上傳者ID:%d", query, user.ID)}if strings.Contains(query, "我們單位") {return fmt.Sprintf("%s 單位ID:%d", query, user.UnitID)}return query
}
向量檢索與權限過濾
// 帶權限過濾的向量檢索
func (r *RAGService) retrieveAPKs(query string, userAccess []string) ([]int, []string, error) {vector, err := r.embeddingSvc.GetEmbedding(query)// 構建權限過濾器filter := &qdrant.Filter{Must: []*qdrant.Condition{{ConditionOneOf: &qdrant.Condition_Field{Field: &qdrant.FieldCondition{Key: "access_scope",Match: &qdrant.Match{MatchValue: &qdrant.Match_Keywords{Keywords: &qdrant.RepeatedStrings{Strings: userAccess},},},},},}},}// 執行向量搜索resp, err := pointsClient.Search(ctx, &qdrant.SearchPoints{CollectionName: "apk_vectors",Vector: vector,Filter: filter,Limit: 3,})// 處理搜索結果...
}
本地服務集成
// 嵌入服務調用
func (e *EmbeddingService) GetEmbedding(text string) ([]float32, error) {requestBody, _ := json.Marshal(map[string][]string{"texts": {text}})resp, _ := http.Post(e.baseURL+"/embed", "application/json", bytes.NewBuffer(requestBody))var result struct { Embeddings [][]float32 `json:"embeddings"` }json.NewDecoder(resp.Body).Decode(&result)return result.Embeddings[0], nil
}// LLM服務調用
func (r *RAGService) generateAnswer(prompt string) (string, error) {requestBody, _ := json.Marshal(map[string]interface{}{"prompt": prompt,"model": "deepseek-coder:6.7b",})resp, _ := http.Post("http://localhost:5001/generate", "application/json", bytes.NewBuffer(requestBody))var result struct { Response string `json:"response"` }json.NewDecoder(resp.Body).Decode(&result)return result.Response, nil
}
API接口示例
# 添加APK
curl -X POST http://localhost:8080/apks \-H "Content-Type: application/json" \-d '{"name": "支付寶", "uploader_id": 1, "visible_units": [101, 102]}'# 智能問答
curl -X POST http://localhost:8080/query \-H "Content-Type: application/json" \-d '{"user_id": 1, "question": "我在哪天上傳了支付寶?"}'
快速啟動
# 1. 啟動依賴服務
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=apk_rag -d mysql:latest# 2. 啟動本地模型服務
ollama serve && ollama pull llama3
python local_embedding.py &
python local_llm.py &# 3. 啟動Go服務
go run .
技術棧
組件 | 技術選型 | 作用 |
---|---|---|
后端服務 | Go + Gin | API服務和業務邏輯 |
嵌入模型 | BGE-M3 | 文本向量化 |
LLM服務 | Ollama + Llama3/DeepSeek | 文本生成 |
向量數據庫 | Qdrant | 向量存儲和檢索 |
關系數據庫 | MySQL | 結構化數據存儲 |
實際做 RAG 開發中的一些感悟
其實大多數業務系統是不需要使用 RAG
的,先搞清楚自己到底要不要上 RAG
。
上述 demo
極為簡單,是丐版,離真正的生產使用還差了好遠。如果真的考慮做一個 RAG
系統,可以考慮考慮以下問題(實際生產中的問題更多):
RAG
有一步是數據向量化,是不是可以不用向量化,我直接通過elastic search
之類的服務做存儲,然后搜出來數據,自己組裝prompt
丟給大模型。向量化有什么作用?- 什么是
embedding
? - 向量存儲方案選型?
- 模型怎么選,選哪個?
- 文檔怎么切?
- 如何同當前系統進行結合?
- 輸出結果不理想怎么辦,如何調優?
- 如何去評估
RAG
的效果好不好? - 拒答閾值怎么定?
- 生產級加固,成本和延遲,可觀測性?
最難的點還是在于如何精準的搜索到最相關的上下文。
總結
實際生產中,首先得再問一下,是否真的有必要上 RAG
。
大模型的 RAG
入門并不難,難的是各種細節的調整(數據處理等)。
擼了一個丐版的 RAG
小 demo
,向量化 → 近似召回 → Prompt 拼裝 → 大模型生成。
最后提一嘴,最后調用大模型的參數量越大越好,上下文長度越長越好。
參考
- vanna,和你的數據庫聊天
- LLM RAG值得做嗎?
- 👀10分鐘搞懂RAG架構:離線索引+在線檢索的閉環秘密
- AI方面的常見術語&&描述