LangChain 模型(Models)

一、概要

在 LangChain 中,模型(Models) 是连接应用程序与各种大语言模型(LLM)的标准化组件。它通过统一的接口封装了不同提供商的 API 差异,使开发者能够以一致的方式调用、组合和扩展模型能力,而无需关心底层实现细节。

二、模型的核心作用

模型组件(Models)是 LangChain 1.0 的基础能力层,负责:

  1. 统一对接各类 LLM(OpenAI、Anthropic、通义千问、Llama 等)
  2. 提供标准化调用接口(invoke/batch/stream/ainvoke)
  3. 封装模型参数、流式、结构化输出、工具调用等高级能力
  4. 作为链(Chain)、智能体(Agent)、RAG 的底层推理单元

三、模型的三大分类

LangChain 将模型分为三类,以适应不同的应用场景:

类别 描述 典型类 输入 输出
LLMs(纯文本模型) 接受字符串提示并返回字符串补全的传统语言模型。 OpenAI、Anthropic、Cohere 字符串 字符串
Chat Models(聊天模型) 基于消息列表(角色:系统、用户、助手)的对话模型,通常具有更自然的交互。 ChatOpenAI、ChatAnthropic、ChatGoogleGenerativeAI List[BaseMessage] AIMessage(包含内容及工具调用信息)
Embeddings(嵌入模型) 将文本转换为高维向量,用于语义搜索、聚类、推荐。 OpenAIEmbeddings、HuggingFaceEmbeddings 字符串 List[float](向量)

现在做应用 95% 用 ChatModel,LLM 只用于老模型、简单补全场景。

3.1 语言模型(LLMs)

3.1.1 定义与特点

  • 定义
    • LLM 在 LangChain 中代表"文本补全模型"。这类模型的设计目标是根据给定的提示文本(prompt),续写最可能的后续文本。可以把它理解为:给一段文字,续写下去
  • 特点
    • 输入:一个简单的字符串(prompt)。
    • 输出:一个字符串(completion)。
    • 无角色区分:所有输入都被视为连续的文本,没有系统、用户、助手等角色概念。
    • 不原生支持对话、工具调用、结构化输出(需要自己封装)

3.1.2 最简使用示例(OpenAI 文本补全模型)

python 复制代码
from langchain_openai import OpenAI

# 文本补全模型(不是聊天!)
llm = OpenAI(
    model="gpt-3.5-turbo-instruct",
    temperature=0,
    max_tokens=256
)

# 输入是字符串
prompt = "请解释什么是大语言模型:"

# 输出是字符串
result = llm.invoke(prompt)
print(result)

3.1.3 标准接口与核心方法

在 LangChain 1.0 中,所有语言模型(无论是传统的 LLM 还是 ChatModel)都遵循统一的 Runnable 协议。这意味着它们拥有相同的基础方法签名,能够无缝集成到 LangChain Expression Language(LCEL)管道中。这种标准化的设计使得开发者可以轻松切换不同的模型提供商,而无需改变调用代码。

3.1.3.1 标准接口:BaseLLM

所有 LLM 实现都继承自 BaseLLM 抽象基类,提供统一的方法集。

方法 作用 同步版本 异步版本
invoke 单次调用,返回完整输出 invoke(input) ainvoke(input)
stream 流式调用,逐个返回输出块 stream(input) astream(input)
batch 批量调用 batch(inputs) abatch(inputs)
  • 特点:

    • 所有方法都接受输入(字符串、消息列表或字典)并返回输出(字符串或消息)。
    • 支持配置参数(如 temperature、max_tokens)通过调用时传递或使用 bind 预设。
    • 内置重试、超时、回调等机制。
  • 核心方法

    1. invoke(prompt: str, **kwargs) -> str:给定提示,返回补全文本。

      python 复制代码
      # 简单字符串输入(底层自动转为 HumanMessage)
      result = llm.invoke("介绍下 LangChain 1.0 的核心特点")
      print("输出内容:", result.content)
      print("输出类型:", type(result))  # AIMessage 类型,包含 content/role 等属性

      输出示例:

      python 复制代码
      输出内容: LangChain 1.0统一Agent入口,基于LangGraph,支持中间件、状态管理,模块化更强,生产级能力更完善。
      输出类型: <class 'langchain_core.messages.ai.AIMessage'>
    2. batch([prompt1, prompt2]) -> List[str]:批量处理。

      python 复制代码
      # 批量输入(列表形式)
      inputs = [
          "LangChain 1.0 智能体的核心是什么?",
          "LangChain 1.0 对比 0.x 有哪些改进?"
      ]
      
      # 批量调用
      results = llm.batch(inputs, max_concurrency=2)  # max_concurrency:最大并发数
      for i, res in enumerate(results):
          print(f"\n问题{i+1}:{inputs[i]}")
          print(f"回答:{res.content}")

      关键参数:

      • max_concurrency:控制并发数,避免一次性请求过多导致 API 限流(建议设 2-5)。
      • 适用场景:批量处理问答、文本生成、数据标注等。
    3. stream(prompt) -> Iterator[str]:流式返回生成片段。

      python 复制代码
      # 流式调用,逐字输出
      for chunk in llm.stream("用3句话介绍 LangChain 1.0"):
          print(chunk.content, end="", flush=True)  # flush=True 确保实时输出

      输出效果(逐字打印):

      python 复制代码
      LangChain 1.0重构了Agent体系,统一create_agent入口,降低了开发门槛。
      它基于LangGraph构建,原生支持状态管理、中间件等生产级特性。
      同时保持了模块化设计,兼容主流大模型和第三方工具。
  • 异步方法:

    • ainvoke、abatch、astream:对应的异步版本。
  • 生成方法(生成多个候选):

    • generate(prompts: List[str], **kwargs) -> LLMResult:返回包含多个生成结果的复杂对象(包括文本、token 用量等)。

      python 复制代码
      result = llm.generate(["推荐一本好书"] * 3)  # 生成3个候选
      for generation in result.generations[0]:
          print(generation.text)
      print(result.llm_output)  # 包含 token 用量等信息

3.1.4 核心参数分类及详解

3.1.4.1 生成控制参数

这些参数直接决定模型输出的随机性、多样性和长度。

参数名 作用 类型/范围 默认值 说明
temperature 控制随机性 float (0~2) 1.0 越高越随机,越低越确定
top_p 核采样,动态过滤低概率词 float (0~1) 1.0 与 temperature 通常二选一微调
top_k 限制候选词数量(部分模型支持) int - 只从概率最高的 k 个词中选择
max_tokens 最大生成 token 数 int 模型相关 生成部分的最大长度,不含提示词
stop 停止序列 str/list None 遇到该字符串时停止生成
frequency_penalty 频率惩罚 float (-2~2) 0 惩罚高频词,减少重复
presence_penalty 存在惩罚 float (-2~2) 0 惩罚已出现过的词,鼓励新话题
logit_bias 对数偏置 dict {} 直接修改指定 token 的生成概率
best_of 候选项数(部分模型支持) int 1 生成多个候选,返回 log 概率最高的
seed 随机种子(部分模型支持) int None 固定种子使结果可复现
logprobs 返回对数概率 bool/int False 用于调试或置信度分析
  1. Temperature(温度)

    • 作用:控制生成结果的随机性,即模型选择下一个词时的"冒险程度"。

    • 取值范围:通常 0.0 ~ 2.0(部分模型支持更高)。

    • 默认值:1.0(不同模型可能略有差异)。

      • 低温度(如 0.1):模型会更倾向于选择概率最高的词,输出更加确定、保守,适合事实性问答、代码生成等需要准确性的场景。
      • 高温度(如 1.5):模型选择概率较低的词的几率增大,输出更加多样、有创意,但可能产生不连贯或偏离主题的内容,适合创意写作、头脑风暴。
    • 示例:

      python 复制代码
      # OpenAI API 示例
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "讲一个关于猫的笑话"}],
          temperature=0.2  # 保守,可能重复常见笑话
      )
    • 调优建议:

      • 如果希望每次输出都大致相同,使用低温度(0~0.3)。
      • 如果希望有创意变化,使用中等温度(0.5~1.0)。
      • 除非需要极端随机,否则不建议超过 1.5。
  2. Top_p(核采样,Nucleus Sampling)

    • 作用:动态选择概率累积和达到 p 的最小词集合,然后从中采样。与 temperature 类似,也是控制随机性,但机制不同。

    • 取值范围:0.0 ~ 1.0。

    • 默认值:1.0(考虑所有词)。

      • top_p=0.9:只考虑概率累积和达到 90% 的最可能的词,忽略剩余的低概率词。这可以过滤掉不合理的词,同时保留一定多样性。
      • top_p=0.1:只考虑概率最高的几个词,输出更加确定。
    • 与 temperature 的关系:通常建议不要同时大幅调整两者------一般固定其中一个,微调另一个。实践中,top_p 常用于替代 temperature 实现更平滑的随机性控制。

    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "写一首关于春天的短诗"}],
          top_p=0.8  # 忽略概率最低的20%的词
      )
  3. Top_k

    • 作用:从概率最高的 k 个词中随机选择下一个词。

    • 取值范围:正整数,通常 0~100。

    • 默认值:0(表示不启用,或模型默认设置)。

      • top_k=40:只从概率最高的 40 个词中选择,忽略其他所有词。这可以避免生成极其罕见的词,同时保持一定多样性。
      • top_k=1:等价于贪心解码(greedy decoding),总是选择概率最高的词,等同于 temperature=0。
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "下一句是什么?"}],
          top_k=50  # 只从 top50 中选择
      )
    • 调优建议:top_k 通常与 temperature 或 top_p 配合使用,用于进一步限制候选范围。在需要高度可控的生成中(如代码补全),可以设置较小的 top_k。

  4. Max Tokens(最大生成长度)

    • 作用:限制模型生成的最大 token 数(包括提示词中的 token 吗?------注意:不同 API 定义可能不同。OpenAI 的 max_tokens 是指生成部分的最大 token 数,不包括提示词)。

    • 取值范围:正整数,受模型上下文窗口限制(如 4096、8192、128k 等)。

    • 默认值:由模型决定,通常是上下文窗口的剩余部分。

      • 设置过小可能导致输出被截断。
      • 设置过大可能浪费 tokens 或超出上下文限制。
      • 1 英文 token ≈ 0.75 单词。
      • 1 中文 token ≈ 1.5 字
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "请详细解释量子计算"}],
          max_tokens=500  # 最多生成 500 个 token
      )
  5. Stop Sequences(停止序列)

    • 作用:指定一个或多个字符串,当模型生成到这些字符串时,立即停止生成。返回的结果中不包含停止序列本身。

    • 类型:字符串或字符串列表。

    • 默认值:无。

      • 常用于强制模型输出特定格式,如只生成 JSON 对象,当生成 } 时停止;或用于对话中,当生成 \nUser: 时停止,防止模型模拟用户。
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "用 JSON 格式返回:{ \"name\": \"产品名\", \"price\": 价格 }"}],
          stop=["}"]  # 生成到闭合括号时停止,避免额外内容
      )
    • 调优建议:在多轮对话生成中,常设置 stop=["\nUser:", "\nAssistant:"] 来控制角色切换。

  6. Frequency Penalty(频率惩罚)

    • 作用:根据词在已生成文本中出现的频率来惩罚该词,减少重复。

    • 取值范围:-2.0 ~ 2.0。

    • 默认值:0(无惩罚)。

      • 0:不惩罚
      • 0.1~0.5:轻微减少重复
      • 1.0~2.0:几乎不重复,但可能不通顺
      • 负值:鼓励重复(几乎不用)。
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "写一篇关于环保的文章"}],
          frequency_penalty=0.5  # 减少重复词汇
      )
    • 效果:有助于避免模型反复使用相同的词语或短语,使文本更丰富。

  7. Presence Penalty(存在惩罚)

    • 作用:根据词是否已经出现过(不论出现次数)来惩罚该词,鼓励引入新话题。

    • 取值范围:-2.0 ~ 2.0。

    • 默认值:0。

      • 正值:对已出现的词施加惩罚,促使模型谈论新内容。
      • 负值:鼓励围绕已有话题展开。
    • 与 frequency_penalty 的区别:

      • frequency_penalty 惩罚出现次数多的词,次数越多惩罚越大;
      • presence_penalty 只惩罚是否出现过,出现一次和多次惩罚相同。
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "介绍北京的景点"}],
          presence_penalty=0.3  # 鼓励提及更多不同的景点
      )
    • 调优建议:在需要广泛覆盖内容的场景(如列举、头脑风暴)中,可适当提高 presence_penalty;在需要聚焦主题的场景,可设为 0 或负值。

  8. Logit Bias(对数偏置)

    • 作用:直接修改指定 token 的原始 logit 值(即模型生成该词的原始分数),从而影响其被选中的概率。

    • 类型:字典,键为 token ID(整数),值为偏置值(-100 到 100)。

    • 默认值:无。

      • 正值增加该 token 出现的概率,负值降低概率。
      • 可以用于强制模型输出特定词(如"是"或"否"),或屏蔽不良词汇(设置很大的负值)。
    • 示例(强制模型回答"是"或"否"):

      python 复制代码
      import tiktoken
      
      encoder = tiktoken.encoding_for_model("gpt-4")
      yes_token = encoder.encode("是")[0]
      no_token = encoder.encode("否")[0]
      
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "苹果是水果吗?请用'是'或'否'回答。"}],
          logit_bias={yes_token: 50, no_token: 50},  # 增加这两个 token 的概率
          max_tokens=10
      )
    • 注意:需要知道 token ID,通常需要借助分词器(如 tiktoken)。

  9. Best Of(候选项数)

    • 作用:生成 best_of 个候选结果,并返回其中 log 概率最高的那个(按 token 对数概率和排序)。

    • 取值范围:正整数,通常 <= 20。

    • 默认值:1。

      • 这相当于内部做了多次生成,然后挑选最佳结果,但只输出一个。
      • 可以提升输出质量,但会消耗更多 tokens(每个候选项都计费)。
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "写一个吸引人的广告语"}],
          best_of=5  # 生成 5 条,选最佳
      )
    • 适用场景:需要高质量输出且愿意付出额外成本时使用。

  10. Seed(随机种子)

    • 作用:设置随机种子,使生成结果可复现。

    • 取值范围:整数。

    • 默认值:None(随机)。

      • 设置相同的 seed,在相同模型版本、相同输入参数下,可以得到完全相同的输出(理论上是确定的,但受系统影响可能有微小差异)。
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "说一个谜语"}],
          seed=42
      )
    • 注意:并非所有模型或 API 都支持 seed。OpenAI 的 ChatCompletion 支持 seed 参数(需要模型版本足够新)。

  11. Logprobs(对数概率)

    • 作用:返回生成 token 的对数概率信息,用于分析模型置信度、调试等。

    • 取值范围:布尔值或整数(返回 top 几个 token 的概率)。

    • 默认值:False。

      • 设为 true 或指定 k 值(如 5),可以获取每个生成 token 及其候选 token 的对数概率。
    • 示例:

      python 复制代码
      response = openai.ChatCompletion.create(
          model="gpt-4",
          messages=[{"role": "user", "content": "太阳从哪个方向升起?"}],
          logprobs=True
      )
      print(response.choices[0].logprobs)
3.1.4.2 模型选择与标识参数
参数名 作用 示例值 说明
model 模型名称 "gpt-4", "claude-3-opus" 必须指定
model_version 模型版本(部分提供商支持) "2024-05-13" 如 OpenAI 的日期版本
deployment_name Azure 部署名称 "my-gpt4-deploy" Azure 专用
3.1.4.3 请求配置参数
参数名 作用 类型 默认值 说明
timeout 请求超时时间(秒) float 由客户端决定 防止长时间等待
max_retries 失败重试次数 int 2 网络错误时自动重试
api_key API 密钥 str 从环境变量读取 不同模型提供商标识可能不同
base_url 自定义 API 端点 str None 用于代理或本地部署
organization OpenAI 组织 ID str None OpenAI 专用
user 终端用户标识 str None 用于跟踪和配额管理
3.1.4.4 流式与回调参数
参数名 作用 说明
streaming 是否启用流式输出 bool,默认 False。在 1.0 中更推荐使用 .stream() 方法
callbacks 回调处理器列表 用于监听事件(如新 token、开始、结束)
metadata 附加元数据 字典,用于追踪和日志

3.1.5 参数传递方式

  1. 在初始化时设置全局默认参数

    python 复制代码
    from langchain_openai import ChatOpenAI
    
    # 初始化时设置默认参数
    model = ChatOpenAI(
        model="gpt-4o",
        temperature=0.7,
        max_tokens=500,
        timeout=30,
        max_retries=3,
        api_key="sk-..."  # 也可从环境变量读取
    )
    
    # 调用时使用默认参数
    response = model.invoke("讲个笑话")
  2. 在调用时动态覆盖参数

    python 复制代码
    # 临时降低 temperature,获得更确定的回答
    response = model.invoke(
        "中国的首都是哪里?",
        temperature=0.1  # 覆盖默认的 0.7
    )
  3. 使用 bind 预设参数(LCEL 链中常用)

    python 复制代码
    from langchain_core.prompts import ChatPromptTemplate
    
    prompt = ChatPromptTemplate.from_template("用{style}风格写一首关于{subject}的诗")
    
    # 预设 temperature 和 max_tokens
    poet_chain = prompt | model.bind(temperature=0.9, max_tokens=200)
    
    result = poet_chain.invoke({"style": "古风", "subject": "月亮"})
  4. 在流式输出中使用参数

    python 复制代码
    # 启用流式(通过调用 .stream 自动处理)
    for chunk in model.stream("讲个长一点的故事", temperature=0.8):
        print(chunk.content, end="")
  5. 结合回调记录参数

    python 复制代码
    from langchain_core.callbacks import StdOutCallbackHandler
    
    model.invoke(
        "你好",
        callbacks=[StdOutCallbackHandler()],
        metadata={"session_id": "abc123"}
    )

3.2 聊天模型(Chat Models)

3.2.1 定义与特点

  • 定义
    • 聊天模型是对底层大语言模型(如 GPT-4、Claude、Gemini 等)的一种封装,专门面向对话上下文。
    • 聊天模型的输入是一组带有角色标签的消息(例如系统消息、用户消息、助手消息),输出是助手的一条回复消息。这种设计更贴合现代指令微调模型的使用方式。
  • 特点
    • 输入:List[BaseMessage](消息列表)
    • 输出:AIMessage(可能包含文本内容或工具调用请求)
    • 角色区分:通过不同的消息类型(system、user、assistant、tool)帮助模型理解上下文和意图。
    • 原生支持工具调用:可以绑定工具并处理模型返回的工具调用请求。
    • 与 LangChain 生态无缝集成:支持流式输出、缓存、回调、与 LangGraph 构建复杂智能体。

3.2.2 消息类型

所有消息都继承自 langchain_core.messages.BaseMessage。主要类型如下:

消息类型 角色 说明
SystemMessage system 用于设定助手的行为、角色和全局指令。通常放在消息列表的开头。
HumanMessage user 代表用户的输入(问题或指令)。
AIMessage assistant 模型生成的回复。可能包含文本(content)或工具调用(tool_calls)。
ToolMessage tool 工具执行后的结果。必须包含 tool_call_id 以关联到特定的工具调用。

消息构造示例:

python 复制代码
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage

messages = [
    SystemMessage(content="你是一个乐于助人的助手。用中文回答。"),
    HumanMessage(content="今天天气怎么样?"),
    AIMessage(content="抱歉,我无法获取实时天气信息,你可以告诉我你的城市,我帮你查询。"),
    HumanMessage(content="北京"),
    # 假设后面会调用工具,然后加入 ToolMessage
]

3.2.3 标准接口:BaseChatModel

LangChain 为所有聊天模型定义了统一的抽象基类 BaseChatModel。无论使用哪个模型提供商,调用方式保持一致。

  • 核心方法

    方法 说明
    invoke(messages, **kwargs) -> AIMessage 同步发送消息列表,返回 AIMessage。
    batch(messages_list, **kwargs) -> List[AIMessage] 批量处理多个输入。
    stream(messages, **kwargs) -> Iterator[AIMessageChunk] 流式返回消息块。
    ainvoke()、abatch()、astream() 对应的异步版本。
    bind_tools(tools) 绑定工具列表,使模型能够请求调用这些工具。
    with_structured_output(schema) 强制模型返回符合指定 schema 的结构化数据(如 Pydantic 模型)。
  • 通用参数(实例化时常用)

    • model:模型名称(如 "gpt-4o-mini"、"claude-3-5-sonnet-20240620")
    • temperature:控制随机性(0~2,默认通常为 0.7)
    • max_tokens 或 max_completion_tokens:限制生成的最大 Token 数
    • timeout:请求超时时间
    • max_retries:失败重试次数
    • model_kwargs:传递给模型的其他参数(如 top_p、frequency_penalty)

3.2.4 模型集成

LangChain 1.0 通过各第三方集成包提供对具体模型的支持。以下是一些常见示例:

  • OpenAI

    python 复制代码
    from langchain_openai import ChatOpenAI
    
    llm = ChatOpenAI(
        model="gpt-4o-mini",
        temperature=0.7,
        max_tokens=1000,
        api_key="your-api-key"  # 或通过环境变量 OPENAI_API_KEY 设置
    )
  • Anthropic Claude

    python 复制代码
    from langchain_anthropic import ChatAnthropic
    
    llm = ChatAnthropic(
        model="claude-3-5-sonnet-20240620",
        temperature=0.7
    )
  • Google Gemini

    python 复制代码
    from langchain_google_genai import ChatGoogleGenerativeAI
    
    llm = ChatGoogleGenerativeAI(
        model="gemini-1.5-pro",
        temperature=0.7
    )
  • 国产 Chat Models

    python 复制代码
    # 通义千问
    from langchain_community.chat_models import ChatTongyi
    chat_qwen = ChatTongyi(
        model="qwen-max",
        dashscope_api_key="xxx",  # 阿里云 AccessKey
        streaming=True
    )
    
    # 文心一言
    from langchain_community.chat_models import ChatERNIE
    chat_ernie = ChatERNIE(
        model="ernie-4.0",
        ernie_api_key="xxx",
        ernie_secret_key="xxx"
    )

3.2.5 调用方式详解

3.2.5.1 基本对话
python 复制代码
from langchain_core.messages import HumanMessage, SystemMessage

messages = [
    SystemMessage(content="用中文回答,保持简洁。"),
    HumanMessage(content="什么是机器学习?")
]

response = llm.invoke(messages)
print(response.content)  # 输出模型回复的文本
3.2.5.2 多轮对话

将历史消息和当前用户消息一起传入:

python 复制代码
history = [
    HumanMessage(content="你好!"),
    AIMessage(content="你好!有什么可以帮助你的?"),
    HumanMessage(content="我想了解 LangChain。")
]
response = llm.invoke(history)
3.2.5.3 工具调用

绑定工具后,模型可能会返回 AIMessage 并附带 tool_calls 属性。需要执行工具并将结果以 ToolMessage 返回给模型,让模型继续。

python 复制代码
from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """计算两个数的和。"""
    return a + b

llm_with_tools = llm.bind_tools([add])

# 第一轮:模型请求调用工具
response = llm_with_tools.invoke([HumanMessage("3加5等于多少?")])
if response.tool_calls:
    # 假设只考虑第一个工具调用
    tool_call = response.tool_calls[0]
    tool_name = tool_call["name"]
    tool_args = tool_call["args"]
    tool_call_id = tool_call["id"]  # 重要:用于关联 ToolMessage
    
    # 执行工具(这里简单模拟)
    if tool_name == "add":
        result = add.invoke(tool_args)  # 或直接调用函数
    
    # 构造 ToolMessage 返回给模型
    tool_message = ToolMessage(content=str(result), tool_call_id=tool_call_id)
    
    # 第二轮:将工具结果和历史消息一起发送,让模型生成最终答案
    final_response = llm_with_tools.invoke([
        HumanMessage("3加5等于多少?"),
        response,  # 模型的第一轮回复(包含 tool_calls)
        tool_message
    ])
    print(final_response.content)  # 输出:3加5等于8。
3.2.5.4 结构化输出

使用 with_structured_output 强制模型返回符合 Pydantic 模型或 JSON Schema 的对象。

python 复制代码
from pydantic import BaseModel, Field

class Person(BaseModel):
    name: str = Field(description="人物的名字")
    age: int = Field(description="人物的年龄")

structured_llm = llm.with_structured_output(Person)
person = structured_llm.invoke("鲁迅的信息")
print(person.name, person.age)
3.2.5.4 流式输出

每个 chunk 是 AIMessageChunk,支持累加合并:full_message = chunk1 + chunk2 + ...。

python 复制代码
for chunk in llm.stream([HumanMessage("讲一个故事")]):
    print(chunk.content, end="", flush=True)
3.2.5.5 异步调用

在异步环境(如 FastAPI)中使用 ainvoke 或 astream。

python 复制代码
import asyncio

async def main():
    response = await llm.ainvoke([HumanMessage("你好")])
    print(response.content)

asyncio.run(main())

3.2.6 高级特性

3.2.6.1 与 LangGraph 结合

在 LangGraph 构建的智能体中,聊天模型通常作为图中的一个节点。状态中通常包含 messages 键,存储对话历史。

python 复制代码
from langgraph.graph import StateGraph, MessagesState

def call_model(state: MessagesState):
    # state["messages"] 是消息列表
    response = llm.invoke(state["messages"])
    # 将新消息追加到状态中
    return {"messages": [response]}

# 构建图
graph = StateGraph(MessagesState)
graph.add_node("agent", call_model)
# ... 添加边、工具节点等

LangGraph 会自动处理消息的追加和流转,使得多轮工具调用和状态管理变得非常简单。同时,LangGraph 提供了 stream_mode="updates" 和 astream_events 来流式返回节点执行过程和 Token。

3.2.6.2 缓存

避免重复调用相同输入,节省费用和时间。

python 复制代码
from langchain_core.caches import InMemoryCache
from langchain.globals import set_llm_cache

set_llm_cache(InMemoryCache())
llm.invoke([HumanMessage("你好")])  # 第一次,实际调用
llm.invoke([HumanMessage("你好")])  # 第二次,从缓存读取
3.2.6.3 回调

通过回调监听模型调用的各个阶段(开始、结束、错误、流块等)。

python 复制代码
from langchain_core.callbacks import StdOutCallbackHandler

llm.invoke([HumanMessage("测试")], config={"callbacks": [StdOutCallbackHandler()]})
3.2.6.4 绑定运行时参数

使用 .bind(**kwargs) 可以在调用前绑定一些固定参数(如 response_format、stop 序列等)。

python 复制代码
llm.bind(stop=["\n"]).invoke([HumanMessage("写一首诗")])
3.2.6.5 中间件系统(Middleware)

1.0 新增中间件能力,可拦截 / 修改 Chat Model 的请求 / 响应,实现日志、监控、脱敏等功能:

python 复制代码
from langchain_core.middleware import BaseMiddleware

# 自定义日志中间件
class LoggingMiddleware(BaseMiddleware):
    def invoke(self, input, config, next):
        # 拦截输入
        print(f"Chat Model 输入:{input}")
        # 执行原调用
        output = next(input, config)
        # 拦截输出
        print(f"Chat Model 输出:{output.content}")
        return output

# 绑定中间件
chat_model_with_mw = chat_model.with_config({
    "middleware": [LoggingMiddleware()]
})
3.2.6.6 动态模型选择

根据上下文 / 用户需求动态切换 Chat Model(成本 / 性能平衡):

python 复制代码
from langchain_core.runnables import RunnableLambda

def select_chat_model(input):
    """根据问题复杂度选择模型"""
    if "复杂分析" in input["question"]:
        return ChatOpenAI(model="gpt-4o")  # 高性能模型
    else:
        return ChatOpenAI(model="gpt-3.5-turbo")  # 低成本模型

# 构建动态选择链
chain = RunnableLambda(select_chat_model) | (lambda llm, x: llm.invoke(x["messages"]))
3.2.6.7 统一初始化(init_chat_model)

1.0 推荐的最佳实践,简化多模型切换,降低接入成本:

python 复制代码
from langchain_core.chat_models import init_chat_model

# 统一接口初始化任意 Chat Model
chat_model = init_chat_model(
    model="gpt-4o",
    model_provider="openai",  # 厂商标识:openai/anthropic/tongyi
    temperature=0,
    api_key="sk-xxx",
    streaming=True
)
3.2.6.8 上下文压缩

结合 trim_messages 实现上下文窗口管理,防止超限:

python 复制代码
from langchain_core.messages import trim_messages

# 压缩上下文到 1000 token 以内
trimmer = trim_messages(
    max_tokens=1000,
    strategy="last",  # 保留最后 N 条消息
    token_counter=chat_model
)

# 压缩后的消息列表
trimmed_messages = trimmer.invoke(messages)

3.3 嵌入模型(Embeddings)

3.3.1 定义与作用

  • 定义
    • 嵌入模型是一种将文本(如单词、句子、段落)映射到固定长度数值向量(例如 384 维、768 维、1536 维)的模型。这些向量试图保留原始文本的语义信息,使得语义相似的文本在向量空间中的距离(如余弦相似度)较近。
  • 作用
    • 语义搜索:将查询和文档都转换为向量,通过向量相似度检索最相关的文档。
    • 聚类:对文本向量进行聚类,发现主题分组。
    • 分类:将向量作为特征输入机器学习模型。
    • 推荐系统:基于用户行为或内容向量进行相似推荐。
    • 异常检测:识别与其他文本向量差异较大的文本。
  • 设计思想
    • Query 与 Document 分离,很多 RAG 效果差,就是因为混用了 query/doc。
    • 向量库无关性,Embedding 只管生成向量,不负责存储。

3.3.2 统一接口(所有模型一模一样)

LangChain 为所有嵌入模型定义了统一的抽象基类 Embeddings(位于 langchain_core.embeddings)。该接口包含两个核心方法:

  • embed_documents(texts: List[str]) -> List[List[float]]

    将一批文档(多个文本)转换为向量列表。通常用于索引阶段,将知识库文档批量向量化。

  • embed_query(text: str) -> List[float]

    将单个查询文本转换为向量。通常用于检索阶段,将用户问题向量化,以便与文档向量进行相似度比较。

异步方法:

  • aembed_documents:异步批量嵌入文档。
  • aembed_query:异步嵌入单个查询。

示例:

python 复制代码
# 1. 初始化 embedding 模型
embeddings = SomeEmbeddingModel(...)

# 2. 生成查询向量
query_embedding = embeddings.embed_query("什么是RAG")

# 3. 生成文档向量
doc_embeddings = embeddings.embed_documents([
    "RAG是检索增强生成",
    "Embedding是把文本转向量"
])

3.3.3 核心参数

3.3.3.1 模型选择参数

参数名 作用 示例值 说明
model / model_name 指定嵌入模型 "text-embedding-3-small" 不同提供商命名可能不同(如 OpenAI 用 model,HuggingFace 用 model_name)。
model_kwargs 传递给底层模型的额外参数 {"truncate": True} 用于控制特定模型的行为,如是否截断长文本。

3.3.3.2 请求与网络参数

参数名 作用 默认值 说明
batch_size 批量嵌入时每批处理的文档数 取决于实现 控制内存和请求次数,过大可能导致超时。
timeout 请求超时时间(秒) 由客户端决定 防止长时间等待。
max_retries 失败重试次数 2~3 网络错误时自动重试。
show_progress_bar 是否显示进度条(HuggingFace 等) False 用于长文档批量嵌入时的可视化。

3.3.3.3 认证与端点参数

参数名 作用 示例值 说明
api_key API 密钥 "sk-..." 从环境变量读取为佳。
base_url / endpoint 自定义 API 地址 "http://localhost:8080" 用于代理或本地部署。
organization OpenAI 组织 ID "org-123" OpenAI 专用。
deployment Azure 部署名称 "my-embedding-deploy" Azure OpenAI 专用。

3.3.3.4 输出维度参数

参数名 作用 示例值 说明
dimensions 输出向量维度 1536 部分模型(如 OpenAI text-embedding-3-*)支持降维输出,减少存储成本。
embedding_ctx_length 模型支持的最大输入 token 数 8191 超过此长度需截断或分块。

3.3.3.5 特定提供商参数

不同提供商有特有参数,LangChain 通过各集成包封装。

提供商 特有参数 作用
OpenAI encoding_format 返回向量的格式,如 "float" 或 "base64"。
Cohere input_type 指定输入类型(search_query、search_document 等),优化检索效果。
HuggingFace device 指定运行设备(cpu、cuda)。
HuggingFace normalize_embeddings 是否对向量归一化。

3.3.4 Embeddings 三大类

3.3.4.1 云端闭源 Embedding(最常用、最稳定)
  • OpenAI Embeddings
  • Azure OpenAI
  • Anthropic Embeddings
  • 通义千问 Embedding
  • 文心一言 Embedding
  • 讯飞星火 Embedding

优点: 不用管部署、精度高、稳定

缺点: 收费、有网络依赖

3.3.4.2 开源本地 Embedding(私有化首选)
  • sentence-transformers 系列(bge、m3e、gte)
  • Llama 2 / Mistral 做 embedding
  • 本地量化 GGUF 模型

优点: 隐私、免费、内网可用

缺点: 需要 GPU / 内存、精度略低

3.3.4.3 自定义 Embedding
  • 自己实现 BaseEmbeddings 即可接入任何模型。

3.3.5 最常用 Embedding 模型

LangChain 1.0 通过各个集成包支持多种嵌入模型提供商。以下是一些常见的示例:

  • OpenAI

    python 复制代码
    from langchain_openai import OpenAIEmbeddings
    
    embeddings = OpenAIEmbeddings(
        model="text-embedding-3-small",  # 或 "text-embedding-3-large", "text-embedding-ada-002"
        dimensions=1536,  # 对于 v3 模型可以指定维度
        api_key="your-api-key"
    )
  • 通义千问

    python 复制代码
    from langchain_community.embeddings import ChatTongyiEmbeddings
    
    embeddings = ChatTongyiEmbeddings(
        model="text-embedding-v1",
        dashscope_api_key="..."
    )
  • 文心一言

    python 复制代码
    from langchain_community.embeddings import ERNIEEmbeddings
    
    embeddings = ERNIEEmbeddings(
        model="ernie-embedding-v1",
        ernie_api_key="...",
        ernie_secret_key="..."
    )
  • Cohere

    python 复制代码
    from langchain_cohere import CohereEmbeddings
    
    embeddings = CohereEmbeddings(
        model="embed-english-v3.0",
        cohere_api_key="your-api-key"
    )
  • 本地开源

    python 复制代码
    from langchain_community.embeddings import HuggingFaceEmbeddings
    
    embeddings = HuggingFaceEmbeddings(
        model_name="BAAI/bge-small-zh-v1.5",  # 中文最强轻量
        model_kwargs={"device": "cpu"},      # cpu / cuda
        encode_kwargs={"normalize_embeddings": True}
    )

3.3.6 基本使用方法

  • 同步嵌入文档

    python 复制代码
    documents = ["今天天气真好", "机器学习是人工智能的一个分支", "苹果是一种水果"]
    doc_vectors = embeddings.embed_documents(documents)
    print(len(doc_vectors))  # 3
    print(len(doc_vectors[0]))  # 例如 1536(取决于模型)
  • 同步嵌入查询

    python 复制代码
    query = "今天适合出去玩吗"
    query_vector = embeddings.embed_query(query)
    print(len(query_vector))  # 与文档向量维度相同
  • 异步批量处理

    python 复制代码
    import asyncio
    
    async def main():
        doc_vectors = await embeddings.aembed_documents(documents)
        query_vector = await embeddings.aembed_query(query)
    
    asyncio.run(main())
  • 与向量存储结合

    嵌入模型通常与向量数据库(如 Chroma、FAISS、Pinecone、Weaviate、Qdrant 等)一起使用,构成 RAG 应用的基础。

    示例:使用 Chroma 和 OpenAI 嵌入构建检索器

    python 复制代码
    from langchain_chroma import Chroma
    from langchain_openai import OpenAIEmbeddings
    
    # 初始化嵌入模型
    embeddings = OpenAIEmbeddings()
    
    # 创建向量存储(自动嵌入文档)
    vectorstore = Chroma.from_texts(
        texts=["文档1内容", "文档2内容", "文档3内容"],
        embedding=embeddings,
        persist_directory="./chroma_db"
    )
    
    # 创建检索器
    retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
    
    # 检索与查询相似的文档
    results = retriever.invoke("查询问题")
  • 在 LCEL 链中使用

    python 复制代码
    from langchain_core.runnables import RunnablePassthrough
    
    retriever = vectorstore.as_retriever()
    
    rag_chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | llm
    )

3.3.7 最佳实践

  1. 区分文档和查询嵌入:如果模型支持,利用 embed_documents 和 embed_query 的差异化处理提升检索效果。
  2. 控制批大小:根据 API 限制和内存设置合理的 chunk_size。
  3. 使用缓存:对静态文档集合启用嵌入缓存,避免重复计算,降低成本和延迟。
  4. 选择合适的模型:根据语言、精度、成本、维度需求选择嵌入模型。
  5. 归一化:如果使用余弦相似度,确保向量已归一化(许多模型默认输出归一化向量,或在 encode_kwargs 中设置)。
  6. 监控 Token 消耗:对于付费 API,监控嵌入调用的 Token 使用量(部分集成返回 token 用量信息)。
相关推荐
北京_小杰子1 小时前
Windows10本地安装SQLserver数据库连接的过程
数据库·windows·sqlserver·php
JaydenAI2 小时前
[拆解LangChain执行引擎]一个实例理解LangChain的几种流模式
ai·langchain·agent·pregel
塔中妖2 小时前
Windows 安装 Maven 详细教程(含镜像与本地仓库配置)
java·windows·maven
水饺编程14 小时前
第4章,[标签 Win32] :TextOut 测试案例3代码改编
c语言·c++·windows·visual studio
一个人旅程~16 小时前
win10LTSB2016与win10LTSC2019对于老机型哪个更合适?
linux·windows·经验分享·电脑
大模型真好玩16 小时前
LangChain DeepAgents 速通指南(二)—— Summarization中间件为Agent作记忆加减法
人工智能·langchain·agent
2501_9269783318 小时前
思想波与引力共振理论:统一物理主义意识框架的革命性探索--AGI理论系统基础12
人工智能·经验分享·架构·langchain·agi
无聊的小坏坏18 小时前
RAG 实战 (下):打造多轮对话知识助手
langchain·rag·大模型应用
彭于晏Yan19 小时前
LangChain4j实战三:图像模型
java·spring boot·后端·langchain