精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

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

    文章

    760

    瀏覽量

    44080
  • 數據庫
    +關注

    關注

    7

    文章

    3767

    瀏覽量

    64279
收藏 人收藏

    評論

    相關推薦

    直播預告 大模型 + 知識庫RAG):如何使能行業數智化?

    。最近,有小伙伴留言稱工作中常遇到知識管理問題: 知識管理雜亂無章、查找費時費力,而且信息孤島嚴重、知識難以共享,團隊成員總是重復勞動 ;希望能安排場直播介紹如何通過智能化手段解決
    的頭像 發表于 11-26 23:49 ?62次閱讀
    直播預告 大模型 + <b class='flag-5'>知識庫</b>(<b class='flag-5'>RAG</b>):如何使能行業數智化?

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

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

    從零開始訓練大語言模型需要投資多少錢?

    關于訓練技巧和模型評估的文章,但很少有直接告訴你如何估算訓練時間和成本的。前面分享了些關于大模型/本地知識庫的安裝部署方法,無需編寫代碼,即可使用 Ollama+AnythingLLM搭建企業私有知識庫 ,或者, 三步完成Ll
    的頭像 發表于 11-08 14:15 ?150次閱讀
    從零開始訓練<b class='flag-5'>一</b><b class='flag-5'>個</b>大語言模型需要投資多少錢?

    搭建 AI 問答機器人,需要幾步?

    搭建企業內部AI 問答機器人、知識庫的場景,我們可以選擇大廠的云服務,這相對于大多數用戶來說,是最省事的方案。但很多企業可能會有些私有化的數據,或者受限于企業內部的安全性要求,只
    的頭像 發表于 10-21 15:10 ?292次閱讀
    搭建<b class='flag-5'>一</b><b class='flag-5'>個</b> AI 問答機器人,需要幾步?

    使用OpenVINO和LlamaIndex構建Agentic-RAG系統

    解決大語言模型在知識時效性和專業性上的不足。但同時傳統的 RAG 系統也有它的缺陷,例如靈活性較差,由于 RAG 會過分依賴于向量數據的檢
    的頭像 發表于 10-12 09:59 ?205次閱讀
    使用OpenVINO和LlamaIndex構建Agentic-<b class='flag-5'>RAG</b><b class='flag-5'>系統</b>

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

    非常明顯的短板。盡管這些模型在理解和生成自然語言方面有極高的性能,但它們在處理專業領域的問答時,卻往往不能給出明確或者準確的回答。 這時就需要接有知識庫來滿足產品專有和專業知識
    發表于 09-29 17:12

    TaD+RAG-緩解大模型“幻覺”的組合新療法

    TaD:任務感知解碼技術(Task-aware Decoding,簡稱TaD),京東聯合清華大學針對大語言模型幻覺問題提出的項技術,成果收錄于IJCAI2024。 RAG:檢索增強生成技術
    的頭像 發表于 07-16 15:01 ?1974次閱讀
    TaD+<b class='flag-5'>RAG</b>-緩解大模型“幻覺”的組合新療法

    Java開發者LLM實戰——使用LangChain4j構建本地RAG系統

    1、引言 由于目前比較火的chatGPT是預訓練模型,而訓練大模型是需要較長時間(參數越多學習時間越長,保守估計般是幾個月,不差錢的可以多用點GPU縮短這個時間),這就導致了它所學習的
    的頭像 發表于 07-02 10:32 ?1290次閱讀
    Java開發者LLM實戰——使用LangChain4j構建本地<b class='flag-5'>RAG</b><b class='flag-5'>系統</b>

    大模型應用之路:從提示詞到通用人工智能(AGI)

    鋪平道路。 基于AI大模型的推理功能,結合了RAG(檢索增強生成)、智能體(Agent)、知識庫、向量數據、知識圖譜等先進技術,我們向實現真正的AGI(通用人工智能)邁出了重要步伐。
    的頭像 發表于 06-14 10:20 ?2124次閱讀
    大模型應用之路:從提示詞到通用人工智能(AGI)

    什么是RAGRAG學習和實踐經驗

    高級的RAG能很大程度優化原始RAG的問題,在索引、檢索和生成上都有更多精細的優化,主要的優化點會集中在索引、向量模型優化、檢索后處理等模塊進行優化
    的頭像 發表于 04-24 09:17 ?796次閱讀
    什么是<b class='flag-5'>RAG</b>,<b class='flag-5'>RAG</b>學習和實踐經驗

    英特爾集成顯卡+ChatGLM3大語言模型的企業本地AI知識庫部署

    在當今的企業環境中,信息的快速獲取和處理對于企業的成功至關重要。為了滿足這需求,我們可以將RAG技術與企業本地知識庫相結合,以提供實時的、自動生成的信息處理和決策支持。
    的頭像 發表于 03-29 11:07 ?757次閱讀
    英特爾集成顯卡+ChatGLM3大語言模型的企業本地AI<b class='flag-5'>知識庫</b>部署

    利用知識圖譜與Llama-Index技術構建大模型驅動的RAG系統(下)

    對于語言模型(LLM)幻覺,知識圖譜被證明優于向量數據知識圖譜提供更準確、多樣化、有趣、邏輯和致的信息,減少了LLM中出現幻覺的可能性。
    的頭像 發表于 02-22 14:13 ?1145次閱讀
    利用<b class='flag-5'>知識</b>圖譜與Llama-Index技術構建大模型驅動的<b class='flag-5'>RAG</b><b class='flag-5'>系統</b>(下)

    深入了解RAG技術

    這是任何RAG流程的最后步——基于我們仔細檢索的所有上下文和初始用戶查詢生成答案。最簡單的方法可能是將所有獲取到的上下文(超過某個相關性閾值的)連同查詢次性輸入給LLM。
    的頭像 發表于 01-17 11:36 ?3009次閱讀
    深入了解<b class='flag-5'>RAG</b>技術

    搜索出生的百川智能大模型RAG爬坑之路總結

    今天對百川的RAG方法進行解讀,百川智能具有深厚的搜索背景,來看看他們是怎么爬RAG的坑的吧~
    的頭像 發表于 01-05 15:02 ?1435次閱讀
    搜索出生的百川智能大模型<b class='flag-5'>RAG</b>爬坑之路總結

    如何利用OpenVINO加速LangChain中LLM任務

    RAG)任務,LangChain 可以根據問題從已有的知識庫中進行檢索,并將原始的檢索結果和問題并包裝為Prompt提示送入 LLM 中,以此獲得更加貼近問題需求的答案。
    的頭像 發表于 12-05 09:58 ?779次閱讀