在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何手擼一個自有知識庫的RAG系統

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-06-17 14:59 ? 次閱讀

RAG通常指的是"Retrieval-Augmented Generation",即“檢索增強的生成”。這是一種結合了檢索(Retrieval)和生成(Generation)的機器學習模型,通常用于自然語言處理任務,如文本生成、問答系統等。

我們通過一下幾個步驟來完成一個基于京東云官網文檔的RAG系統

數據收集

建立知識庫

向量檢索

提示詞與模型

數據收集

數據的收集再整個RAG實施過程中無疑是最耗人工的,涉及到收集、清洗、格式化、切分等過程。這里我們使用京東云的官方文檔作為知識庫的基礎。文檔格式大概這樣:

{
    "content": "DDoS IP高防結合Web應用防火墻方案說明n=======================nnnDDoS IP高防+Web應用防火墻提供三層到七層安全防護體系,應用場景包括游戲、金融、電商、互聯網、政企等京東云內和云外的各類型用戶。nnn部署架構n====nnn[!["部署架構"]("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")  nnDDoS IP高防+Web應用防火墻的最佳部署架構如下:nnn* 京東云的安全調度中心,通過DNS解析,將用戶域名解析到DDoS IP高防CNAME。n* 用戶正常訪問流量和DDoS攻擊流量經過DDoS IP高防清洗,回源至Web應用防火墻。n* 攻擊者惡意請求被Web應用防火墻過濾后返回用戶源站。n* Web應用防火墻可以保護任何公網的服務器,包括但不限于京東云,其他廠商的云,IDC等nnn方案優勢n====nnn1. 用戶源站在DDoS IP高防和Web應用防火墻之后,起到隱藏源站IP的作用。n2. CNAME接入,配置簡單,減少運維人員工作。nnn",
    "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":文檔在線地址

向量數據庫的選擇與Retriever實現

向量數據庫是RAG系統的記憶中心。目前市面上開源的向量數據庫很多,那個向量庫比較好也是見仁見智。本項目中筆者選擇則了clickhouse作為向量數據庫。選擇ck主要有一下幾個方面的考慮:

ck再langchain社區的集成實現比較好,入庫比較平滑

向量查詢支持sql,學習成本較低,上手容易

京東云有相關產品且有專業團隊支持,用著放心

文檔向量化及入庫過程

為了簡化文檔向量化和檢索過程,我們使用了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")

有了知識庫以后,可以構建一個簡單的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.gznrediscompare compare single2single --saddr "10.0.1.101:6479" --spassword "redistest0102" --taddr "10.0.1.102:6479" --tpassword  "redistest0102" --comparetimes 3nn```  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.gznrediscompare compare single2single --saddr "10.0.1.101:6479" --spassword "redistest0102" --taddr "10.0.1.102:6479" --tpassword  "redistest0102" --comparetimes 3nn```  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.gznrediscompare compare single2single --saddr "10.0.1.101:6479" --spassword "redistest0102" --taddr "10.0.1.102:6479" --tpassword  "redistest0102" --comparetimes 3nn```  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"
  }
]

返回一個向量距離最小的list

結合模型和prompt,回答問題

為了節約算力資源,我們選擇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做個簡易對話界面

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")


審核編輯 黃宇
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SQL
    SQL
    +關注

    關注

    1

    文章

    779

    瀏覽量

    44641
  • 數據庫
    +關注

    關注

    7

    文章

    3875

    瀏覽量

    65431
收藏 人收藏

    評論

    相關推薦

    AI知識庫的搭建與應用:企業數字化轉型的關鍵步驟

    和應用數據,從而為AI應用提供源源不斷的支持,幫助企業實現全面的數字化轉型。 ? AI知識庫的定義與作用 ? AI知識庫由結構化和非結構化數據組成的資源池,包含了企業的核心
    的頭像 發表于 03-27 15:18 ?181次閱讀

    《AI Agent 應用與項目實戰》閱讀心得3——RAG架構與部署本地知識庫

    RAG技術建立在向量數據的基礎上,通過高維向量空間中的相似度計算來實現語義層面的匹配,這比傳統的關鍵詞搜索更能捕捉文本的深層語義關聯。 第七章通過本地
    發表于 03-07 19:49

    如何從零開始搭建企業AI知識庫

    在數字化轉型的浪潮中,企業逐漸意識到數據不僅是資源,更是驅動業務增長的“燃料”。然而,分散在郵件、文檔系統、本地硬盤甚至員工腦海中的知識,往往如同孤島般難以串聯。AI知識庫的出現,正試圖將這些碎片化
    的頭像 發表于 02-28 14:35 ?427次閱讀

    用騰訊ima和Deepseek建立個人微信知識庫

    ---基于騰訊混元大模型或Deepseek-r推理模型的個人知識庫。大模型是通才,知識庫是專家大模型的訓練數據無法實時更新,而你的知識庫可以動態補充最新信息。大模型對細分領
    的頭像 發表于 02-25 17:33 ?984次閱讀
    用騰訊ima和Deepseek建立個人微信<b class='flag-5'>知識庫</b>

    DeepSeek從入門到精通(2):0成本用DeepSeek(滿血版)搭建本地知識庫

    我們身處數字化浪潮中,知識管理和利用的重要性與日俱增。擁有專屬的本地知識庫,能極大提升工作效率,滿足個性化需求。但對于技術小白來說,搭建這樣的
    的頭像 發表于 02-23 15:34 ?429次閱讀
    DeepSeek從入門到精通(2):0成本用DeepSeek(滿血版)搭建本地<b class='flag-5'>知識庫</b>

    利用OpenVINO和LlamaIndex工具構建多模態RAG應用

    Retrieval-Augmented Generation (RAG) 系統可以通過從知識庫中過濾關鍵信息來優化 LLM 任務的內存占用及推理性能。歸功于文本解析、索引和檢索等成熟工具的應用,為
    的頭像 發表于 02-21 10:18 ?1836次閱讀
    利用OpenVINO和LlamaIndex工具構建多模態<b class='flag-5'>RAG</b>應用

    【「基于大模型的RAG應用開發與優化」閱讀體驗】RAG基本概念

    RAG應用架構具備清晰的分層設計。知識庫構建層,著重于將各類非結構化數據進行有效處理,轉化為計算機能夠理解的形式,通過向量化編碼技術為數據賦予數字特征,并建立動態索引以便快速查詢更新。檢索增強層,采用
    發表于 02-08 00:22

    【「基于大模型的RAG應用開發與優化」閱讀體驗】+第章初體驗

    性能,大幅降低計算成本。 四、典型應用場景與挑戰 1智能問答系統:結合企業知識庫提供精準回答。 2內容生成工具:例如基于行業報告的自動摘要生成。 3性化推薦:通過用戶歷史行為檢索相似內容并生成解釋。 4
    發表于 02-07 10:42

    【「基于大模型的RAG應用開發與優化」閱讀體驗】+Embedding技術解讀

    引入外部知識庫來增強生成模型的能力。而Embedding在 Embedding模型將用戶的問題和文檔中的文本轉換為向量表示,這是RAG系統進行信息檢索和文本生成的基礎。
    發表于 01-17 19:53

    基于華為云 Flexus 云服務器 X 搭建部署——AI 知識庫問答系統(使用 1panel 面板安裝)

    Flexus 云服務器 X 攜手開源力量,為您打造全方位、高性能的知識庫問答系統!無論您是構建企業內部的知識寶庫,還是優化客戶服務體驗,亦或深耕學術研究與教育領域,這創新解決方案都
    的頭像 發表于 01-17 09:45 ?1063次閱讀
    基于華為云 Flexus 云服務器 X 搭建部署——AI <b class='flag-5'>知識庫</b>問答<b class='flag-5'>系統</b>(使用 1panel 面板安裝)

    騰訊ima升級知識庫功能,上線小程序實現共享與便捷問答

    知識管理體驗。 現在,用戶可以在ima平臺上輕松創建知識庫,并設置共享權限,實現多人同時使用和編輯。這功能的增加,極大地提升了團隊協作的效率,使得知識信息的共享和傳遞變得更加流暢。
    的頭像 發表于 12-31 15:32 ?1489次閱讀

    RAG的概念及工作原理

    )與外部知識源集成,增強了其能力。這種集成允許模型動態地引入相關信息,使其能夠生成不僅連貫而且事實準確、上下文相關的回應。RAG系統的主要組成部分包括: ·檢索器(Retriever): 該組件從外部
    的頭像 發表于 12-17 13:41 ?1152次閱讀
    <b class='flag-5'>RAG</b>的概念及工作原理

    名單公布!【書籍評測活動NO.52】基于大模型的RAG應用開發與優化

    使用RAG的思想,那么可以先從企業私有的知識庫中檢索出下面段相關的補充知識。 你把檢索出的補充知識組裝到提示詞中,將其輸入大模型,并要求
    發表于 12-04 10:50

    浪潮信息發布“源”Yuan-EB助力RAG檢索精度新高

    智EPAI為構建企業知識庫提供更高效、精準的知識向量化能力支撐,助力用戶使用領先的RAG技術加速企業知識資產的價值釋放。
    的頭像 發表于 11-26 13:54 ?421次閱讀
    浪潮信息發布“源”Yuan-EB助力<b class='flag-5'>RAG</b>檢索精度新高

    【實操文檔】在智能硬件的大模型語音交互流程中接入RAG知識庫

    非常明顯的短板。盡管這些模型在理解和生成自然語言方面有極高的性能,但它們在處理專業領域的問答時,卻往往不能給出明確或者準確的回答。 這時就需要接有知識庫來滿足產品專有和專業知識
    發表于 09-29 17:12
    主站蜘蛛池模板: 狠狠色狠狠色综合网 | 日本一区二区三区不卡在线看 | 一区二区三区四区在线观看视频 | 久久本道综合色狠狠五月 | 性欧美高清短视频免费 | 男人的亚洲天堂 | 99久久99久久免费精品蜜桃 | 李老汉的性生生活1全部 | 色天使久久综合给合久久97色 | 久久精品国产亚洲5555 | 免费观看视频网站 | 97超频国产在线公开免费视频 | 国产免费小视频 | 美女午夜 | 色亚洲色图 | 久久综合免费视频 | 性欧美高清短视频免费 | 桃花岛亚洲精品tv自拍网站 | 色多多黄 | 视频一区 在线 | 久久久久激情免费观看 | 亚洲精品在线免费观看视频 | 黄色天天影视 | 综合网在线观看 | 亚洲a视频在线 | 国产成在线人视频免费视频 | 曰韩一级 | 不卡一区二区在线观看 | 神马午夜在线观看 | 色涩在线 | 日韩免费观看视频 | 天天干视频网 | free 欧美| 亚欧成人中文字幕一区 | 免费看国产一级片 | 尻美女视频 | 97午夜影院| 美女扒开尿口给男人看的让 | 精品一区 二区三区免费毛片 | 在线看片国产 | 卡一卡二卡三国色天香永不失联 |