2.Langchain 1.2.0 学习 --- Models

LangChain Models 学习笔记

如果你正在开发 AI 应用,那么 LangChain 的 Models 模块是你必须掌握的核心组件。它就像是你与各种大语言模型(LLM)沟通的"翻译官"和"调度中心"。本文将带你全面了解 LangChain 1.2.0 中 Models 的用法,并通过大量示例帮助你快速上手。


1. 初识 LangChain Models

想象一下这样的场景:你开了一家餐厅雇用了来自不同国家的厨师(有会做川菜的、有会做西餐的、有会做日本料理的)。但是你发现一个问题——每个厨师的烹饪风格和流程都不一样,你需要分别用不同的方式和他们沟通。

LangChain Models 就是解决这个问题的"万能经理"。它提供了一套统一的接口,让你能够轻松地与各种大语言模型(OpenAI、Anthropic、百度、阿里等)进行交互,而不需要关心底层 API 的差异。

为什么要掌握 Models API?

  • 统一接口:一套代码切换不同模型
  • 灵活配置:精确控制输出行为
  • 完整功能:支持同步/流式/批量调用、工具调用、结构化输出、多模态等高级特性

2. 快速上手:模型初始化

在 LangChain 中,初始化模型有两种主要方式。让我带你一步步了解。

2.1 使用 init_chat_model(推荐)

这是 LangChain 1.2.0 推荐的统一初始化方式,类似于"一站式服务"——你只需要告诉它想用什么模型,其他的事情它帮你搞定。

from langchain.chat_models import init_chat_model
import os

# 从环境变量读取配置
baidu_api_key = os.getenv("BAIDU_API_KEY")
baidu_base_url = os.getenv("BAIDU_BASEURL")

# 方式一:只指定模型名,提供商自动识别
model = init_chat_model(
    model="kimi-k2.5",
    model_provider="openai",  # 明确指定提供商
    base_url=baidu_base_url,
    api_key=baidu_api_key,
)

# 方式二:使用 "provider:model" 格式
model = init_chat_model(
    model="openai:kimi-k2.5",  # 提供商:模型名
    base_url=baidu_base_url,
    api_key=baidu_api_key,
)

💡 小贴士:如果你省略 model_provider,LangChain 会尝试自动识别。但显式指定可以避免歧义,也更易于理解和维护。

2.2 使用具体的模型类

有时候你需要更精细的控制,这时候可以直接使用具体的模型类,比如 ChatOpenAI

from langchain_openai import ChatOpenAI

# 完整的配置选项
model = ChatOpenAI(
    base_url="https://api.baidu.com/v1",  # API 端点
    api_key="your-api-key",                # API 密钥
    model="minimax-m2.5",                  # 模型名称
    temperature=0.7,                        # 温度参数
    max_tokens=1000,                        # 最大输出 token 数
    timeout=30,                             # 超时时间(秒)
    max_retries=6,                         # 最大重试次数
)

# 快速测试
response = model.invoke("你好,请介绍一下自己")
print(response.content)

3. 核心参数详解:像调味料一样配置你的模型

如果说大语言模型是一道菜,那么参数就是烹饪时的调味料。不同的调味料组合,会做出完全不同口味菜肴。让我为你详细讲解每个参数的作用和推荐用法。

3.1 temperature——控制"创意"还是"保守"

想象一下:你聘请了一位厨师。temperature=0 时,这位厨师严格按照菜谱操作,每次做出的菜几乎一模一样;temperature=1.5 时,这位厨师极具创意,每次都可能给你带来惊喜(或者惊吓)。

temperature 的取值范围是 0-2,数值越低输出越确定保守,数值越高输出越创意随机。

from langchain_openai import ChatOpenAI
import os

baidu_api_key = os.getenv("BAIDU_API_KEY")
baidu_base_url = os.getenv("BAIDU_BASEURL")

# 演示不同 temperature 的效果
for temp in [0, 0.7, 1.5]:
    print(f"\n{'='*50}")
    print(f"🌡️ Temperature = {temp}")
    print(f"{'='*50}")

    model_temp = ChatOpenAI(
        temperature=temp,
        max_tokens=100,
        base_url=baidu_base_url,
        api_key=baidu_api_key,
        model="kimi-k2.5",
    )

    # 同一问题,多次调用观察差异
    for i in range(2):
        response = model_temp.invoke("用一句话描述人工智能")
        print(f"  回答 {i+1}: {response.content}")
场景 推荐 Temperature 说明
代码生成 0.0 - 0.3 需要精确、确定性的输出
数据提取 0.0 - 0.3 需要结构化、一致的输出
问答系统 0.3 - 0.7 平衡准确性和自然度
创意写作 0.7 - 1.0 需要多样性和创造性
头脑风暴 1.0 - 1.5 最大化创意输出

3.2 max_tokens——控制输出的"预算"

想象你给厨师一个食材预算。max_tokens=50 意味着只能用很少的食材做一道小菜;max_tokens=300 则可以做一个丰盛的大餐。

max_tokens 控制模型生成的最大 token 数量,用于限制输出长度和控制成本。

# 不同 max_tokens 的效果
for max_tok in [50, 150, 300]:
    print(f"\n📏 max_tokens = {max_tok}")

    model_max = ChatOpenAI(
        max_tokens=max_tok,
        temperature=0.7,
        base_url=baidu_base_url,
        api_key=baidu_api_key,
        model="kimi-k2.5",
    )

    response = model_max.invoke("请详细介绍 Python 编程语言的特点")
    print(f"输出长度: {len(response.content)} 字符")
    print(f"内容预览: {response.content[:100]}...")
场景 推荐 max_tokens 说明
简短回答 50-100 节省成本,快速响应
中等回答 150-300 平衡详细度和成本
长文档生成 500-1000 允许详细解释
代码生成 500-2000 代码通常需要更多空间

3.3 top_p——核采样的秘密

想象服务员给你菜单,但只给你看最可能点到的菜品。top_p=0.1 只展示最热门的 10% 菜品,top_p=0.9 则展示 90% 的菜品供你选择。

top_p(核采样)是 temperature 的替代方案,用于控制输出多样性。通常不建议同时调整这两个参数。

# 演示 top_p 效果
for top_p in [0.1, 0.5, 0.9]:
    print(f"\n🎯 top_p = {top_p}")

    model_top = ChatOpenAI(
        top_p=top_p,
        temperature=0,  # 固定为 0 以便观察 top_p 效果
        max_tokens=100,
        base_url=baidu_base_url,
        api_key=baidu_api_key,
        model="kimi-k2.5",
    )

    response = model_top.invoke("列举三种编程语言")
    print(f"回答: {response.content}")
场景 推荐 top_p 说明
精确输出 0.1 - 0.3 只考虑高概率词,减少随机性
平衡模式 0.5 - 0.7 兼顾质量和多样性
创意生成 0.8 - 0.95 允许更多样化的选择

3.4 frequency_penalty——避免重复的"词汇税"

想象一位作家,如果他在文章中重复使用同一个词,就要交"词汇税"。frequency_penalty 越高,作者越会被迫使用不同的表达方式。

# 演示 frequency_penalty 效果
for penalty in [0, 0.5, 1.5]:
    print(f"\n🔄 frequency_penalty = {penalty}")

    model_fp = ChatOpenAI(
        frequency_penalty=penalty,
        temperature=0.7,
        max_tokens=150,
        base_url=baidu_base_url,
        api_key=baidu_api_key,
        model="kimi-k2.5",
    )

    response = model_fp.invoke("用丰富的词汇描述编程的美好")
    print(f"输出: {response.content}")
场景 推荐值 说明
默认 0 无特殊需求时不调整
减少重复 0.3 - 0.7 避免相同词汇过度重复
高度多样 1.0 - 1.5 强制使用不同表达方式

3.5 presence_penalty——话题探索的"推进器"

这位作家如果在一个话题上停留太久,就会被"推"到新话题。presence_penalty 越高,文章引入新主题的可能性越大。

# 演示 presence_penalty 效果
for penalty in [-0.5, 0, 1.0]:
    print(f"\n💡 presence_penalty = {penalty}")

    model_pp = ChatOpenAI(
        presence_penalty=penalty,
        temperature=0.7,
        max_tokens=200,
        base_url=baidu_base_url,
        api_key=baidu_api_key,
        model="kimi-k2.5",
    )

    response = model_pp.invoke("先介绍 Python,然后自然地切换到其他编程语言")
    print(f"输出: {response.content}")
场景 推荐值 说明
深入讨论 -0.5 - -0.2 保持在同一主题深入探讨
默认 0 平衡主题切换
广泛覆盖 0.5 - 1.0 鼓励覆盖多个不同主题

3.6 seed——让输出"可复现"的魔法种子

就像你在玩大富翁游戏时设定随机种子,每次用同样的骰子和起始位置,游戏过程和结果是完全一样的。seed 参数让模型输出可复现。

# 测试相同 seed + temperature=0 = 相同输出
print("测试1: 相同 seed,应该得到相同输出\n")
for i in range(2):
    model_seed = ChatOpenAI(
        seed=42,
        temperature=0,  # 必须为 0 才能完全复现
        base_url=baidu_base_url,
        api_key=baidu_api_key,
        model="kimi-k2.5",
    )
    response = model_seed.invoke("用10个字定义人工智能")
    print(f"  运行 {i+1}: {response.content}")

# 测试不同 seed = 不同输出
print("\n测试2: 不同 seed,应该得到不同输出\n")
for seed in [1, 999]:
    model_seed = ChatOpenAI(
        seed=seed,
        temperature=0.5,
        base_url=baidu_base_url,
        api_key=baidu_api_key,
        model="kimi-k2.5",
    )
    response = model_seed.invoke("用一句话形容夏天")
    print(f"  seed={seed}: {response.content}")
场景 推荐设置 说明
测试/调试 固定 seed + temperature=0 确保结果可复现
生产环境 不设置或随机 seed 获得自然的输出变化
A/B 测试 使用不同 seed 比较相同参数下的输出差异

3.7 stop——让模型"适可而止"

这就像是告诉服务员:"上完这三道菜后就停,不要再上了。"stop 参数让模型在遇到指定字符串时立即停止生成。

# 单个停止字符串
model_stop = ChatOpenAI(
    stop=".",
    max_tokens=200,
    base_url=baidu_base_url,
    api_key=baidu_api_key,
    model="kimi-k2.5",
)
response = model_stop.invoke("人工智能正在改变世界。它影响了许多行业。")
print(f"输出: {response.content}")
print(f"停止原因: {response.response_metadata.get('finish_reason')}")

# 多个停止字符串
model_stop2 = ChatOpenAI(
    stop=["步骤 3", "总结"],
    max_tokens=500,
    base_url=baidu_base_url,
    api_key=baidu_api_key,
    model="kimi-k2.5",
)
response = model_stop2.invoke("请列出步骤:步骤1:准备工作 步骤2:开始实施 步骤3:验证结果 步骤4:总结")
print(f"输出: {response.content}")
场景 推荐 stop 设置 说明
单句输出 "." 或 "\n" 限制为单句或单行
列表生成 ["1.", "2.", "3."] 限制列表项数
结构化输出 ["}", "]"] 在 JSON/数组结束处停止
特定标记 ["", "[STOP]"] 自定义停止标记

3.8 timeout 和 max_retries——网络问题的"防护盾"

想象你点了一份外卖,timeout 就像是等待送餐的最长时间。如果超过了,订单可能取消或者你会重新下单。max_retries 就是你愿意尝试重新下单的次数。

# 生产环境推荐配置
model_production = ChatOpenAI(
    timeout=60,           # 60秒超时
    max_retries=10,       # 最多重试10次
    temperature=0.3,
    base_url=baidu_base_url,
    api_key=baidu_api_key,
    model="kimi-k2.5",
)

# 快速响应配置
model_fast = ChatOpenAI(
    timeout=10,           # 10秒超时
    max_retries=2,        # 最多重试2次
    temperature=0.7,
    base_url=baidu_base_url,
    api_key=baidu_api_key,
    model="kimi-k2.5",
)

4. 模型的"三板斧":invoke、stream、batch

LangChain 提供了三种主要的模型调用方式,就像不同的沟通方式适用于不同场景。

4.1 invoke——同步调用,像打电话

最简单的调用方式,等待模型完全生成回答后再返回。

from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage

model = ChatOpenAI(model="glm-5", api_key=baidu_api_key, base_url=baidu_base_url)

# 单条消息调用
response = model.invoke("为什么鹦鹉会说话?")
print(f"回答: {response.content}")
print(f"Token 使用: {response.usage_metadata}")

# 多轮对话
conversation = [
    SystemMessage("你是一个友好的中文助手。"),
    HumanMessage("你好!"),
]
response = model.invoke(conversation)
print(f"回答: {response.content}")

4.2 stream——流式调用,像看直播

实时获取模型输出,提供更好的用户体验,特别适合长文本生成场景。

print("🌊 流式输出:\n")
full_response = ""

for chunk in model.stream("讲一个关于AI的短故事"):
    content = chunk.content
    full_response += content
    print(content, end="", flush=True)  # 实时显示

print(f"\n\n✅ 流式输出完成,总长度: {len(full_response)} 字符")

💡 使用场景:当用户需要等待较长时间才能看到完整回答时,流式输出可以显著提升体验,让用户"看得见"AI 正在思考。

4.3 batch——批量调用,像群发消息

同时处理多个独立请求,提高效率降低成本。

# 批量调用
questions = [
    "什么是Python?",
    "什么是JavaScript?",
    "什么是Rust?"
]

responses = model.batch(questions)

for q, r in zip(questions, responses):
    print(f"❓ {q}")
    print(f"   💡 {r.content}\n")

# 按完成顺序返回(适合耗时不同的任务)
for response in model.batch_as_completed(questions):
    print(f"✅ 完成: {response.text}...")

# 控制并发数(避免 API 限流)
many_questions = [f"问题 {i}: 什么是编程语言?" for i in range(10)]
responses = model.batch(many_questions, config={"max_concurrency": 3})

5. 工具调用(Tool Calling)——让 AI 学会"使用工具"

想象一位博学的助手,虽然知识渊博,但有时候也需要查资料、计算数据。Tool Calling 就是让 AI 学会主动"寻求帮助"的能力。

5.1 定义工具

from langchain.tools import tool

@tool
def get_weather(location: str) -> str:
    """获取指定地区的天气。"""
    weather_data = {
        "北京": "晴天,25°C",
        "上海": "多云,22°C",
        "纽约": "小雨,18°C"
    }
    return weather_data.get(location, f"未知天气信息: {location}")

@tool
def calculate(expression: str) -> str:
    """计算数学表达式。"""
    try:
        result = eval(expression)
        return f"结果: {result}"
    except:
        return "计算错误"

5.2 绑定工具并调用

# 将工具绑定到模型
model_with_tools = model.bind_tools([get_weather, calculate])

# 调用模型
response = model_with_tools.invoke("北京的天气怎么样?")
print(f"工具调用: {response.tool_calls}")

# 执行工具
for tool_call in response.tool_calls:
    result = get_weather.invoke(tool_call)
    print(f"工具结果: {result.content}")

5.3 完整的工具调用流程

# 完整流程示例
messages = [{"role": "user", "content": "北京和纽约的天气怎么样?"}]

# 1. 模型决定调用工具
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)

# 2. 执行工具
for tool_call in ai_msg.tool_calls:
    if tool_call['name'] == 'get_weather':
        result = get_weather.invoke(tool_call)
        messages.append(result)

# 3. 将结果返回给模型,生成最终回答
final_response = model_with_tools.invoke(messages)
print(f"最终回答: {final_response.text}")

6. 结构化输出——让 AI 回答"格式化"

想象你填写表格时,只需要按格式填就好,不需要自己排版。结构化输出就是让 AI 按照你定义的"表格"来回答。

6.1 使用 Pydantic 模型(推荐)

from pydantic import BaseModel, Field
from typing import List

class Movie(BaseModel):
    """电影信息"""
    title: str = Field(description="电影标题")
    year: int = Field(description="上映年份")
    director: str = Field(description="导演")
    rating: float = Field(description="评分(0-10)", ge=0, le=10)
    genres: List[str] = Field(description="电影类型列表")

# 创建结构化输出模型
model_structured = model.with_structured_output(Movie)

# 调用
response = model_structured.invoke("提供电影《阿甘正传》的详细信息")
print(f"标题: {response.title}")
print(f"年份: {response.year}")
print(f"导演: {response.director}")
print(f"评分: {response.rating}")
print(f"类型: {response.genres}")
print(f"对象类型: {type(response)}")  # <class '__main__.Movie'>

6.2 使用 TypedDict(轻量级)

from typing import TypedDict, Annotated

class PersonDict(TypedDict):
    """人物信息"""
    name: Annotated[str, ..., "姓名"]
    age: Annotated[int, ..., "年龄"]
    occupation: Annotated[str, ..., "职业"]

model_typeddict = model.with_structured_output(PersonDict)
response = model_typeddict.invoke("介绍一下爱因斯坦")
print(response)  # {'name': '阿尔伯特·爱因斯坦', 'age': 76, 'occupation': '物理学家'}

6.3 使用 JSON Schema

json_schema = {
    "title": "Book",
    "description": "书籍信息",
    "type": "object",
    "properties": {
        "title": {"type": "string", "description": "书名"},
        "author": {"type": "string", "description": "作者"},
        "published_year": {"type": "integer", "description": "出版年份"},
        "isbn": {"type": "string", "description": "ISBN编号"}
    },
    "required": ["title", "author", "published_year"]
}

model_json_schema = model.with_structured_output(json_schema, method="json_schema")
response = model_json_schema.invoke("提供《三国演义》的信息")
import json
print(json.dumps(response, indent=2, ensure_ascii=False))
方法 优点 缺点 适用场景
Pydantic 自动验证、类型安全、支持嵌套 需要定义模型类 生产环境、复杂结构
TypedDict 轻量、无需实例化 无运行时验证 简单结构、快速原型
JSON Schema 最大灵活性、跨语言 冗长、无验证 动态结构、外部集成

7. 多模态模型——让 AI"看见"世界

传统 AI 只能"读"文字,现代 AI 还能"看"图片、"听"音频。多模态模型就是 AI 的"五感"。

7.1 图像输入

from langchain_core.messages import HumanMessage

model_vision = ChatOpenAI(model="qwen3-omni-flash", api_key=ali_api_key, base_url=ail_base_url)

# 方式一:通过 URL
message = HumanMessage(
    content=[
        {"type": "text", "text": "描述这张图片的内容:"},
        {
            "type": "image_url",
            "image_url": {"url": "https://example.com/image.jpg"}
        },
    ]
)
response = model_vision.invoke([message])
print(response.text)

# 方式二:通过 Base64 编码本地图像
import base64

def encode_image(image_path: str) -> str:
    with open(image_path, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")

base64_image = encode_image("/path/to/image.jpg")
message = HumanMessage(
    content=[
        {"type": "text", "text": "描述这张图片:"},
        {
            "type": "image_url",
            "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
        },
    ]
)

7.2 PDF 输入

# PDF URL 方式
pdf_message = HumanMessage(
    content=[
        {"type": "text", "text": "总结这份 PDF 文档的主要内容:"},
        {
            "type": "file",
            "file": {
                "url": "https://example.com/document.pdf",
                "filename": "document.pdf"
            }
        },
    ]
)

# PDF Base64 方式
with open("document.pdf", "rb") as f:
    pdf_base64 = base64.b64encode(f.read()).decode("utf-8")

pdf_message = HumanMessage(
    content=[
        {"type": "text", "text": "分析这份文档:"},
        {
            "type": "file",
            "file": {
                "filename": "document.pdf",
                "file_data": pdf_base64
            }
        },
    ]
)

7.3 Content Block 标准格式

LangChain 1.2.0 引入了标准化的 Content Block 格式:

# 使用 content_blocks 属性(推荐)
message = HumanMessage(
    content_blocks=[
        {"type": "text", "text": "分析这张图片:"},
        {"type": "image", "url": "https://example.com/image.jpg"}
    ]
)

# 或使用 Base64
message = HumanMessage(
    content_blocks=[
        {"type": "text", "text": "描述这张图片:"},
        {
            "type": "image",
            "base64": "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQy...",
            "mime_type": "image/jpeg"
        },
    ]
)

8. 最佳实践总结

参数选择速查表

┌─────────────────────────────────────────────────────────────┐
│                      Temperature 选择指南                     │
├─────────────────────────────────────────────────────────────┤
│ 代码生成/数学计算:  temperature=0.0 - 0.2                    │
│ 数据提取/分类:     temperature=0.0 - 0.3                    │
│ 对话/问答:         temperature=0.3 - 0.7                    │
│ 创意写作:          temperature=0.7 - 1.0                    │
│ 头脑风暴:          temperature=1.0 - 1.5                    │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      Max Tokens 设置建议                     │
├─────────────────────────────────────────────────────────────┤
│ 简短回答:    max_tokens=100-300                              │
│ 中等长度:    max_tokens=500-1000                             │
│ 长文档:      max_tokens=2000-4000                            │
│ 代码生成:    max_tokens=2000-4000                            │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      生产环境推荐配置                          │
├─────────────────────────────────────────────────────────────┤
│ model = ChatOpenAI(                                           │
│     model="gpt-4o",                                          │
│     timeout=60,           # 复杂查询需要更长时间              │
│     max_retries=10,       # 网络不稳定时增加重试             │
│     temperature=0.3,      # 根据场景调整                     │
│ )                                                            │
└─────────────────────────────────────────────────────────────┘

9. 总结

本文全面介绍了 LangChain 1.2.0 中 Models 的核心概念和用法:

  1. 模型初始化init_chat_model() vs 直接实例化
  2. 核心参数:temperature、max_tokens、top_p 等参数的作用和推荐值
  3. 调用方式:invoke(同步)、stream(流式)、batch(批量)
  4. 工具调用:让 AI 能够主动使用外部工具
  5. 结构化输出:Pydantic、TypedDict、JSON Schema 三种方式
  6. 多模态模型:图像、PDF、音频输入处理

📝 个人笔记:本文档基于 LangChain 1.2.0 版本,不同版本可能存在 API 差异,请以官方文档为准;文中使用LLM为百度千帆,多模态大模型使用阿里百炼

posted @ 2026-03-17 21:26  刘莫语  阅读(138)  评论(0)    收藏  举报