模型(Models)详解:LLM与大语言模型、ChatModel与文本补全模型、模型参数调优、多模型切换与API密钥管理

模型这一块,说白了就是整个 LangChain 的发动机。你链写得再花哨,提示词写得再漂亮,最后都得交给模型去干活。我刚开始接触 LangChain 时,以为模型就是调个 API 完事,后来才发现里面的门道还真不少。

LLM 模型与大语言模型:到底有什么区别?

先把这个概念理清楚。很多人把 LLM 和大语言模型混着叫,其实在 LangChain 里,它们有明确的层级关系。

概念 说明 LangChain 中的对应
大语言模型(LLM) 泛指所有大规模预训练语言模型,如 GPT-4、Claude、文心一言 底层模型本身
LLM 类 LangChain 对文本补全模型的抽象封装 from langchain.llms import OpenAI
ChatModel 类 LangChain 对对话模型的抽象封装 from langchain.chat_models import ChatOpenAI

我个人习惯把 LLM 类叫做「老派模型」,ChatModel 叫做「新派模型」。为什么这么分?因为 LLM 类接收的是纯文本字符串,返回的也是纯文本。而 ChatModel 接收的是消息列表(HumanMessage、AIMessage、SystemMessage),返回的也是结构化的消息对象。

核心区别一句话:LLM 类做文本补全,ChatModel 做对话补全。现在主流应用基本都用 ChatModel,但有些遗留系统或特定场景仍然需要 LLM 类。

ChatModel 与文本补全模型:选哪个?

我在项目中遇到过这样一个场景:做一个客服问答系统,一开始用了 LLM 类,每次都要手动拼接对话历史,代码又臭又长。后来换成 ChatModel,几行代码就搞定了。

来看看它们的具体差异:

特性 LLM(文本补全) ChatModel(对话模型)
输入格式 纯字符串 消息列表(HumanMessage, SystemMessage 等)
输出格式 纯字符串 AIMessage 对象(包含 content 和额外信息)
适用场景 文本生成、摘要、翻译 多轮对话、角色扮演、指令跟随
典型模型 text-davinci-003(已退役) gpt-3.5-turbo, gpt-4

代码示例对比一下:

# LLM 类 —— 文本补全
from langchain.llms import OpenAI

llm = OpenAI(model="text-davinci-003")
result = llm("给我写一首关于春天的诗")
print(result)  # 直接输出诗的内容

# ChatModel 类 —— 对话模型
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage

chat = ChatOpenAI(model="gpt-3.5-turbo")
messages = [
    SystemMessage(content="你是一个诗人"),
    HumanMessage(content="给我写一首关于春天的诗")
]
result = chat(messages)
print(result.content)  # 通过 .content 获取文本

我的建议:新项目直接用 ChatModel。除非你是在做纯文本处理任务(比如批量生成文章),否则 ChatModel 的灵活性远高于 LLM 类。

模型参数调优:temperature、max_tokens 等

调参数这件事,我踩过不少坑。记得有一次做代码生成,temperature 设成了 0.9,结果模型每次生成的代码都不一样,调试起来简直崩溃。后来把 temperature 降到 0.1,问题就解决了。

核心参数一览:

参数 作用 取值范围 我的经验值
temperature 控制输出的随机性。越高越有创意,越低越确定 0.0 ~ 2.0 代码/事实类用 0.1,创意写作用 0.7
max_tokens 限制输出最大 token 数 取决于模型(通常 1~4096) 先设 512,不够再加
top_p 核采样,只考虑概率累积到 p 的 token 0.0 ~ 1.0 一般不动,调 temperature 就够了
frequency_penalty 惩罚重复出现的 token -2.0 ~ 2.0 需要去重时设 0.5
presence_penalty 鼓励谈论新话题 -2.0 ~ 2.0 对话多样性不够时设 0.3

实际调参代码:

from langchain.chat_models import ChatOpenAI

chat = ChatOpenAI(
    model="gpt-4",
    temperature=0.3,        # 低温度,保证稳定性
    max_tokens=1024,        # 限制输出长度
    frequency_penalty=0.5,  # 减少重复
    presence_penalty=0.2    # 稍微鼓励新内容
)

response = chat([
    HumanMessage(content="用 Python 写一个快速排序算法")
])
print(response.content)

避坑指南:我曾经把 max_tokens 设得太小(比如 50),结果模型输出被截断,返回的内容不完整。另一个坑是 temperature 和 top_p 同时调,官方建议只调其中一个,否则效果会互相干扰。

多模型切换与 API 密钥管理

实际项目中,你不可能只用一家模型。我做过一个系统,白天用 GPT-4 处理复杂问题,晚上用 GPT-3.5-turbo 处理简单请求,既保证质量又省钱。多模型切换的核心就是「工厂模式」。

先看一个简单的多模型切换实现:

from langchain.chat_models import ChatOpenAI, ChatAnthropic
from langchain.llms import OpenAI

class ModelFactory:
    def __init__(self):
        self._models = {}
    
    def register_model(self, name, model_instance):
        self._models[name] = model_instance
    
    def get_model(self, name):
        if name not in self._models:
            raise ValueError(f"模型 {name} 未注册")
        return self._models[name]

# 使用示例
factory = ModelFactory()
factory.register_model("gpt4", ChatOpenAI(model="gpt-4", temperature=0.1))
factory.register_model("gpt35", ChatOpenAI(model="gpt-3.5-turbo", temperature=0.3))
factory.register_model("claude", ChatAnthropic(model="claude-2"))

# 根据需求切换
current_model = factory.get_model("gpt4")
result = current_model([HumanMessage(content="解释量子计算")])

API 密钥管理这块,我见过最糟糕的做法是把密钥硬编码在代码里,然后不小心提交到 GitHub。嗯,那画面太美我不敢看。

正确的做法:

  1. 环境变量:用 os.getenv() 读取,配合 .env 文件
  2. 密钥轮换:多个密钥轮流使用,避免单个密钥超限
  3. 权限最小化:只给模型调用权限,不给管理权限

一个带密钥轮换的封装:

import os
import itertools
from langchain.chat_models import ChatOpenAI

class KeyRotatingChat:
    def __init__(self, keys: list, **kwargs):
        self._keys = itertools.cycle(keys)
        self._kwargs = kwargs
        self._current_key = None
    
    def _get_chat(self):
        self._current_key = next(self._keys)
        return ChatOpenAI(
            openai_api_key=self._current_key,
            **self._kwargs
        )
    
    def __call__(self, messages):
        chat = self._get_chat()
        try:
            return chat(messages)
        except Exception as e:
            print(f"密钥 {self._current_key[:8]}... 失败: {e}")
            # 换下一个密钥重试
            chat = self._get_chat()
            return chat(messages)

# 使用
keys = [
    os.getenv("OPENAI_API_KEY_1"),
    os.getenv("OPENAI_API_KEY_2"),
    os.getenv("OPENAI_API_KEY_3")
]
chat = KeyRotatingChat(keys, model="gpt-4", temperature=0.1)

小技巧:我习惯把密钥放在 .env 文件中,然后用 python-dotenv 加载。这样不同环境(开发、测试、生产)可以有不同的密钥配置,互不干扰。

本章知识体系

下面这张图把模型相关的核心概念串起来了,你可以对照着梳理自己的理解:

LangChain 模型知识体系 LangChain 模型层 LLM 类(文本补全) ChatModel 类(对话模型) 核心参数调优 temperature | max_tokens | top_p | frequency_penalty | presence_penalty 多模型切换 工厂模式 | 模型注册 | 动态选择 API 密钥管理 环境变量 | 密钥轮换 | 权限控制 实践建议 新项目用 ChatModel | 低温度保稳定 | 密钥绝不硬编码