iT邦幫忙

2024 iThome 鐵人賽

DAY 15
0
生成式 AI

從系統設計切入,探索 GenAI 在企業中的實踐系列 第 15

[Day15] 掌握設計模式開發核心組件-單例、工廠模式

  • 分享至 

  • xImage
  •  

以下提及課程為 LLM Twin: Building Your Production-Ready AI Replica


在整理完在 GenAI 開發過程中,隨著規模大,影響開發效率最顯著的部份後,接著回課程內容,由於現在還在鐵人賽期間,每天能產出的篇幅有限,我的修課方式會是每天從課程中提取一個重點來延伸撰寫。

今天的主題聚焦於設計模式,在第一堂爬蟲系統開發中的應用中,作者介紹了 LinkedIn、Medium、GitHub 和 Substack 等平台的資料爬取工具的程式碼,並將內容分別整理為文章、社群貼文和程式碼進行儲存。而這即是借用設計模式的幫助,不僅提高了程式的重用性、也增強了系統的可維護性和擴展性。

其中作者主要使用了三種設計模式,首先是在 BaseAbstractCrawler 類別中實踐 模板方法模式(Template Method Pattern),將共用邏輯像是登入與頁面滾動這些重複的部分集中管理,減少冗餘的程式碼;而 策略模式(Strategy Pattern) 則讓系統更有彈性和擴展性,使得增加新類型的爬蟲變得簡單而直觀;最後是 工廠方法模式(Factory Method Pattern) 的運用,讓系統可以依據不同參數動態調整的爬蟲實體,提強了整個系統的適應能力。

這樣的設計為接下來的擴展帶來了便利性,舉例來說,當需要新增新平台(如Twitter)的爬蟲工具時,我們只需創建一個新的 TwitterCrawler 類別並實作其中的功能,就可以在不改動現有程式的情況下,實現無縫整合。不僅簡化了開發流程,同時維持系統的一致性和可靠性。


在總共 23 個設計模式當中,我挑選了六個使用頻率高、也是相對好理解的方法來介紹,並各自列舉幾個能在 GenAI 開發應用的情境,配合了一個程式範例:

設計模式 重點 GenAI 應用
單例模式 (Singleton) 確保全局唯一實例 LLM 模型初始化
工廠模式 (Factory Method) 靈活創建對象 跨型態檔案讀取
觀察者模式 (Observer) 實現事件驅動 資料庫更新觸發處理
模板模式 (Template Method) 定義算法骨架 資料前處理流程框架
裝飾器模式 (Decorator) 動態添加功能 靈活組合資料處理步驟
策略模式 (Strategy) 動態切換算法 檢索策略調整

單例模式 (Singleton)

  1. 介紹:是一種創建型設計模式,主要是確保一個類別在整個系統中只有一個實體存在。常應用於全局資源管理,尤其是大型或資源密集型對象。
  2. Gen AI 應用情境:
    • LLM 管理:確保整個服務中只有一個 LLM 實體,如 GPT-4,避免多次加載造成的資源浪費。
    • 向量數據庫連接:維護單一的向量數據庫連接,確保所有操作都使用相同的連接,提高效率並簡化資源管理。
    • 檢索引擎:為檢索引擎創建單一實體,確保所有查詢使用相同的索引和配置。
    • 全局配置管理:管理RAG系統的全局配置,如 API key、模型參數等。
    • 緩存系統:創建統一的緩存實體,用於儲存常見查詢結果或中間處理數據,提高響應速度。
  3. 案例與說明:以下使用單例模式實現 LLM 加載。
import time

class LargeLanguageModel:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            print("初始化大型語言模型...")
            cls._instance = super().__new__(cls)
            cls._instance.model = "GPT-4"  # 假設使用 GPT-4
            time.sleep(2)  # 模擬模型加載時間
        return cls._instance

    def generate_response(self, prompt: str) -> str:
        return f"這是 {self.model} 對 '{prompt}' 的回應:..."

def chat_with_ai(prompt: str) -> str:
    llm = LargeLanguageModel() 
    return llm.generate_response(prompt)

def main():
    prompts = [
        "什麼是機器學習?",
        "解釋一下深度學習",
        "AI 的未來發展趨勢是什麼?"
    ]
    # 當多次呼叫 LLM 時,只會建立一個實例
    for prompt in prompts:
        print(f"\n用戶: {prompt}")
        response = chat_with_ai(prompt)
        print(f"AI: {response}")

if __name__ == "__main__":
    main()
  1. LargeLanguageModel 類使用 __new__ 實現單例模式。首次創建實體時,它會初始化模型。
  2. 後續的實體化請求會直接返回已創建的實體,避免重複初始化。
  3. chat_with_ai 函數每次調用都會獲取 LLM 實例,但實際上總是使用同一個實體。
  4. 主程序模擬了多次使用 LLM 的場景,展示了即使多次調用,也只會創建和使用一個 LLM 實體。

工廠方法模式 (Factory Method)

  1. 介紹:是一種創建型設計模式,提供了一種靈活的方式來創建不同類型的物件。這種設計使得系統更容易擴展新的類型,同時降低了系統各部分的耦合度。
  2. Gen AI 應用情境:
    • 模型選擇:根據任務類型(如文本生成、圖像生成、代碼生成等)動態選擇適合的 AI 模型。
    • 提示工程(Prompt Engineering):為不同類型的生成任務創建專門的提示模板工廠,以優化提示效果。
    • 輸出格式化:根據不同的輸出需求(如 JSON、HTML、純文本等)選擇適當的輸出格式化器。
    • 資料預處理管道:為不同類型的輸入數據(如結構化數據、非結構化文本、圖像等)創建專門的預處理管道。
    • 向量化策略:根據不同的嵌入模型或任務需求,選擇適當的文本向量化方法。
    • 微調策略選擇:根據模型類型和任務需求,選擇合適的微調策略(如 LoRA、P-tuning 等)。
    • 評估指標工廠:根據不同的生成任務,動態選擇合適的評估指標(如 BLEU、ROUGE、自定義指標等)。
    • 部署策略:根據不同的部署環境(如雲端、邊緣設備、移動端等)選擇適當的模型優化和部署方法。
  3. 案例與說明:以下是一個使用工廠方法模式實現文件加載器的Python示例。
from abc import ABC, abstractmethod
import csv
from typing import List, Dict

class DocumentLoader(ABC):
    @abstractmethod
    def load(self, file_path: str) -> str:
        pass

class PDFLoader(DocumentLoader):
    def load(self, file_path: str) -> str:
        # 在實際應用中,這裡會使用如 PyPDF2 之類的庫來讀取 PDF
        print(f"使用 PDF 加載器讀取文件:{file_path}")
        return f"這是從 {file_path} 讀取的 PDF 內容"

class TXTLoader(DocumentLoader):
    def load(self, file_path: str) -> str:
        print(f"使用 TXT 加載器讀取文件:{file_path}")
        with open(file_path, 'r', encoding='utf-8') as file:
            return file.read()

class DocumentLoaderFactory:
    @staticmethod
    def create_loader(file_type: str) -> DocumentLoader:
        if file_type.lower() == "pdf":
            return PDFLoader()
        elif file_type.lower() == "txt":
            return TXTLoader()
        else:
            raise ValueError(f"不支持的文件類型: {file_type}")

# 使用範例
def process_document(file_path: str, file_type: str):
    factory = DocumentLoaderFactory()
    loader = factory.create_loader(file_type)
    content = loader.load(file_path)
    return content

def main():
    # 模擬處理不同類型的文件
    pdf_content = process_document("example.pdf", "pdf")
    txt_content = process_document("example.txt", "txt")

if __name__ == "__main__":
    main()
  1. DocumentLoader 是一個抽象基類,定義了文件加載器的通用接口。
  2. PDFLoaderTXTLoader 是具體的加載器類,實現了特定文件類型的加載邏輯。
  3. DocumentLoaderFactory 是工廠類,根據文件類型創建相應的加載器。
  4. process_document 函數展示了如何使用工廠來處理不同類型的文件,而不需要知道具體的加載器實現細節。
  5. 主程序模擬了處理不同類型文件的場景,展示了工廠方法的靈活性。

這種設計允許我們輕鬆地添加新的文件類型支持(如 CSV、JSON 等),只需創建新的加載器類並在工廠中添加相應的邏輯。這提高了系統的可擴展性和維護性,特別適合處理多種數據源的RAG系統。

接下來的四個案例會在明天繼續介紹:)


ref.
Refactoring.Guru | design-patterns


上一篇
[Day14] 加速開發:CI/CD 實踐自動化部署策略
下一篇
[Day16] 掌握設計模式開發核心組件-觀察者、模板模式
系列文
從系統設計切入,探索 GenAI 在企業中的實踐30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言