ChatModelFactory、EmbeddingModelFactory
講解代碼:import os
from dotenv import load_dotenv, find_dotenv_ = load_dotenv(find_dotenv())from langchain_openai import ChatOpenAI, OpenAIEmbeddings, AzureChatOpenAI, AzureOpenAIEmbeddingsclass ChatModelFactory:model_params = {"temperature": 0,"seed": 42,}@classmethoddef get_model(cls, model_name: str, use_azure: bool = False):if "gpt" in model_name:if not use_azure:return ChatOpenAI(model=model_name, **cls.model_params)else:return AzureChatOpenAI(azure_deployment=model_name,api_version="2024-05-01-preview",**cls.model_params)elif model_name == "deepseek":# 換成開源模型試試# https://siliconflow.cn/# 一個 Model-as-a-Service 平臺# 可以通過與 OpenAI API 兼容的方式調用各種開源語言模型。return ChatOpenAI(model="deepseek-ai/DeepSeek-V2-Chat", # 模型名稱openai_api_key=os.getenv("SILICONFLOW_API_KEY"), # 在平臺注冊賬號后獲取openai_api_base="https://api.siliconflow.cn/v1", # 平臺 API 地址**cls.model_params,)@classmethoddef get_default_model(cls):return cls.get_model("gpt-3.5-turbo")class EmbeddingModelFactory:@classmethoddef get_model(cls, model_name: str, use_azure: bool = False):if model_name.startswith("text-embedding"):if not use_azure:return OpenAIEmbeddings(model=model_name)else:return AzureOpenAIEmbeddings(azure_deployment=model_name,openai_api_version="2024-05-01-preview",)else:raise NotImplementedError(f"Model {model_name} not implemented.")@classmethoddef get_default_model(cls):return cls.get_model("text-embedding-ada-002")
以下是這段代碼的逐層解析,該代碼實現了大語言模型(LLM)和嵌入模型的統一調用接口,支持多種云服務和開源模型:
一、環境初始化
import os
from dotenv import load_dotenv, find_dotenv# 加載.env文件中的環境變量
_ = load_dotenv(find_dotenv())
- 關鍵技術:
dotenv
庫自動尋找項目根目錄下的.env
文件(包括上級目錄)- 將環境變量(如API Key)注入系統環境變量
- 典型
.env
內容:OPENAI_API_KEY = "sk-xxx" AZURE_OPENAI_KEY = "azure-xxx" SILICONFLOW_API_KEY = "sf-xxx"
二、聊天模型工廠(ChatModelFactory)
1. 基礎配置
class ChatModelFactory:model_params = {"temperature": 0, # 控制生成隨機性(0=確定性最高)"seed": 42, # 固定隨機種子保證可復現性}
- 核心參數:
temperature
: 影響生成多樣性(0為最保守,1為最隨機)seed
: 確保相同輸入得到相同輸出(對測試和調試至關重要)
2. 模型選擇邏輯
@classmethod
def get_model(cls, model_name: str, use_azure: bool = False):# OpenAI官方服務if "gpt" in model_name:if not use_azure:return ChatOpenAI(model=model_name, **cls.model_params)else:return AzureChatOpenAI(azure_deployment=model_name, # Azure部署名稱api_version="2024-05-01-preview", # 最新API版本**cls.model_params)# 第三方開源模型平臺elif model_name == "deepseek":return ChatOpenAI(model="deepseek-ai/DeepSeek-V2-Chat",openai_api_key=os.getenv("SILICONFLOW_API_KEY"),openai_api_base="https://api.siliconflow.cn/v1",**cls.model_params,)
-
多服務支持:
服務類型 適用場景 關鍵參數 OpenAI官方 直接使用OpenAI的API model="gpt-3.5-turbo"
Azure OpenAI 企業級Azure云服務 azure_deployment
SiliconFlow平臺 調用DeepSeek等國產開源模型 自定義API Base URL -
設計亮點:
- 統一接口:不同服務使用相同調用方式(均繼承自
BaseChatModel
) - 無縫切換:通過
use_azure
布爾參數切換云服務商 - 開箱即用:預置最新API版本(
2024-05-01-preview
)
- 統一接口:不同服務使用相同調用方式(均繼承自
3. 默認模型配置
@classmethod
def get_default_model(cls):return cls.get_model("gpt-3.5-turbo")
- 最佳實踐:將
gpt-3.5-turbo
設為默認模型(性價比與性能平衡)
三、嵌入模型工廠(EmbeddingModelFactory)
1. 模型分發邏輯
class EmbeddingModelFactory:@classmethoddef get_model(cls, model_name: str, use_azure: bool = False):if model_name.startswith("text-embedding"):if not use_azure:return OpenAIEmbeddings(model=model_name)else:return AzureOpenAIEmbeddings(azure_deployment=model_name,openai_api_version="2024-05-01-preview",)else:raise NotImplementedError(f"Model {model_name} not implemented.")
- 模型識別:通過
text-embedding
前綴判斷為嵌入模型 - 服務兼容性:
- OpenAI:直接指定模型名稱(如
text-embedding-ada-002
) - Azure:使用部署名稱(需與Azure門戶中的部署名一致)
- OpenAI:直接指定模型名稱(如
2. 默認配置
@classmethod
def get_default_model(cls):return cls.get_model("text-embedding-ada-002")
- 行業標準:
text-embedding-ada-002
是OpenAI最常用的嵌入模型
四、關鍵技術點解析
1. 環境變量管理
- 安全實踐:通過
.env
文件隔離敏感信息 - 多平臺支持:
即使使用非OpenAI服務,也復用# SiliconFlow示例 openai_api_key=os.getenv("SILICONFLOW_API_KEY") openai_api_base="https://api.siliconflow.cn/v1"
openai_
前綴的參數名,保持接口統一
2. 工廠模式優勢
優勢 | 具體體現 |
---|---|
解耦合 | 業務代碼無需關心模型初始化細節 |
擴展性 | 新增模型只需修改工廠類 |
配置集中化 | 所有模型參數在單個類中管理 |
3. 多云服務兼容
# Azure的特殊參數
AzureChatOpenAI(azure_deployment="gpt-35-turbo", # 部署名稱(可能與模型名不同)api_version="2024-05-01-preview" # 必須指定
)
- 注意差異:Azure的部署名稱可能與OpenAI模型名稱不同(如
gpt-35-turbo
對應OpenAI的gpt-3.5-turbo
)
五、使用示例
1. 基礎調用
# 獲取默認聊天模型
chat_model = ChatModelFactory.get_default_model()# 獲取Azure版嵌入模型
embed_model = EmbeddingModelFactory.get_model("text-embedding-ada-002", use_azure=True
)
2. 完整工作流
from langchain.schema import HumanMessage# 初始化模型
model = ChatModelFactory.get_model("gpt-4", use_azure=False)# 執行對話
messages = [HumanMessage(content="你好!")]
response = model.invoke(messages)
print(response.content)
六、擴展建議
1. 添加新模型支持
# 在ChatModelFactory中添加
elif model_name == "moonshot":return ChatOpenAI(model="moonshot-v1",openai_api_key=os.getenv("MOONSHOT_API_KEY"),openai_api_base="https://api.moonshot.cn/v1",**cls.model_params)
2. 動態參數配置
# 允許運行時修改參數
@classmethod
def get_model(cls, model_name: str, **kwargs):params = {**cls.model_params, **kwargs}return ChatOpenAI(model=model_name, **params)
3. 錯誤處理增強
try:return AzureChatOpenAI(...)
except AuthenticationError as e:print("Azure認證失敗,請檢查API Key和部署名稱")
七、架構圖示
該代碼為構建多模型AI應用提供了標準化基礎設施,開發者可以通過簡單的參數切換實現:
- 不同云服務商之間的遷移
- 開源模型與商業模型的混合使用
- 嵌入模型與對話模型的協同工作
@Classmethod
@classmethod
是 Python 中一個重要的裝飾器,用于定義類方法。它的核心作用是為類提供一種不依賴實例卻能操作類本身或類層級數據的途徑。以下是逐層解析:
一、核心特性
1. 方法簽名
class MyClass:@classmethoddef my_method(cls, arg1, arg2): # 第一個參數必須是類本身(慣例命名為`cls`)pass
cls
參數:自動接收當前類(而非實例)作為第一個參數- 調用方式:可通過
類名.方法名()
或實例.方法名()
調用
2. 與普通實例方法的對比
方法類型 | 第一個參數 | 可訪問內容 | 典型用途 |
---|---|---|---|
實例方法 | self | 實例屬性/方法 | 操作實例級數據 |
類方法 | cls | 類屬性/其他類方法 | 工廠模式、類配置操作 |
二、核心應用場景
1. *工廠模式(核心代碼中的用法)
class ChatModelFactory:@classmethoddef get_model(cls, model_name: str): # 不創建實例即可獲取模型if model_name == "gpt":return cls._create_openai_model()else:return cls._create_custom_model()# 直接通過類調用
model = ChatModelFactory.get_model("gpt")
- 優勢:無需實例化工廠類即可創建目標對象
- 擴展性:子類可重寫方法改變創建邏輯
2. 替代構造函數
class Date:def __init__(self, year, month, day):self.year = year@classmethoddef from_string(cls, date_str): # 接受不同格式的輸入year, month, day = map(int, date_str.split("-"))return cls(year, month, day) # 調用主構造函數# 使用示例
date = Date.from_string("2023-08-01")
3. 類狀態管理
class Counter:_count = 0@classmethoddef increment(cls):cls._count += 1 # 修改類屬性@classmethoddef get_count(cls):return cls._count # 讀取類屬性Counter.increment()
print(Counter.get_count()) # 輸出: 1
三、繼承場景下的行為
class Animal:@classmethoddef identify(cls):print(f"I am {cls.__name__}")class Dog(Animal):passAnimal.identify() # 輸出: I am Animal
Dog.identify() # 輸出: I am Dog 🐛 cls自動指向實際調用類
- 多態性:子類調用父類方法時,
cls
指向子類 - 應用價值:實現繼承鏈中的工廠方法
四、與 @staticmethod
的對比
特性 | @classmethod | @staticmethod |
---|---|---|
第一個參數 | 自動傳入類 (cls ) | 無自動參數 |
訪問類屬性 | ? 可直接通過cls 訪問 | ? 需通過類名硬編碼訪問 |
調用其他類方法 | ? 可通過cls.method() | ? 需硬編碼類名 |
典型應用場景 | 需要類引用的操作 | 工具函數 |
代碼示例對比
class Utilities:@classmethoddef class_util(cls):print(f"Called from {cls.__name__}")@staticmethoddef static_util():print("Generic utility")class SubUtilities(Utilities):passSubUtilities.class_util() # 輸出: Called from SubUtilities
SubUtilities.static_util() # 輸出: Generic utility
五、在示例代碼中的作用
class ChatModelFactory:model_params = {"temperature": 0} # 類屬性@classmethoddef get_model(cls, model_name: str):return ChatOpenAI(**cls.model_params) # 通過cls訪問類屬性
- 統一配置管理:通過
cls.model_params
確保所有方法使用相同配置 - 無需實例化:直接
ChatModelFactory.get_model()
調用 - 擴展性:子類可重寫
model_params
改變默認參數
六、最佳實踐原則
- 優先用于工廠方法:當需要創建類實例但需封裝復雜邏輯時
- 避免濫用:不需要訪問類狀態時使用
@staticmethod
- 命名規范:始終將第一個參數命名為
cls
(非強制但強烈建議) - 繼承友好設計:通過
cls
實現多態,而非硬編碼類名
掌握 @classmethod
的使用,能大幅提升面向對象代碼的靈活性和可維護性,尤其在需要類層級操作而非實例層級操作的場景下表現出色。