第3章 LangChain 核心抽象:Models 与 Messages

上一章我们完成了LangChain开发环境的搭建,相当于为大模型应用开发准备好了"工具房"。本章将聚焦LangChain最基础、最核心的两个抽象概念------Models(模型)Messages(消息):Models是LangChain与大模型交互的"入口",决定了回答的质量和能力;Messages是交互的"载体",定义了用户、AI和系统之间的对话逻辑。

本章将从"模型分类→模型集成→消息类型→生成控制→高级特性→实战落地"逐步展开,所有代码示例均简洁可复制、标注官方来源,兼顾新手入门和实际开发需求,帮你彻底吃透Models与Messages的核心用法,为后续链式调用、Agent开发打下基础。

3.1 LLM 与 ChatModel 的区别与适用场景

LangChain中,与大模型交互的核心接口分为两类:LLM(大语言模型)ChatModel(聊天模型)。很多新手容易混淆两者,其实它们的核心区别在于"交互格式"和"适用场景",选择对了模型类型,能大幅提升开发效率。

3.1.1 核心区别(一张表看懂)

对比维度 LLM(大语言模型) ChatModel(聊天模型)
交互格式 纯文本输入(字符串),输出纯文本(字符串) 消息列表输入(Message对象),输出消息对象(AIMessage)
核心特点 简单直接,无需关注消息结构,适合纯文本生成 支持多轮对话、系统提示,结构清晰,适合聊天场景
调用方式 使用 invoke(text) 调用,输入字符串 使用 invoke(messages) 调用,输入消息列表
典型模型 GPT-3(text-davinci-003)、Llama 2(text模型) GPT-3.5-turbo、GPT-4、Claude、Llama 3(chat模型)

3.1.2 代码示例(直观对比)

1. LLM 调用示例(以OpenAI的text-davinci-003为例)
python 复制代码
from langchain_openai import OpenAI
from dotenv import load_dotenv
import os

load_dotenv()

# 初始化LLM(纯文本交互)
llm = OpenAI(
    model_name="text-davinci-003",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.7
)

# 调用:输入纯文本字符串
response = llm.invoke("简单介绍LangChain")
print("LLM输出(纯文本):", response)

依赖安装:pip install langchain-openai==0.1.6;代码来源:LangChain LLM官方示例(python.langchain.com/docs/langch...)。

2. ChatModel 调用示例(以GPT-3.5-turbo为例)
python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os

load_dotenv()

# 初始化ChatModel(消息列表交互)
chat_model = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.7
)

# 调用:输入消息列表(此处为单条用户消息)
response = chat_model.invoke([HumanMessage(content="简单介绍LangChain")])
print("ChatModel输出(消息对象):", response.content)

代码来源:LangChain ChatModel官方示例(python.langchain.com/docs/langch...)。

3.1.3 适用场景选择(新手必看)

  • 优先选 ChatModel 的场景:多轮对话(如聊天机器人)、需要系统提示(System Prompt)、需要明确区分用户/AI消息、使用主流聊天模型(GPT-3.5/4、Claude、Llama 3);

  • LLM 的场景:纯文本生成(如文案、摘要)、使用旧版文本模型(如text-davinci-003)、简单场景无需复杂消息结构;

  • 注意:LangChain 1.0+版本更推荐使用ChatModel,其功能更全面、更贴合当前大模型的交互逻辑,LLM更多用于兼容旧版模型。

3.2 使用 OpenAI、Anthropic、Hugging Face 模型

LangChain的核心优势之一是"统一模型接口"------无论使用OpenAI、Anthropic还是Hugging Face的模型,调用方式高度一致,无需修改核心代码,只需替换模型初始化逻辑。本节聚焦3类主流云端/开源模型的集成,示例简洁可直接运行。

3.2.1 OpenAI 模型(GPT-3.5/4,最常用)

OpenAI的ChatModel是LangChain开发中最常用的模型,支持GPT-3.5-turbo、GPT-4等,调用方式如下(延续上一节的ChatModel示例,补充多轮对话):

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from dotenv import load_dotenv
import os

load_dotenv()

# 初始化OpenAI ChatModel
chat_openai = ChatOpenAI(
    model_name="gpt-3.5-turbo",  # 可替换为gpt-4
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.5
)

# 多轮对话:系统提示 + 用户消息 + AI消息 + 新用户消息
messages = [
    SystemMessage(content="你是一名LangChain开发助手,回答简洁易懂,不超过3句话。"),
    HumanMessage(content="LangChain的Models抽象有什么用?"),
    AIMessage(content="统一模型接口,让不同大模型调用方式一致,降低开发成本。"),
    HumanMessage(content="那ChatModel和LLM的区别是什么?")
]

# 调用模型
response = chat_openai.invoke(messages)
print("OpenAI响应:", response.content)

代码来源:LangChain OpenAI集成文档(python.langchain.com/docs/integr...);注意:需科学上网,API密钥需在OpenAI平台获取(详见第2章)。

3.2.2 Anthropic 模型(Claude,长文本优势)

Anthropic的Claude模型以"长上下文窗口"著称(如Claude 3 Opus支持200k上下文),适合长文本处理,LangChain集成方式如下:

python 复制代码
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os

load_dotenv()

# 初始化Claude模型(需配置ANTHROPIC_API_KEY)
chat_claude = ChatAnthropic(
    model_name="claude-3-sonnet-20240229",
    api_key=os.getenv("ANTHROPIC_API_KEY"),
    temperature=0.6
)

# 调用模型
response = chat_claude.invoke([HumanMessage(content="用一句话说明Claude模型的优势")])
print("Claude响应:", response.content)

依赖安装:pip install langchain-anthropic==0.1.14;API密钥获取:访问Anthropic官网(console.anthropic.com/);代码来源:LangChain Anthropic集成文档(python.langchain.com/docs/integr...)。

3.2.3 Hugging Face 模型(开源模型,可云端/本地调用)

Hugging Face提供大量开源模型(如Llama 2、Mistral),可通过LangChain直接调用云端模型(Hugging Face Inference Endpoints)或本地模型,这里以云端调用为例:

python 复制代码
from langchain_community.chat_models import ChatHuggingFace
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os

load_dotenv()

# 初始化Hugging Face ChatModel(云端调用)
chat_hf = ChatHuggingFace(
    model_name="mistralai/Mistral-7B-Instruct-v0.2",
    huggingfacehub_api_token=os.getenv("HUGGINGFACE_API_TOKEN"),
    temperature=0.7
)

# 调用模型
response = chat_hf.invoke([HumanMessage(content="介绍一下Mistral模型")])
print("Hugging Face响应:", response.content)

依赖安装:pip install langchain-community==0.1.13 huggingface-hub==0.22.2;API密钥获取:访问Hugging Face官网(huggingface.co/settings/to...);代码来源:LangChain Hugging Face集成文档(python.langchain.com/docs/integr...)。

3.2.4 核心总结

LangChain对主流模型的集成遵循"统一接口"原则------无论使用哪种模型,初始化后均通过invoke()调用,区别仅在于"模型名称"和"API密钥",这也是LangChain"模块化"设计的体现,极大降低了模型替换的成本。

3.3 本地部署模型集成(Llama.cpp、vLLM、Ollama)

在隐私敏感、无网络或成本控制场景下,本地部署开源模型是最佳选择。本节介绍3种主流本地模型部署工具(Ollama、Llama.cpp、vLLM)的LangChain集成方法,其中Ollama最适合新手,vLLM适合高性能场景,Llama.cpp适合轻量部署。

3.3.1 Ollama(新手首选,轻量便捷)

Ollama是最易用的本地模型部署工具,支持一键拉取、运行开源模型(Llama 3、Qwen、Mistral等),LangChain集成无需复杂配置,步骤如下(延续第2章内容,补充多轮对话):

python 复制代码
from langchain_community.chat_models import ChatOllama
from langchain_core.messages import HumanMessage, SystemMessage

# 初始化本地Ollama模型(已拉取llama3:8b)
chat_ollama = ChatOllama(
    model="llama3:8b",  # 模型名称,需提前用ollama pull拉取
    temperature=0.7,
    max_tokens=100  # 控制输出长度
)

# 多轮对话调用
messages = [
    SystemMessage(content="你是本地部署的AI助手,回答简洁。"),
    HumanMessage(content="本地模型和云端模型的区别是什么?")
]

response = chat_ollama.invoke(messages)
print("Ollama响应:", response.content)

注意:需提前安装Ollama并拉取对应模型(ollama pull llama3:8b);代码来源:LangChain Ollama集成文档(python.langchain.com/docs/integr...)。

3.3.2 Llama.cpp(轻量部署,低配置适配)

Llama.cpp是一款轻量级开源模型部署工具,支持将Llama系列模型转换为二进制文件,在低配置设备(如笔记本)上运行,LangChain集成步骤如下:

  1. 安装依赖:pip install langchain-community==0.1.13 llama-cpp-python==0.2.24

  2. 下载模型:从Hugging Face下载转换好的Llama 2模型(如llama-2-7b-chat.Q4_K_M.gguf);

  3. LangChain调用示例:

python 复制代码
from langchain_community.llms import LlamaCpp
from langchain_core.prompts import PromptTemplate

# 初始化Llama.cpp模型(本地模型文件路径)
llm_llama_cpp = LlamaCpp(
    model_path="./llama-2-7b-chat.Q4_K_M.gguf",  # 本地模型文件路径
    temperature=0.7,
    max_tokens=100,
    n_ctx=2048  # 上下文窗口大小
)

# 调用模型(LLM接口,纯文本输入)
prompt = PromptTemplate.from_template("请回答:{question}")
response = llm_llama_cpp.invoke(prompt.format(question="Llama.cpp的优势是什么?"))
print("Llama.cpp响应:", response)

代码来源:LangChain Llama.cpp集成文档(python.langchain.com/docs/integr...);注意:模型文件较大(约4GB),需提前下载。

3.3.3 vLLM(高性能部署,适合高并发)

vLLM是一款高性能开源模型部署工具,支持高并发请求,适合生产环境本地部署,LangChain集成步骤如下:

  1. 安装依赖:pip install langchain-community==0.1.13 vllm==0.4.0

  2. 启动vLLM服务:终端执行vllm serve meta-llama/Llama-2-7b-chat-hf(需提前下载模型);

  3. LangChain调用示例:

python 复制代码
from langchain_community.chat_models import ChatVLLM
from langchain_core.messages import HumanMessage

# 连接本地vLLM服务
chat_vllm = ChatVLLM(
    model="meta-llama/Llama-2-7b-chat-hf",
    temperature=0.7,
    max_tokens=100,
    vllm_kwargs={"tensor_parallel_size": 1}  # 并行度,根据GPU配置调整
)

# 调用模型
response = chat_vllm.invoke([HumanMessage(content="vLLM为什么适合高并发?")])
print("vLLM响应:", response.content)

代码来源:LangChain vLLM集成文档(python.langchain.com/docs/integr...);注意:vLLM需要GPU支持(推荐NVIDIA GPU),适合高性能场景。

3.3.4 本地模型选型建议

  • 新手/快速验证:优先选 Ollama,一键部署,无需复杂配置;

  • 低配置设备(如笔记本):选 Llama.cpp,轻量占用,支持CPU运行;

  • 生产环境/高并发:选 vLLM,高性能,支持批量请求;

  • 模型选择:优先选7B参数模型(如llama3:8b、Qwen-7B),平衡性能和资源占用。

3.4 消息类型详解:HumanMessage、AIMessage、SystemMessage

在ChatModel交互中,所有输入都是"消息列表",LangChain定义了3种核心消息类型,分别对应"用户输入、AI输出、系统提示",它们共同构成了多轮对话的逻辑,掌握这些消息类型,才能灵活实现复杂的聊天场景。

3.4.1 核心消息类型(3种必掌握)

所有消息类型均继承自BaseMessage,核心区别在于"角色"和"用途",具体如下:

1. SystemMessage(系统消息)
  • 作用:定义AI的"角色、行为准则、回答要求",相当于给AI设定"人设",贯穿整个对话过程;

  • 特点:通常放在消息列表的最前面,只需要设置一次(多轮对话中可重复设置,覆盖之前的准则);

  • 示例:SystemMessage(content="你是一名LangChain开发专家,回答需包含代码示例,简洁明了。")

2. HumanMessage(用户消息)
  • 作用:用户输入的查询、问题或指令,是AI生成回答的核心依据;

  • 特点:多轮对话中,每次用户输入都是一条HumanMessage,与AI的AIMessage交替出现;

  • 示例:HumanMessage(content="如何使用LangChain的SystemMessage?")

3. AIMessage(AI消息)
  • 作用:AI生成的回答,通常是ChatModel的输出结果;

  • 特点:多轮对话中,需将历史AIMessage加入消息列表,让AI"记住"之前的回答;

  • 示例:AIMessage(content="使用SystemMessage需导入对应的类,放在消息列表最前面,示例如下:...")

3.4.2 代码示例(多轮对话,完整消息流程)

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from dotenv import load_dotenv
import os

load_dotenv()

chat_model = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.6
)

# 构建多轮对话消息列表(系统消息→用户消息→AI消息→新用户消息)
messages = [
    # 系统消息:设定AI角色和回答要求
    SystemMessage(content="你是LangChain消息类型助手,回答仅围绕3种核心消息类型,不扩展其他内容。"),
    # 第一轮:用户提问,AI回答
    HumanMessage(content="LangChain有哪几种核心消息类型?"),
    AIMessage(content="核心消息类型有3种:SystemMessage(系统提示)、HumanMessage(用户输入)、AIMessage(AI输出)。"),
    # 第二轮:用户追问,AI继续回答
    HumanMessage(content="SystemMessage的作用是什么?")
]

# 调用模型,获取新的AI消息
new_ai_message = chat_model.invoke(messages)
print("新AI回答:", new_ai_message.content)

# 将新的AI消息加入列表,用于下一轮对话
messages.append(new_ai_message)
print("\n完整消息列表:")
for msg in messages:
    print(f"【{msg.type}】: {msg.content}")

代码来源:LangChain Messages官方示例(python.langchain.com/docs/langch...);运行结果可清晰看到消息类型的交互逻辑,以及多轮对话中消息列表的变化。

3.4.3 其他常用消息类型(可选)

除了3种核心消息类型,LangChain还提供两种辅助消息类型,适合特殊场景:

  • FunctionMessage:用于工具调用场景,存储工具调用的结果(后续Agent章节详细讲解);

  • ToolMessage:与FunctionMessage配套,传递工具调用的参数和结果。

3.5 控制生成行为:temperature、max_tokens、stop sequences

调用大模型时,我们需要控制其生成行为(如回答的随机性、长度、结束条件),避免出现"回答过长、偏离主题、随机性过高"等问题。LangChain支持通过3个核心参数控制生成行为,所有模型(ChatModel/LLM)均适用。

3.5.1 核心参数详解(3个必掌握)

参数名称 作用 取值范围 使用建议
temperature(温度) 控制回答的随机性和创造性,值越高,回答越随机、有创造性;值越低,回答越严谨、固定 0 ~ 2 严谨场景(如问答、代码):0.10.5;创意场景(如文案、故事):0.71.5
max_tokens(最大 tokens 数) 控制AI回答的最大长度(tokens 是模型处理文本的基本单位,1个中文约等于1~2个tokens) 正整数(根据模型限制调整) 根据需求设定,避免回答过长(如聊天场景设100200,长文本场景设5001000)
stop sequences(停止序列) 设定AI回答的"终止条件",当AI生成的文本包含停止序列时,立即停止生成 字符串或字符串列表 适合固定格式场景(如生成列表时,以"### 结束"为停止序列)

3.5.2 代码示例(参数实战)

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os

load_dotenv()

# 1. 低temperature(0.2):严谨、固定回答
chat_low_temp = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.2,
    max_tokens=100
)

# 2. 高temperature(1.5):随机、有创造性回答
chat_high_temp = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=1.5,
    max_tokens=100
)

# 3. 带stop sequences:生成到"### 结束"时停止
chat_stop_seq = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.7,
    max_tokens=200,
    stop=["### 结束"]  # 停止序列
)

# 测试不同参数的效果
question = "用3句话介绍LangChain的Models抽象"

print("=== 低temperature(0.2) ===")
print(chat_low_temp.invoke([HumanMessage(content=question)]).content)

print("\n=== 高temperature(1.5) ===")
print(chat_high_temp.invoke([HumanMessage(content=question)]).content)

print("\n=== 带stop sequences ===")
print(chat_stop_seq.invoke([HumanMessage(content=question + ",结尾加上### 结束")]).content)

代码来源:LangChain模型参数官方文档(python.langchain.com/docs/langch...);运行后可直观看到不同参数对生成结果的影响,建议实际开发中根据场景调整。

3.5.3 注意事项

  • max_tokens 设定不宜过大,否则会增加成本(云端模型按tokens收费),且可能导致回答冗余;

  • stop sequences 需根据生成格式设定,避免出现"未生成完整内容就停止"的情况;

  • 不同模型对参数的支持略有差异(如部分本地模型不支持stop sequences),需参考对应模型的文档。

3.6 流式输出(Streaming)实现与前端对接

默认情况下,LangChain调用模型时,会等待模型生成完整回答后再返回(同步输出),这种方式在回答较长时,会出现"长时间无响应"的问题,影响用户体验。流式输出(Streaming)可实现"边生成、边返回",类似ChatGPT的打字效果,是聊天类应用的必备功能。

3.6.1 流式输出核心原理

流式输出通过"迭代器"实现:模型生成文本时,会将内容分块返回,LangChain通过stream()方法返回迭代器,开发者可遍历迭代器,逐块获取生成内容,实现实时输出。

3.6.2 LangChain 流式输出代码示例(后端)

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os

load_dotenv()

# 初始化ChatModel,支持流式输出
chat_stream = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.7,
    streaming=True  # 开启流式输出
)

# 流式调用:使用stream()方法,返回迭代器
print("流式输出(边生成边显示):")
for chunk in chat_stream.stream([HumanMessage(content="详细介绍LangChain的流式输出原理,分3点说明。")]):
    # 逐块打印生成内容,不换行
    print(chunk.content, end="", flush=True)

代码来源:LangChain流式输出官方示例(python.langchain.com/docs/langch...);运行后可看到文本"逐字生成"的效果,与ChatGPT的交互体验一致。

3.6.3 与前端对接(简单实战,Flask示例)

实际开发中,流式输出需要与前端对接,通过WebSocket或SSE(服务器推送事件)将分块内容推送到前端,实现实时显示。下面给出Flask后端+简单前端的示例(后端部分):

python 复制代码
from flask import Flask, request, Response
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os

load_dotenv()
app = Flask(__name__)

# 初始化流式模型
chat_stream = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    streaming=True,
    temperature=0.7
)

# 流式接口:接收用户提问,返回流式响应
@app.route("/stream_chat", methods=["POST"])
def stream_chat():
    data = request.json
    question = data.get("question")

    # 定义流式响应生成器
    def generate():
        for chunk in chat_stream.stream([HumanMessage(content=question)]):
            yield f"data: {chunk.content}\n\n"  # SSE格式

    # 返回SSE响应
    return Response(generate(), mimetype="text/event-stream")

if __name__ == "__main__":
    app.run(debug=True)

依赖安装:pip install flask==2.3.3;前端对接说明:前端通过EventSource监听/stream_chat接口,接收后端推送的分块内容,逐字渲染到页面(前端代码简单示例,可直接复制使用):

html 复制代码
<!DOCTYPE html>
<html>
  <body>
    <input type="text" id="question" placeholder="请输入问题" />
    <button onclick="streamChat()">发送</button>
    <div id="response"></div>

    <script>
      function streamChat() {
        const question = document.getElementById("question").value;
        const responseDiv = document.getElementById("response");
        responseDiv.innerHTML = "";

        // 建立SSE连接
        const eventSource = new EventSource(`/stream_chat`, {
          method: "POST",
          body: JSON.stringify({ question: question }),
          headers: { "Content-Type": "application/json" },
        });

        // 接收分块内容,逐字渲染
        eventSource.onmessage = function (e) {
          responseDiv.innerHTML += e.data;
        };

        // 连接关闭
        eventSource.onclose = function () {
          console.log("流式输出结束");
        };
      }
    </script>
  </body>
</html>

代码说明:后端通过SSE推送流式内容,前端通过EventSource接收,实现"边输入、边显示"的交互效果,适合聊天机器人、问答系统等场景。

3.7 异步调用(async/await)提升性能

默认情况下,LangChain调用模型是"同步调用"------一次只能处理一个请求,后续请求需等待前一个请求完成,效率较低。异步调用(async/await)可实现"同时处理多个请求",提升并发性能,适合高并发场景(如多用户同时提问)。

LangChain的所有模型接口均支持异步调用,只需将invoke()替换为ainvoke(),配合async/await语法即可实现。

3.7.1 异步调用基础示例

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os
import asyncio

load_dotenv()

# 初始化ChatModel(支持异步调用)
chat_async = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.7
)

# 定义异步函数
async def async_chat(question):
    # 异步调用:ainvoke()
    response = await chat_async.ainvoke([HumanMessage(content=question)])
    return response.content

# 运行异步函数
if __name__ == "__main__":
    question = "LangChain异步调用的优势是什么?"
    result = asyncio.run(async_chat(question))
    print("异步调用结果:", result)

代码来源:LangChain异步调用官方示例(python.langchain.com/docs/langch...);注意:异步函数需通过asyncio.run()运行,不能直接调用。

3.7.2 多请求并发异步调用(核心实战)

异步调用的核心优势是"并发处理多个请求",下面示例实现"同时处理3个请求",对比同步调用和异步调用的效率差异:

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from dotenv import load_dotenv
import os
import asyncio
import time

load_dotenv()

chat_async = ChatOpenAI(
    model_name="gpt-3.5-turbo",
    api_key=os.getenv("OPENAI_API_KEY"),
    temperature=0.7
)

# 1. 同步调用(依次处理3个请求)
def sync_chat(questions):
    start_time = time.time()
    results = []
    for q in questions:
        response = chat_async.invoke([HumanMessage(content=q)])
        results.append(response.content)
    end_time = time.time()
    print(f"同步调用耗时:{end_time - start_time:.2f}秒")
    return results

# 2. 异步调用(并发处理3个请求)
async def async_chat_single(question):
    return await chat_async.ainvoke([HumanMessage(content=question)])

async def async_chat_batch(questions):
    start_time = time.time()
    # 并发执行多个异步任务
    tasks = [async_chat_single(q) for q in questions]
    results = await asyncio.gather(*tasks)
    end_time = time.time()
    print(f"异步调用耗时:{end_time - start_time:.2f}秒")
    return [res.content for res in results]

# 测试对比
if __name__ == "__main__":
    questions = [
        "介绍LangChain的Models抽象",
        "介绍LangChain的Messages类型",
        "介绍LangChain的流式输出"
    ]

    # 同步调用
    sync_results = sync_chat(questions)
    # 异步调用
    async_results = asyncio.run(async_chat_batch(questions))

    print("\n同步调用结果:", sync_results)
    print("\n异步调用结果:", async_results)

运行结果说明:异步调用耗时约为同步调用的1/3(具体耗时取决于网络和模型响应速度),并发优势明显;代码中使用asyncio.gather()实现多个异步任务的并发执行,是高并发场景的常用方法。

3.7.3 注意事项

  • 异步调用需配合支持异步的框架(如FastAPI、Starlette),Flask默认不支持异步,需使用Flask-AsyncExt扩展;

  • 云端模型有API调用频率限制,并发请求数量不宜过多,避免触发限流;

  • 本地模型的异步调用效果取决于模型部署工具(如vLLM支持异步,Ollama异步支持有限)。

3.8 【实战】构建多模型切换的问答接口

本节通过一个完整实战案例,整合本章所学知识点------构建一个"多模型切换的问答接口",支持切换OpenAI、DeepSeek、Ollama三种模型,实现同步/流式输出、异步调用,验证Models与Messages的核心用法,同时为后续Web应用开发打下基础。

3.8.1 实战需求

  • 支持3种模型切换:OpenAI(云端)、DeepSeek(云端)、Ollama(本地);

  • 支持两种输出模式:同步输出、流式输出;

  • 支持异步调用,提升并发性能;

  • 统一接口,模型切换时无需修改核心代码;

  • 使用.env管理API密钥,确保敏感信息安全。

3.8.2 实战准备

  • 激活虚拟环境,安装所需依赖: pip install langchain-core==0.1.33 langchain-community==0.1.13 langchain-openai==0.1.6 python-dotenv==1.0.1 flask==2.3.3

  • 配置.env文件(添加所需API密钥): `OPENAI_API_KEY=你的OpenAI API密钥 DEEPSEEK_API_KEY=你的DeepSeek API密钥

Ollama无需配置API密钥`

  • 安装Ollama并拉取llama3:8b模型(ollama pull llama3:8b)。

3.8.3 完整实战代码

python 复制代码
"""
实战:构建多模型切换的问答接口
代码来源:LangChain官方示例改编(https://python.langchain.com/docs/get_started/quickstart)
功能:支持OpenAI、DeepSeek、Ollama模型切换,同步/流式输出,异步调用
"""
from dotenv import load_dotenv
import os
import asyncio
from flask import Flask, request, Response
from langchain_openai import ChatOpenAI
from langchain_community.chat_models import ChatDeepSeek, ChatOllama
from langchain_core.messages import SystemMessage, HumanMessage

# 1. 加载环境变量
load_dotenv()

# 2. 初始化Flask应用
app = Flask(__name__)

# 3. 定义模型工厂(统一模型初始化,支持切换)
def get_model(model_type, streaming=False):
    """
    获取指定类型的模型
    model_type: openai / deepseek / ollama
    streaming: 是否开启流式输出
    """
    if model_type == "openai":
        return ChatOpenAI(
            model_name="gpt-3.5-turbo",
            api_key=os.getenv("OPENAI_API_KEY"),
            temperature=0.7,
            streaming=streaming
        )
    elif model_type == "deepseek":
        return ChatDeepSeek(
            model_name="deepseek-chat",
            api_key=os.getenv("DEEPSEEK_API_KEY"),
            temperature=0.7,
            streaming=streaming
        )
    elif model_type == "ollama":
        return ChatOllama(
            model="llama3:8b",
            temperature=0.7,
            streaming=streaming,
            max_tokens=200
        )
    else:
        raise ValueError("不支持的模型类型,可选:openai、deepseek、ollama")

# 4. 同步问答接口(支持模型切换)
@app.route("/sync_chat", methods=["POST"])
def sync_chat():
    data = request.json
    model_type = data.get("model_type", "deepseek")  # 默认使用DeepSeek
    question = data.get("question")

    if not question:
        return {"code": 400, "message": "请输入问题"}

    try:
        # 获取模型,调用模型
        model = get_model(model_type)
        messages = [
            SystemMessage(content="你是多模型问答助手,回答简洁易懂,不超过3句话。"),
            HumanMessage(content=question)
        ]
        response = model.invoke(messages)
        return {
            "code": 200,
            "model_type": model_type,
            "response": response.content
        }
    except Exception as e:
        return {"code": 500, "message": f"调用失败:{str(e)}"}

# 5. 流式问答接口(支持模型切换)
@app.route("/stream_chat", methods=["POST"])
def stream_chat():
    data = request.json
    model_type = data.get("model_type", "deepseek")
    question = data.get("question")

    if not question:
        return Response('{"code": 400, "message": "请输入问题"}', mimetype="application/json")

    try:
        model = get_model(model_type, streaming=True)
        messages = [
            SystemMessage(content="你是多模型问答助手,回答简洁易懂,不超过3句话。"),
            HumanMessage(content=question)
        ]

        # 流式生成响应
        def generate():
            for chunk in model.stream(messages):
                yield f"data: {chunk.content}\n\n"

        return Response(generate(), mimetype="text/event-stream")
    except Exception as e:
        return Response(f'{"code": 500, "message": "调用失败:{str(e)}"}', mimetype="application/json")

# 6. 异步问答接口(并发处理多请求)
async def async_chat_single(model_type, question):
    model = get_model(model_type)
    messages = [
        SystemMessage(content="你是多模型问答助手,回答简洁易懂,不超过3句话。"),
        HumanMessage(content=question)
    ]
    response = await model.ainvoke(messages)
    return {
        "model_type": model_type,
        "response": response.content
    }

@app.route("/async_chat_batch", methods=["POST"])
def async_chat_batch():
    data = request.json
    tasks = data.get("tasks", [])  # 格式:[{"model_type": "deepseek", "question": "xxx"}, ...]

    if not tasks:
        return {"code": 400, "message": "请传入任务列表"}

    try:
        # 并发执行多个异步任务
        async_tasks = [async_chat_single(task["model_type"], task["question"]) for task in tasks]
        results = asyncio.run(asyncio.gather(*async_tasks))
        return {"code": 200, "results": results}
    except Exception as e:
        return {"code": 500, "message": f"调用失败:{str(e)}"}

# 7. 启动服务
if __name__ == "__main__":
    app.run(debug=True, port=5000)

3.8.4 接口测试(实战验证)

启动服务后,可通过Postman、curl或前端页面测试接口,以下是3个核心接口的测试示例:

1. 同步问答接口(/sync_chat)

请求方式:POST,请求体(JSON):

json 复制代码
{
  "model_type": "openai",
  "question": "多模型切换接口的核心优势是什么?"
}

响应结果:

json 复制代码
{
  "code": 200,
  "model_type": "openai",
  "response": "核心优势是统一接口,可灵活切换不同模型,无需修改核心代码,适配不同场景需求。"
}
2. 流式问答接口(/stream_chat)

请求方式:POST,请求体与同步接口一致,通过前端页面(3.6.3节的HTML代码)测试,可看到"边生成边显示"的效果。

3. 异步批量接口(/async_chat_batch)

请求方式:POST,请求体(JSON):

json 复制代码
{
  "tasks": [
    {
      "model_type": "deepseek",
      "question": "LangChain的Messages有哪几种核心类型?"
    },
    { "model_type": "ollama", "question": "本地模型和云端模型的区别是什么?" },
    { "model_type": "openai", "question": "异步调用的优势是什么?" }
  ]
}

响应结果:返回3个任务的并发执行结果,耗时远低于同步调用。

相关推荐
AI精钢2 小时前
NVIDIA 可以挑战中国 AI 在开源社区的统治地位吗?
人工智能·ai·开源·llm·nvidia·open source·open weight
小小小小小鹿2 小时前
Claude Code Agent Skills 入门指南(上):原理与规范 —— 让 AI Agent 拥有"肌肉记忆"的可扩展能力
llm·ai编程·claude
skywalk81632 小时前
AI 编程软件的邪修用法:让AI编程软件为我们实现龙虾功能(目前好像实现不了)
人工智能·ai编程
牛奶10 小时前
AI辅助开发最佳实践:2026年新方法
前端·aigc·ai编程
Setsuna_F_Seiei12 小时前
AI 对话应用之 JS 的流式接口数据处理
前端·javascript·ai编程
新缸中之脑13 小时前
5个能访问浏览器的AI编程工具
ai编程
开longlong了吗?15 小时前
Luan Takeaway——大模型驱动的智能外卖管理系统( Spring Cloud、Langchain4j )
后端·spring·spring cloud·langchain
品克缤15 小时前
Trading-Analysis:基于“规则+LLM”的行情分析终端(兼谈 Vibe Coding 实战感)
前端·后端·node.js·vue·express·ai编程·llama
王小酱16 小时前
A2UI:让 AI Agent "说出"用户界面的开放协议
openai·ai编程·aiops