RAG 从入门到放弃?丐版 demo 实战笔记(go+python)

背景

我当前有一个业务系统,希望能添加一个机器人助手。直接使用大模型,由于缺少相关的业务数据,效果并不理想,了解一下 RAG

什么是 RAG

RAG(Retrieval Augmented Generation),搜索引擎 + 大模型

简单来说就是从一个数据源中先捞出一部分数据,有个前置的筛选操作(通常是向量数据库),然后将搜索出的数据组成 prompt 喂给大模型,最终获取大模型的返回值,进行过滤输出。

Top-K 结果
用户输入问题
查询向量化
Embedding Model
向量数据库
近似搜索 ANN
检索片段
+ 原始文本
构建提示词
Prompt Engineering
系统指令 + 上下文 + 问题
大模型生成答案
LLM Generation
返回带引用的回答
Sources / 页码

什么时候要用到 RAG

其实大多数的业务系统可以不上 RAG,通常情况下的业务系统都是通过数据库记录数据,很少有需要做数据推理、解释、总结的相关功能,如果真遇到了需要语义匹配(例如:任务表中有任务描述)等刚需场景再考虑上。

  • 数据规模大:需要参考的知识库太大,超过了模型上下文限制。
  • 时效性与准确性:数据经常更新,每次更新都要重新训练模型,成本就太高了。
  • 多租户/版本数据隔离:非公开数据(例:常见的SaaS系统都有用户角色控制权限,数据仅某些角色可见)。
  • 长尾:出现频率低、种类多的一些罕见任务或小众需求。

题外话:发现了一个开源库 vanna 可以直接和数据库进行对话。

这个我也测试了一下,其原理简单说就是

  1. 训练:数据库结构(DDL)、字段说明、示例 SQL 等扔进向量库,建成私有知识库。
  2. 提问:用自然语言问问题时,系统先检索最相关的上下文,再喂给 LLM 生成可直接执行的 SQL,本地运行并返回结果/图表。整个过程数据不出本地,且每次成功查询会自动回注向量库,持续自我优化。

CODE SHOW

使用 AI 编程简单做了一个小 demo,github源码

技术架构

客户端请求
Go API服务 :8080
本地嵌入服务 :5000
本地LLM服务 :5001
MySQL数据库 :3306
Qdrant向量数据库 :6333
BGE-M3嵌入模型
Ollama + Llama3/DeepSeek
用户表
APK表
权限表
向量存储
权限过滤

核心特性

  • 完全本地化:使用本地嵌入模型和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 + GinAPI服务和业务逻辑
嵌入模型BGE-M3文本向量化
LLM服务Ollama + Llama3/DeepSeek文本生成
向量数据库Qdrant向量存储和检索
关系数据库MySQL结构化数据存储

实际做 RAG 开发中的一些感悟

其实大多数业务系统是不需要使用 RAG 的,先搞清楚自己到底要不要上 RAG

上述 demo 极为简单,是丐版,离真正的生产使用还差了好远。如果真的考虑做一个 RAG 系统,可以考虑考虑以下问题(实际生产中的问题更多):

  1. RAG 有一步是数据向量化,是不是可以不用向量化,我直接通过 elastic search 之类的服务做存储,然后搜出来数据,自己组装 prompt 丢给大模型。向量化有什么作用?
  2. 什么是 embedding
  3. 向量存储方案选型?
  4. 模型怎么选,选哪个?
  5. 文档怎么切?
  6. 如何同当前系统进行结合?
  7. 输出结果不理想怎么办,如何调优?
  8. 如何去评估 RAG 的效果好不好?
  9. 拒答阈值怎么定?
  10. 生产级加固,成本和延迟,可观测性?

最难的点还是在于如何精准的搜索到最相关的上下文

总结

实际生产中,首先得再问一下,是否真的有必要上 RAG

大模型的 RAG 入门并不难,难的是各种细节的调整(数据处理等)。

撸了一个丐版的 RAGdemo,向量化 → 近似召回 → Prompt 拼装 → 大模型生成。

最后提一嘴,最后调用大模型的参数量越大越好,上下文长度越长越好。

参考

  • vanna,和你的数据库聊天
  • LLM RAG值得做吗?
  • 👀10分钟搞懂RAG架构:离线索引+在线检索的闭环秘密
  • AI方面的常见术语&&描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/922429.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/922429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《IDEA 突然“三无”?三秒找回消失的绿色启动键、主菜单和项目树!》

目录 一、左上角绿色启动键凭空消失 1.1 解决办法 二、顶部 File / Edit / View... 整条主菜单栏 罢工 2.1 解决办法 三、左侧 Project 工具窗口 集体失联,只剩 External Libraries 孤零零 3.1 解决办法 昨天下午撸代码,不知道按到了哪儿&#xff…

软件工程实践二:Spring Boot 知识回顾

文章目录一、创建项目(Spring Boot 向导)二、项目最小代码示例三、运行与验证四、标准目录结构与说明五、Maven 依赖最小示例(仅供参考)六、常用配置(application.yml 示例)七、返回 JSON 与统一异常八、Va…

【系列文章】Linux中的并发与竞争[04]-信号量

【系列文章】Linux中的并发与竞争[04]-信号量 该文章为系列文章:Linux中的并发与竞争中的第4篇 该系列的导航页连接: 【系列文章】Linux中的并发与竞争-导航页 文章目录【系列文章】Linux中的并发与竞争[04]-信号量一、信号量二、实验程序的编写2.1驱动…

Elasticsearch启动失败?5步修复权限问题

文章目录🚨 为什么会出现这个问题?✅ 解决方案:修复数据目录权限并确保配置生效步骤 1:确认数据目录存在且权限正确步骤 2:确认 elasticsearch.yml 中的配置步骤 3:**删除或清空 /usr/share/elasticsearch/…

Docker push 命令:镜像发布与管理的艺术

Docker push 命令:镜像发布与管理的艺术1. 命令概述2. 命令语法3. 核心参数解析4. 推送架构图解5. 完整工作流程6. 实战场景示例6.1 基础推送操作6.2 企业级推送流程6.3 多架构镜像推送7. 镜像命名规范详解8. 安全最佳实践8.1 内容信任机制8.2 最小权限原则9. 性能优…

智能合约测试框架全解析

概述 智能合约测试库是区块链开发中至关重要的工具,用于确保智能合约的安全性、正确性和可靠性。以下是主流的智能合约测试库及其详细解析。 一、主流测试框架对比 测试框架开发语言主要特点适用场景Hardhat WaffleJavaScript/TypeScript强大的调试功能&#xf…

【大模型算法工程师面试题】大模型领域新兴的主流库有哪些?

文章目录 大模型领域新兴主流库全解析:国产化适配+优劣对比+选型指南(附推荐指数) 引言 一、总览:大模型工具链选型框架(含推荐指数) 二、分模块详解:优劣对比+推荐指数+选型建议 2.1:训练框架(解决“千亿模型怎么训”) 2.2:推理优化(解决“模型跑起来慢”) 2.3:…

端口打开与服务可用

端口打开与服务可用“端口已打开但服务不可用” 并非矛盾,而是网络访问中常见的分层问题。要理解这一点,需要先明确 “端口打开” 和 “服务可用” 的本质区别:1. 什么是 “端口打开”?“端口打开” 通常指 操作系统的网络层监听该…

ByteDance_FrontEnd

约面了,放轻松,好好面 盲点 基础知识 Function 和 Object 都是函数,而函数也是对象。 Object.prototype 是几乎所有对象的原型链终点(其 proto 是 null)。 Function.prototype 是所有函数的原型(包括 Obje…

go语言,彩色验证码生成,加减法验证,

代码结构相关代码 captcha/internal/captcha/generator.go package captchaimport (_ "embed" // 👈 启用 embed"image""image/color""image/draw""image/png""io""math/rand""golang.…

PuTTY软件访问ZYNQ板卡的Linux系统

PuTTY 是一款非常经典、轻量级、免费的 SSH、Telnet 和串行端口连接客户端,主要运行于 Windows 平台。它是在开源许可下开发的,因其小巧、简单、可靠而成为系统管理员、网络工程师和开发人员的必备工具。网上有非常多的下载资源。 我们使用PuTTY软件对ZY…

做一个RBAC权限

在分布式应用场景下,我们可以利用网关对请求进行集中处理,实现了低耦合,高内聚的特性。 登陆权限验证和鉴权的功能都可以在网关层面进行处理: 用户登录后签署的jwt保存在header中,用户信息则保存在redis中网关应该对不…

【算法】day1 双指针

1、移动零(同向分3区域) 283. 移动零 - 力扣(LeetCode) 题目: 思路:注意原地操作。快排也是这个方法:左边小于等于 tmp,右边大于 tmp,最后 tmp 放到 dest。 代码&#…

Linux 日志分析:用 ELK 搭建个人运维监控平台

Linux 日志分析:用 ELK 搭建个人运维监控平台 🌟 Hello,我是摘星! 🌈 在彩虹般绚烂的技术栈中,我是那个永不停歇的色彩收集者。 🦋 每一个优化都是我培育的花朵,每一个特性都是我放飞…

Linux网络:socket编程UDP

文章目录前言一,socket二,服务端socket3-1 创建socket3-2 绑定地址和端口3-3 接收数据3-4 回复数据3-5关闭socket3-6 完整代码三,客户端socket3-1 为什么客户端通常不需要手动定义 IP 和端口前言 学习 socket 编程的意义在于:它让…

【从零到公网】本地电脑部署服务并实现公网访问(IPv4/IPv6/DDNS 全攻略)

从零到公网:本地电脑部署服务并实现公网访问(IPv4/IPv6/DDNS 全攻略) 适用场景:本地 API 服务、大模型推理服务、NAS、远程桌面等需要公网访问的场景 关键词:公网 IP、端口映射、内网穿透、IPv6、Cloudflare DDNS 一、…

模块二 落地微服务

11 | 服务发布和引用的实践 服务发布和引用常见的三种方式:Restful API、XML配置以及IDL文件。今天我将以XML配置方式为例,给你讲解服务发布和引用的具体实践以及可能会遇到的问题。 XML配置方式的服务发布和引用流程 1. 服务提供者定义接口 服务提供者发…

C++程序员速通C#:从Hello World到数据类型

C程序员光速入门C#(一):总览、数据类型、运算符 一.Hello world! 随着.NET的深入人心,作为一个程序员,当然不能在新技术面前停而止步,面对着c在.net中的失败,虽然有一丝遗憾,但是我们应该认识到…

Linux相关概念和易错知识点(44)(IP地址、子网和公网、NAPT、代理)

目录1.IP地址(1)局域网和公网①局域网a.网关地址b.局域网通信②运营商子网③公网(2)NAPT①NAPT过程②理解NAPT③理解源IP和目的IPa.目的IPb.源IP③最长前缀匹配④NAT技术缺陷2.代理服务(1)正向代理&#xf…

工业智能终端赋能自动化生产线建设数字化管理

在当今数字化浪潮的推动下,自动化生产线正逐渐成为各行各业提升效率和降低成本的重要选择。随着智能制造的深入发展,工业智能终端的引入不仅为生产线带来了技术革新,也赋予了数字化管理新的动力。一、工业智能终端:一体化设计&…