当前位置: 首页 > news >正文

【AI大模型应用开发工程师特训笔记】第04讲(第8章):面向对象编程

目录

8.1 从“函数”到“对象”的思维升级

8.1.1 为什么需要对象?

8.1.2 类与对象:蓝图与实例

8.2 定义第一个 AI 相关的类

8.2.1 最简单的类结构

8.2.2 添加属性:记录模型的特征

8.2.3 添加方法:让对象能“做事”

8.3 构造函数 __init__ 与属性详解

8.3.1 带默认值的属性

8.3.2 类属性 vs 实例属性

8.4 封装:把内部细节藏起来

8.5 继承:基于通用模型创建专用模型

8.5.1 基本继承

8.5.2 重写方法:改变父类的行为

8.5.3 多继承(了解即可)

8.6 多态:不同的对象,相同的方法名

8.7 特殊方法(魔术方法):让对象更像“原生”数据

8.7.1 __str__ 和 __repr__:定义对象的字符串表示

8.7.2 __len__:让 len() 可用

8.7.3 __call__:让对象像函数一样被调用

8.8 综合实战:构建一个可扩展的 LLM 客户端系统

8.9 本章小结


之前我们学习了函数和模块,可以把一段代码封装成可复用的“工具”。但在更复杂的 AI 应用中(比如一个完整的对话机器人、多模型调度器、工具调用链),我们需要更高级的组织方式:把数据和操作数据的方法打包在一起,这就是面向对象编程(OOP)。本章会带你用 AI 大模型相关的例子,轻松理解类、对象、继承等概念。

8.1 从“函数”到“对象”的思维升级

8.1.1 为什么需要对象?

假设你要写一个处理 OpenAI API 调用的程序。用函数式写法,你可能会这样:

def call_llm(prompt, model, temperature): # 调用 API 的逻辑 return response def count_tokens(text): return len(text.split()) def estimate_cost(model, tokens): # 根据模型计算费用 return cost

但缺点很明显:modeltemperature这些参数要反复传递,而且不同用户的不同模型配置难以管理。如果能把“一个模型实例”的所有属性(模型名、温度、最大 token)和它的行为(调用、计费、token 统计)打包在一起,代码会清晰很多。

8.1.2 类与对象:蓝图与实例

  • :一个蓝图或模板,定义了一类事物应该有什么属性(数据)和方法(能做什么)。

  • 对象:根据蓝图创建出来的具体实例,每个对象可以有不同的属性值。

类比:类就像是汽车的设计图纸,对象就是根据图纸造出来的一辆辆真车。每辆车有自己的颜色、车牌号,但它们都遵循同一个设计(能加速、刹车)。

8.2 定义第一个 AI 相关的类

8.2.1 最简单的类结构

class LLM: """大语言模型类(最简单的版本)""" pass # 创建对象 my_model = LLM() print(type(my_model)) # <class '__main__.LLM'>

8.2.2 添加属性:记录模型的特征

属性就是属于某个对象的数据。

class LLM: def __init__(self, name, context_length): """构造函数:在创建对象时自动调用,用于初始化属性""" self.name = name # 实例属性 self.context_length = context_length # 创建两个不同的模型对象 gpt4 = LLM("gpt-4", 8192) claude = LLM("claude-3", 200000) print(gpt4.name) # gpt-4 print(claude.context_length) # 200000
  • __init__是 Python 中的构造函数,第一个参数必须是self,代表对象本身。

  • self.name = name表示给这个对象添加一个叫name的属性,并把它赋值为传入的参数。

8.2.3 添加方法:让对象能“做事”

方法就是定义在类内部的函数,第一个参数也是self

class LLM: def __init__(self, name, context_length, price_per_1k): self.name = name self.context_length = context_length self.price_per_1k = price_per_1k def estimate_cost(self, input_tokens, output_tokens): """估算本次调用的费用(美元)""" total_tokens = input_tokens + output_tokens return total_tokens / 1000 * self.price_per_1k def can_handle(self, prompt_length): """检查提示词长度是否在上下文限制内""" return prompt_length <= self.context_length # 使用 gpt4 = LLM("gpt-4", 8192, 0.03) cost = gpt4.estimate_cost(1500, 300) print(f"费用: ${cost}") # 费用: $0.054 print(gpt4.can_handle(10000)) # False

注意:调用方法时,self不需要手动传递,Python 会自动把gpt4作为self传进去。

8.3 构造函数__init__与属性详解

8.3.1 带默认值的属性

class Conversation: def __init__(self, system_prompt="你是AI助手", model="gpt-3.5"): self.system_prompt = system_prompt self.model = model self.messages = [] # 存储对话历史 def add_user_message(self, content): self.messages.append({"role": "user", "content": content}) def add_assistant_message(self, content): self.messages.append({"role": "assistant", "content": content}) def show_history(self): for msg in self.messages: print(f"{msg['role']}: {msg['content']}") # 创建对话 chat = Conversation("你是一位Python专家") chat.add_user_message("如何定义类?") chat.add_assistant_message("用class关键字...") chat.show_history()

8.3.2 类属性 vs 实例属性

在Python中,类属性是直接定义在类体中的变量,被该类的所有实例共享,通过类名.属性实例.属性访问(但实例修改时通常只创建实例属性,不会影响类属性);而实例属性是在实例方法内通过self.属性定义的,每个实例独立拥有自己的副本,修改实例属性不会影响其他实例或类属性。简单区分:类属性属于“类蓝图”,实例属性属于“每个具体对象”。

  • 实例属性:每个对象独有的,如上例中的self.name

  • 类属性:属于类本身,所有对象共享的。

class LLM: # 类属性:记录所有已知模型的计数 total_models_created = 0 def __init__(self, name): self.name = name LLM.total_models_created += 1 # 每次创建对象加 1 print(LLM.total_models_created) # 0 gpt = LLM("gpt-4") claude = LLM("claude-3") print(LLM.total_models_created) # 2

8.4 封装:把内部细节藏起来

封装是指把对象的内部状态(属性)和实现细节隐藏起来,只通过公开的方法与外界交互。Python通过命名约定来实现“私有”:

  • 单下划线_name:表示“受保护的”,外部不应直接访问,但依然可以。

  • 双下划线__name:名称修饰,外部不能直接访问。

class APIClient: def __init__(self, api_key): self.__api_key = api_key # 私有属性 self._base_url = "https://api.openai.com" # 受保护 def call(self, prompt): # 内部使用 __api_key 发起请求 return f"使用密钥 {self.__api_key[:5]}... 调用成功,回复:{prompt}" client = APIClient("sk-123456") print(client.call("Hello")) # print(client.__api_key) # AttributeError print(client._base_url) # 可以访问,但约定不要这样做

封装的好处:你可以随时改变内部实现(如更换 API 提供商),只要公开方法签名不变,调用方代码完全不需要修改。

8.5 继承:基于通用模型创建专用模型

继承允许你定义一个子类,它自动拥有父类的所有属性和方法,并可以增加或重写(覆盖)一些功能。

8.5.1 基本继承

class BaseLLM: def __init__(self, name, context_length): self.name = name self.context_length = context_length def generate(self, prompt): return f"{self.name} 生成: {prompt}" # 子类:支持函数调用的模型 class FunctionCallingLLM(BaseLLM): def call_function(self, func_name, args): return f"{self.name} 正在调用函数 {func_name},参数 {args}" gpt4 = FunctionCallingLLM("gpt-4", 8192) print(gpt4.generate("Hello")) # 继承的方法 print(gpt4.call_function("get_weather", {"city": "Beijing"})) # 子类新方法

8.5.2 重写方法:改变父类的行为

class GPT4(BaseLLM): def generate(self, prompt): # 调用父类方法并补充内容 base_response = super().generate(prompt) return base_response + " [额外:使用高精度计算]" model = GPT4("gpt-4", 8192) print(model.generate("讲个笑话")) # 输出:gpt-4 生成: 讲个笑话 [额外:使用高精度计算]

8.5.3 多继承(了解即可)

Python 支持一个子类继承多个父类,但容易复杂。AI 框架中较少见。

class Streamable: def stream(self): return "流式输出" class Cacheable: def cache(self): return "缓存命中" class AdvancedLLM(BaseLLM, Streamable, Cacheable): pass adv = AdvancedLLM("claude", 100000) print(adv.stream())

8.6 多态:不同的对象,相同的方法名

多态允许不同类的对象对同一个方法名做出不同的响应。在 AI 中,你可以定义一个统一的generate接口,然后不同模型类各自实现它。

class OpenAIModel: def generate(self, prompt): return "OpenAI 回复: " + prompt class AnthropicModel: def generate(self, prompt): return "Anthropic 回复: " + prompt def chat(model, prompt): print(model.generate(prompt)) gpt = OpenAIModel() claude = AnthropicModel() chat(gpt, "你好") # OpenAI 回复: 你好 chat(claude, "你好") # Anthropic 回复: 你好

8.7 特殊方法(魔术方法):让对象更像“原生”数据

Python中,有一类以双下划线开头和结尾的方法(比如initstrlen),它们被称为“魔术方法”。魔术方法不是让你直接调用的,而是 Python 在特定场景下自动调用的。通过实现这些方法,你可以让自己的类实例表现得像 Python 内置的列表、字符串、数字一样,支持len()str()+等操作。

零基础理解:可以把魔术方法理解为“潜规则”或“约定”。比如,当Python看到len(x)时,它会自动去调用xlen方法。你只要在类里写好了len方法,Python 就知道你的对象也能问“有多长”。

常用魔术方法举例

  • init:初始化方法。当你创建对象时(比如p = Person()),Python 自动调用它,用来设置对象的初始属性。

  • str:字符串表示。当你使用print(对象)str(对象)时,Python 自动调用它,返回一个“给人看”的友好字符串。

  • repr:开发时用的字符串表示。在交互环境中直接输入对象名时显示,通常返回一个可以用来重建对象的表达式。

  • len:长度。当你调用len(对象)时,Python自动调用它,返回一个整数。

  • add:加法。当你使用对象1 + 对象2时,Python自动调用左边对象的add方法,把右边的对象传进去。

8.7.1__str____repr__:定义对象的字符串表示

class LLM: def __init__(self, name, context): self.name = name self.context = context def __str__(self): return f"LLM({self.name}, ctx={self.context})" model = LLM("gpt-4", 8192) print(model) # LLM(gpt-4, ctx=8192)

8.7.2__len__:让len()可用

class ConversationHistory: def __init__(self): self.messages = [] def add(self, msg): self.messages.append(msg) def __len__(self): return len(self.messages) hist = ConversationHistory() hist.add("hello") hist.add("world") print(len(hist)) # 2

8.7.3__call__:让对象像函数一样被调用

class TemperatureScaler: def __init__(self, factor=1.2): self.factor = factor def __call__(self, temperature): return temperature * self.factor scale = TemperatureScaler(1.5) print(scale(0.7)) # 1.05(对象名后面加括号,就像函数调用)

这在 AI 框架中常用于配置某些可调用的参数变换。

8.8 综合实战:构建一个可扩展的 LLM 客户端系统

我们将用面向对象的方法,设计一个支持多厂商、带缓存、带计费的模型客户端。

import hashlib import time # ---------- 1. 基础模型接口(抽象基类,但不严格要求)---------- class BaseLLM: def __init__(self, name, price_per_1k): self.name = name self.price_per_1k = price_per_1k self.total_cost = 0.0 def generate(self, prompt, **kwargs): """子类必须实现具体调用逻辑""" raise NotImplementedError def _record_cost(self, input_tokens, output_tokens): cost = (input_tokens + output_tokens) / 1000 * self.price_per_1k self.total_cost += cost return cost # ---------- 2. 具体模型实现 ---------- class OpenAIClient(BaseLLM): def __init__(self, api_key, model_name="gpt-3.5-turbo"): super().__init__(model_name, price_per_1k=0.002) self.api_key = api_key def generate(self, prompt, temperature=0.7): # 模拟 API 调用(实际会用 requests 库) print(f"[OpenAI] 调用 {self.name},temperature={temperature}") # 模拟 token 计数 input_tokens = len(prompt) // 4 output_text = f"OpenAI 回复:{prompt}" output_tokens = len(output_text) // 4 cost = self._record_cost(input_tokens, output_tokens) return { "text": output_text, "input_tokens": input_tokens, "output_tokens": output_tokens, "cost": cost } class AnthropicClient(BaseLLM): def __init__(self, api_key, model_name="claude-3"): super().__init__(model_name, price_per_1k=0.025) self.api_key = api_key def generate(self, prompt, temperature=0.7): print(f"[Anthropic] 调用 {self.name},temperature={temperature}") input_tokens = len(prompt) // 4 output_text = f"Claude 回复:{prompt}" output_tokens = len(output_text) // 4 cost = self._record_cost(input_tokens, output_tokens) return { "text": output_text, "input_tokens": input_tokens, "output_tokens": output_tokens, "cost": cost } # ---------- 3. 带缓存的装饰器模式(简化) ---------- class CachedLLM: def __init__(self, llm_client): self.llm = llm_client self.cache = {} def generate(self, prompt, **kwargs): key = hashlib.md5(f"{prompt}_{kwargs}".encode()).hexdigest() if key in self.cache: print("缓存命中!") return self.cache[key] else: result = self.llm.generate(prompt, **kwargs) self.cache[key] = result return result # ---------- 4. 使用 ---------- if __name__ == "__main__": # 创建原始客户端 openai = OpenAIClient(api_key="sk-xxx", model_name="gpt-4") # 增加缓存功能 cached_openai = CachedLLM(openai) # 第一次调用 res1 = cached_openai.generate("讲个笑话", temperature=0.8) print(res1["text"]) print(f"花费: ${res1['cost']:.4f}") # 第二次调用相同 prompt(会命中缓存) res2 = cached_openai.generate("讲个笑话", temperature=0.8) print(res2["text"]) print(f"总成本: {openai.total_cost}")

运行上述代码,输出如下内容:

tianpeng@DESKTOP-4L1UF5S:~/my-ai-service$ poetry run python src/my_ai_service/loop.py [OpenAI] 调用 gpt-4,temperature=0.8 OpenAI 回复:讲个笑话 花费: $0.0000 缓存命中! OpenAI 回复:讲个笑话 总成本: 8e-06 tianpeng@DESKT

8.9 本章小结

概念

含义

AI 示例

类 class

设计蓝图

class LLM:

对象 instance

根据类创建的具体实例

gpt4 = LLM("gpt-4")

属性 attribute

对象的数据

self.name,self.context_length

方法 method

对象的行为

def generate(self, prompt):

__init__

构造函数,初始化对象

设置 API 密钥、默认温度

封装

隐藏内部细节

私有属性__api_key

继承

子类复用父类代码

class FunctionCallingLLM(BaseLLM):

多态

不同对象相同方法名不同行为

model.generate(prompt)对不同模型调不同的实现

魔术方法

让对象支持Python内置操作

__str__,__len__,__call__

http://www.jsqmd.com/news/907845/

相关文章:

  • 2026南通驾校推荐榜:C1/C2/D/E 证培训、摩托车驾培、机器人教学驾校多维解析 摘要 - 海棠依旧大
  • 2025-2026年上海吉日搬场有限公司电话查询:选择搬场服务前需核实资质与合同条款分析 - 品牌推荐
  • 从助焊膏选择到焊后清理:一次搞懂QFN芯片手工焊接的全流程避坑要点
  • 知识嫁接技术:突破边缘AI部署瓶颈的新方法
  • C51数学函数性能优化与嵌入式开发实践
  • 从《绝地求生》到《原神》:盘点那些用虚幻引擎和Unity 3D打造的现象级PC游戏
  • AI电台主持人系统架构:从情感语音合成到实时交互的工程实践
  • 2026年质量好的山东微型千类轴承/高速千类轴承/替代进口千类轴承/精密千类轴承实力工厂推荐 - 品牌宣传支持者
  • 保姆级教程:在CentOS 7.9上用OpenStack All-in-One搞定虚拟机上网(附浮动IP配置)
  • 2025-2026年上海吉日搬场有限公司电话查询:搬家前需核实服务范围与合同条款指南 - 品牌推荐
  • 2025-2026年犀鸟搬场服务(上海)有限公司电话查询:搬家服务选择前需核实资质与合同 - 品牌推荐
  • Win11下复活IE浏览器:一个DLL文件替换的保姆级教程(解决老旧系统兼容问题)
  • 没有USB转TTL模块?别急!用STM32F103C8T6单片调试HC-06蓝牙的保姆级避坑指南
  • 从“猫狗大战”到图像生成:用PyTorch搭建DCGAN玩转动漫头像创作
  • 3D堆叠架构突破LLM推理内存墙与热管理挑战
  • 2026年口碑好的浇注料/轻质浇注料/粘土质耐火浇注料/磷酸盐结合浇注料源头工厂推荐 - 品牌宣传支持者
  • 别再用strcmp了!这道ZZULIOJ 1155题,教你用ASCII码映射搞定自定义字符串比较
  • 稀疏专家混合在视觉Transformer中的应用:原理、实现与调优
  • Mali-C10 GDC工具:图像畸变校正实战指南
  • 论文AI率降到安全线要多少钱?2026年降AI工具TOP10省钱榜
  • AI重构职场沟通:从策略性说服到伦理边界的探索
  • 2025-2026年北京恒瑞宏晟机电设备有限公司电话查询:选型前请核实资质与合同条款 - 品牌推荐
  • 2026年比较好的羽衣甘蓝粉代餐/羽衣甘蓝粉贴牌/江苏羽衣甘蓝粉/羽衣甘蓝粉原料主流厂家对比评测 - 行业平台推荐
  • AI意识探索:从量子计算到认知架构的技术路径与伦理挑战
  • 单卡微调大模型:QLoRA技术原理与实战指南
  • Sora 2提示词调试黑箱破解:3分钟定位motion drift根源——基于Transformer注意力热力图的逆向诊断法
  • 2025-2026年北京十大装修公司推荐:环保家装防甲醛评测注意事项选择指南 - 品牌推荐
  • 告别客户端!用BarTender Print Portal实现远程标签打印的完整配置流程
  • DevSecOps实战:三大核心原则与自动化安全流水线构建
  • 别再只盯着96了!SIP通话中RTP负载类型(Payload Type)的实战配置与避坑指南