另外, 本次開發(fā)的運(yùn)行環(huán)境是 Intel Mac ,其他 操作系統(tǒng) 也可以。 下載模型等可能需要梯子。

Langchain 簡(jiǎn)介

https://www.langchain.com/langchain

Langchain 是當(dāng)前 大模型 應(yīng)用開發(fā)的主流框架之一,旨在幫助開發(fā)者構(gòu)建和部署基于大型語(yǔ)言模型( LLM )的應(yīng)用。它提供了一系列的工具和接口,使得與LLM交互變得簡(jiǎn)單。通過 Langchain,開發(fā)者可以輕松創(chuàng)建定制的高級(jí)應(yīng)用,如 聊天機(jī)器人 、問答系統(tǒng)和多種智能應(yīng)用。

Langchain 的核心在于其“鏈”概念,這是一個(gè)模塊化的組件系統(tǒng),包括 Model I/O (模型輸入輸出)、Retrieval(數(shù)據(jù)檢索)、Chains(鏈)、Agents(代理)、Memory( 內(nèi)存 )、和 Callbacks( 回調(diào) )。這些組件可靈活組合,以支持復(fù)雜的應(yīng)用邏輯。

Model I/O 模塊負(fù)責(zé)處理與語(yǔ)言模型的直接交互,包括發(fā)送請(qǐng)求和解析響應(yīng)。Retrieval 模塊用于增強(qiáng)語(yǔ)言模型的回答能力,通過向量數(shù)據(jù)庫(kù)檢索相關(guān)信息來支持回答生成。Chains 模塊則是多個(gè)組件的集成,用于構(gòu)建更復(fù)雜的應(yīng)用邏輯。

Langchain 的生態(tài)系統(tǒng)還包括 LangSmith、LangGraph 和 LangServe 等工具,這些工具能幫助開發(fā)者高效管理從原型到生產(chǎn)的各個(gè)階段,以便優(yōu)化 LLM 應(yīng)用。

Ollama 簡(jiǎn)介

https://ollama.com/

Ollama 是一個(gè)開箱即用的用于在本地運(yùn)行 大模型 的框架。它的主要功能和特點(diǎn)包括:

  1. 支持多種大型語(yǔ)言模型 :Ollama 支持包括 通義千問、Llama 2、Mistral 和 Gemma 等在內(nèi)的多種大型語(yǔ)言模型,這些模型可用于不同的應(yīng)用場(chǎng)景。

  2. 易于使用 :Ollama 旨在使用戶能夠輕松地在本地環(huán)境中啟動(dòng)和運(yùn)行 大模型 ,適用于 macOS 、Windows 和 Linux 系統(tǒng),同時(shí)支持 cpu 和 gpu 。

  3. 模型庫(kù) :Ollama 提供了一個(gè)模型庫(kù),用戶可以從中下載不同的模型。這些模型有不同的參數(shù)和大小,以滿足不同的需求和硬件條件。Ollama 支持的模型庫(kù)可以通過 https://ollama.com/library 進(jìn)行查找。

  4. 自定義模型 :用戶可以通過簡(jiǎn)單的步驟自定義模型,例如修改模型的溫度參數(shù)來調(diào)整創(chuàng)造性和連貫性,或者設(shè)置特定的系統(tǒng)消息。

  5. API 和集成 :Ollama 還提供了 REST API ,用于運(yùn)行和管理模型,以及與其他應(yīng)用程序的集成選項(xiàng)。

  6. 社區(qū)貢獻(xiàn) :Ollama 社區(qū)貢獻(xiàn)豐富,包括多種集成插件和界面,如 Web 和桌面應(yīng)用、 Telegram 機(jī)器人、Obsidian 插件等。

總的來說,Ollama 是一個(gè)為了方便用戶在本地運(yùn)行和管理大型語(yǔ)言模型而設(shè)計(jì)的框架,具有良好的可擴(kuò)展性和多樣的使用場(chǎng)景。

后面在捏 Bot 的過程中需要使用 Ollama,我們需要先安裝,訪問以下鏈接 進(jìn)行下載安裝。

https://ollama.com/download/

安裝完之后,確保 ollama 后臺(tái)服務(wù)已啟動(dòng)(在 mac 上啟動(dòng) ollama 應(yīng)用程序即可,在 linux 上可以通過 ollama serve 啟動(dòng))。我們可以通過 ollama list 進(jìn)行確認(rèn),當(dāng)我們還沒下載模型的時(shí)候,正常會(huì)顯示空:

可以通過 ollama 命令下載模型,

# 模型列表參考:https://ollama.com/library$ ollama pull [model] 

目前,我下載了 4 個(gè)模型:

幾個(gè)模型簡(jiǎn)介如下:

Gemma:Gemma 是由 Google 推出的輕量級(jí)模型,Google 表示,“Gemma 2B 和 7B 與其他開放式模型相比,在其規(guī)模上實(shí)現(xiàn)了同類最佳的性能?!?本次開發(fā),下載的是 7B 模型。

Mistral:Mistral 是由歐洲法國(guó) Mistral AI 團(tuán)隊(duì)推出的 大模型 ,該模型采用了分組查詢注意力(GQA)以實(shí)現(xiàn)更快的推斷速度。本次開發(fā),下載的是 7B 模型。

Mixtral:Mixtral 也是由 Mistral AI 團(tuán)隊(duì)推出的 大模型 ,但 Mixtral 是一個(gè) 8*7B 的 MoE 模型,在大多數(shù) 基準(zhǔn)測(cè)試 中都優(yōu)于 Llama 2 70B 和 GPT-3.5 。

Qwen:Qwen(通義千問)是由阿里巴巴推出的 大模型 ,本次開發(fā),下載的是 7B 模型。

萬(wàn)物皆可 RSS

巧婦難為無米之炊 。不管是獲取日常新聞,還是獲取 A 股行情,都需要有穩(wěn)定靠譜的 數(shù)據(jù)源 。大家可能第一時(shí)間會(huì)想到爬蟲,但自己去搭建和維護(hù)這樣一個(gè)爬蟲系統(tǒng)還是比較麻煩的。有沒有其他更好的方式呢?

這就需要用到「上古神器」 RSS 了!

大家可能會(huì)覺得 RSS 已經(jīng)過時(shí)了?,F(xiàn)如今,打開手機(jī),今日頭條、微博、微信等 APP 時(shí)不時(shí)就會(huì)給你推送最新的資訊,日常生活工作好像沒有用到 RSS 的場(chǎng)景。

確實(shí),大部分情況下,我們想要獲取資訊,手機(jī) APP 基本夠用了。

但是,如果你想針對(duì)一些特定的需求,需要從某些網(wǎng)站上獲取最新通知或相關(guān)信息呢?

比如,

在這種情況下,我們可能會(huì)把網(wǎng)站添加到書簽欄,然后時(shí)不時(shí)就會(huì)打開看一下,這種做法無疑是比較低效的,一旦網(wǎng)站變多,更是不現(xiàn)實(shí)。

如果我們能把真正想要關(guān)注的信息匯聚在同一個(gè)平臺(tái)上,并且一旦有更新,就能第一時(shí)間在各種終端(如電腦、手機(jī)、Kindle 等)收到提醒,那豈不是美哉。

這里,我給大家推薦一個(gè)寶藏項(xiàng)目:

RSSHub

https://docs.rsshub.app/zh/

感謝 RSSHub 這個(gè)開源項(xiàng)目,它給各種各樣的網(wǎng)站生成了 RSS 源,堪稱「 萬(wàn)物皆可 RSS 」。

你能想到的大部分社交媒體(如 微博、Twitter、知乎等)、傳統(tǒng)媒體(如央視新聞、路透社等)和金融媒體(如財(cái)聯(lián)社、東方財(cái)富、格隆匯等),都能夠配合 RSSHub,進(jìn)行訂閱。

通過 RSSHub 以及其他渠道,我個(gè)人維護(hù)了一個(gè)訂閱源,如下:

感興趣的讀者, 關(guān)注本公眾號(hào),然后發(fā)送 rss ,即可下載我打包好的 RSS 訂閱源。

那么,有了 RSS 訂閱源,我們就可以通過 Python 解析 RSS 訂閱源來實(shí)時(shí)獲取相關(guān)數(shù)據(jù)。

| 流程拆解

有了數(shù)據(jù),就意味著成功了一半。

| 創(chuàng)建 Python 虛擬環(huán)境

創(chuàng)建 python 虛擬環(huán)境 ,并安裝相關(guān)庫(kù),我安裝的是當(dāng)前最新的庫(kù),版本如下:

conda create -n finance_bot python=3.10conda activate finance_botpip install ollama langchain faiss-cpu gradio feedparser sentence-transformers lxml

| 導(dǎo)入依賴庫(kù)

加載所需的庫(kù)和模塊。

import ollamaimport feedparserimport gradio as gr
from lxml import etree
from langchain.vectorstores import FAISS
from langchain.docstore.document import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings.huggingface import HuggingFaceEmbeddings

其中,

| 從訂閱源獲取內(nèi)容

下面函數(shù)用于從指定 的 RSS 訂閱 url 提 取內(nèi)容,這里只是給了一個(gè) url,如果需要接收多個(gè) url,只要稍微改動(dòng)即可。然后,通過一個(gè)專門的文本拆分器將長(zhǎng)文本拆分成較小的塊,并附帶相關(guān)的元數(shù)據(jù)如標(biāo)題、發(fā)布日期和鏈接。最終,這些文檔被合并成一個(gè)列表并返回,可用于進(jìn)一步的數(shù)據(jù)處理或信息提取任務(wù)。

import feedparser
from lxml import etree
from some_text_splitting_library import RecursiveCharacterTextSplitter  # 假設(shè)這是某個(gè)文本拆分庫(kù)

def get_content(url):
    """
    使用 feedparser 庫(kù)解析提供的 URL,通常用于讀取 RSS 或 Atom 類型的數(shù)據(jù)流。
    """
    # 解析 URL 數(shù)據(jù)
    data = feedparser.parse(url)

    # 初始化文檔列表
    docs = []

    # 遍歷解析后的數(shù)據(jù)條目
    for news in data['entries']:
        # 使用 lxml 的 etree 通過 xpath 提取干凈的文本內(nèi)容
        summary = etree.HTML(text=news['summary']).xpath('string(.)')

        # 初始化文檔拆分器,設(shè)定塊大小和重疊大小
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=1000, 
            chunk_overlap=200, 
            length_function=len
        )

        # 拆分文檔
        split_docs = text_splitter.create_documents(
            texts=[summary], 
            metadatas=[{k: news[k] for k in ('title', 'published', 'link')}]
        )

        # 將拆分后的文檔合并到主列表
        docs.extend(split_docs)

    # 返回解析后的數(shù)據(jù)和文檔列表
    return data, docs

| 為文檔內(nèi)容生成向量

這里,我們使用文本向量模型 bge-m3 。

https://huggingface.co/BAAI/bge-m3

bge-m3 是智源研究院 發(fā)布的新一代通用向量模型,它具有以下特點(diǎn):

從 hf 下載好模型之后,假設(shè)放置在某個(gè)路徑 /path/to/bge-m3,通過下面函數(shù),利用 FAISS 創(chuàng)建一個(gè)高效的向量存儲(chǔ)。

from some_embedding_library import HuggingFaceEmbeddings  # 假設(shè)這是某個(gè)嵌入向量庫(kù)
from some_vector_store_library import FAISS  # 假設(shè)這是某個(gè)向量存儲(chǔ)庫(kù)

def create_docs_vector(docs):
    """
    為文檔列表創(chuàng)建向量表示,并存儲(chǔ)到向量數(shù)據(jù)庫(kù)中。

    參數(shù):
        docs (list): 文檔列表,每個(gè)文檔應(yīng)包含文本內(nèi)容和元數(shù)據(jù)。

    返回:
        vector_store: 向量存儲(chǔ)對(duì)象,可用于后續(xù)的相似性搜索等操作。
    """
    # 初始化嵌入模型
    embeddings = HuggingFaceEmbeddings(
        model_name="/path/to/bge-m3",
        encode_kwargs={'normalize_embeddings': True}
    )

    # 創(chuàng)建向量存儲(chǔ)對(duì)象
    vector_store = FAISS.from_documents(docs, embeddings)

    # 返回向量存儲(chǔ)對(duì)象
    return vector_store

| 實(shí)現(xiàn) RAG

基于用戶的問題,從向量數(shù)據(jù)庫(kù)中檢索相關(guān)段落,并根據(jù)設(shè)定的閾值進(jìn)行過濾,最后讓模型參考上下文信息回答用戶的問題,從而實(shí)現(xiàn) RAG。

def rag_chain(question, vector_store, model='qwen', threshold=0.3):
    """
    實(shí)現(xiàn)一個(gè)基于檢索增強(qiáng)生成(Retrieval-Augmented Generation, RAG)的問答鏈。

    參數(shù):
        question (str): 用戶提出的問題。
        vector_store (FAISS): 向量存儲(chǔ)對(duì)象,用于檢索相關(guān)文檔。
        model (str): 使用的模型名稱,默認(rèn)為 'qwen'。
        threshold (float): 相似度閾值,用于過濾相關(guān)性較低的文檔,默認(rèn)為 0.3。

    返回:
        tuple: 包含模型生成的回答和檢索到的上下文內(nèi)容。
    """
    # 從向量數(shù)據(jù)庫(kù)中檢索與問題相關(guān)的文檔
    related_docs = vector_store.similarity_search_with_relevance_scores(question)

    # 過濾掉相似度小于設(shè)定閾值的文檔
    related_docs = list(filter(lambda x: x[1] > threshold, related_docs))

    # 格式化檢索到的文檔
    context = "\n\n".join([f"[citation:{i}] {doc[0].page_content}" for i, doc in enumerate(related_docs)])

    # 保存文檔的元數(shù)據(jù),如 title、link 等
    metadata = {str(i): doc[0].metadata for i, doc in enumerate(related_docs)}

    # 構(gòu)建系統(tǒng)提示詞
    system_prompt = (
        f"""
        當(dāng)你收到用戶的問題時(shí),請(qǐng)編寫清晰、簡(jiǎn)潔、準(zhǔn)確的回答。
        你會(huì)收到一組與問題相關(guān)的上下文,每個(gè)上下文都以參考編號(hào)開始,如[citation:x],其中x是一個(gè)數(shù)字。
        請(qǐng)使用這些上下文,并在適當(dāng)?shù)那闆r下在每個(gè)句子的末尾引用上下文。
        你的答案必須是正確的,并且使用公正和專業(yè)的語(yǔ)氣寫作。請(qǐng)限制在1024個(gè)tokens之內(nèi)。
        不要提供與問題無關(guān)的信息,也不要重復(fù)。
        不允許在答案中添加編造成分,如果給定的上下文沒有提供足夠的信息,就說“缺乏關(guān)于xx的信息”。
        請(qǐng)用參考編號(hào)引用上下文,格式為[citation:x]。
        如果一個(gè)句子來自多個(gè)上下文,請(qǐng)列出所有適用的引用,如[citation:3][citation:5]。
        除了代碼和特定的名字和引用,你的答案必須用與問題相同的語(yǔ)言編寫,如果問題是中文,則回答也是中文。
        這是一組上下文:
        {context}
        """
    )

    # 構(gòu)建用戶提示詞
    user_prompt = f"用戶的問題是:{question}"

    # 調(diào)用模型生成回答
    response = ollama.chat(
        model=model,
        messages=[
            {'role': 'system', 'content': system_prompt},
            {'role': 'user', 'content': user_prompt}
        ]
    )

    # 打印系統(tǒng)提示和用戶提示(用于調(diào)試)
    print(system_prompt + user_prompt)

    # 返回模型生成的回答和檢索到的上下文
    return response['message']['content'], context

| 創(chuàng)建網(wǎng)頁(yè) UI

最后,通過 gradio 創(chuàng)建網(wǎng)頁(yè) UI ,并進(jìn)行評(píng)測(cè)。

if __name__ == "__main__":
    # 初始化 HuggingFace 嵌入模型
    hf_embedding = HuggingFaceEmbeddings(
        model_name="/path/to/bge-m3",
        encode_kwargs={'normalize_embeddings': True}
    )

    # 財(cái)聯(lián)社 RSS 鏈接
    url = "https://rsshub.app/cls/depth/1003"

    try:
        # 嘗試解析 RSS 鏈接
        data, docs = get_content(url)
    except Exception as e:
        print(f"解析 RSS 鏈接時(shí)遇到問題:{e}")
        print("請(qǐng)檢查鏈接的合法性,或稍后重試。")
        exit(1)  # 如果解析失敗,則退出程序

    # 創(chuàng)建向量存儲(chǔ)
    vector_store = create_docs_vector(docs, hf_embedding)

    # 創(chuàng)建 Gradio 界面
    import gradio as gr

    interface = gr.Interface(
        fn=lambda question, model, threshold: rag_chain(question, vector_store, model, threshold),
        inputs=[
            gr.Textbox(lines=2, placeholder="請(qǐng)輸入你的問題...", label="問題"),
            gr.Dropdown(['gemma', 'mistral', 'mixtral', 'qwen:7b'], label="選擇模型", value='gemma'),
            gr.Number(label="檢索閾值", value=0.3)
        ],
        outputs=[
            gr.Text(label="回答"),
            gr.Text(label="相關(guān)上下文")
        ],
        title="資訊問答B(yǎng)ot",
        description="輸入問題,我會(huì)查找相關(guān)資料,然后整合并給你生成回復(fù)"
    )

    # 運(yùn)行界面
    interface.launch()

生成的 Web UI 如下:

問答測(cè)試

對(duì)于同樣的問題和上下文,我基于 Qwen-7b、Gemma、Mistral、Mixtral 和 GPT-4 分別進(jìn)行了多次測(cè)試。下面是一些 case:

qwen

gemma

mistral

mixtral

gpt4

主要結(jié)論(只是針對(duì)有限的幾次測(cè)試,個(gè)人主觀評(píng)判)如下:

總結(jié)

1. 本文展示了如何使用 Langchain Ollama 技術(shù)棧在本地部署一個(gè)資訊問答機(jī)器人,同時(shí)結(jié)合 RSSHub 来處理和提供資訊。

2. 上下文 數(shù)據(jù)質(zhì)量和大模型的性能決定了 RAG 系統(tǒng)性能的上限 。

3. RAG 通過結(jié)合檢索技術(shù)和生成模型來提升答案的質(zhì)量和相關(guān)性,可以 緩解大模型幻覺、信息滯后的問題,但并不意味著可以消除 。

4. 對(duì)于期望在本地環(huán)境利用 AI 技術(shù)來搭建 RAG 系統(tǒng)的用戶來說,本文提供了一個(gè)具有實(shí)際操作價(jià)值的參考方案。

上一篇:

激蕩二十年:HTTPAPI的變遷

下一篇:

AIAgent如何實(shí)現(xiàn)?6張4090 魔改Llama2:一句指令拆分任務(wù)、調(diào)用函數(shù)
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)