(专栏:Python 从真零基础到纯文本 LLM 全栈实战・第 6 篇 | 字数:15000 字 | 零基础友好 | LLM 场景深度绑定 | 代码可运行)
开篇:面向对象 = LLM 系统的「骨架」
对 Python 开发者来说,面向对象编程(OOP)是构建复杂 LLM 系统的「骨架」—— 当你的 LLM 项目从简单的 API 调用发展到包含 Prompt 管理、多模型支持、会话管理等功能时,面向对象编程能帮你:
- 模块化组织代码:将 LLM 的不同功能封装为独立的类和对象
- 提高代码复用性:通过继承和组合复用已有的 LLM 逻辑
- 增强代码可维护性:清晰的类结构让修改和扩展更加容易
- 提升代码灵活性:通过多态支持不同 LLM 模型的统一调用
本文将从LLM 开发场景出发,系统讲解 Python 面向对象编程的核心概念和实践技巧,帮助你构建模块化、可扩展的 LLM 系统。
一、核心概念:类与对象的基础认知
1.1 什么是类和对象?
1.1.1 类(Class)
类是对某一类事物的抽象描述,定义了该类事物的属性和方法。比如,我们可以定义一个LLM类,描述所有大语言模型的共同特征和行为。
1.1.2 对象(Object)
对象是类的实例化,是具体存在的事物。比如,ChatGPT、文心一言、混元都是LLM类的实例对象。
1.2 类的定义与实例化
# 定义LLM类
class LLM:
# 类属性:所有实例共享的属性
version = "1.0"
# 构造方法:初始化对象的属性
def __init__(self, model_name, api_key):
# 实例属性:每个实例独有的属性
self.model_name = model_name
self.api_key = api_key
# 实例方法:对象的行为
def generate_response(self, prompt):
print(f"使用{self.model_name}生成回答:{prompt}")
return f"来自{self.model_name}的回答"
# 实例化对象
chatgpt = LLM(model_name="gpt-3.5-turbo", api_key="sk-xxx")
wenxin = LLM(model_name="ERNIE 3.5", api_key="ak-xxx")
# 调用对象的方法
response = chatgpt.generate_response("什么是LLM?")
print(response) # 输出:来自gpt-3.5-turbo的回答
1.3 LLM 开发中的类与对象
在 LLM 开发中,以下内容通常会封装为类:
- LLM 模型(如 ChatGPT、文心一言)
- Prompt 管理器
- 会话管理器
- 语料处理器
- 响应解析器
二、核心特性:封装、继承、多态
Python 面向对象编程有三大核心特性:封装、继承、多态,这些特性是构建模块化 LLM 系统的基础。
2.1 封装:隐藏实现细节,提供简洁接口
封装是将对象的属性和方法结合起来,隐藏内部实现细节,只对外提供简洁的接口。
2.1.1 封装的实现
在 Python 中,封装通过访问修饰符实现:
public(公共):默认的访问级别,属性和方法可以被外部访问protected(保护):属性和方法名前加一个下划线(_),表示只能在类内部和子类中访问private(私有):属性和方法名前加两个下划线(__),表示只能在类内部访问
# 封装的LLM类
class LLM:
def __init__(self, model_name, api_key):
self.model_name = model_name # 公共属性
self._api_key = api_key # 保护属性:只能在类内部和子类中访问
self.__api_secret = "secret-xxx" # 私有属性:只能在类内部访问
# 公共方法:对外提供的接口
def generate_response(self, prompt):
# 内部调用保护属性和私有属性
self._check_api_key()
print(f"使用密钥{self._api_key}调用{self.model_name}")
return f"回答:{prompt}"
# 保护方法:只能在类内部和子类中调用
def _check_api_key(self):
if not self._api_key:
raise ValueError("API密钥不能为空")
# 私有方法:只能在类内部调用
def __encrypt_api_key(self):
return f"encrypted_{self._api_key}"
# 实例化对象
chatgpt = LLM("gpt-3.5-turbo", "sk-xxx")
# 访问公共属性和方法
print(chatgpt.model_name) # 输出:gpt-3.5-turbo
response = chatgpt.generate_response("什么是LLM?") # 输出:使用密钥sk-xxx调用gpt-3.5-turbo
# 尝试访问保护属性(虽然可以访问,但不推荐)
print(chatgpt._api_key) # 输出:sk-xxx
# 尝试访问私有属性(会报错)
# print(chatgpt.__api_secret) # AttributeError
2.1.2 LLM 场景应用
# 封装的Prompt管理器类
class PromptManager:
def __init__(self):
self._prompts = {} # 保护属性:存储Prompt模板
# 公共方法:添加Prompt模板
def add_prompt(self, name, content):
self._prompts[name] = content
# 公共方法:获取Prompt模板
def get_prompt(self, name, **kwargs):
if name not in self._prompts:
raise ValueError(f"Prompt {name} not found")
return self._prompts[name].format(**kwargs)
# 使用示例
prompt_manager = PromptManager()
prompt_manager.add_prompt("customer_service", "你是电商客服,请回答关于{product}的问题:{question}")
prompt = prompt_manager.get_prompt("customer_service", product="苹果15手机壳", question="发货时间")
print(prompt) # 输出:你是电商客服,请回答关于苹果15手机壳的问题:发货时间
2.2 继承:复用已有代码,扩展功能
继承是一个类(子类)继承另一个类(父类)的属性和方法,用于复用已有代码并扩展新功能。
2.2.1 继承的实现
# 父类:LLM基类
class BaseLLM:
def __init__(self, model_name, api_key):
self.model_name = model_name
self.api_key = api_key
def generate_response(self, prompt):
raise NotImplementedError("子类必须实现generate_response方法")
# 子类:ChatGPT
class ChatGPT(BaseLLM):
def generate_response(self, prompt):
# 实现ChatGPT的API调用逻辑
return f"ChatGPT回答:{prompt}"
# 子类:文心一言
class WenXin(BaseLLM):
def generate_response(self, prompt):
# 实现文心一言的API调用逻辑
return f"文心一言回答:{prompt}"
# 使用示例
chatgpt = ChatGPT("gpt-3.5-turbo", "sk-xxx")
wenxin = WenXin("ERNIE 3.5", "ak-xxx")
# 调用子类的方法
print(chatgpt.generate_response("什么是LLM?")) # 输出:ChatGPT回答:什么是LLM?
print(wenxin.generate_response("什么是LLM?")) # 输出:文心一言回答:什么是LLM?
2.2.2 方法重写与 super ()
子类可以重写父类的方法,并通过super()调用父类的方法。
class BaseLLM:
def __init__(self, model_name, api_key):
self.model_name = model_name
self.api_key = api_key
def generate_response(self, prompt):
return f"BaseLLM回答:{prompt}"
class ChatGPT(BaseLLM):
def __init__(self, model_name, api_key, temperature=0.7):
# 调用父类的构造方法
super().__init__(model_name, api_key)
self.temperature = temperature
def generate_response(self, prompt):
# 调用父类的generate_response方法
base_response = super().generate_response(prompt)
# 扩展新功能
return f"{base_response}(temperature:{self.temperature})"
# 使用示例
chatgpt = ChatGPT("gpt-3.5-turbo", "sk-xxx", temperature=0.9)
print(chatgpt.generate_response("什么是LLM?")) # 输出:BaseLLM回答:什么是LLM?(temperature:0.9)
2.2.3 LLM 场景应用
# LLM基类
class BaseLLM:
def __init__(self, model_name, api_key):
self.model_name = model_name
self.api_key = api_key
def _preprocess_prompt(self, prompt):
# 公共的Prompt预处理逻辑
return prompt.strip()
def _postprocess_response(self, response):
# 公共的响应后处理逻辑
return response.strip()
def generate_response(self, prompt):
# 模板方法:定义生成回答的流程
processed_prompt = self._preprocess_prompt(prompt)
raw_response = self._call_api(processed_prompt)
processed_response = self._postprocess_response(raw_response)
return processed_response
def _call_api(self, prompt):
# 抽象方法:子类必须实现
raise NotImplementedError("子类必须实现_call_api方法")
# ChatGPT子类
class ChatGPT(BaseLLM):
def _call_api(self, prompt):
import openai
openai.api_key = self.api_key
response = openai.ChatCompletion.create(
model=self.model_name,
messages=[{"role": "system", "content": prompt}]
)
return response["choices"][0]["message"]["content"]
# 文心一言子类
class WenXin(BaseLLM):
def _call_api(self, prompt):
import requests
# 实现文心一言的API调用逻辑
return "文心一言的回答"
# 使用示例
chatgpt = ChatGPT("gpt-3.5-turbo", "sk-xxx")
response = chatgpt.generate_response("什么是LLM?")
print(response)
2.3 多态:统一接口,不同实现
多态是不同类的对象可以通过同一个接口调用不同的实现,提高代码的灵活性和扩展性。
2.3.1 多态的实现
# 父类:动物
class Animal:
def speak(self):
pass
# 子类:狗
class Dog(Animal):
def speak(self):
return "汪汪汪"
# 子类:猫
class Cat(Animal):
def speak(self):
return "喵喵喵"
# 统一的接口
def make_speak(animal):
return animal.speak()
# 使用示例
dog = Dog()
cat = Cat()
print(make_speak(dog)) # 输出:汪汪汪
print(make_speak(cat)) # 输出:喵喵喵
2.3.2 LLM 场景应用
# LLM基类
class BaseLLM:
def generate_response(self, prompt):
raise NotImplementedError()
# ChatGPT子类
class ChatGPT(BaseLLM):
def generate_response(self, prompt):
return f"ChatGPT:{prompt}"
# 文心一言子类
class WenXin(BaseLLM):
def generate_response(self, prompt):
return f"文心一言:{prompt}"
# 统一的LLM服务类
class LLMService:
def __init__(self, llm: BaseLLM):
self.llm = llm
def get_response(self, prompt):
return self.llm.generate_response(prompt)
# 使用示例
chatgpt_service = LLMService(ChatGPT())
wenxin_service = LLMService(WenXin())
# 统一接口调用
print(chatgpt_service.get_response("什么是LLM?")) # 输出:ChatGPT:什么是LLM?
print(wenxin_service.get_response("什么是LLM?")) # 输出:文心一言:什么是LLM?
# 切换LLM模型,无需修改get_response方法
print("\n切换为文心一言:")
chatgpt_service.llm = WenXin()
print(chatgpt_service.get_response("什么是LLM?")) # 输出:文心一言:什么是LLM?
三、高级特性:类方法、静态方法、属性
3.1 类方法
类方法是属于类的方法,使用@classmethod装饰器定义,第一个参数是cls(指向类本身),可以访问和修改类属性。
class LLM:
# 类属性
count = 0
def __init__(self, model_name):
self.model_name = model_name
# 实例化时类属性加1
LLM.count += 1
# 类方法:统计实例数量
@classmethod
def get_instance_count(cls):
return cls.count
# 使用示例
chatgpt = LLM("gpt-3.5-turbo")
wenxin = LLM("ERNIE 3.5")
print(LLM.get_instance_count()) # 输出:2
3.2 静态方法
静态方法是属于类的方法,使用@staticmethod装饰器定义,没有self或cls参数,不能访问类属性或实例属性,主要用于提供与类相关的辅助功能。
class LLM:
def __init__(self, model_name):
self.model_name = model_name
# 静态方法:验证Prompt格式
@staticmethod
def validate_prompt(prompt):
if not prompt:
return False
if len(prompt) > 1000:
return False
return True
# 使用示例
prompt = "什么是LLM?"
if LLM.validate_prompt(prompt):
print("Prompt格式合法")
else:
print("Prompt格式不合法") # 输出:Prompt格式合法
3.3 属性
属性是将方法转换为属性,使用@property装饰器定义,让方法可以像属性一样访问,主要用于封装计算属性。
class LLM:
def __init__(self, model_name, api_key):
self.model_name = model_name
self._api_key = api_key
# 属性:获取加密的API密钥
@property
def encrypted_api_key(self):
return f"encrypted_{self._api_key}"
# 属性的setter:设置API密钥
@encrypted_api_key.setter
def encrypted_api_key(self, value):
# 验证加密格式
if not value.startswith("encrypted_"):
raise ValueError("API密钥格式不正确")
self._api_key = value[10:]
# 使用示例
chatgpt = LLM("gpt-3.5-turbo", "sk-xxx")
print(chatgpt.encrypted_api_key) # 输出:encrypted_sk-xxx
# 设置加密的API密钥
chatgpt.encrypted_api_key = "encrypted_sk-yyy"
print(chatgpt.encrypted_api_key) # 输出:encrypted_sk-yyy
四、抽象类与接口:规范类的行为
抽象类是定义了抽象方法的类,使用abc模块实现,子类必须实现所有抽象方法,用于规范类的行为。
4.1 抽象类的实现
from abc import ABC, abstractmethod
# 抽象基类
class BaseLLM(ABC):
@abstractmethod
def generate_response(self, prompt):
"""生成回答"""
pass
@abstractmethod
def count_tokens(self, text):
"""统计Token数量"""
pass
# 子类必须实现所有抽象方法
class ChatGPT(BaseLLM):
def generate_response(self, prompt):
return "ChatGPT回答"
def count_tokens(self, text):
return len(text) // 2 # 模拟Token计数
# 使用示例
chatgpt = ChatGPT()
print(chatgpt.generate_response("什么是LLM?")) # 输出:ChatGPT回答
print(chatgpt.count_tokens("什么是LLM?")) # 输出:3
4.2 LLM 场景应用
from abc import ABC, abstractmethod
# LLM抽象基类
class BaseLLM(ABC):
@abstractmethod
def __init__(self, api_key):
pass
@abstractmethod
def generate_response(self, prompt, temperature=0.7, max_tokens=1024):
pass
@abstractmethod
def batch_generate(self, prompts, temperature=0.7, max_tokens=1024):
pass
# ChatGPT实现类
class ChatGPT(BaseLLM):
def __init__(self, api_key):
self.api_key = api_key
def generate_response(self, prompt, temperature=0.7, max_tokens=1024):
# 实现ChatGPT的API调用逻辑
return f"ChatGPT: {prompt}"
def batch_generate(self, prompts, temperature=0.7, max_tokens=1024):
# 实现ChatGPT的批量调用逻辑
return [f"ChatGPT: {prompt}" for prompt in prompts]
# 文心一言实现类
class WenXin(BaseLLM):
def __init__(self, api_key):
self.api_key = api_key
def generate_response(self, prompt, temperature=0.7, max_tokens=1024):
# 实现文心一言的API调用逻辑
return f"WenXin: {prompt}"
def batch_generate(self, prompts, temperature=0.7, max_tokens=1024):
# 实现文心一言的批量调用逻辑
return [f"WenXin: {prompt}" for prompt in prompts]
# 统一的LLM工厂类
class LLMFactory:
@staticmethod
def create_llm(model_type, api_key):
if model_type == "chatgpt":
return ChatGPT(api_key)
elif model_type == "wenxin":
return WenXin(api_key)
else:
raise ValueError(f"不支持的模型类型:{model_type}")
# 使用示例
llm = LLMFactory.create_llm("chatgpt", "sk-xxx")
print(llm.generate_response("什么是LLM?")) # 输出:ChatGPT: 什么是LLM?
# 批量生成
prompts = ["什么是LLM?", "LLM的应用场景有哪些?"]
results = llm.batch_generate(prompts)
print(results) # 输出:['ChatGPT: 什么是LLM?', 'ChatGPT: LLM的应用场景有哪些?']
五、面向对象设计原则:构建高质量 LLM 系统
5.1 单一职责原则
一个类只负责一个单一的功能。比如,PromptManager类只负责 Prompt 的管理,不负责 API 调用。
5.2 开放封闭原则
软件实体对扩展开放,对修改封闭。比如,通过继承扩展新的 LLM 模型,而不是修改已有代码。
5.3 里氏替换原则
子类必须能够替换父类而不影响程序的正确性。比如,所有 LLM 子类都应该实现generate_response方法。
5.4 依赖倒置原则
依赖抽象而不是具体实现。比如,LLMService类依赖BaseLLM抽象类,而不是具体的ChatGPT类。
5.5 接口隔离原则
客户端不应该依赖它不需要的接口。比如,将LLM类的功能拆分为GenerateResponse和BatchGenerate两个接口。
5.6 迪米特法则
一个对象对其他对象的了解应该尽可能少。比如,LLMService类只需要知道LLM类的generate_response方法,不需要知道其内部实现。
5.7 合成复用原则
优先使用组合而不是继承来实现代码复用。比如,LLMService类可以组合PromptManager类,而不是继承它。
六、LLM 系统实战:构建模块化的 LLM 服务
6.1 项目需求
构建一个模块化的 LLM 服务,包含以下功能:
- 支持多种 LLM 模型(ChatGPT、文心一言)
- Prompt 模板管理
- 会话管理
- API 调用与响应解析
6.2 项目结构
llm_system/
├── __init__.py
├── base_llm.py # LLM抽象基类
├── chatgpt.py # ChatGPT实现类
├── wenxin.py # 文心一言实现类
├── prompt_manager.py # Prompt管理类
├── session_manager.py # 会话管理类
├── llm_factory.py # LLM工厂类
└── main.py # 入口文件
6.3 核心代码实现
6.3.1 base_llm.py
from abc import ABC, abstractmethod
class BaseLLM(ABC):
@abstractmethod
def __init__(self, api_key):
pass
@abstractmethod
def generate_response(self, prompt, temperature=0.7, max_tokens=1024):
pass
@abstractmethod
def count_tokens(self, text):
pass
6.3.2 prompt_manager.py
class PromptManager:
def __init__(self):
self._prompts = {}
def add_prompt(self, name, template):
self._prompts[name] = template
def get_prompt(self, name, **kwargs):
if name not in self._prompts:
raise ValueError(f"Prompt {name} not found")
return self._prompts[name].format(**kwargs)
def update_prompt(self, name, template):
if name not in self._prompts:
raise ValueError(f"Prompt {name} not found")
self._prompts[name] = template
def delete_prompt(self, name):
if name not in self._prompts:
raise ValueError(f"Prompt {name} not found")
del self._prompts[name]
def list_prompts(self):
return list(self._prompts.keys())
6.3.3 session_manager.py
class SessionManager:
def __init__(self):
self._sessions = {}
def create_session(self, session_id, llm):
self._sessions[session_id] = {
"llm": llm,
"history": []
}
def get_session(self, session_id):
if session_id not in self._sessions:
raise ValueError(f"Session {session_id} not found")
return self._sessions[session_id]
def update_session_history(self, session_id, user_input, llm_response):
session = self.get_session(session_id)
session["history"].append({"user": user_input, "assistant": llm_response})
def delete_session(self, session_id):
if session_id not in self._sessions:
raise ValueError(f"Session {session_id} not found")
del self._sessions[session_id]
def list_sessions(self):
return list(self._sessions.keys())
6.3.4 chatgpt.py
from .base_llm import BaseLLM
class ChatGPT(BaseLLM):
def __init__(self, api_key):
self.api_key = api_key
def generate_response(self, prompt, temperature=0.7, max_tokens=1024):
# 模拟ChatGPT API调用
return f"ChatGPT: {prompt} (temperature: {temperature}, max_tokens: {max_tokens})"
def count_tokens(self, text):
# 模拟Token计数
return len(text) // 2
6.3.5 wenxin.py
from .base_llm import BaseLLM
class WenXin(BaseLLM):
def __init__(self, api_key):
self.api_key = api_key
def generate_response(self, prompt, temperature=0.7, max_tokens=1024):
# 模拟文心一言API调用
return f"WenXin: {prompt} (temperature: {temperature}, max_tokens: {max_tokens})"
def count_tokens(self, text):
# 模拟Token计数
return len(text) // 2.5
6.3.6 llm_factory.py
from .chatgpt import ChatGPT
from .wenxin import WenXin
class LLMFactory:
@staticmethod
def create_llm(model_type, api_key):
if model_type == "chatgpt":
return ChatGPT(api_key)
elif model_type == "wenxin":
return WenXin(api_key)
else:
raise ValueError(f"不支持的模型类型:{model_type}")
6.3.7 main.py
from llm_system.prompt_manager import PromptManager
from llm_system.session_manager import SessionManager
from llm_system.llm_factory import LLMFactory
# 初始化Prompt管理器
prompt_manager = PromptManager()
prompt_manager.add_prompt(
"customer_service",
"你是电商客服,请回答关于{product}的问题:\n{question}"
)
# 初始化LLM工厂
llm_factory = LLMFactory()
# 创建ChatGPT实例
chatgpt = llm_factory.create_llm("chatgpt", "sk-xxx")
wenxin = llm_factory.create_llm("wenxin", "ak-xxx")
# 初始化会话管理器
session_manager = SessionManager()
# 创建会话
session_id = "session_123"
session_manager.create_session(session_id, chatgpt)
# 处理用户请求
product = "苹果15手机壳"
user_question = "发货时间是什么时候?"
prompt = prompt_manager.get_prompt("customer_service", product=product, question=user_question)
response = chatgpt.generate_response(prompt)
session_manager.update_session_history(session_id, user_question, response)
print(f"用户:{user_question}")
print(f"AI:{response}")
# 切换模型
print("\n切换为文心一言:")
session_manager.get_session(session_id)["llm"] = wenxin
user_question = "材质是什么?"
prompt = prompt_manager.get_prompt("customer_service", product=product, question=user_question)
response = session_manager.get_session(session_id)["llm"].generate_response(prompt)
session_manager.update_session_history(session_id, user_question, response)
print(f"用户:{user_question}")
print(f"AI:{response}")
# 查看会话历史
print("\n会话历史:")
for item in session_manager.get_session(session_id)["history"]:
print(f"用户:{item['user']}")
print(f"AI:{item['assistant']}")
# 统计Token数量
token_count = chatgpt.count_tokens(prompt)
print(f"\nPrompt的Token数量:{token_count}")
6.4 运行结果
用户:发货时间是什么时候?
AI:ChatGPT: 你是电商客服,请回答关于苹果15手机壳的问题:
发货时间是什么时候? (temperature: 0.7, max_tokens: 1024)
切换为文心一言:
用户:材质是什么?
AI:WenXin: 你是电商客服,请回答关于苹果15手机壳的问题:
材质是什么? (temperature: 0.7, max_tokens: 1024)
会话历史:
用户:发货时间是什么时候?
AI:ChatGPT: 你是电商客服,请回答关于苹果15手机壳的问题:
发货时间是什么时候? (temperature: 0.7, max_tokens: 1024)
用户:材质是什么?
AI:WenXin: 你是电商客服,请回答关于苹果15手机壳的问题:
材质是什么? (temperature: 0.7, max_tokens: 1024)
Prompt的Token数量:18
七、零基础避坑指南
7.1 不要过度使用继承
优先使用组合而不是继承,继承会增加类之间的耦合度。
7.2 避免类的职责过多
一个类只负责一个单一的功能,避免出现 “万能类”。
7.3 不要滥用私有属性和方法
私有属性和方法只在必要时使用,过度封装会导致代码的灵活性降低。
7.4 不要忽略抽象类
抽象类可以规范类的行为,提高代码的一致性和可维护性。
7.5 不要使用全局变量
全局变量会导致代码的耦合度提高,尽量将变量封装到类的内部。
八、总结:面向对象编程与 LLM 开发的「未来」
面向对象编程是构建复杂 LLM 系统的核心技术,它通过封装、继承、多态等特性,帮助开发者构建模块化、可扩展、可维护的 LLM 系统。在 LLM 开发中,面向对象编程的主要应用场景包括:
- 多模型支持:通过继承和多态实现不同 LLM 模型的统一调用
- 模块化设计:将 LLM 的不同功能封装为独立的类和对象
- 代码复用:通过继承和组合复用已有的 LLM 逻辑
- 系统扩展:通过开放封闭原则扩展新的功能
随着 LLM 技术的不断发展,LLM 系统的规模和复杂度也会不断增加,面向对象编程将成为开发者构建高质量 LLM 系统的必备技能。
下一篇我们将学习《Python 文件 IO:LLM 语料与对话历史的持久化》,讲解如何在 Python 中读取和写入 LLM 的语料和对话历史。
247

被折叠的 条评论
为什么被折叠?



