100行代码实现自己的RAG知识库

news2024/9/23 7:28:49

背景

由于日常工作需要对接各种第三方合作方,对接过程中的文档繁多、沟通不及时、问题排查繁琐以及工作具有重复性等问题愈发明显。合作方遇到对接问题需要提工单经门户网站–>产品部门接口人–>开发人员问题排查/修复–>产品部门接口人–>合作方收到回复,这种模式联调、验收流程较长。

考虑到前期对接过程中积累的问题日志、对接规范、指导手册、接口文档,如何让开发、产品、运营以及合作方有效利用这些知识?首先就想到了大模型,它具有强大的自然语言理解和文档整理能力,但其缺少对接流程的垂类领域知识?于是想到了RAG(检索增强生成技术)给两者建立了桥梁!

1. RAG技术介绍

RAG (Retrieval-Augmented Generation) 是一种结合了检索和生成的混合式深度学习模型,常用于处理复杂的自然语言处理任务。RAG模型通过将外部知识库中的信息与生成模型结合在一起,可以提供更准确和上下文相关的答案。具体来说,RAG由两个部分组成:

  1. 检索模块:负责从预先建立的知识库中检索与输入问题最相关的文档或信息片段。这通常通过向量检索技术实现,向量检索能够支持语义匹配,而不仅仅是关键词匹配,从而提高了检索的准确性。

  2. 生成模块:接收检索到的内容并生成最终的自然语言响应。这个模块通常基于大型生成模型(如 GPT-4),能够理解和生成复杂的自然语言。

这种技术的优势在于它能够利用海量的外部数据进行知识补充,从而提升回答的质量和准确性。这在动态性强、知识库更新频繁的场景中尤为重要。

RAG原理

2. RAG搭建常见流程

在实际应用中,搭建一个基于 RAG 的知识库通常包括以下几个步骤:

  1. 文档加载,并按一定条件切割成片段;
  2. 将切割的文本片段灌入向量数据库;
  3. 封装检索接口;
  4. 构建调用流程:Query -> 检索 -> Prompt -> LLM -> 回复。

3. 编码实现

下面用极少的代码快速搭建一个RAG系统,包括服务端和web界面,仅用于demo展示,生成级的 RAG 系统要复杂的多的多。

项目结构

项目结构

核心代码

如果纯自己编码实现 RAG,小一千行代码是要的,这里只能借助成熟的大模型开发框架来简化开发过程,把重心放到流程上去,本例使用了 LangChain,关键代码给出注释,可自己咨询大模型进行理解和改进。

LangChain:一套在大模型能力上封装的工具框架(SDK),它为开发者提供了一系列工具和组件,以简化语言模型在复杂任务中的集成和应用,尤其是涉及到多步骤的流程和需要结合外部数据源的场景。

import uvicorn
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from dotenv import load_dotenv, find_dotenv
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.prompts import ChatPromptTemplate
from starlette.middleware.cors import CORSMiddleware

# 加载环境变量,读取本地 .env 文件,里面定义了 OPENAI_API_KEY
_ = load_dotenv(find_dotenv())

# llm
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 加载文档,可换成PDF、txt、doc等其他格式文档
loader = TextLoader('../docs/解答手册.md', encoding='utf-8')
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter.from_language(language="markdown", chunk_size=200, chunk_overlap=0)
texts = text_splitter.create_documents(
    [documents[0].page_content]
)

# 选择向量模型,并灌库
db = FAISS.from_documents(texts, OpenAIEmbeddings(model="text-embedding-ada-002"))
# 获取检索器,选择 top-2 相关的检索结果
retriever = db.as_retriever(search_kwargs={"k": 2})

# 创建带有 system 消息的模板
prompt_template = ChatPromptTemplate.from_messages([
    ("system", """你是一个对接问题排查机器人。
               你的任务是根据下述给定的已知信息回答用户问题。
               确保你的回复完全依据下述已知信息。不要编造答案。
               请用中文回答用户问题。
               
               已知信息:
               {context} """),
    ("user", "{question}")
])

# 自定义的提示词参数
chain_type_kwargs = {
    "prompt": prompt_template,
}

# 定义RetrievalQA链
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",  # 使用stuff模式将上下文拼接到提示词中
    chain_type_kwargs=chain_type_kwargs,
    retriever=retriever
)

# 构建 FastAPI 应用,提供服务
app = FastAPI()

# 可选,前端报CORS时
app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=['*'],
    allow_headers=['*'],
)


# 定义请求模型
class QuestionRequest(BaseModel):
    question: str


# 定义响应模型
class AnswerResponse(BaseModel):
    answer: str

    
# 提供查询接口 http://127.0.0.1:8000/ask
@app.post("/ask", response_model=AnswerResponse)
async def ask_question(request: QuestionRequest):
    try:
        # 获取用户问题
        user_question = request.question
        print(user_question)

        # 通过RAG链生成回答
        answer = qa_chain.run(user_question)

        # 返回答案
        answer = AnswerResponse(answer=answer)
        print(answer)
        return answer
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

运行环境

代码采用 python3.11 版本运行,并安装了如下依赖:

# pip install -r requirements.txt
fastapi==0.112.1
langchain==0.2.14
langchain_community==0.2.12
langchain_openai==0.1.22
langchain_text_splitters==0.2.2
pydantic==2.8.2
python-dotenv==1.0.1
Requests==2.32.3
starlette==0.38.2
uvicorn==0.30.6

QA准备

按照自己熟悉的文档组织方式组织QA,并按照业务需求选择是将Q向量化,还是将QA一起向量化,本例采用如下格式组织QA,并且QA一起向量化。

### xx接口不通怎么办
请首先确认接口地址以及鉴权参数,可找coderjia进行排查

效果展示

简陋的客户端界面:

用户界面

咨询知识库存在的知识:

效果展示

咨询知识库不存在的知识:

效果展示

4. 总结与优化点

以上只是搭建搭建基于RAG的知识库最基本的步骤,实际应用时,有几点优化建议:

  1. 知识库的动态更新:随着时间的推移,知识库中的信息可能会过时或无效,因此需要设计自动化的知识更新机制,以保证系统回答的准确性和时效性。

  2. 模型微调:在不同的应用场景中,可能需要对调用的模型进行选择,或者对提示词进行优化,来引导模型生成更符合预期的输出。

  3. 混合检索策略:可以结合向量检索与传统的关键词检索策略,在保证检索精度的同时,提高召回率。

  4. 系统可扩展性:确保系统能够随着数据量和请求量的增加而扩展,避免性能瓶颈。使用分布式检索和生成技术是实现这一目标的关键。

  5. 用户反馈循环:引入用户反馈机制,定期分析用户的查询和系统的响应,持续改进模型和知识库,提升整体系统的智能水平。
    更符合预期的输出。

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

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

相关文章

公链大变局:ETH老态龙钟,SOL势如破竹

今年年初,比特币现货ETF的通过引发了大量资金涌入加密市场,比特币价格一度突破前高,市场一片繁荣。然而,这一波行情却并未如预期般延续到以太坊。相反,在8月初,以太坊(ETH)价格近乎腰…

C语言基础⑨——指针

一、指针的引入 int —— 4位;float —— 4位;double —— 8位;short —— 2位;long —— 8位; 为函数修改实参提供支撑;为动态内存管理提供支持;为动态数据结构提供支持;为内存访问…

MT6761 快充同步

MT6761 是反激式电源的高性能60V同步整流器。MT6761兼容各种反激转换器类型。支持 DCM、CCM 和准谐振模式。MT6761集成了一个60V功率MOSFET&#xff0c;可以取代肖特基二极管&#xff0c;提高效率。V SW <V TH-ON 时&#xff0c;MT6761内部 MOSFET 导通。V SW >V TH-OFF …

【AI 绘画】模型转换与快速生图(基于diffusers)

AI 绘画- 模型转换与快速生图&#xff08;基于diffusers&#xff09; 1. 本章介绍 本次主要展示一下不同框架内文生图模型转换&#xff0c;以及快速生成图片的方法。 SDXL文生图 2. sdxl_lightning基本原理 模型基本原理介绍如下 利用蒸馏方法获取小参数模型。首先&#x…

三、前后端分离通用权限系统(3)

&#x1f33b;&#x1f33b;目录 一、角色管理1.1、测试 controller 层1.2、整合 Swagger21.2.1、Swagger 介绍1.2.2、集成 knife4j1.2.2.1 添加依赖1.2.2.2 添加 knife4j 配置类1.2.2.3 Controller 层添加注解1.2.2.4、测试 1.3、定义统一返回结果对象1.3.1、定义统一返回结果…

备战秋招60天算法挑战,Day21

题目链接&#xff1a; https://leetcode.cn/problems/number-of-1-bits/ 视频题解&#xff1a; https://www.bilibili.com/video/BV1ir421M7XU/ LeetCode 191.位1的个数 题目描述 编写一个函数&#xff0c;输入是一个无符号整数 &#xff08;以二进制串的形式&#xff09;&am…

C语言 ——— 学习并使用calloc和realloc函数

目录 calloc函数的功能 学习并使用calloc函数​编辑 realloc函数的功能 学习并使用realloc函数​编辑 calloc函数的功能 calloc函数的功能和malloc函数的功能类似&#xff0c;于malloc函数的区别只在于calloc函数会再返回地址之前把申请的空间的每个字节初始化为全0 C语言…

tweens运动详解

linear 线性匀速运动效果Sine.easeIn 正弦曲线的缓动(sin(t))/ 从0开始加速的缓动,也就是先慢后快Sine.easeOut 正弦曲线的缓动(sin(t))/ 减速到0的缓动,也就是先快后慢Sine.easeInOut 正弦曲线的缓动(sin(t))/ 前半段从0开始加速,后半段减速到0的缓动Quad.easeIn 二次…

c语言基础-------指针变量和变量指针

在 C 语言中,“变量指针”和“指针变量”这两个术语虽然经常交替使用,但它们的侧重点有所不同。 指针变量 “指针变量”是指其值为内存地址的变量。指针变量的类型定义了它所指向的数据类型,例如 int * 是一个指向整型数据的指针变量。 以下是一个指针变量的例子: int v…

数据埋点系列 16| 数据可视化高级技巧:从洞察到视觉故事

数据可视化是将复杂数据转化为直观、易懂的视觉表现的艺术和科学。本文将探讨一些高级的数据可视化技巧&#xff0c;帮助您创建更具吸引力和洞察力的数据展示。 目录 1. 高级图表类型1.1 桑基图&#xff08;Sankey Diagram&#xff09;1.2 树状图&#xff08;Treemap&#xf…

3、目标定位(视觉测距)

目标定位的目的&#xff1a;获取物品相对于视觉模块的三维坐标&#xff0c;并将其转换为物品相对于机械臂坐标原点的三维坐标。 要获取物品三维坐标&#xff0c;则首先要测量物品距离摄像头的距离&#xff0c;又因为摄像头安装在机械臂末端上方&#xff0c;所以获取物品相对于摄…

基于springboot的高校学生服务平台的设计与实现--附源码91686

目录 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1系统开发流程 2.2.2 用户登录流程 2.2.3 系统操作流程 2.2.4 添加信息流程 2.2.5 修改信息流程 2.2.6 删除信息流程 2.3 系统功能分析 …

代码随想录算法训练营第二十天| 235. 二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点

目录 一、LeetCode 235. 二叉搜索树的最近公共祖先思路&#xff1a;C代码 二、LeetCode 701.二叉搜索树中的插入操作思路C代码 三、LeetCode 450.删除二叉搜索树中的节点思路C代码 总结 一、LeetCode 235. 二叉搜索树的最近公共祖先 题目链接&#xff1a;LeetCode 235. 二叉搜…

C语言:for、while、do-while循环语句

目录 前言 一、while循环 1.1 while语句的执行流程 1.2 while循环的实践 1.3 while循环中的break和continue 1.3.1 break 1.3.2 continue 二、for循环 2.1 语法形式 2.2 for循环的执行流程 2.3 for循环的实践 2.4 for循环中的break和continue 2.4.1 break 2.4.2 …

Java数组03:数组边界、数组的使用

本节内容视频链接&#xff1a;https://www.bilibili.com/video/BV12J41137hu?p55&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV12J41137hu?p55&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.数组边界 数组下标的合法区间[ 0, Len…

综合监管云平台存在信息泄露漏洞_中科智远综合监管云平台

0x01阅读须知 本文章仅供参考&#xff0c;此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考。本文章仅用于信息安全防御技术分享&#xff0c;因用于其他用途而产生不良后果,作者不承担任何法律责任&#…

昇腾 - 快速理解AscendCL(Ascend Computing Language)基础概念的HelloWord

昇腾 - 快速理解AscendCL&#xff08;Ascend Computing Language&#xff09;基础概念的HelloWord flyfish AscendCL&#xff08;Ascend Computing Language&#xff09;是一套用于在昇腾平台上开发深度神经网络应用的C语言API库&#xff0c;提供运行资源管理、内存管理、模型…

鸿蒙(API 12 Beta3版)【录像流二次处理(C/C++)】媒体相机开发指导

通过ImageReceiver创建录像输出&#xff0c;获取录像流实时数据&#xff0c;以供后续进行图像二次处理&#xff0c;比如应用可以对其添加滤镜算法等。 开发步骤 导入NDK接口&#xff0c;接口中提供了相机相关的属性和方法&#xff0c;导入方法如下。 // 导入NDK接口头文件#in…

ArcGIS Pro基础:软件的常用设置:中文语言、自动保存、默认底图

上图所示&#xff0c;在【选项】&#xff08;Options&#xff09;里找到【语言】设置&#xff0c;将语言切换为中文选项&#xff0c;记得在安装软件时&#xff0c;需要提前安装好ArcGIS语言包。 上图所示&#xff0c;在【选项】里找到【编辑】设置&#xff0c;可以更改软件默认…

Java面试八股之如何保证消息队列中消息不重复消费

如何保证消息队列中消息不重复消费 要保证消息队列中的消息不被重复消费&#xff0c;通常需要从以下几个方面来着手&#xff1a; 消息确认机制&#xff1a; 对于像RabbitMQ这样的消息队列系统&#xff0c;可以使用手动确认&#xff08;manual acknowledge&#xff09;机制来…