AI大模型开发实战:如何构建京东自有RAG知识库系统

RAG(Retrieval-Augmented Generation)意思是“检索增强的生成”。这是一种结合检索(Retrieval)和生成(Generation)的机器学习模型,通常用于自然语言处理任务,如文本生成、问答系统等。

在AI大模型开发实战中,搭建自有的RAG知识库对系统具有十分重要意义,可以提升模型的回答准确性、增强领域专业性、提高响应速度、保护数据隐私、实现个性化服务,并持续优化和改进大模型的性能。比如我们研发的智慧魔方系统,学习辅导模块功能对问答准确性、专业性、个性化服务等都有很强的要求,因此RAG也作为一项必不可缺的开发技术。

下面我们基于京东云官网文档内容介绍下如何构建一个京东自有的RAG知识库系统。构建过程主要有以下4个方面:

  • 数据收集

  • 建立知识库

  • 知识库检索

  • 提示词与模型

1、数据收集****

数据的收集在整个RAG实施过程中无疑是最耗人工的,涉及到收集、清洗、格式化、切分等过程。这里我们使用京东云的官方文档作为知识库的基础。文档格式大概这样:

{``"content": "DDoS IP高防结合Web应用防火墙方案说明\n=======================\n\n\nDDoS IP高防+Web应用防火墙提供三层到七层安全防护体系,应用场景包括游戏、金融、电商、互联网、政企等京东云内和云外的各类型用户。\n\n\n部署架构\n====\n\n\n[![\\\"部署架构\\\"](\\\"https://jdcloud-portal.oss.cn-north-1.jcloudcs.com/cn/image/Advanced%20Anti-DDoS/Best-Practice02.png\\\")](\\\"https://jdcloud-portal.oss.cn-north-1.jcloudcs.com/cn/image/Advanced%20Anti-DDoS/Best-Practice02.png\\\")\n\nDDoS IP高防+Web应用防火墙的最佳部署架构如下:\n\n\n* 京东云的安全调度中心,通过DNS解析,将用户域名解析到DDoS IP高防CNAME。\n* 用户正常访问流量和DDoS攻击流量经过DDoS IP高防清洗,回源至Web应用防火墙。\n* 攻击者恶意请求被Web应用防火墙过滤后返回用户源站。\n* Web应用防火墙可以保护任何公网的服务器,包括但不限于京东云,其他厂商的云,IDC等\n\n\n方案优势\n====\n\n\n1. 用户源站在DDoS IP高防和Web应用防火墙之后,起到隐藏源站IP的作用。\n2. CNAME接入,配置简单,减少运维人员工作。\n\n\n",``"title": "DDoS IP高防结合Web应用防火墙方案说明",``"product": "DDoS IP高防",``"url": "https://docs.jdcloud.com/cn/anti-ddos-pro/anti-ddos-pro-and-waf"``}

每条数据是一个json格式,包含四个字段,分别是"content":文档内容;“title”:文档标题;“product”:相关产品;“url”:文档在线地址。

**2、建立知识库
**

1)向量数据库的选择

向量数据库是RAG系统的记忆中心。目前市面上开源的向量数据库很多,哪个向量库比较好也是见仁见智。在项目中我们选择了clickhouse作为向量数据库,主要有以下几个方面的考虑:

  • clickhouse在langchain社区的集成实现比较好,入库比较平滑

  • 向量查询支持sql,学习成本较低,上手容易

  • 京东云有相关产品且有专业团队支持,用着放心

2)文档向量化及入库过程

为了简化文档向量化和检索过程,我们使用了longchain的Retriever工具集。首先将文档向量化,代码如下:

from libs.jd_doc_json_loader import JD_DOC_Loader``from langchain_community.document_loaders import DirectoryLoader``   ``root_dir = "/root/jd_docs"``loader = DirectoryLoader(`    `'/root/jd_docs', glob="**/*.json", loader_cls=JD_DOC_Loader)``docs = loader.load()

langchain 社区里并没有提供针对特定格式的装载器,为此,我们自定义了JD_DOC_Loader来实现加载过程,代码如下。

import json``import logging``from pathlib import Path``from typing import Iterator, Optional, Union``   ``from langchain_core.documents import Document``   ``from langchain_community.document_loaders.base import BaseLoader``from langchain_community.document_loaders.helpers import detect_file_encodings``   ``logger = logging.getLogger(__name__)``   ``class JD_DOC_Loader(BaseLoader):`    `"""Load text file.``   `    `Args:`        `file_path: Path to the file to load.``   `        ``encoding: File encoding to use. If `None`, the file will be loaded``        `with the default system encoding.``   `        `autodetect_encoding: Whether to try to autodetect the file encoding`            `if the specified encoding fails.`    `"""``   `    `def __init__(`        `self,`        `file_path: Union[str, Path],`        `encoding: Optional[str] = None,`        `autodetect_encoding: bool = False,`    `):`        `"""Initialize with file path."""`        `self.file_path = file_path`        `self.encoding = encoding`        `self.autodetect_encoding = autodetect_encoding``   `    `def lazy_load(self) -> Iterator[Document]:`        `"""Load from file path."""`        `text = ""`        `from_url = ""`        `try:`            `with open(self.file_path, encoding=self.encoding) as f:`                `doc_data = json.load(f)`                `text = doc_data["content"]`                `title = doc_data["title"]`                `product = doc_data["product"]`                `from_url = doc_data["url"]``   `                `# text = f.read()`        `except UnicodeDecodeError as e:`            `if self.autodetect_encoding:`                `detected_encodings = detect_file_encodings(self.file_path)`                `for encoding in detected_encodings:`                    `logger.debug(f"Trying encoding: {encoding.encoding}")`                    `try:`                        `with open(self.file_path, encoding=encoding.encoding) as f:`                            `text = f.read()`                        `break`                    `except UnicodeDecodeError:`                        `continue`            `else:`                `raise RuntimeError(f"Error loading {self.file_path}") from e`        `except Exception as e:`            `raise RuntimeError(f"Error loading {self.file_path}") from e`        `# metadata = {"source": str(self.file_path)}`        `metadata = {"source": from_url, "title": title, "product": product}`        `yield Document(page_content=text, metadata=metadata)``   

上述代码功能主要是解析json文件,填充Document的page_content字段和metadata字段。接下来使用langchain 的 clickhouse 向量工具集进行文档入库。

import langchain_community.vectorstores.clickhouse as clickhouse``from langchain.embeddings import HuggingFaceEmbeddings``   ``model_kwargs = {"device": "cuda"}``embeddings = HuggingFaceEmbeddings(`    `model_name="/root/models/moka-ai-m3e-large", model_kwargs=model_kwargs)``   ``settings = clickhouse.ClickhouseSettings(`    `table="jd_docs_m3e_with_url", username="default", password="xxxxxx", host="10.0.1.94")``   ``docsearch = clickhouse.Clickhouse.from_documents(`    `docs, embeddings, config=settings)

入库成功后,进行一下检验。

import langchain_community.vectorstores.clickhouse as clickhouse``from langchain.embeddings import HuggingFaceEmbeddings``   ``model_kwargs = {"device": "cuda"}~~~~``embeddings = HuggingFaceEmbeddings(`    `model_name="/root/models/moka-ai-m3e-large", model_kwargs=model_kwargs)``   ``settings = clickhouse.ClickhouseSettings(`    `table="jd_docs_m3e_with_url_splited", username="default", password="xxxx", host="10.0.1.94")``ck_db = clickhouse.Clickhouse(embeddings, config=settings)``ck_retriever = ck_db.as_retriever(`    `search_type="similarity_score_threshold", search_kwargs={'score_threshold': 0.9})``ck_retriever.get_relevant_documents("如何创建mysql rds")

3、知识库检索

有了知识库以后,可以构建一个简单的restful 检索服务,这里我们使用fastapi来实现。

from fastapi import FastAPI``from pydantic import BaseModel``from singleton_decorator import singleton``from langchain_community.embeddings import HuggingFaceEmbeddings``import langchain_community.vectorstores.clickhouse as clickhouse``import uvicorn``import json``   ``app = FastAPI()``app = FastAPI(docs_url=None)``app.host = "0.0.0.0"``   ``model_kwargs = {"device": "cuda"}``embeddings = HuggingFaceEmbeddings(`    `model_name="/root/models/moka-ai-m3e-large", model_kwargs=model_kwargs)``settings = clickhouse.ClickhouseSettings(`    `table="jd_docs_m3e_with_url_splited", username="default", password="xxxx", host="10.0.1.94")``ck_db = clickhouse.Clickhouse(embeddings, config=settings)``ck_retriever = ck_db.as_retriever(`    `search_type="similarity", search_kwargs={"k": 3})``   ``   ``class question(BaseModel):`    `content: str``   ``   ``@app.get("/")``async def root():`    `return {"ok"}``   ``   ``@app.post("/retriever")``async def retriver(question: question):`    `global ck_retriever`    `result = ck_retriever.invoke(question.content)`    `return result``   ``   ``if __name__ == '__main__':`    `uvicorn.run(app='retriever_api:app', host="0.0.0.0",`                `port=8000, reload=True)

返回结果的格式如下:

[`  `{`    `"page_content": "云缓存 Redis--Redis迁移解决方案\n###RedisSyncer 操作步骤\n####数据校验\n```\nwget   https://github.com/TraceNature/rediscompare/releases/download/v1.0.0/rediscompare-1.0.0-linux-amd64.tar.gz\nrediscompare compare single2single --saddr \\\"10.0.1.101:6479\\\" --spassword \\\"redistest0102\\\" --taddr \\\"10.0.1.102:6479\\\" --tpassword  \\\"redistest0102\\\" --comparetimes 3\n\n```\n**Github 地址:** [https://github.com/TraceNature/redissyncer-server](\\\"https://github.com/TraceNature/redissyncer-server\\\")",`    `"metadata": {`      `"product": "云缓存 Redis",`      `"source": "https://docs.jdcloud.com/cn/jcs-for-redis/doc-2",`      `"title": "Redis迁移解决方案"`    `},`    `"type": "Document"`  `},`  `{`    `"page_content": "云缓存 Redis--Redis迁移解决方案\n###RedisSyncer 操作步骤\n####数据校验\n```\nwget   https://github.com/TraceNature/rediscompare/releases/download/v1.0.0/rediscompare-1.0.0-linux-amd64.tar.gz\nrediscompare compare single2single --saddr \\\"10.0.1.101:6479\\\" --spassword \\\"redistest0102\\\" --taddr \\\"10.0.1.102:6479\\\" --tpassword  \\\"redistest0102\\\" --comparetimes 3\n\n```\n**Github 地址:** [https://github.com/TraceNature/redissyncer-server](\\\"https://github.com/TraceNature/redissyncer-server\\\")",`    `"metadata": {`      `"product": "云缓存 Redis",`      `"source": "https://docs.jdcloud.com/cn/jcs-for-redis/doc-2",`      `"title": "Redis迁移解决方案"`    `},`    `"type": "Document"`  `},`  `{`    `"page_content": "云缓存 Redis--Redis迁移解决方案\n###RedisSyncer 操作步骤\n####数据校验\n```\nwget   https://github.com/TraceNature/rediscompare/releases/download/v1.0.0/rediscompare-1.0.0-linux-amd64.tar.gz\nrediscompare compare single2single --saddr \\\"10.0.1.101:6479\\\" --spassword \\\"redistest0102\\\" --taddr \\\"10.0.1.102:6479\\\" --tpassword  \\\"redistest0102\\\" --comparetimes 3\n\n```\n**Github 地址:** [https://github.com/TraceNature/redissyncer-server](\\\"https://github.com/TraceNature/redissyncer-server\\\")",`    `"metadata": {`      `"product": "云缓存 Redis",`      `"source": "https://docs.jdcloud.com/cn/jcs-for-redis/doc-2",`      `"title": "Redis迁移解决方案"`    `},`    `"type": "Document"`  `}``]

4、提示词与模型

为了节约算力资源,我们选择qwen 1.8B模型,一张v100卡刚好可以容纳一个qwen模型和一个m3e-large embedding 模型。
  • answer 服务
from fastapi import FastAPI``from pydantic import BaseModel``from langchain_community.llms import VLLM``from transformers import AutoTokenizer``from langchain.prompts import PromptTemplate``import requests``import uvicorn``import json``import logging``   ``app = FastAPI()``app = FastAPI(docs_url=None)``app.host = "0.0.0.0"``   ``logger = logging.getLogger()``logger.setLevel(logging.INFO)``to_console = logging.StreamHandler()``logger.addHandler(to_console)``   ``   ``# load model``# model_name = "/root/models/Llama3-Chinese-8B-Instruct"``model_name = "/root/models/Qwen1.5-1.8B-Chat"``tokenizer = AutoTokenizer.from_pretrained(model_name)``llm_llama3 = VLLM(`    `model=model_name,`    `tokenizer=tokenizer,`    `task="text-generation",`    `temperature=0.2,`    `do_sample=True,`    `repetition_penalty=1.1,`    `return_full_text=False,`    `max_new_tokens=900,``)``   ``# prompt``prompt_template = """``你是一个云技术专家``使用以下检索到的Context回答问题。``如果不知道答案,就说不知道。``用中文回答问题。``Question: {question}``Context: {context}``Answer:` `"""``   ``prompt = PromptTemplate(`    `input_variables=["context", "question"],`    `template=prompt_template,``)``   ``   ``def get_context_list(q: str):`    `url = "http://10.0.0.7:8000/retriever"`    `payload = {"content": q}`    `res = requests.post(url, json=payload)`    `return res.text``   ``   ``class question(BaseModel):`    `content: str``   ``   ``@app.get("/")``async def root():`    `return {"ok"}``   ``   ``@app.post("/answer")``async def answer(q: question):`    `logger.info("invoke!!!")`    `global prompt`    `global llm_llama3`    `context_list_str = get_context_list(q.content)``   `    `context_list = json.loads(context_list_str)`    `context = ""`    `source_list = []``   `    `for context_json in context_list:`        `context = context+context_json["page_content"]`        `source_list.append(context_json["metadata"]["source"])`    `p = prompt.format(context=context, question=q.content)`    `answer = llm_llama3(p)`    `result = {`        `"answer": answer,`        `"sources": source_list`    `}`    `return result``   ``   ``if __name__ == '__main__':`    `uvicorn.run(app='retriever_api:app', host="0.0.0.0",`                `port=8888, reload=True)
上述代码通过使用Retriever接口查找与问题相似的文档,作为context组合prompt推送给模型生成答案。
  • gradio 服务

主要的answer问答服务实现后,我们使用gradio服务做个简易对话界面。

import json``import gradio as gr``import requests``   ``   ``def greet(name, intensity):`    `return "Hello, " + name + "!" * int(intensity)``   ``   ``def answer(question):`    `url = "http://127.0.0.1:8888/answer"`    `payload = {"content": question}`    `res = requests.post(url, json=payload)`    `res_json = json.loads(res.text)`    `return [res_json["answer"], res_json["sources"]]``   ``   ``demo = gr.Interface(`    `fn=answer,`    `# inputs=["text", "slider"],`    `inputs=[gr.Textbox(label="question", lines=5)],`    `# outputs=[gr.TextArea(label="answer", lines=5),`    `#          gr.JSON(label="urls", value=list)]`    `outputs=[gr.Markdown(label="answer"),`             `gr.JSON(label="urls", value=list)]``)``   ``   ``demo.launch(server_name="0.0.0.0")
    经过上述数据收集、建立知识库、知识库检索、提示词与模型四个过程,我们就成功构建出了一个基本的京东自有RAG知识库系统,提升了通用模型响应的准确度和专业性。

    在大多数场景下,模型提供正确问答能力至关重要,比如医疗诊断、法律咨询、学习辅导等应用场景。在我们的智慧魔方系统中不仅采用上述技术方案优化AI模型,还需要考虑模型响应中的幻觉问题,模型幻觉问题也是一项AI大模型的不可彻底消除的缺陷,需要使用多种解决方案进行优化和环节,感兴趣的朋友欢迎关注老梁,我们后续分享。

如何学习AI大模型 ?

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。【保证100%免费】🆓

对于0基础小白入门:

如果你是零基础小白,想快速入门大模型是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以根据这些资料规划好学习计划和方向。

😝有需要的小伙伴,可以VX扫描下方二维码免费领取🆓

👉1.大模型入门学习思维导图👈

要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。

对于从来没有接触过AI大模型的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。(全套教程文末领取哈)
在这里插入图片描述

👉2.AGI大模型配套视频👈

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,每个章节都是当前板块的精华浓缩。

在这里插入图片描述
在这里插入图片描述

👉3.大模型实际应用报告合集👈

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。(全套教程文末领取哈)

在这里插入图片描述

👉4.大模型落地应用案例PPT👈

光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。(全套教程文末领取哈)

在这里插入图片描述

👉5.大模型经典学习电子书👈

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。(全套教程文末领取哈)
img

在这里插入图片描述

👉6.大模型面试题&答案👈

截至目前大模型已经超过200个,在大模型纵横的时代,不仅大模型技术越来越卷,就连大模型相关的岗位和面试也开始越来越卷了。为了让大家更容易上车大模型算法赛道,我总结了大模型常考的面试题。(全套教程文末领取哈)

在这里插入图片描述
👉学会后的收获:👈
基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习

这份完整版的 AI 大模型学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取🆓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值