本文聚焦 LangChain 对语言模型接口的核心抽象 ------
BaseLanguageModel
,结合源码深入剖析其在多模型适配中的角色,并探讨工厂模式等设计思想如何提升模型集成能力。
一、什么是 BaseLanguageModel?
在 LangChain 中,BaseLanguageModel
是所有语言模型类的统一基类,位于模块 langchain_core.language_models.base
中。
它作为 LangChain 的 Runnable
抽象体系的一部分,定义了语言模型统一的配置接口、token 使用信息获取、流式生成支持等结构,但 并不直接实现文本生成或对话功能。
python
class BaseLanguageModel(
RunnableSerializable[LanguageModelInput, LanguageModelOutputVar], ABC
):
"""Abstract base class for interfacing with language models.
All language model wrappers inherited from BaseLanguageModel.
"""
该基类是为以下两类模型服务的抽象基类:
BaseLLM
:传统的纯文本生成语言模型(如 text-davinci),位于langchain_core.language_models.llms.py
模块中。
python
class BaseLLM(BaseLanguageModel[str], ABC):
"""Base LLM abstract interface.
It should take in a prompt and return a string.
"""
callback_manager: Optional[BaseCallbackManager] = Field(default=None, exclude=True)
"""[DEPRECATED]"""
model_config = ConfigDict(
arbitrary_types_allowed=True,
)
BaseChatModel
:基于对话格式的语言模型(如 GPT-4、Claude、Mistral),位于langchain_core.language_models.chat_models.py
模块中。
python
class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
"""Base class for chat models.
Key imperative methods:
Methods that actually call the underlying model.
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| Method | Input | Output | Description |
+===========================+================================================================+=====================================================================+==================================================================================================+
| `invoke` | str | list[dict | tuple | BaseMessage] | PromptValue | BaseMessage | A single chat model call. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `ainvoke` | ''' | BaseMessage | Defaults to running invoke in an async executor. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `stream` | ''' | Iterator[BaseMessageChunk] | Defaults to yielding output of invoke. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `astream` | ''' | AsyncIterator[BaseMessageChunk] | Defaults to yielding output of ainvoke. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `astream_events` | ''' | AsyncIterator[StreamEvent] | Event types: 'on_chat_model_start', 'on_chat_model_stream', 'on_chat_model_end'. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `batch` | list['''] | list[BaseMessage] | Defaults to running invoke in concurrent threads. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `abatch` | list['''] | list[BaseMessage] | Defaults to running ainvoke in concurrent threads. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `batch_as_completed` | list['''] | Iterator[tuple[int, Union[BaseMessage, Exception]]] | Defaults to running invoke in concurrent threads. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
| `abatch_as_completed` | list['''] | AsyncIterator[tuple[int, Union[BaseMessage, Exception]]] | Defaults to running ainvoke in concurrent threads. |
+---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
...
"""
二、invoke 方法
虽然 BaseLanguageModel
没有显式实现 invoke()
,但它继承自 RunnableSerializable
→ Runnable
,后者为 LangChain 中所有模块提供了统一的执行入口:
python
# langchain_core.runnables.base
class Runnable(Protocol):
def invoke(self, input: InputType, config: RunnableConfig = None) -> OutputType: ...
因此,任何继承自 BaseLanguageModel
的模型类 自动拥有了 invoke()
方法 ,可用于链式组合执行。 BaseLLM
与 BaseChatModel
都在各自子类中重写了 invoke()
方法,它们的输入接口保持一致(通常为 LanguageModelInput
),但输出类型不同:BaseLLM
输出纯文本结果,而 BaseChatModel
输出结构化的消息对象(BaseMessage
)。
BaseLLM.invoke()
python
@override
def invoke(
self,
input: LanguageModelInput,
config: Optional[RunnableConfig] = None,
*,
stop: Optional[list[str]] = None,
**kwargs: Any,
) -> str:
config = ensure_config(config)
return (
self.generate_prompt(
[self._convert_input(input)],
stop=stop,
callbacks=config.get("callbacks"),
tags=config.get("tags"),
metadata=config.get("metadata"),
run_name=config.get("run_name"),
run_id=config.pop("run_id", None),
**kwargs,
)
.generations[0][0]
.text
)
BaseChatModel.invoke()
python
@override
def invoke(
self,
input: LanguageModelInput,
config: Optional[RunnableConfig] = None,
*,
stop: Optional[list[str]] = None,
**kwargs: Any,
) -> BaseMessage:
config = ensure_config(config)
return cast(
"ChatGeneration",
self.generate_prompt(
[self._convert_input(input)],
stop=stop,
callbacks=config.get("callbacks"),
tags=config.get("tags"),
metadata=config.get("metadata"),
run_name=config.get("run_name"),
run_id=config.pop("run_id", None),
**kwargs,
).generations[0][0],
).message
👀 cast()
是 Python 类型系统中的一个函数,来自标准库模块 typing
。它的作用主要是给类型系统看的注释,不会改变实际数据类型,所以请确保你的 cast 是合理的,不然只是自欺欺人。
三、工厂模式与多模型适配结构
LangChain 在早期版本中将主流模型厂商(如 OpenAI、Anthropic、Alibaba 等)的封装类直接集中维护在主包中,并统一继承自 BaseChatModel
。然而在最新版本中,LangChain 已将这类具体实现迁移到子项目 langchain-community
,形成"核心逻辑"和"社区接入"的分离架构。
在 langchain-community
包中,你可以找到如下模型的适配器类:
langchain_community.chat_models.openai.ChatOpenAI
python
class ChatOpenAI(BaseChatModel):
"""`OpenAI` Chat large language models API.
To use, you should have the ``openai`` python package installed, and the
environment variable ``OPENAI_API_KEY`` set with your API key.
Any parameters that are valid to be passed to the openai.create call can be passed
in, even if not explicitly saved on this class.
Example:
.. code-block:: python
from langchain_community.chat_models import ChatOpenAI
openai = ChatOpenAI(model="gpt-3.5-turbo")
"""
langchain_community.chat_models.anthropic.ChatAnthropic
python
class ChatAnthropic(BaseChatModel, _AnthropicCommon):
"""`Anthropic` chat large language models.
To use, you should have the ``anthropic`` python package installed, and the
environment variable ``ANTHROPIC_API_KEY`` set with your API key, or pass
it as a named parameter to the constructor.
Example:
.. code-block:: python
import anthropic
from langchain_community.chat_models import ChatAnthropic
model = ChatAnthropic(model="<model_name>", anthropic_api_key="my-api-key")
"""
langchain_community.chat_models.tongyi.ChatTongyi
python
class ChatTongyi(BaseChatModel):
"""Alibaba Tongyi Qwen chat model integration.
...
"""
这些类通过重写 invoke
/_generate
方法,实现:
- 模型输入转换(参数、消息格式)
- 模型 API 调用(REST / SDK)
- 模型输出统一封装(
BaseMessage
) - 错误重试 / 输出解析 / 日志跟踪
ChatOpenAI._generate()
python
def _generate(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
stream: Optional[bool] = None,
**kwargs: Any,
) -> ChatResult:
should_stream = stream if stream is not None else self.streaming
if should_stream:
stream_iter = self._stream(
messages, stop=stop, run_manager=run_manager, **kwargs
)
return generate_from_stream(stream_iter)
message_dicts, params = self._create_message_dicts(messages, stop)
params = {
**params,
**({"stream": stream} if stream is not None else {}),
**kwargs,
}
response = self.completion_with_retry(
messages=message_dicts, run_manager=run_manager, **params
)
return self._create_chat_result(response)
ChatTongyi._generate()
python
def _generate(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> ChatResult:
generations = []
if self.streaming:
generation_chunk: Optional[ChatGenerationChunk] = None
for chunk in self._stream(
messages, stop=stop, run_manager=run_manager, **kwargs
):
if generation_chunk is None:
generation_chunk = chunk
else:
generation_chunk += chunk
assert generation_chunk is not None
generations.append(self._chunk_to_generation(generation_chunk))
else:
params: Dict[str, Any] = self._invocation_params(
messages=messages, stop=stop, **kwargs
)
resp = self.completion_with_retry(**params)
generations.append(
ChatGeneration(**self._chat_generation_from_qwen_resp(resp))
)
return ChatResult(
generations=generations,
llm_output={
"model_name": self.model_name,
},
)
示例:OpenAI 聊天模型
python
import os
from langchain_community.chat_models import ChatOpenAI
from langchain_core.messages import HumanMessage
model = ChatOpenAI(
model='deepseek-chat',
openai_api_key=os.getenv('DEEPSEEK_API_KEY'),
openai_api_base='https://api.deepseek.com',
max_tokens=1024
)
response = model.invoke(
[HumanMessage(content="一句话回答这个问题:AI会成为第一生产力吗?")])
print(response.content)
我没有 OpenAI 的 API Key,DeepSeek API 使用与 OpenAI 兼容的 API 格式,所以替代一下。
输出:

四、BaseLLM 与 BaseChatModel 的区别
在 LangChain 的语言模型抽象体系中,BaseLLM
与 BaseChatModel
是两个并列的核心基类,它们都继承自 BaseLanguageModel
,并作为 Runnable
可组合模块用于构建链、代理和应用框架。
它们的区别主要体现在输入输出格式、生成逻辑、使用场景等方面:
特性 | BaseLLM |
BaseChatModel |
---|---|---|
输入类型 | str (纯文本) |
List[BaseMessage] (结构化消息列表) |
输出类型 | str 或 LLMResult |
BaseMessage 或 ChatResult |
使用场景 | 文本生成、摘要、续写、补全 | 多轮对话、工具调用、代理决策、意图识别等 |
是否重写 invoke() |
✅ 重写 | ✅ 重写 |
内部核心方法 | _generate(prompt: PromptValue) |
_generate(messages: list[BaseMessage]) |
是否支持流式输出 | ✅ 支持(token 级流式输出) | ✅ 支持(message 内容流式分块) |
📌 典型子类包括:
BaseLLM
→OpenAI(text-davinci)
、HuggingFaceHub
BaseChatModel
→ChatOpenAI
、ChatAnthropic
、ChatBaichuan
🎯 使用接口一致性
尽管输入输出有所不同,二者都遵循 Runnable
接口标准,统一支持:
.invoke()
:执行一次推理.stream()
:流式输出(用于实时响应).batch()
:批量请求.with_config()
/.with_retry()
等链式组合方式
五、自定义一个 Chat 模型类(继承 BaseChatModel)
自定义一个对话模型 EchoChatModel
,用于模拟回显响应。
python
from langchain_core.language_models.chat_models import BaseChatModel
from langchain_core.messages import BaseMessage, AIMessage
from langchain_core.outputs import ChatResult, ChatGeneration
class EchoChatModel(BaseChatModel):
@property
def _llm_type(self) -> str:
return "echo-chat"
def _generate(
self,
messages: list[BaseMessage],
stop: list[str] = None,
**kwargs
) -> ChatResult:
content = f"Echo: {messages[-1].content}"
return ChatResult(
generations=[
ChatGeneration(
message=AIMessage(content=content)
)
]
)
这在测试代理行为或调试链路时非常有用。
python
from langchain_core.messages import HumanMessage
model = EchoChatModel()
response = model.invoke([HumanMessage(content="我向你提出了一个问题!")])
print(response.content)
输出:

六、设计模式与解耦价值
LangChain 采用"抽象基类 + 工厂方法 +统一协议"组合的方式封装 LLM:
- 所有语言模型遵循统一的
Runnable
调用接口(invoke
/stream
/batch
) - 不同模型类型拆分为
BaseLLM
与BaseChatModel
两个方向 - 各厂商通过继承封装模型差异,实现极高的复用性
这让我们在构建 Chain、Agent、工具执行器等复杂流程时,可以自由切换底层模型而不影响业务逻辑。
🔚 小结
BaseLanguageModel
是 LangChain 中抽象所有语言模型的基础invoke()
来自Runnable
接口体系,支持链式组合BaseLLM
/BaseChatModel
提供了具体模型的适配规范- 工厂模式实现解耦、多模型统一适配、可测性与可扩展性强
接下来我们将深入解析 LangChain 的 PromptTemplate 模板系统,掌握变量绑定、FewShot 示例注入与格式化机制,构建高可控的提示生成链路。