【零基础入门 LLM 开发 · Day 11】:ChatOpenAI vs init_chat_model------一行换供应商
场景
Day 10 起我们的代码都是这么开头的:
python
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model=..., api_key=..., base_url=...)
直接实例化,直观明了。但它有个隐形约束:类名焊死了供应商 ------ChatOpenAI 只会说"OpenAI 协议"这一种话。哪天想试 Claude、Gemini 或本地模型,每个文件都要改 import 和构造代码。
最近的练习文件换成了另一种写法:init_chat_model。这篇讲清两者区别,顺便把常见供应商的接入写法一次备齐。
姿势一:ChatOpenAI 直连
python
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model=os.getenv("YUMC_MODEL_NAME"),
api_key=os.getenv("YUMC_MODEL_API_KEY"),
base_url=os.getenv("YUMC_MODEL_BASE_URL"), # 指向任何 OpenAI 兼容端点
temperature=0.7,
)
- 优点 :类型明确,IDE 补全参数一个不落;装的包也最少(
langchain-openai一个就够); - 局限:只会 OpenAI 协议。对"兼容端点"来说这恰恰不是缺点(见下文),但要接原生 Anthropic / Google 接口就得换类、换包。
姿势二:init_chat_model 工厂
python
from langchain.chat_models import init_chat_model
model = init_chat_model(
model=os.getenv("YUMC_MODEL_NAME"),
model_provider="openai", # 决定实际造出哪个类
temperature=0,
api_key=os.getenv("YUMC_MODEL_API_KEY"),
base_url=os.getenv("YUMC_MODEL_BASE_URL"),
)
model_provider 是工厂的图纸 :"openai" → 内部实例化 ChatOpenAI,"anthropic" → ChatAnthropic......其余参数原样透传给对应的类。换供应商 = 改一个字符串。
验证一下工厂没骗你:
python
model = init_chat_model(model="gpt-4o-mini", model_provider="openai")
print(type(model)) # <class 'langchain_openai.chat_models.base.ChatOpenAI'>
| ChatOpenAI 直连 | init_chat_model 工厂 | |
|---|---|---|
| 本质 | 具体类 | 按字符串选类的工厂函数 |
| 换供应商 | 改 import + 构造代码 | 只改 model_provider(或配置) |
| IDE 补全 | 好 | 一般(返回类型是动态的) |
| 依赖 | 只需对应一家的包 | 用哪家就得装哪家的包 |
| 适用 | 教学/demo、只用一家 | 多模型切换、通用工具 |
不同供应商的写法(速查表)
路线 A:官方集成包 ------每家一个 model_provider 值 + 一个要单独安装的包:
| 供应商 | model_provider | 需要安装 | model 示例 |
|---|---|---|---|
| OpenAI | openai |
langchain-openai | gpt-4o-mini |
| Anthropic | anthropic |
langchain-anthropic | claude-sonnet-4-5 |
google_genai |
langchain-google-genai | gemini-2.0-flash |
|
| DeepSeek | deepseek |
langchain-deepseek | deepseek-chat |
| Ollama(本地) | ollama |
langchain-ollama | qwen2.5(本地已 pull 的模型名) |
python
model = init_chat_model("claude-sonnet-4-5", model_provider="anthropic")
# api_key 从环境变量 ANTHROPIC_API_KEY 自动读取,也可以显式传
路线 B:OpenAI 兼容协议 ------很多国产服务不提供官方集成包,但都提供"OpenAI 兼容接口",统统走 model_provider="openai" + 自家 base_url:
| 服务 | base_url |
|---|---|
| 智谱 GLM | https://open.bigmodel.cn/api/paas/v4 |
| Kimi(月之暗面) | https://api.moonshot.cn/v1 |
| 通义千问(兼容模式) | https://dashscope.aliyuncs.com/compatible-mode/v1 |
| DeepSeek 官方 | https://api.deepseek.com |
| 你自己的 .env | YUMC_MODEL_BASE_URL(本系列一直在用的就是这种) |
python
model = init_chat_model(
model="glm-5.3-flash",
model_provider="openai", # 协议是 OpenAI 的
base_url="https://open.bigmodel.cn/api/paas/v4", # 但地址是智谱的
api_key=os.getenv("ZHIPU_API_KEY"),
)
本系列的
.env(YUMC_MODEL_*)就是路线 B:协议标准、地址自选。所以代码从 Day 1 到今天几乎没变过。
小技巧:新版还支持冒号简写,一行连供应商带模型名一起写:
python
model = init_chat_model("openai:gpt-4o-mini")
怎么选?
- 教学阶段 / 确定只用 OpenAI 系 :
ChatOpenAI直连------直观、补全友好; - 想随时切换模型对比效果 / 做通用工具 :
init_chat_model------把供应商选择变成一行配置; - 两者可以混用:核心代码面向 LangChain 的统一消息/工具接口编程,初始化交给工厂。
今日踩坑点
- 没装对应的集成包 :
init_chat_model(model_provider="anthropic")但没装langchain-anthropic,报ModuleNotFoundError------工厂是按需导入的,图纸认了、零件没货。 - 兼容端点漏了
base_url:以为传了api_key就行,请求直奔官方api.openai.com,拿着智谱的 key 报 401。路线 B 的base_url是命根子。 - 参数拼写错误被"透传" :
init_chat_model(..., temperatre=0)不报"参数不存在",而是把未知参数转发给底层类,最后在 API 调用时才炸:TypeError: unexpected keyword argument 'temperatre'------报错位置离案发现场很远(Day 14 的methond同款坑)。参数拼错先查构造处。 - 换了供应商 ≠ 行为一致 :
bind_tools、with_structured_output各家支持度不同(Day 14 的json_schema假装支持问题就是典型)。切了供应商,这些能力要重新验证。
今日小练习
- 必做:把 Day 10 的
ChatOpenAI换成init_chat_model,跑通同样的对话,print(type(model))亲眼看看工厂造出了什么。 - 进阶:写一个
load_model()函数------供应商、模型名、密钥全部从.env读取,实现"不改一行代码换供应商"。 - 思考:把
base_url改成一个不存在的地址,和直接删掉base_url,分别报什么错?为什么报错不一样?
明日预告
Day 12:LangChain 流式输出------比 Day 5 手动拼 delta 简单得多,一行 for 搞定。
附录:完整练习代码
langchainTest4-tools2.py 的初始化段(tools 系列练习文件统一用这种写法)
python
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
load_dotenv()
model = init_chat_model(
model=os.getenv("YUMC_MODEL_NAME"),
model_provider="openai",
temperature=0,
api_key=os.getenv("YUMC_MODEL_API_KEY"),
base_url=os.getenv("YUMC_MODEL_BASE_URL"),
)
换供应商实战:只动 .env,代码零修改
python
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
load_dotenv()
# .env 里配什么就用什么:
# YUMC_MODEL_NAME=glm-5.3-flash
# YUMC_MODEL_API_KEY=你的密钥
# YUMC_MODEL_BASE_URL=https://open.bigmodel.cn/api/paas/v4
# 想换 Kimi?改这三行配置即可,下面的代码原封不动。
model = init_chat_model(
model=os.getenv("YUMC_MODEL_NAME"),
model_provider="openai", # 兼容协议走 openai
api_key=os.getenv("YUMC_MODEL_API_KEY"),
base_url=os.getenv("YUMC_MODEL_BASE_URL"),
)
response = model.invoke("用一句话介绍你自己")
print(response.content)