LangChain Language Model
这一节我们来看 Langchain 的 Language Model。
1. Language Model 的 UML 类图
Language Model 有如下基类:
- BaseLanguageModel
- BaseChatModel
- BaseLLM
Language Model 基类不多,让我们直接问大模型这些类的语义
|
|
在 LangChain 中,language_models
子包是核心模块之一,负责抽象和实现对底层语言模型(如 OpenAI、Anthropic、Cohere 等)的调用逻辑。你提到的两个类:
BaseLanguageModel
BaseChatModel
它们是这一模块中的两个重要抽象基类。我们可以从语义(功能定位)和继承关系两个角度来解释它们的作用:
BaseLanguageModel
— 通用语言模型基类
🌐 语义说明:
BaseLanguageModel
是所有语言模型的最基础抽象类,它统一封装了“调用一个语言模型并返回生成结果”的基础行为,不限制模型的交互方式(即支持 completion、chat、function 调用等多种形式)。
✅ 它更偏底层、更抽象、更通用。
🧩 关键职责:
-
提供通用的接口定义,如:
generate()
: 对多个提示进行批量生成。invoke()
: 对一个输入生成输出。- 输出
LLMResult
/ChatResult
等结构化结果。
-
定义 tracing(运行追踪)、缓存、回调处理等底层机制的接口。
-
子类一般会重写
_generate()
来实现自己的核心逻辑。
🧬 典型子类有:
LLM
: 基于文本补全(text completion)模型。ChatModel
: 基于多轮对话(chat-based)模型。
BaseChatModel
— 面向“对话模型”的抽象基类
💬 语义说明:
BaseChatModel
是 BaseLanguageModel
的一个子类,用于封装 chat-based 模型的标准行为,如 OpenAI 的 gpt-3.5-turbo
、Anthropic Claude 等。它们都以多轮对话消息(如 user、system、assistant)为输入。
✅ 这是一个对话风格模型(Chat Model)专用的抽象基类。
🧩 关键职责:
- 将
List[BaseMessage]
类型作为输入(比如 SystemMessage、HumanMessage、AIMessage)。 - 实现
generate()
方法来处理多个 chat prompt。 - 提供
predict_messages()
接口,返回结构化的 AIMessage。 - 定义
_generate()
和_combine_messages()
等钩子供子类实现。
🎯 使用场景:
当你希望封装一个聊天风格接口(如 OpenAI 的 ChatCompletion API),你应该继承这个类,而不是 BaseLanguageModel
。
类名 | 语义定位 | 输入类型 | 使用场景 | 子类示例 |
---|---|---|---|---|
BaseLanguageModel |
所有语言模型的统一抽象 | Prompt(字符串或消息) | 底层统一抽象层,主要定义接口与共性行为 | LLM , BaseChatModel |
BaseChatModel |
面向 Chat 类型语言模型的抽象 | List[BaseMessage] |
构建支持多角色对话的模型(如 GPT) | ChatOpenAI , ChatAnthropic |
|
|
LanguageModel 的实现比较复杂,我先来对比这几个类的抽象层次,再来看具体的代码。
2. 属性和抽象方法
2.1 BaseLanguageModel
|
|
属性名 | 类型 | 默认值 | 是否参与序列化 | 语义解释 |
---|---|---|---|---|
cache |
Union[BaseCache, bool, None] |
None |
❌ exclude=True |
指定是否启用响应缓存: - True : 使用全局缓存- False : 不使用缓存- BaseCache 实例:使用自定义缓存- None : 若已设置全局缓存则使用,否则不缓存。注意:不支持 streaming 缓存。 |
verbose |
bool |
_get_verbosity() |
❌ exclude=True , 不在 repr 中显示 |
控制是否打印模型返回的文本结果,适用于调试时查看生成内容。 |
callbacks |
Callbacks |
None |
❌ exclude=True |
为 LLM 调用添加回调机制(如 tracing、logging、streaming 等),贯穿调用生命周期。 |
tags |
Optional[list[str]] |
None |
❌ exclude=True |
附加到 run trace 的标签,可用于运行的标记和过滤。 |
metadata |
Optional[dict[str, Any]] |
None |
❌ exclude=True |
附加元数据到 run trace,支持记录运行的额外上下文信息。 |
custom_get_token_ids |
Optional[Callable[[str], list[int]]] |
None |
❌ exclude=True |
自定义的 tokenizer 函数,用于统计 token 数(常用于 token 限制或费用评估)。 |
BaseLanguageModel 的主要作用是定义接口:
|
|
BaseLanguageModel 继承自 RunnableSerializable,但是并没有提供 invoke 的默认实现。
所以 BaseLanguageModel 主要有三个接口方法:
generate_prompt
agenerate_prompt
invoke
BaseLanguageModel 还有一些过期的接口,这里未列出。
2.2 BaseChatModel
|
|
属性名 | 类型 | 默认值 | 是否序列化 | 说明 |
---|---|---|---|---|
callback_manager |
Optional[BaseCallbackManager] |
None |
❌ exclude=True |
已废弃,请使用 callbacks 。用于管理回调函数生命周期,如 tracing、logging、token 统计等。 |
rate_limiter |
Optional[BaseRateLimiter] |
None |
❌ exclude=True |
请求速率限制器,可限制调用频率,避免 API 超额。 |
disable_streaming |
Union[bool, Literal["tool_calling"]] |
False |
✅ | 是否关闭流式输出: - True : 始终关闭流式,改用普通调用- "tool_calling" :仅当调用包含 tools 参数时关闭流式- False (默认):支持流式时使用流式返回(如 .stream() ) |
BaseChatModel 重载了 Runnable 的大多数方法,因此代码比较长。我再次问了 chatgpt,在回答里摘录了下面有关所有方法的总结图。但是这个还不足以帮我们沥青方法之间的调用关系。所以我们先来看 BaseChatModel 抽象了哪些方法。
|
|
通过搜索 abstractmethod 和 NotImplementedError 我找到 BaseChatModel 定义的如下方法。
|
|
通过搜索这些方法可以找到如下的调用链:
|
|
2.3 BaseLLM
我们对 BaseLLM 重复上述过程:
|
|
抽象方法的调用链:
|
|
通过对比我们可以发现:
- BaseLLM、BaseChatModel 都将 BaseLanguageModel 的接口转换到了 _generate
- 都要求子类实现 _stream 方法
- 但是两者方法接受的参数不同,BaseLLM 接受
list[str]
,BaseChatModel 接受list[BaseMessage]
- 两者的返回值不同,BaseLLM 返回
LLMResult
,BaseChatModel 返回ChatResult
下面我们先来看 BaseChatModel 的代码。
3. BaseChatModel
3.1 invoke
BaseChatModel invoke 需要关注以下实现细节:
- invoke 内调用
self._convert_input
将输入标准化为list[PromptValue]
- generate_prompt 内将
list[PromptValue]
转化为list[list[BaseMessage]]
子 list 代表一个完整的 Prompt - generate 完成多个独立的 Prompt 调用过程
|
|
3.2 generate
generate 的调用过程分成了如下几个部分:
- callback_manager 的调用,这一部分详见
- 遍历 messages 参数,执行
_generate_with_cache
获取 ChatResult - 合并 ChatResult 为 LLMResult 返回
- 代码执行的过程中有两次 message 的转换,详见:
|
|
3.3 _generate_with_cache
generate 的调用过程分成了如下几个部分:
- 检索缓存,限流(rate_limiter),这一部分详见
- 检查是不是应该使用 stream 方法获取结果,如果是调用
self._stream
,否则调用self._generate
|
|
4.3 SimpleChatModel
SimpleChatModel 假设模型只返回 str,并给了一个 _generate 的默认实现。
|
|
4. BaseLLM
4.1 invoke
BaseLLM invoke 需要关注以下实现细节:
- invoke 内调用
self._convert_input
将输入标准化为list[PromptValue]
- generate_prompt 内将
list[PromptValue]
转化为list[str]
调用 generate - generate 完成多个独立的 Prompt 调用过程
|
|
4.2 generate
generate:
- 如果 callbacks 是多个,那么检查 callbacks、tags、metadata、run_name 这些元数据参数,是否与 prompts 数量是否相等,并为每一个 prompt 构造一个 CallbackManager
- 如果 callbacks 是一个构造一个 CallbackManager 多个副本
- 调用 get_prompts 函数,从 cache 中检索
- 如果没有 cache 对所有输入 promts 调用
_generate_helper
- 有缓存,对未命中缓存调用
_generate_helper
- 合并结果输出
|
|
4.3 _generate_helper
_generate_helper 实现比较简单,唯一需要注意的是,BaseLLM 的 _generate
方法与 BaseChatModel 有多区别:
BaseLLM._generate
处理的是多个独立 prompt,所以_generate_helper
对结果进行了展开BaseChatModel._generate
只处理一个 prompt,这个 prompt 包含多个 message
|
|
4.5 调用链总结
至此我们可以对 LanguageModel 的调用链做一下总结:
|
|
4.4 LLM
在 BaseLLM 的基础上 langchain-core 还实现了一个 LLM 类。这个类对 BaseLLM 做了一个简单的接口转换。
|
|
5. Fake Model
有关 ChatGpt 具体的 Model实现在 langchain 库内,我们会在单独的章节里详细讲解。这里我们看一下 langchain-core 给我们提供的测试用 FakeModel 类。
FakeModel 有如下几个:
- FakeListLLM
- FakeStreamingListLLM
- FakeMessagesListChatModel
- FakeListChatModel
- FakeChatModel
- GenericFakeChatModel
- ParrotFakeChatModel
这些 model 都比较简单,不在一一列出代码。