工业级大模型学习之路019:LangChain零基础入门教程(第二篇):LLM 模块与模型抽象

一、为什么需要 LLM 抽象?

1.1 大模型 API 碎片化的行业痛点

在 LangChain 出现之前,开发 LLM 应用需要面对严重的接口碎片化问题。不同厂商的大模型 API 在请求格式、参数命名、返回值结构、错误码等方面完全不兼容,导致:

  • 切换模型成本极高:从 OpenAI 切换到 Claude 需要重写所有模型调用代码
  • 重复造轮子:每个项目都需要重新实现重试、限流、日志、Token 统计等通用功能
  • 代码可维护性差:硬编码的 API 调用散落在代码各处,难以统一升级和维护

示例:不同模型的原生 API 调用对比

python 复制代码
# OpenAI原生API
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "你好"}],
    temperature=0.7
)
print(response.choices[0].message.content)

# 字节跳动豆包原生API
from volcenginesdkarkruntime import Ark
client = Ark()
response = client.chat.completions.create(
    model="ep-20240515123456789",
    messages=[{"role": "user", "content": "你好"}],
    temperature=0.7
)
print(response.choices[0].message.content)

# 阿里通义千问原生API
from dashscope import Generation
response = Generation.call(
    model="qwen-turbo",
    messages=[{"role": "user", "content": "你好"}],
    temperature=0.7
)
print(response.output.choices[0].message.content)

可以看到,三个模型的 API 看起来相似,但在客户端初始化、模型名称、返回值结构等方面存在细微差异,这些差异会随着模型数量的增加被无限放大。

1.2 LangChain 的解决方案:统一抽象层

LangChain 通过BaseChatModel基类定义了所有聊天模型的统一接口,将不同厂商的 API 差异封装在底层,为上层应用提供了完全一致的编程体验。

LangChain LLM 抽象架构图

这种设计带来了三大核心优势:

  1. 模型无关性:上层应用代码不依赖任何特定模型,切换模型只需要修改一行配置
  2. 功能复用:重试、限流、日志、监控等通用功能可以在抽象层统一实现
  3. 可扩展性 :新增模型只需要实现BaseChatModel接口,上层应用无需任何修改

1.3 四种调用模式的适用场景

LangChain 的BaseChatModel支持四种调用模式,分别适用于不同的业务场景:

调用模式 方法 适用场景 特点
同步调用 invoke() 简单请求、低并发场景 代码简单,阻塞等待结果
异步调用 ainvoke() 高并发服务、批量处理 非阻塞,支持高并发
流式输出 stream() 聊天机器人、实时交互 逐令牌返回结果,提升用户体验
批量调用 batch() 批量处理大量请求 合并请求,提高吞吐量

二、核心 API 详解

2.1 BaseChatModel 基类

BaseChatModel是所有聊天模型的抽象基类,定义了所有模型必须实现的核心方法和属性。它继承自Runnable,因此天然支持 LCEL 表达式语言,可以与其他 Runnable 组件无缝组合。

BaseChatModel 核心方法

python 复制代码
from langchain_core.language_models import BaseChatModel
from langchain_core.messages import BaseMessage, AIMessage
from typing import List, Optional

class BaseChatModel:
    def invoke(
        self,
        input: List[BaseMessage] | str,
        config: Optional[RunnableConfig] = None
    ) -> AIMessage:
        """同步调用模型,返回完整的AI消息"""
        pass

    async def ainvoke(
        self,
        input: List[BaseMessage] | str,
        config: Optional[RunnableConfig] = None
    ) -> AIMessage:
        """异步调用模型"""
        pass

    def stream(
        self,
        input: List[BaseMessage] | str,
        config: Optional[RunnableConfig] = None
    ) -> Iterator[AIMessageChunk]:
        """流式调用模型,返回消息块迭代器"""
        pass

    async def astream(
        self,
        input: List[BaseMessage] | str,
        config: Optional[RunnableConfig] = None
    ) -> AsyncIterator[AIMessageChunk]:
        """异步流式调用模型"""
        pass

    def batch(
        self,
        inputs: List[List[BaseMessage] | str],
        config: Optional[RunnableConfig] = None
    ) -> List[AIMessage]:
        """批量调用模型"""
        pass

2.2 消息类型系统

LangChain 定义了一套标准化的消息类型系统,用于表示对话中的不同角色和内容。所有消息都继承自BaseMessage基类。

核心消息类型

消息类型 角色 用途
HumanMessage 用户 表示用户发送的消息
AIMessage AI 助手 表示 AI 生成的回复消息
SystemMessage 系统 表示系统提示词,用于设定 AI 的角色和行为
ToolMessage 工具 表示工具调用的返回结果
FunctionMessage 函数 旧版函数调用消息,已被ToolMessage替代

消息内容块(ContentBlock) : LangChain 1.2 + 支持多模态内容,消息的content字段可以是字符串或内容块列表。内容块可以是文本、图像、音频、视频等多种类型。

python 复制代码
from langchain_core.messages import HumanMessage

# 纯文本消息
text_message = HumanMessage(content="你好,LangChain!")

# 多模态消息(文本+图像)
multimodal_message = HumanMessage(content=[
    {"type": "text", "text": "这张图片里有什么?"},
    {
        "type": "image_url",
        "image_url": {"url": "https://example.com/image.jpg"}
    }
])

2.3 主流大模型集成

LangChain 通过官方 Partner 包提供了对主流大模型的支持,所有模型都实现了BaseChatModel接口,使用方式完全一致。

2.3.1 OpenAI GPT 系列(官方推荐)

OpenAI 是 LangChain 生态支持最完善的模型,也是开发和测试的首选。

安装依赖

python 复制代码
poetry add langchain-openai==0.2.2
python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage

# 初始化模型
llm = ChatOpenAI(
    model="gpt-4o-mini-2024-07-18",  # 推荐使用带版本号的模型名称
    temperature=0,
    max_tokens=1024,
    timeout=30,
    max_retries=2
)

# 调用模型
messages = [
    SystemMessage(content="你是一个专业的Python开发助手"),
    HumanMessage(content="什么是装饰器?")
]

response = llm.invoke(messages)
print(response.content)
2.3.2 字节跳动豆包 4.0(国内首选)

字节跳动豆包是国内性能和效果最好的大模型之一,LangChain 通过langchain-volcengine包提供支持。

安装依赖

bash 复制代码
poetry add langchain-volcengine==0.1.3
python 复制代码
from langchain_volcengine import ChatVolcEngine
from langchain_core.messages import HumanMessage

# 初始化模型
# 需要在.env中配置VOLC_ACCESSKEY和VOLC_SECRETKEY
llm = ChatVolcEngine(
    model="ep-20240515123456789",  # 替换为你的模型端点ID
    temperature=0,
    max_tokens=1024
)

# 调用方式与OpenAI完全一致
response = llm.invoke([HumanMessage(content="什么是装饰器?")])
print(response.content)
2.3.3 阿里通义千问 3.5

阿里通义千问是国内另一个主流大模型,LangChain 通过langchain-dashscope包提供支持。

安装依赖

python 复制代码
poetry add langchain-dashscope==0.1.6
python 复制代码
from langchain_dashscope import ChatTongyi
from langchain_core.messages import HumanMessage

# 初始化模型
# 需要在.env中配置DASHSCOPE_API_KEY
llm = ChatTongyi(
    model="qwen-turbo",
    temperature=0,
    max_tokens=1024
)

# 调用方式完全一致
response = llm.invoke([HumanMessage(content="什么是装饰器?")])
print(response.content)
2.3.4 本地模型集成(Ollama)

对于需要本地部署的场景,Ollama 是最简单的本地大模型运行工具,LangChain 通过langchain-ollama包提供支持。

安装 Ollama

  1. 访问Ollama 官网下载并安装
  2. 运行ollama pull qwen:7b下载 Qwen 2.5 7B 模型

安装依赖

python 复制代码
poetry add langchain-ollama==0.2.0
python 复制代码
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage

# 初始化本地模型
llm = ChatOllama(
    model="qwen:7b",
    temperature=0,
    max_tokens=1024
)

# 调用方式完全一致
response = llm.invoke([HumanMessage(content="什么是装饰器?")])
print(response.content)

关键结论:所有模型的调用方式完全相同,切换模型只需要修改初始化代码,上层业务逻辑无需任何改动。

2.4 模型参数深度解析

LangChain 的BaseChatModel支持一系列通用参数,用于控制模型的输出行为。理解这些参数的作用是优化 LLM 应用效果的关键。

参数 作用 取值范围 推荐值 场景说明
temperature 控制输出的随机性 0-2 0(事实性任务)、0.7(创意性任务) 值越高,输出越随机、越有创意;值越低,输出越确定、越一致
max_tokens 限制模型生成的最大令牌数 1 - 模型上下文窗口 1024-4096 防止生成过长的回复,控制成本
top_p 核采样参数,控制词汇选择范围 0-1 0.9 值越小,输出越集中在高概率词汇上;值越大,输出越多样
frequency_penalty 频率惩罚,减少重复内容 -2.0-2.0 0.0-1.0 值越高,越不容易出现重复的短语
presence_penalty 存在惩罚,鼓励生成新主题 -2.0-2.0 0.0-1.0 值越高,越容易引入新的话题
timeout 请求超时时间(秒) 正数 30-60 防止请求长时间阻塞
max_retries 最大重试次数 非负整数 2-3 自动重试失败的请求

参数调优最佳实践

  • 事实性任务 (问答、摘要、代码生成):temperature=0,保证输出的准确性和一致性
  • 创意性任务 (写作、头脑风暴、文案生成):temperature=0.7-1.0,增加输出的多样性
  • 永远不要使用temperature=2:会导致输出完全混乱,没有任何意义
  • top_ptemperature不要同时调整,通常只调整其中一个即可

三、工业级最佳实践

简单的模型调用只能用于原型开发,要达到生产环境的要求,必须实现重试、降级、限流、监控等一系列工业级特性。

3.1 模型工厂模式

模型工厂模式是管理多个模型的最佳实践,它将模型的初始化逻辑封装在工厂类中,上层应用通过配置获取模型实例,实现了配置与代码的分离。

工业级模型工厂实现

python 复制代码
from typing import Dict, Optional
from pydantic import BaseModel, Field
from langchain_core.language_models import BaseChatModel
from langchain_openai import ChatOpenAI
from langchain_ollama import ChatOllama

class ModelConfig(BaseModel):
    """模型配置类"""
    provider: str = Field(description="模型提供商:openai/ollama")
    model_name: str = Field(description="模型名称")
    temperature: float = Field(default=0.0)
    max_tokens: int = Field(default=1024)
    timeout: int = Field(default=30)
    max_retries: int = Field(default=2)

class ModelFactory:
    """模型工厂类"""
    _instances: Dict[str, BaseChatModel] = {}

    @classmethod
    def get_model(cls, config: ModelConfig) -> BaseChatModel:
        """获取模型实例(单例)"""
        instance_key = f"{config.provider}:{config.model_name}:{config.temperature}"
        
        if instance_key not in cls._instances:
            if config.provider == "openai":
                model = ChatOpenAI(
                    model=config.model_name,
                    temperature=config.temperature,
                    max_tokens=config.max_tokens,
                    timeout=config.timeout,
                    max_retries=config.max_retries
                )
            elif config.provider == "ollama":
                model = ChatOllama(
                    model=config.model_name,
                    temperature=config.temperature,
                    max_tokens=config.max_tokens,
                    timeout=config.timeout
                )
            else:
                raise ValueError(f"不支持的提供商:{config.provider}")
            
            cls._instances[instance_key] = model
        
        return cls._instances[instance_key]

# 使用示例
config = ModelConfig(
    provider="openai",
    model_name="gpt-4o-mini",
    temperature=0
)
llm = ModelFactory.get_model(config)
print(llm.invoke("你好"))

3.2 重试机制:指数退避 + 抖动

使用 LangChain 内置的ModelRetryMiddleware实现工业级重试策略,解决 API 不稳定问题。

通用实现

python 复制代码
from langchain_core.middleware import ModelRetryMiddleware
from tenacity import stop_after_attempt, wait_exponential_jitter

# 创建重试中间件
retry_middleware = ModelRetryMiddleware(
    stop=stop_after_attempt(3),  # 最多重试3次
    wait=wait_exponential_jitter(
        multiplier=1,  # 初始等待1秒
        min=1,         # 最小等待1秒
        max=10         # 最大等待10秒
    ),
    # 只重试可恢复的异常
    retry_exceptions=(
        TimeoutError,
        ConnectionError,
        openai.RateLimitError,
        openai.APIError,
        openai.APIConnectionError
    )
)

# 应用到模型
llm_with_retry = llm.with_middleware(retry_middleware)

3.3 自动降级策略

当主模型不可用时,自动切换到备用模型,保证服务可用性。

通用实现

python 复制代码
# 主模型:GPT-4o-mini
primary_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 备用模型:本地Qwen 7B
fallback_llm = ChatOllama(model="qwen:7b", temperature=0)

# 组合模型:主模型失败时自动切换到备用
robust_llm = primary_llm.with_fallbacks([fallback_llm])

3.4 Token 统计与成本控制

使用CostTrackingMiddleware自动统计 Token 使用量和成本。

通用实现

python 复制代码
from langchain_core.middleware import CostTrackingMiddleware

cost_tracker = CostTrackingMiddleware()
llm_with_cost = llm.with_middleware(cost_tracker)

# 调用模型
response = llm_with_cost.invoke("统计Token使用量")

# 获取统计结果
print(f"总Token数:{cost_tracker.total_tokens}")
print(f"输入Token:{cost_tracker.prompt_tokens}")
print(f"输出Token:{cost_tracker.completion_tokens}")
print(f"总成本:${cost_tracker.total_cost:.6f}")

四、新建项目

现有 RAG 项目在整合过程中,发现遇到依赖版本问题,无法使用langchain1.x以上版本,所以决定重新创建新工程。

4.1 项目初始化

复制代码
# 创建项目目录
mkdir langchain-2026 && cd langchain-2026

# 创建虚拟环境(必须,隔离系统Python)
python -m venv .venv

# 激活虚拟环境
# Windows PowerShell
.venv\Scripts\Activate.ps1

4.2 项目标准结构

html 复制代码
langchain-2026-framework/
├── .env                  # 环境变量(敏感信息)
├── .gitignore            # Git忽略文件
├── requirements.txt      # 依赖清单
├── main.py               # 项目入口
├── config/               # 配置管理
│   ├── __init__.py
│   └── settings.py       # 全局配置
├── core/                 # 核心业务层
│   ├── __init__.py
│   ├── llm_factory.py    # 模型工厂(核心)
│   ├── rag.py            # RAG模块(后续扩展)
│   └── agent.py          # Agent模块(后续扩展)
├── utils/                # 通用工具
│   ├── __init__.py
│   ├── logger.py         # 日志系统
│   └── exceptions.py     # 自定义异常
└── tests/                # 单元测试
    └── test_llm.py       # LLM模块测试

4.3 依赖安装(2026 年 5 月最新稳定版)

创建requirements.txt,写入以下内容(无需指定版本,自动安装最新兼容版,不要用中文):

html 复制代码
# LangChain核心生态(2026年5月最新稳定版)
langchain
langchain-core
langchain-openai
langchain-ollama
langgraph
langsmith

# 工具依赖
python-dotenv
pydantic-settings
tenacity
aiohttp

# 开发依赖
pytest
black
isort

安装依赖:

bash 复制代码
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple

4.4 配置管理 config/settings.py

python 复制代码
from pydantic_settings import BaseSettings, SettingsConfigDict
from pydantic import Field
from pathlib import Path

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore"
    )

    # 项目基础配置
    app_name: str = Field(default="LangChain 2026开发框架", description="应用名称")
    debug: bool = Field(default=True, description="调试模式")

    # 大模型API配置
    doubao_api_key: str = Field(default="", description="豆包API密钥")
    doubao_base_url: str = Field(default="https://ark.cn-beijing.volces.com/api/v3", description="豆包API地址")
    openai_api_key: str = Field(default="", description="OpenAI API密钥")

    # 默认模型配置
    default_provider: str = Field(default="doubao", description="默认模型提供商")
    default_model: str = Field(default="doubao-seed-2-0-code-xxxx", description="默认模型名称")
    llm_temperature: float = Field(default=0.1, description="温度参数")
    llm_max_tokens: int = Field(default=1024, description="最大生成长度")
    llm_timeout: int = Field(default=60, description="超时时间(秒)")
    llm_max_retries: int = Field(default=3, description="最大重试次数")

    # LangSmith可观测性配置
    langchain_tracing_v2: bool = Field(default=False, description="是否开启LangSmith追踪")
    langchain_api_key: str = Field(default="", description="LangSmith API密钥")
    langchain_project: str = Field(default="langchain-2026-framework", description="LangSmith项目名称")

    # 日志配置
    log_level: str = Field(default="INFO", description="日志级别")
    log_dir: Path = Field(default=Path("./logs"), description="日志目录")

# 全局单例
settings = Settings()

4.5 日志系统 utils/logger.py

python 复制代码
import logging
from logging.handlers import RotatingFileHandler
from pathlib import Path
from config.settings import settings

def setup_logger():
    """配置全局日志系统"""
    # 创建日志目录
    settings.log_dir.mkdir(exist_ok=True)
    
    # 获取根日志器
    logger = logging.getLogger()
    logger.setLevel(settings.log_level)
    logger.handlers.clear()

    # 日志格式
    formatter = logging.Formatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )

    # 控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    console_handler.setLevel(logging.INFO)

    # 文件处理器
    file_handler = RotatingFileHandler(
        filename=settings.log_dir / "app.log",
        maxBytes=10*1024*1024,
        backupCount=5,
        encoding="utf-8"
    )
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.DEBUG)

    # 添加处理器
    logger.addHandler(console_handler)
    logger.addHandler(file_handler)

    # 第三方库日志级别
    logging.getLogger("httpx").setLevel(logging.WARNING)
    logging.getLogger("openai").setLevel(logging.WARNING)
    logging.getLogger("langchain").setLevel(logging.INFO)

    logger.info("✅ 日志系统初始化完成")
    return logger

# 全局日志器
logger = setup_logger()

4.6 自定义异常 utils/exceptions.py

python 复制代码
from utils.logger import logger

class FrameworkBaseException(Exception):
    """框架基础异常类"""
    def __init__(self, message: str, error_code: int = 1000):
        self.message = message
        self.error_code = error_code
        super().__init__(self.message)
        logger.error(f"[{self.error_code}] {self.message}")

class ModelLoadError(FrameworkBaseException):
    """模型加载失败异常"""
    def __init__(self, model_name: str, details: str = ""):
        message = f"模型加载失败:{model_name}"
        if details:
            message += f",详细信息:{details}"
        super().__init__(message, error_code=1001)

class GenerationError(FrameworkBaseException):
    """生成失败异常"""
    def __init__(self, details: str = ""):
        message = "回答生成失败"
        if details:
            message += f",详细信息:{details}"
        super().__init__(message, error_code=1002)

4.7 核心模型工厂 core/llm_factory.py

python 复制代码
from typing import Dict, Optional, Iterator, AsyncIterator
from langchain_core.language_models import BaseChatModel
from langchain_openai import ChatOpenAI
from langchain_ollama import ChatOllama
from langchain_core.runnables import RunnableRetry
from tenacity import stop_after_attempt, wait_exponential_jitter
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
from config.settings import settings
from utils.logger import logger
from utils.exceptions import ModelLoadError, GenerationError

class LLMFactory:
    """
    大模型工厂类(2026最新版)
    支持:豆包、OpenAI、本地Ollama模型
    内置:重试、降级、Token统计、流式输出
    """
    _instances: Dict[str, BaseChatModel] = {}

    @classmethod
    def get_llm(
        cls,
        provider: str = None,
        model_name: str = None,
        temperature: float = None,
        max_tokens: int = None
    ) -> BaseChatModel:
        """
        获取模型实例(单例模式)
        :param provider: 模型提供商:doubao/openai/ollama
        :param model_name: 模型名称
        :param temperature: 温度参数
        :param max_tokens: 最大生成长度
        :return: LangChain ChatModel实例
        """
        # 使用默认配置
        provider = provider or settings.default_provider
        model_name = model_name or settings.default_model
        temperature = temperature if temperature is not None else settings.llm_temperature
        max_tokens = max_tokens or settings.llm_max_tokens

        # 生成唯一实例键
        instance_key = f"{provider}:{model_name}:{temperature}:{max_tokens}"

        if instance_key not in cls._instances:
            try:
                # 创建基础模型
                base_llm = cls._create_base_llm(provider, model_name, temperature, max_tokens)
                
                # 添加重试机制(LangChain 2026标准写法)
                llm_with_retry = base_llm.with_retry(
                    retry_if_exception_type=(TimeoutError, ConnectionError, Exception),
                    wait_exponential_jitter=True,
                    stop_after_attempt=settings.llm_max_retries,
                    exponential_jitter_params={"initial": 1, "max": 10}
                )

                cls._instances[instance_key] = llm_with_retry
                logger.info(f"✅ 模型初始化成功:{provider} {model_name}")

            except Exception as e:
                raise ModelLoadError(f"{provider} {model_name}", str(e)) from e

        return cls._instances[instance_key]

    @classmethod
    def _create_base_llm(
        cls,
        provider: str,
        model_name: str,
        temperature: float,
        max_tokens: int
    ) -> BaseChatModel:
        """创建基础模型实例"""
        if provider == "doubao":
            # 豆包API完全兼容OpenAI格式
            return ChatOpenAI(
                api_key=settings.doubao_api_key,
                base_url=settings.doubao_base_url,
                model=model_name,
                temperature=temperature,
                max_tokens=max_tokens,
                timeout=settings.llm_timeout
            )
        
        elif provider == "openai":
            return ChatOpenAI(
                api_key=settings.openai_api_key,
                model=model_name,
                temperature=temperature,
                max_tokens=max_tokens,
                timeout=settings.llm_timeout
            )
        
        elif provider == "ollama":
            return ChatOllama(
                model=model_name,
                temperature=temperature,
                max_tokens=max_tokens,
                timeout=settings.llm_timeout * 2
            )
        
        else:
            raise ValueError(f"不支持的模型提供商:{provider}")

    @classmethod
    def generate(
        cls,
        prompt: str | list[BaseMessage],
        provider: str = None,
        model_name: str = None,
        temperature: float = None,
        max_tokens: int = None
    ) -> str:
        """
        同步生成文本
        :param prompt: 提示词(字符串或消息列表)
        :return: 生成的文本
        """
        try:
            llm = cls.get_llm(provider, model_name, temperature, max_tokens)
            
            # 处理字符串输入
            if isinstance(prompt, str):
                messages = [HumanMessage(content=prompt)]
            else:
                messages = prompt

            response = llm.invoke(messages)
            
            # 统计Token使用量
            if response.usage_metadata:
                logger.debug(
                    f"Token统计 | 总:{response.usage_metadata['total_tokens']} | "
                    f"输入:{response.usage_metadata['input_tokens']} | "
                    f"输出:{response.usage_metadata['output_tokens']}"
                )

            return response.content.strip()

        except Exception as e:
            raise GenerationError(str(e)) from e

    @classmethod
    def stream_generate(
        cls,
        prompt: str | list[BaseMessage],
        provider: str = None,
        model_name: str = None,
        temperature: float = None,
        max_tokens: int = None
    ) -> Iterator[str]:
        """流式生成文本"""
        try:
            llm = cls.get_llm(provider, model_name, temperature, max_tokens)
            
            if isinstance(prompt, str):
                messages = [HumanMessage(content=prompt)]
            else:
                messages = prompt

            for chunk in llm.stream(messages):
                if chunk.content:
                    yield chunk.content

        except Exception as e:
            logger.error(f"流式生成失败:{str(e)}")
            yield "抱歉,生成回答时发生错误,请稍后重试。"

    @classmethod
    async def astream_generate(
        cls,
        prompt: str | list[BaseMessage],
        provider: str = None,
        model_name: str = None,
        temperature: float = None,
        max_tokens: int = None
    ) -> AsyncIterator[str]:
        """异步流式生成文本"""
        try:
            llm = cls.get_llm(provider, model_name, temperature, max_tokens)
            
            if isinstance(prompt, str):
                messages = [HumanMessage(content=prompt)]
            else:
                messages = prompt

            async for chunk in llm.astream(messages):
                if chunk.content:
                    yield chunk.content

        except Exception as e:
            logger.error(f"异步流式生成失败:{str(e)}")
            yield "抱歉,生成回答时发生错误,请稍后重试。"

4.8 环境变量配置 .env

html 复制代码
# 豆包API(推荐,中文效果好)
DOUBAO_API_KEY=你的豆包API密钥
DOUBAO_BASE_URL=https://ark.cn-beijing.volces.com/api/v3

# OpenAI API(可选)
# OPENAI_API_KEY=你的OpenAI API密钥

# LangSmith可观测性(可选,调试用)
# LANGCHAIN_TRACING_V2=true
# LANGCHAIN_API_KEY=你的LangSmith API密钥
# LANGCHAIN_PROJECT=langchain-2026-framework

# 调试模式
DEBUG=true

4.9 项目入口与验证 main.py

python 复制代码
from dotenv import load_dotenv
load_dotenv()  # 必须在导入其他模块之前加载环境变量

from core.llm_factory import LLMFactory
from langchain_core.messages import SystemMessage, HumanMessage
import asyncio

def test_basic_generate():
    """测试基础生成功能"""
    print("=== 测试基础生成功能 ===")
    response = LLMFactory.generate("用3句话解释什么是大语言模型")
    print(f"回答:{response}\n")

def test_stream_generate():
    """测试流式生成功能"""
    print("=== 测试流式生成功能 ===")
    print("回答:", end="", flush=True)
    for chunk in LLMFactory.stream_generate("写一首关于夏天的七言绝句"):
        print(chunk, end="", flush=True)
    print("\n")

def test_system_prompt():
    """测试系统提示词"""
    print("=== 测试系统提示词 ===")
    messages = [
        SystemMessage(content="你是一个专业的Python开发助手,只回答Python相关问题"),
        HumanMessage(content="什么是装饰器?")
    ]
    response = LLMFactory.generate(messages)
    print(f"回答:{response}\n")

@pytest.mark.asyncio
async def test_astream_generate():
    """测试异步流式生成"""
    print("=== 测试异步流式生成 ===")
    print("回答:", end="", flush=True)
    async for chunk in LLMFactory.astream_generate("什么是异步编程?"):
        print(chunk, end="", flush=True)
    print("\n")

if __name__ == "__main__":
    print("🚀 LangChain 2026开发框架启动\n")
    
    # 运行所有测试
    test_basic_generate()
    test_stream_generate()
    test_system_prompt()
    
    # 运行异步测试
    asyncio.run(test_astream_generate())
    
    print("🎉 所有测试通过!框架搭建完成")

4.10 测试

相关推荐
AI医影跨模态组学2 小时前
Int J Surg华中科技大学同济医学院附属协和医院:可解释机器学习模型预测胰腺癌早期复发:整合瘤内瘤周影像组学及身体成分分析
人工智能·机器学习·论文·医学·医学影像·影像组学
龙侠九重天2 小时前
Embedding 模型深度使用——语义搜索与聚类
人工智能·深度学习·数据挖掘·大模型·llm·embedding·聚类
唐璜Taro2 小时前
AI Agent 智能体:从入门到实战的学习路线
学习·ai
凯瑟琳.奥古斯特2 小时前
操作系统核心结构解析
java·开发语言·c++·python·职场和发展
闭关修炼啊哈2 小时前
[IdeaLoop · 灵感回路] AI时代独立开发者·创业/副业灵感日报 · 2026-05-20 晚报
人工智能
麻雀飞吧2 小时前
非 CTP 柜台连接天勤:众期融航易达等网关差异备忘
python
L、2182 小时前
CANN 通信库 HCCL 实战:昇腾多卡训练时 AllReduce 为什么卡在这个地方?
人工智能·安全
@蔓蔓喜欢你2 小时前
CSS 变量:样式开发的新维度
人工智能·ai
BJ_bafangonline2 小时前
Houdini 与 AI 的深度融合:从合成数据生成到机器学习训练的全流程解析
人工智能·机器学习·houdini