大语言模型(LLM)和嵌入模型的统一调用接口
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_deploymentSiliconFlow平台 调用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 的使用,能大幅提升面向对象代码的灵活性和可维护性,尤其在需要类层级操作而非实例层级操作的场景下表现出色。
相关文章:
大语言模型(LLM)和嵌入模型的统一调用接口
ChatModelFactory、EmbeddingModelFactory 讲解代码:import os from dotenv import load_dotenv, find_dotenv_ load_dotenv(find_dotenv())from langchain_openai import ChatOpenAI, OpenAIEmbeddings, AzureChatOpenAI, AzureOpenAIEmbeddingsclass ChatModelF…...
大白话html语义化标签优势与应用场景
大白话html语义化标签优势与应用场景 大白话解释 语义化标签就是那些名字能让人一看就大概知道它是用来做什么的标签。以前我们经常用<div>来做各种布局,但是<div>本身没有什么实际的含义,就像一个没有名字的盒子。而语义化标签就像是有名…...
Scala:在哪里写类的属性?类的属性必须私有吗?类的必须初始化吗?
哪里写类的属性 直接在类体中定义属性 class Circle {private var _radius: Double 0.0def radius: Double _radiusdef radius_(newRadius: Double): Unit {_radius newRadius}def area: Double scala.math.Pi * _radius * _radius } 可以在类体内部直接定义属性。例如&am…...
Android源码编译命令详解
一、引言 先看下面几条指令,相信编译过Android源码的人都再熟悉不过的。 source setenv.sh lunch make -j8记得最初刚接触Android时,同事告诉我用上面的指令就可以编译Android源码,指令虽短但过几天就记不全或者忘记顺序,每次编…...
任务11:路由器配置与静态路由配置
目录 一、概念 二、路由器配置 三、配置静态路由CSDN 原创主页:不羁https://blog.csdn.net/2303_76492156?typeblog 一、概念 1、路由器的作用:通过路由表进行数据的转发。 2、交换机的作用:通过学习和识别 MAC 地址,依据 M…...
Unity之如何实现哔哩哔哩直播弹幕游戏
前言 什么是直播间互动? 当我们使用哔哩哔哩进行直播或者观看视频时,我们可以通过接入哔哩哔哩提供的 直播&互动玩法SDK,让直播和视频可以与Unity3D游戏客户端或者游戏服务器进行互动。 环境要求 Unity 2020.x或更高版本 依赖库:Newtonsoft Json Unity Package 在P…...
Python实例:PyMuPDF实现PDF翻译,英文翻译为中文,并按段落创建中文PDF
基于PyMuPDF与百度翻译的PDF翻译处理系统开发:中文乱码解决方案与自动化排版实践 一 、功能预览:将英文翻译为中文后创建的PDF 二、完整代码 from reportlab.lib.pagesizes import letter from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle...
LeeCode题库第四十六题
46.全排列 项目场景: 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&am…...
LangChain4j开发RAG入门示例
本文将详细介绍如何基于Java语言,使用Langchain4j开源框架、Milvus向量数据、阿里Qwen大模型,开发一个RAG入门级简单示例。本示例虽然简单,但涉及到多个知识点,包括:Milvus初始化、Embedding模型、文档切片、Springboo…...
快速从C过度C++(一):namespace,C++的输入和输出,缺省参数,函数重载
📝前言: 本文章适合有一定C语言编程基础的读者浏览,主要介绍从C语言到C过度,我们首先要掌握的一些基础知识,以便于我们快速进入C的学习,为后面的学习打下基础。 这篇文章的主要内容有: 1&#x…...
课程《Deep Learning Specialization》
在coursera上,Deep Learning Specialization 课程内容如下图所示:...
微服务与消息队列RabbitMQ
简介 同步模式 异步模式 内容 解决方案RabbitMQ 同步调用的优缺点 同步调用的优势是什么? 时效性强,等待到结果后才返回。 同步调用的问题是什么? 拓展性差性能下降级联失败问题...
苹果 M3 Ultra 芯片深度解析:AI 时代的性能革命
2025 年 3 月 5 日,苹果正式发布了其史上最强 PC 芯片 ——M3 Ultra。这款基于 UltraFusion 封装技术的旗舰级 SoC,不仅延续了苹果芯片在能效比上的传统优势,更通过架构创新与硬件升级,将 AI 计算能力推向了新高度。本文将从性能突…...
通义千问:Qwen2.5-0.5B模型架构解释
通义千问:Qwen2.5-0.5B模型架构解释 1. 模型权重文件 .mdl、.msc:存储模型核心参数,是模型训练后学习到的知识载体,包含神经网络各层权重,加载后模型才能执行推理、生成等任务。 .mdl文件:通常是模型的核心权重数据文件,存储神经网络各层的权重参数、张量等关键数据,是…...
安装完flash-attn,使用时报错undefined symbol
去flash attention官网下载安装包, 注意需要根据自己的torch版本,cuda版本(可以选择低于自己cuda版本的) 和python版本进行选择。 如果whl文件名上包含参数abiTRUE,则会报错。需要安装包含abiFALSE的whl文件。 卸载:卸载原先报错的flash-attn pip uni…...
【Linux】冯诺依曼体系与操作系统理解
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:Linux 目录 前言 一、冯诺依曼体系结构 二、操作系统 1. 操作系统的概念 2. 操作系统存在的意义 3. 操作系统的管理方式 4. 补充:理解系统调用…...
玩转ChatGPT:GPT 深入研究功能
一、写在前面 民间总结: 理科看Claude 3.7 Sonnet 文科看DeepSeek-R1 那么,ChatGPT呢? 看Deep Research(深入研究)功能。 对于科研狗来说,在这个文章爆炸的时代,如何利用AI准确、高效地收…...
虚函数和虚表的原理是什么?
虚函数是一个使用virtual关键字声明的成员函数,在基类中声明虚函数,在子类中可以使用override重写该函数。虚函数根据指针或引用指向的实际对象调用,实现运行时的多态。 虚函数表(虚表)是一个用于存储虚函数地址的数组…...
laravel es 相关代码 ElasticSearch
来源: github <?phpnamespace App\Http\Controllers;use Elastic\Elasticsearch\ClientBuilder; use Illuminate\Support\Facades\DB;class ElasticSearch extends Controller {public $client null;public function __construct(){$this->client ClientB…...
字节跳动C++客户端开发实习生内推-抖音基础技术
智能手机爱好者和使用者,追求良好的用户体验; 具有良好的编程习惯,代码结构清晰,命名规范; 熟练掌握数据结构与算法、计算机网络、操作系统、编译原理等课程; 熟练掌握C/C/OC/Swift一种或多种语言ÿ…...
C语言_数据结构总结6:链式栈
纯c语言代码,不涉及C 顺序栈的实现,欢迎查看这篇文章:C语言_数据结构总结5:顺序栈-CSDN博客 0. 结构单元 #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef struct Linknode { ElemType…...
DQN(Deep Q - Network)原理举例说明
DQN(Deep Q - Network)原理举例说明 1. 基本概念回顾 DQN 结合了深度学习和 Q - learning 算法,用深度神经网络来近似 Q 值函数,解决传统 Q - learning 在处理高维状态空间时的局限性。Q 值表示在某个状态下采取某个动作所能获得的期望累积奖励。 以下是DQN和A3C的原理对…...
物联网-IoTivity:开源的物联网框架
IoTivity 是一个开源的物联网(IoT)框架,旨在为物联网设备提供互操作性、安全性和可扩展性。它由 Open Connectivity Foundation (OCF) 主导开发,遵循 OCF 的标准,致力于实现设备之间的无缝连接和通信。IoTivity 提供了一个统一的框架,支持设备发现、数据交换、设备管理和…...
基于DeepSeek的智慧医药系统(源码+部署教程)
运行环境 智慧医药系统运行环境如下: 前端: HTMLCSS后端:Java AIGCDeepseekIDE工具:IDEA技术栈:Springboot HTMLCSS MySQL 主要角色 智慧医药系统主要分为两个角色。 游客 尚未进行注册和登录。具备登录注册、…...
基于Linux系统的边缘智能终端(RK3568+EtherCAT+PCIe+4G+5G)
背景 现有产品基本都是传统的产品,比如之前写的RTU还有基于Linux系统的物联网采集终端都是传统意义的产品,大家做的都差不多,能拼的除了价格之外就是软硬件的基本功了,好的产品肯定是要经过时间的磨合的。没有任何人可以写出来没有…...
Java 线程池内部任务出异常后,如何知道是哪个线程出了异常?
你的回答(口语化,面试场景) 好的,这个问题需要结合线程池的异常处理机制来回答。 Java线程池内部任务抛出的异常默认会被“吞掉”,但可以通过以下方法定位具体线程的异常: 方法1:在任务代码中捕…...
热图回归(Heatmap Regression)
热图回归(Heatmap Regression)是一种常用于关键点估计任务的方法,特别是在人体姿态估计中。它的基本思想是通过生成热图来表示某个关键点在图像中出现的概率或强度。以下是热图回归的主要特点和工作原理: 主要特点 热图表示: 每个关键点对应一个热图,热图中的每个像素值…...
信奥赛CSP-J复赛集训(模拟算法专题)(6):P6352 [COCI 2007/2008 #3] CETIRI
信奥赛CSP-J复赛集训(模拟算法专题)(6):P6352 [COCI 2007/2008 #3] CETIRI 题目描述 你原本有 4 4 4 个数,它们从小到大排序后构成了等差数列。 但是现在丢失了一个数,并且其余的三个数的顺序…...
2025-03-09 学习记录--C/C++-PTA 习题11-1 输出月份英文名
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。💪🏻 一、题目描述 ⭐️ 裁判测试程序样例: #include <stdio.h>char *getmonth( int n );int main() {int n;char …...
spring IOC(实现原理)
文章目录 依赖注入控制反转相关Spring 框架的 Bean管理的配置文件方式实例化Bean的三种方式无参构造器实例化静态工厂方法实例化实例工厂方法实例化静态和动态对比 注解常用注解纯注解 其它问题为什么p 命名空间方式需要无参构造 依赖注入 **依赖注入(DI࿰…...
