返回文章列表

大語言模型建構企業級應用

本文探討如何利用大語言模型 (LLM) 建構企業級應用程式,著重於檢索增強生成 (RAG) 技術。文章涵蓋了 RAG 的流程、優勢、實際應用案例以及架構,並詳細說明如何使用 Solr 建立和擴充套件知識函式庫,以及如何實作檢索功能以提升問答系統的效能和準確性。同時也探討了 Solr

Web 開發 機器學習

大語言模型(LLM)的出現為企業級應用程式開發帶來了新的可能性。然而,僅僅使用 LLM 的 API 並不足以建構成熟的企業級應用,更需要關注可擴充套件性和知識更新等議題。檢索增強生成(RAG)技術有效地解決了 LLM 的知識截止問題,並提升了生成內容的準確性。透過 RAG,企業級應用可以根據特定領域的知識函式庫,提供更精準、可靠的服務。本文將探討 RAG 的核心概念、架構以及實作細節,並以 Solr 作為檢索工具示範如何建構一個高效能的企業級問答系統。同時,也將探討如何擴充套件 Solr 以支援更大規模的知識函式庫,以及如何最佳化硬體資源和監控,以確保系統的穩定性和效能。

使用大語言模型建構企業級應用程式

在前一章中,我們探討了大語言模型(LLMs)的強大功能及其在建立展示應用程式中的實際應用。我們發現LLMs能夠透過資料抓取、問答和摘要來理解網站內容。此外,我們還學習瞭如何從PDF檔案和影片記錄中提取洞察,深入研究影片字幕摘要和問答。

現在,我們將邁出重要的一步,進入由LLMs驅動的企業級應用程式的世界。在本章中,我們將轉換方向,沉浸在開發超越簡單展示的應用程式的複雜性中。企業級應用程式需要更高階別的成熟度、可擴充套件性和適應性,以滿足商業世界的嚴格標準。我們的旅程將探索利用LLMs開發強壯的解決方案,以滿足企業的多樣化需求。

我們瞭解,建立企業級應用程式需要對特定領域的挑戰有深入的瞭解,並致力於提供卓越的服務。為了讓您具備必要的專業知識,我們將揭示先進的技術和最佳實踐,使您能夠滿足企業環境的獨特需求。

在本章進展過程中,您將深入瞭解如何從非結構化資料中提取有意義的洞察,並透過問答和開發引人入勝的使用者介面來提升使用者經驗。

當您到達本章末尾時,您將擁有使用LLMs開發成熟企業級應用程式的知識和技能。這些應用程式將使企業能夠做出明智的決策、自動化流程,並從大量資料中解鎖隱藏的價值。

檢索增強問答聊天機器人

想像一下,當像ChatGPT這樣的大語言模型突然出現時,網上世界所產生的興奮。這些根據網路的聊天機器人擁有令人驚嘆的能力,可以理解和生成文字,讓包括我在內的人們感到真正驚訝。

為了探索它們的能力,我們很多人登入並測試了這些LLMs。我們要求它們撰寫俳句、起草動機信或製作電子郵件回覆。我們很快發現,LLMs擅長生成富有創意的內容和處理日常語言任務以及其他自然語言處理挑戰。

隨著LLMs周圍的熱潮增長,人們開始思考如何將它們整合到自己的應用程式中。然而,人們很快意識到,僅僅圍繞LLM API開發一個簡單的包裝器並不能保證成功。要真正產生影響,提供超出LLMs已經提供的內容是至關重要的。

LLMs面臨的一個主要障礙是我們所說的知識截止。這意味著LLMs無法意識到任何在它們訓練之後發生的事件或資訊。因此,如果你詢問ChatGPT(根據GPT-3.5)關於2023年的事件,它將無法給出準確的回應。

知識截止問題

這些限制雖然重要,卻沒有澆滅人們對LLMs的熱情。相反,它們激發了人們增強LLMs能力、找到創新方法來利用其優勢並克服其知識截止挑戰的慾望。

如果您詢問LLM有關其訓練資料集中未包含的事件,也會出現同樣的問題。LLM的知識僅限於其在訓練期間接觸到的資訊,這意味著它有一個知識截止日期。這個日期對於公開可用的資訊來說很重要。然而,值得注意的是,LLM不知道甚至在知識截止日期之前可能存在的私人或機密資料。

考慮這樣一個場景:一家公司希望利用自定義的LLM來回答有關其機密資訊的特定問題。在這種情況下,LLM的訓練資料中不會包含該私人資訊,使其無法提供準確的回應。

另一方面,LLM所瞭解的公開可用資訊可能已經需要更新。世界在不斷演變,每天都有新的事件和發現發生。LLM的訓練可能尚未涵蓋最新的更新,這可能會影響其對當前事件回應的準確性和相關性。

虛構內容的問題

這些限制凸顯了在尋求答案或將LLM用於特定應用時,瞭解其知識背景和範圍的重要性。評估LLM的訓練資料、考慮資訊的相關性以及認識其對公共和私人領域理解中的潛在差距至關重要。

LLMs提出了另一個挑戰:它們能夠生成聽起來非常真實的文字,即使它不夠準確。要發現無效的資訊可能相當棘手,特別是在缺失資料的情況下。在這種情況下,LLM很可能會編造一個聽起來令人信服但最終不正確的答案,而不是承認其缺乏基本事實。這種現象在LLM領域被稱為幻覺。

檢索增強生成(RAG)流程

為了說明,讓我們探索研究和法院參照的領域。核實這些來源的準確性至關重要。在撰寫本章時,一位律師因盲目信任ChatGPT生成的法院參照而陷入麻煩。在未進行必要審查的情況下,該律師完全依賴LLM提供的來源。不幸的是,這導致了意想不到的併發症,凸顯了毫無疑問地接受LLM生成資訊的潛在陷阱。

這個現實世界的例子是一個鮮明的提醒,需要在依賴LLMs時謹慎行事並進行批判性思考。雖然LLMs擅長製作看起來真實的文字,但獨立核實其生成資訊的準確性和有效性至關重要。特別是在像法律研究這樣的精確度至關重要的領域,毫無疑問地接受LLM生成的參照可能會導致嚴重的後果。

進行徹底的事實核查並從多個可靠來源核實資訊對於確保準確性和避免潛在陷阱至關重要。

檢索增強方法採用不同的方法,利用LLMs根據您資料來源中的相關檔案生成答案的力量。圖9-1顯示了檢索增強生成(RAG)流程的簡化版本。

圖表翻譯: 此圖示展示了檢索增強生成(RAG)流程的工作原理,首先檢索與使用者查詢相關的檔案,然後利用這些檔案生成答案,最後傳回答案給使用者。

內容解密:

  1. 使用者查詢: 使用者向系統提出一個查詢或問題。
  2. 檢索相關檔案: 系統根據使用者查詢檢索相關檔案。
  3. 使用相關檔案生成答案: 利用檢索到的相關檔案,系統生成一個答案。
  4. 傳回答案: 最終,系統將生成的答案傳回給使用者。

這個RAG流程有效地利用了LLMs的能力,同時透過根據相關檔案生成答案來克服其知識截止和幻覺等限制。這種方法提高了回答的準確性和可靠性,使其非常適合企業級應用。

使用大語言模型建立企業級應用程式:檢索增強生成(RAG)技術

簡化RAG流程

當使用者提出問題時,第一步是計算查詢與檔案資料函式庫中檔案之間的相似度。然後,將提取的檔案作為上下文與問題結合,建立提示。最後,將提示傳遞給大語言模型(LLM),以生成根據資料函式庫中增強知識的真實答案。本章後續部分將探討RAG流程的詳細組成部分和實施步驟。

RAG的優勢

與僅依賴LLM內部知識不同,RAG方法利用LLM的能力來增強來自提供檔案的資訊。這樣,您就可以存取超出LLM訓練範圍的特定和上下文資訊。

檢索增強生成的真實應用案例

在探討RAG架構之前,讓我們回顧一些真實的應用案例:

  • 即時客戶支援:客戶支援系統可以透過檢索增強來存取最新的產品資訊和使用者手冊,從而幫助LLM為客戶提供準確的產品查詢答案。
  • 財務報告和分析:財務分析師使用檢索增強生成來存取實時市場資料、監管更新和公司財務資料,從而能夠生成最新的報告、預測和分析。
  • 醫療資訊合成:醫療專業人員可以透過利用LLM並結合患者記錄、臨床和最新的醫學研究來增強他們的理解和知識。
  • 法律研究:律師和法律研究人員使用RAG來存取和解釋大量的法律檔案,從而能夠參考當前法律、案例先例和法律文章。
  • 內容創作和企劃:在媒體和內容創作領域,檢索增強使LLM能夠納入相關的事實、統計資料和參考資料,從而保證內容的準確性和可靠性。

RAG架構

RAG架構的主要組成部分包括:

  • 檔案儲存:所有檔案首先被抓取和清理後儲存在此檔案中。
  • 資訊檢索:使用檢索器根據使用者查詢搜尋最相關的檔案。
  • 重新排序器 :重新排序器元件找到與使用者查詢最相關的檔案。
  • 語言模型:大語言模型根據檢索器提供的檔案生成/提取答案。
  • 使用者應用程式:這充當了終端使用者和流程之間的介面,允許使用者輸入問題並自動生成答案。

建立知識函式庫

建立知識函式庫對於整合大語言模型以建立企業級應用程式至關重要。知識函式庫是一個集中的資訊儲存函式庫,可以幫助企業有效地組織、管理和分享知識。您可以利用此知識幫助LLM避免幻覺。

步驟1:收集資料

首先,收集用於建立知識函式庫的資料。您可以從http://www.manualsonline.com/取得使用者手冊,以建立語料函式庫。

import requests
from bs4 import BeautifulSoup

# 傳送HTTP請求取得網頁內容
url = "http://www.manualsonline.com/"
response = requests.get(url)

# 解析網頁內容
soup = BeautifulSoup(response.text, 'html.parser')

# 提取使用者手冊連結
manual_links = []
for link in soup.find_all('a'):
    if 'manual' in link.get('href'):
        manual_links.append(link.get('href'))

# 將提取的連結儲存到檔案中
with open('manual_links.txt', 'w') as f:
    for link in manual_links:
        f.write(link + '\n')

內容解密:

這段程式碼首先傳送HTTP請求取得指定網頁的內容,然後使用BeautifulSoup解析網頁內容。接著,它提取包含“manual”字樣的連結,並將這些連結儲存到一個檔案中。這樣,您就可以收集使用者手冊的連結,為建立知識函式庫做準備。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 大語言模型建構企業級應用

package "LLM 企業級應用" {
    package "RAG 技術" {
        component [檢索增強生成] as rag
        component [知識函式庫] as kb
        component [克服知識截止] as cutoff
    }

    package "檢索架構" {
        component [Solr 搜尋引擎] as solr
        component [向量檢索] as vector
        component [非結構化資料] as unstructured
    }

    package "企業需求" {
        component [可擴充套件性] as scale
        component [私有資料整合] as private
        component [問答系統] as qa
    }
}

rag --> kb : 知識注入
kb --> cutoff : 即時更新
cutoff --> solr : 檢索實作
solr --> vector : 相似度搜尋
vector --> unstructured : 資料處理
unstructured --> scale : 企業擴展
scale --> private : 機密資料
private --> qa : 精準回答

note right of rag
  RAG 優勢:
  - 解決知識截止
  - 提升準確性
  - 整合領域知識
end note

note right of scale
  企業需求:
  - 可擴充套件架構
  - 硬體資源最佳化
  - 系統穩定監控
end note

@enduml

圖表翻譯: 此圖示展示了收集使用者手冊連結的流程。首先,傳送HTTP請求取得網頁內容。然後,解析網頁內容並提取包含“manual”字樣的連結。最後,將這些連結儲存到檔案中,以供後續處理使用。

建立企業級應用程式的檢索系統

在建立企業級的應用程式時,檢索系統扮演著至關重要的角色。一個高效的檢索系統能夠快速準確地檢索相關資訊,從而提升使用者的體驗。本章節將介紹如何使用Solr作為檢索工具來建立一個強大的檢索系統。

步驟1:準備資料

首先,我們需要準備資料。在本例中,我們可以使用已經準備好的55,000個手冊資料。你可以選擇下載這些手冊的壓縮檔案,或者直接從提供的Google Drive連結下載:https://drive.google.com/drive/folders/1-gX1DlmVodP6OVRJC3WBRZoGgxPuJvvt。

下載完成後,請解壓縮檔案,並將所有zip檔案放在同一個目錄下,以便後續的索引建立。

步驟2:設定Solr檢索系統

步驟2.1:下載Solr二進位制檔案

前往https://solr.apache.org/downloads.html下載Solr的二進位制發布版本。

步驟2.2:安裝Solr

將下載的Solr壓縮檔案解壓縮到本地主目錄。請根據你下載的Solr版本調整命令。

cd ~/
tar zxf solr-9.2.1.tgz

步驟2.3:啟動Solr Cloud服務

以互動模式啟動Solr。

./bin/solr start -e cloud

該指令會提示你輸入本地叢集的Solr節點數量,預設為2,你可以根據需要進行調整。完成節點設定後,輸入集合名稱(例如:Manuals)。接著,設定分片數量和副本數量,預設值均為2。

最後,選擇組態目錄名稱,可以選擇sample_techproducts_configs作為Manuals集合的組態。

步驟2.4:索引檔案

索引的目的是組織和結構化資料,使其能夠被快速準確地檢索。使用以下命令對55,000個手冊進行索引:

./bin/post -c Manuals /Users/shivamsolanki/Desktop/Generative-AI-Book/Chapter-9/EManuals_Corpus/*

請確保提供正確的目錄路徑。該過程大約需要三個小時。你可以觀察到類別似以下的訊息:

124476 files indexed.
COMMITting Solr index changes to http://localhost:8983/solr/Manuals/update...
Time spent: 3:03:03.075

擴充套件索引以支援企業級知識函式庫

在本地開發環境中設定Solr對於數萬個檔案是可行的,但對於企業級知識函式庫來說,可能包含數百萬甚至數十億個檔案。在單一機器上執行Solr可能會遇到挑戰,例如:

  • 索引時間:處理和索引龐大的資料集可能需要數天或數周。
  • 效能瓶頸:單一機器的記憶體和處理能力限制可能導致查詢回應緩慢。
  • 可擴充套件性:隨著知識函式庫的增長,需要進行顯著的硬體升級。

為瞭解決這些限制,可以考慮以下擴充套件策略:

  • 雲端檢索器:允許水平擴充套件叢集,增加節點以提升效能和可擴充套件性。
  • 分片:將資料分成更小的區塊,並在多個節點上複製,以提高效率和效能。
  • 複製因子:在多個節點上建立分片的副本,以確保冗餘和容錯能力。

硬體資源與監控最佳化

擴充套件檢索器需要足夠的硬體資源,包括CPU核心、記憶體和儲存容量。同時,需要持續監控叢集的效能和資源利用率,並實施自動擴充套件策略和最佳化Solr組態,以確保最佳效能。

設定檢索系統

建立知識函式庫後,我們將設定資訊檢索元件,如圖9-5所示。這將使我們能夠高效地檢索相關資訊,從而支援企業級RAG應用程式的執行。

圖表翻譯:

此圖示展示了企業級檢索系統的架構,包括資料準備、Solr設定、索引建立和擴充套件策略等關鍵步驟。透過這個架構,可以有效地管理和檢索龐大的資料集,為企業級應用提供強大的支援。

運用 Solr 提升檢索增強問答系統的實作

在建立一個企業級的檢索增強問答系統時,Solr 扮演著至關重要的角色。Solr 是一種高效能的搜尋引擎,能夠快速地從大量檔案中找出最相關的結果。本章節將探討如何利用 Solr 實作檢索功能,並結合程式碼實作來說明其運作原理。

Solr 的搜尋機制

當你在 Solr 中執行搜尋時,它會採用一種聰明的機制來找出與查詢最相關的檔案。首先,Solr 會分析你的搜尋查詢,並將其與已索引的資料進行比較,以找出符合搜尋條件的檔案。接著,它會根據各種因素(如搜尋詞在檔案中出現的頻率)對這些檔案進行排名。這樣可以確保最相關的結果被顯示給你,從而使你的搜尋體驗更快、更準確。

你可以使用類別似以下的查詢來搜尋單一詞彙:

curl "http://localhost:8983/solr/Manuals/select?q=Nokia"

或者,你也可以直接透過 Solr 的 UI 進行查詢,如圖所示。

建立檢索增強問答系統

現在,讓我們開始建立我們的檢索增強問答系統。首先,我們需要定義一個名為 solr_retriever() 的函式,該函式接受使用者輸入的查詢。

import requests
import re
import pandas as pd

def solr_retriever(question):
    solr_url = f'http://localhost:7574/solr/Manuals/select?q={question}&q.op=AND&wt=json'
    response = requests.get(solr_url)
    query_results = response.json()
    total_documents = query_results['response']['numFound']
    print(f"{total_documents} documents found.")
    
    results_list = []
    
    if total_documents > 0:
        total_documents = min(total_documents, 10)
        for i in range(total_documents):
            content_unicode = query_results['response']['docs'][i]['content'][0]
            content_decoded = content_unicode.encode("ascii", "ignore").decode()
            keyword = "{: shortdesc} "
            cleaned_text = skip_unwanted_characters(content_decoded, keyword)
            pattern = r'\{\s*:\s*[\w#-]+\s*\}|\{\s*:\s*\w+\s*\}|\n\s*\n'
            cleaned_text = re.sub(pattern, '', cleaned_text)
            cleaned_text = preprocess_text(cleaned_text)
            document_info = {
                "document": {
                    "rank": i,
                    "document_id": query_results['response']['docs'][i]['id'][0],
                    "text": cleaned_text[1000:3000],
                },
            }
            results_list.append(document_info)
        
        results_to_display = [result['document'] for result in results_list]
        df = pd.DataFrame.from_records(results_to_display, columns=['rank', 'document_id', 'text'])
        df.dropna(inplace=True)
        print('===========================================================')
        print(f'QUERY: {question}')
        return results_list

內容解密:

  1. solr_retriever() 函式:此函式負責向 Solr 伺服器傳送查詢請求,並處理傳回的結果。
  2. URL 建構solr_url 是根據使用者輸入的 question 建構的,用於向 Solr 伺服器傳送 GET 請求。
  3. 結果處理:函式首先取得符合查詢的檔案總數,然後對結果進行處理,包括文字清理和格式化,最後傳回相關檔案的資訊列表。
  4. 文字清理:使用正規表示式和特定的清理函式(如 skip_unwanted_characterspreprocess_text)來清理和格式化文字內容。
  5. 結果展示:將處理後的結果儲存於 DataFrame 中,並列印查詢結果。

程式碼解析

該程式碼主要分為以下幾個區塊:

  1. URL 建構和請求:建構 Solr 查詢 URL 並傳送 GET 請求,取得查詢結果。

    solr_url = f'http://localhost:7574/solr/Manuals/select?q={question}&q.op=AND&wt=json'
    response = requests.get(solr_url)
    query_results = response.json()
    

    內容解密:

    • 建構查詢 URL,包含查詢引數和運算子。
    • 傳送 GET 請求至 Solr 伺服器。
    • 將傳回的 JSON 回應解析為 Python 物件。
  2. 檔案資訊提取:從查詢結果中提取相關檔案資訊。

    total_documents = query_results['response']['numFound']
    print(f"{total_documents} documents found.")
    

    內容解密:

    • 取得符合查詢的檔案總數。
    • 列印檔案總數。
  3. 搜尋結果處理:處理搜尋結果,包括文字清理和格式化。

    for i in range(total_documents):
        content_unicode = query_results['response']['docs'][i]['content'][0]
        content_decoded = content_unicode.encode("ascii", "ignore").decode()
        # ... 其他清理步驟
    

    內容解密:

    • 對每個檔案進行迭代處理。
    • 清理和格式化檔案內容。
  4. 結果展示:將處理後的結果儲存於 DataFrame 中並展示。

    results_to_display = [result['document'] for result in results_list]
    df = pd.DataFrame.from_records(results_to_display, columns=['rank', 'document_id', 'text'])
    df.dropna(inplace=True)
    

    內容解密:

    • 將結果列表轉換為適合展示的格式。
    • 建立 DataFrame 以便於結果的展示和進一步處理。
  5. 輸出和傳回:列印查詢結果並傳回相關檔案的資訊列表。

    print(f'QUERY: {question}')
    return results_list
    

    內容解密:

    • 列印目前查詢的問題。
    • 傳回包含檔案資訊的列表。