LangChain v1.0+ 入门详解:概念、架构、组件、模板与实战

LangChain v1.0+ 入门详解:概念、架构、组件、模板与实战

一、背景与定位

LangChain 是一套专为构建大语言模型(LLM)原生应用设计的开源框架,其核心价值并非简单封装 LLM 调用接口,而是解决 LLM 与外部系统协同的核心问题:

将 LLM 与外部数据、工具、记忆系统、业务流程进行可靠、可维护、可扩展的编排,让 LLM 从"孤立的文本生成器"变为"能落地的智能应用核心"。

LangChain v1.0 是框架的里程碑版本,相较于 v0.x 完成了底层架构的重构,核心变化包括:

  • 架构完全模块化,API 稳定性大幅提升(破坏性更新显著减少)
  • 确立 Runnable / LCEL(LangChain Expression Language) 为核心抽象层,统一所有组件的交互范式
  • 清晰划分 应用层(Chains / Agents)基础设施层(Models / Tools / Memory / Retrievers),降低开发耦合度
  • 强化生产级特性(可观测性、容错、并发),适配企业级场景

本文以 LangChain v1.0+ 为基准,系统拆解其核心概念、基础架构、核心组件、标准化开发模板,并解答实战中的常见问题。


二、LangChain v1.0+ 基础架构

LangChain v1.0+ 采用分层式模块化架构,整体可分为 4 个核心层级,各层级职责清晰、可独立替换,架构逻辑如下:
输入/输出
调度
依赖
用户交互层
编排层
核心能力层
基础设施层
API接口/FastAPI
CLI/终端
前端界面
Runnable/LCEL
Chains
Agents
Models
Prompts
Tools
Memory
Retrievers
OutputParsers
模型供应商集成

OpenAI/Deepseek/Ollama...
数据存储

Redis/FAISS/Milvus...
工具适配器

API/函数/数据库
可观测性

LangSmith/Tracing

架构层级说明

  1. 用户交互层:应用的入口与出口,负责接收用户输入(文本、参数)并返回处理结果,常见形式包括 API 接口、CLI 终端、前端界面等。
  2. 编排层:LangChain 的核心调度层,通过 Runnable/LCEL 定义组件的执行流程,Chains 处理固定流程编排,Agents 处理动态决策流程。
  3. 核心能力层:构建 LLM 应用的基础能力组件,涵盖模型调用、提示词管理、工具调用、记忆、检索、输出解析等核心能力。
  4. 基础设施层:底层依赖组件,负责对接外部系统(模型供应商、数据库、第三方工具),并提供可观测性、缓存等支撑能力。

架构核心特点:

  • 组件化:所有能力拆分为独立组件,可按需组合、替换(如替换不同 LLM、不同向量数据库)
  • 声明式:通过 LCEL 声明流程,而非命令式代码,降低编排复杂度
  • 可扩展:各层级均提供扩展接口,支持自定义组件(如自定义 Tool、自定义 OutputParser)

三、LangChain v1.0+ 核心概念与组件详解

1. 模型层:LLM 与 ChatModel

LangChain 对不同类型的大语言模型进行了统一抽象,核心分为两类接口,适配不同的模型交互方式:

类型 交互模式 适用场景 示例模型
LLM 文本输入 → 文本输出(prompt → text) 传统补全类任务、非对话式场景 GPT-3.5-turbo-instruct、Claude Instant
ChatModel 消息列表输入 → 消息输出(messages → message) 对话式场景、多轮交互、工具调用 GPT-4o、Claude 3、Gemini

核心用法(推荐优先使用 ChatModel)

python 复制代码
"""
通用大模型接入配置文件 llm.py
支持:OpenAI/Anthropic/Ollama/Xinference/DeepSeek/Qwen/OneAPI/vLLM 等
"""
import os
from langchain_openai import ChatOpenAI

from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

# ===================== 基础配置(可通过环境变量注入) =====================
# 通用配置
TEMPERATURE = 0.2  # 随机性,0-1 越低越稳定
MAX_TOKENS = 1000  # 最大输出长度

# 各平台API Key(优先从环境变量读取,避免硬编码)
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "your-api-key")
ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY", "your-anthropic-key")
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "your-deepseek-key")
QWEN_API_KEY = os.getenv("QWEN_API_KEY", "sk-xxxxxxx")

# 自定义端点配置(OneAPI/Xinference/vLLM 等)
CUSTOM_BASE_URL = {
    "oneapi": os.getenv("ONEAPI_BASE_URL", "http://localhost:3000/v1"),
    "xinference": os.getenv("XINFERENCE_BASE_URL", "http://localhost:9997/v1"),
    "vllm": os.getenv("VLLM_BASE_URL", "http://localhost:8000/v1"),
    "deepseek": os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1"),
    "qwen": os.getenv("QWEN_BASE_URL", "http://localhost:9997/v1")
}

# ===================== 各类型模型初始化 =====================

# 1. OpenAI 官方模型(含 OneAPI 兼容)
def init_openai_llm(model="gpt-4o-mini", base_url=None, api_key=None):
    """
    初始化 OpenAI 系列模型(支持 OneAPI 代理)
    :param model: 模型名称(gpt-4o-mini/gpt-3.5-turbo 等)
    :param base_url: 自定义端点(OneAPI 时填写)
    :param api_key: API Key(默认读取环境变量)
    """
    return ChatOpenAI(
        model=model,
        temperature=TEMPERATURE,
        api_key=api_key or OPENAI_API_KEY,
        base_url=base_url or CUSTOM_BASE_URL["oneapi"],
        max_tokens=MAX_TOKENS,
        timeout=15
    )

# 2. Anthropic 模型(Claude)
def init_anthropic_llm(model="claude-3-haiku-20240307", api_key=None):
    """初始化 Anthropic Claude 模型"""
    return ChatAnthropic(
        model=model,
        temperature=TEMPERATURE - 0.1,  # Claude 建议稍低的随机性
        api_key=api_key or ANTHROPIC_API_KEY,
        max_tokens=MAX_TOKENS
    )

# 3. Ollama 本地模型(如 Llama3、Qwen 本地版)
def init_ollama_llm(model="qwen:7b", base_url="http://localhost:11434"):
    """
    初始化 Ollama 本地部署模型
    :param model: 本地模型名称(ollama list 查看)
    :param base_url: Ollama 服务地址
    """
    return ChatOllama(
        model=model,
        base_url=base_url,
        temperature=TEMPERATURE,
        max_tokens=MAX_TOKENS,
        # 自定义 Ollama 参数
        extra={"num_ctx": 8192}  # 上下文窗口大小
    )

# 4. Xinference 模型(跨框架统一推理服务)
def init_xinference_llm(model="qwen-7b-chat", api_key=None):
    """
    初始化 Xinference 部署的模型
    :param model: Xinference 中注册的模型名称
    :param api_key: Xinference 认证密钥(可选)
    """
    return ChatOpenAI(
        model=model,
        temperature=TEMPERATURE,
        api_key=api_key or "none",  # Xinference 可填任意值,仅做格式兼容
        base_url=CUSTOM_BASE_URL["xinference"],
        max_tokens=MAX_TOKENS
    )

# 5. DeepSeek 模型(官方 API)
def init_deepseek_llm(model="deepseek-chat"):
    """初始化 DeepSeek 官方 API 模型"""
    return ChatOpenAI(
        model=model,
        temperature=TEMPERATURE,
        api_key=DEEPSEEK_API_KEY,
        base_url=CUSTOM_BASE_URL["deepseek"],
        max_tokens=MAX_TOKENS
    )

# 6. 通义千问 Qwen(阿里云 DashScope 兼容 OpenAI 接口)
def init_qwen_llm(model="Qwen3-Instruct:30B"):
    """初始化通义千问(阿里云 DashScope 兼容模式)"""
    return ChatOpenAI(
        model=model,
        temperature=TEMPERATURE,
        api_key=QWEN_API_KEY,
        base_url=CUSTOM_BASE_URL["qwen"],
        max_tokens=MAX_TOKENS
    )

# 7. vLLM 高性能推理服务(兼容 OpenAI 接口)
def init_vllm_llm(model="Llama-3-8b-Instruct-v1.1"):
    """
    初始化 vLLM 部署的模型(超高吞吐)
    :param model: vLLM 加载的模型名称
    """
    return ChatOpenAI(
        model=model,
        temperature=TEMPERATURE,
        api_key="none",  # vLLM 本地部署无需 API Key,填任意值
        base_url=CUSTOM_BASE_URL["vllm"],
        max_tokens=MAX_TOKENS,
        timeout=30  # vLLM 首次加载可能稍慢,延长超时
    )

# ===================== 快捷初始化示例(按需调用) =====================
# 示例1:初始化 OneAPI 代理的 OpenAI 模型
openai_llm = init_openai_llm(
    model="gpt-4o-mini",
    base_url=CUSTOM_BASE_URL["oneapi"]
)

# 示例2:初始化本地 Qwen 模型
qwen_llm = init_qwen_llm(
    model="Qwen3-Instruct:30B"
)

# 示例3:初始化 Xinference 部署的模型
xinference_llm = init_xinference_llm(
    model="qwen-7b-chat"
)

# 示例4:初始化 DeepSeek 官方模型
deepseek_llm = init_deepseek_llm(
    model="deepseek-chat"
)

# 示例5:初始化 vLLM 高性能模型
vllm_llm = init_vllm_llm(
    model="Llama-3-8b-Instruct-v1.1"
)

# ===================== 通用调用示例(验证模型可用性) =====================
def test_llm(llm, prompt_text="你好,请介绍一下自己"):
    """
    测试模型是否正常响应
    :param llm: 初始化后的模型实例
    :param prompt_text: 测试提示词
    :return: 模型响应内容
    """
    prompt = ChatPromptTemplate.from_messages([
        ("user", prompt_text)
    ])
    chain = prompt | llm
    try:
        response = chain.invoke({})
        print(f"✅ 模型响应成功:\n{response.content}\n")
        return response.content
    except Exception as e:
        print(f"❌ 模型调用失败:{str(e)}\n")
        return None
    


# 测试示例(取消注释运行)
if __name__ == "__main__":
#     test_llm(openai_llm)          # 测试 OneAPI/OpenAI
    test_llm(qwen_llm)     # 测试 Ollama 本地模型
#     test_llm(xinference_llm)      # 测试 Xinference 模型
#     test_llm(deepseek_llm)        # 测试 DeepSeek 模型
#     test_llm(vllm_llm)            # 测试 vLLM 模型

关键特性

  • LangChain 仅做接口抽象,不负责模型推理,模型调用由供应商 SDK 完成
  • 支持主流模型供应商(OpenAI/Azure/Anthropic/Ollama/Google 等),通过独立包集成(如 langchain_openai、langchain_anthropic)
  • 统一的模型配置(temperature、max_tokens 等),切换模型无需修改核心逻辑

2. 提示词层:PromptTemplate 与 ChatPromptTemplate

v1.0+ 中提示词不再是简单字符串,而是强类型、可校验、可组合的 Prompt 对象,核心分为两类:

(1)基础 PromptTemplate(适用于 LLM)
python 复制代码
from langchain_core.prompts import PromptTemplate

# 基础模板
prompt = PromptTemplate(
    template="请解释 {concept} 的核心原理,目标受众:{audience}",
    input_variables=["concept", "audience"],  # 显式声明变量
    validate_template=True  # 校验模板变量完整性
)

# 格式化提示词
formatted_prompt = prompt.format(concept="LCEL", audience="Python 编程大师傅")
(2)ChatPromptTemplate(适用于 ChatModel,推荐)

专为对话模型设计,支持区分消息角色(system/human/ai),贴合 ChatModel 的交互范式:

python 复制代码
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

# 基础对话模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是{role},回答必须简洁,不超过100字"),  # 系统指令
    MessagesPlaceholder(variable_name="history"),       # 对话历史占位符
    ("human", "{question}")                             # 用户输入
])

# 格式化示例
formatted_messages = prompt.format_messages(
    role="Python 编程大师傅",
    history=[],  # 初始无对话历史
    question="什么是 LangChain Runnable?"
)

核心优势

  • 角色区分:明确 system/human/ai 消息类型,贴合主流 ChatModel 的交互规范
  • 变量校验:初始化时校验模板变量完整性,避免运行时 KeyError
  • 可组合性:支持嵌套模板、消息占位符(适配多轮对话)
  • 复用性:可将通用提示词封装为模板,跨场景复用

3. 核心抽象:Runnable

Runnable 是 LangChain v1.0+ 的第一公民,定义了所有可执行组件的统一接口:

任何可以被"运行"的对象(Prompt、Model、Parser、Chain、自定义函数),都是 Runnable。

(1)Runnable 核心方法
方法 作用 使用场景
invoke(input) 单次同步调用,返回完整结果 简单单次请求
batch(inputs, batch_size=5) 批量调用,返回结果列表 批量处理任务(如批量生成文案)
stream(input) 流式输出,返回生成器 实时展示结果(如前端流式响应)
ainvoke(input) 异步单次调用 异步编程场景(FastAPI/Starlette)
astream(input) 异步流式输出 异步 + 流式场景

基础用法示例

python 复制代码
# 1. 单个 Runnable 调用
from llm import qwen_llm
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_template("请用一句话描述 {topic}")
result = prompt.invoke({"topic": "LangChain"})  # 输出格式化后的消息列表

# 2. 流式调用示例
chain = prompt | qwen_llm
for chunk in chain.stream({"topic": "LangChain v1.0"}):
    print(chunk.content, end="", flush=True)  # 逐字输出
(2)Runnable 组合:| 运算符(LCEL 核心)

通过 | 运算符可将多个 Runnable 串联为一个新的 Runnable,这是 LCEL 的核心语法:

python 复制代码
from llm import qwen_llm
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template("请用一句话描述 {topic}")
# 组合 Prompt → LLM → 字符串解析
chain = prompt | llm | StrOutputParser()

# 调用组合后的 Runnable
result = chain.invoke({"topic": "LangChain 架构"})
print(result)  # 直接输出解析后的字符串

4. 编排语言:LCEL(LangChain Expression Language)

LCEL 是 LangChain 官方推荐的声明式流程编排语言,基于 Runnable 的组合能力,用简洁的语法描述组件的执行流程,替代 v0.x 中命令式的 Chains 代码。

(1)LCEL 基础语法
python 复制代码
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from llm import qwen_llm

# 基础流程:Prompt → LLM → 解析
basic_chain = (
    ChatPromptTemplate.from_template(
        "分析 {text} 的情感倾向,输出JSON:{{{{'sentiment': '正面/负面/中性'}}}}"
    )
    | qwen_llm
    | StrOutputParser()
)

# 复杂流程:并行处理 + 结果合并
complex_chain = (
    RunnableParallel({
        "sentiment": basic_chain,          # 并行执行情感分析
        "text": RunnablePassthrough()      # 关键:透传原始的 text 变量
    })
    | ChatPromptTemplate.from_template(
        "文本:{text}\n情感倾向:{sentiment}\n请总结以上信息"
    )
    | qwen_llm
    | StrOutputParser()
)

# 调用复杂流程
result = complex_chain.invoke({"text": "LangChain v1.0 架构更清晰,开发体验大幅提升!"})
print(result)
(2)LCEL 核心优势
  • 可读性强:流程按执行顺序书写,直观易懂
  • 天然支持流式:组合后的 Chain 自动继承流式能力,无需额外开发
  • 可插拔扩展:可在流程中插入日志、缓存、校验等中间件
  • 类型安全:自动校验各步骤的输入输出类型,减少运行时错误
  • 兼容异步:无需修改流程代码,即可切换同步/异步调用

5. 输出层:OutputParser(输出解析)

LLM 输出是非结构化文本,OutputParser 负责将其转换为结构化数据,是生产级应用的核心组件,v1.0+ 提供了丰富的解析器类型:

(1)核心解析器类型
解析器 作用 适用场景
StrOutputParser 转换为纯字符串 简单文本输出场景
JsonOutputParser 转换为 JSON 字典 结构化数据输出场景
PydanticOutputParser 转换为 Pydantic 模型对象 强类型结构化输出、数据校验
CommaSeparatedListOutputParser 转换为逗号分隔的列表 生成列表类结果(如关键词、步骤)
(2)核心用法示例(Pydantic 解析器,推荐生产级使用)
python 复制代码
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from llm import qwen_llm

# 定义结构化输出模型
class ArticleSummary(BaseModel):
    title: str = Field(description="文章标题")
    key_points: list[str] = Field(description="核心要点,至少3条")
    word_count: int = Field(description="文章字数")

# 初始化解析器
parser = PydanticOutputParser(pydantic_object=ArticleSummary)

format_instructions = parser.get_format_instructions().replace("{", "{{").replace("}", "}}")

# 构建提示词(使用转义后的格式说明)
prompt = ChatPromptTemplate.from_messages([
    ("system", f"请解析文章并输出结构化数据,严格按照以下格式要求输出,不要额外文字:\n{format_instructions}"),
    ("human", "文章内容:{content}")
])

# 组合流程
chain = prompt | qwen_llm | parser

# 调用并解析
content = """LangChain v1.0 于2024年发布,核心重构了架构,确立了Runnable作为核心抽象,
LCEL成为官方推荐的编排方式,组件化程度更高,API稳定性大幅提升。"""
result = chain.invoke({"content": content})

# 结构化结果使用
print(f"标题:{result.title}")
print(f"核心要点:{result.key_points}")
print(f"字数:{result.word_count}")
(3)容错处理(生产级必备)

LLM 输出可能不符合格式要求,可通过 RetryOutputParser 实现自动重试:

python 复制代码
from langchain_core.output_parsers import RetryOutputParser
from llm import qwen_llm
# 包装解析器,添加自动重试
retry_parser = RetryOutputParser.from_llm(
    parser=parser,
    llm=qwen_llm
)

# 组合带重试的流程
retry_chain = prompt | qwen_llm| retry_parser

6. 工具层:Tool 与 Tool Calling

Tool 是 LangChain 定义的标准化工具调用接口,让 LLM 能够调用外部工具(函数、API、数据库、计算器等),扩展 LLM 的能力边界。

(1)Tool 定义方式
方式1:装饰器定义(推荐)
python 复制代码
from langchain_core.tools import tool
from typing import Optional

@tool
def calculate(expression: str) -> float:
    """
    计算数学表达式的结果,支持加减乘除、幂运算(^)、括号
    
    参数:
        expression: 数学表达式字符串,例如 "3 + 5 * (2 - 8)^2"
    """
    # 替换幂运算符号,适配 Python 语法
    expr = expression.replace("^", "**")
    try:
        result = eval(expr)  # 生产环境建议使用更安全的表达式解析库
        return float(result)
    except Exception as e:
        return f"计算失败:{str(e)}"

# 查看 Tool 元数据(供 LLM 理解工具用途)
print(calculate.name)  # 工具名称
print(calculate.description)  # 工具描述
print(calculate.args)  # 参数说明
方式2:自定义 Tool 类(复杂场景)
python 复制代码
from langchain_core.tools import BaseTool, Tool
from pydantic import BaseModel, Field

# 定义工具参数模型
class WeatherInput(BaseModel):
    city: str = Field(description="城市名称,如北京、上海")
    date: Optional[str] = Field(default=None, description="查询日期,格式 YYYY-MM-DD")


def weather_query(city: str, date: Optional[str] = None) -> str:
    """查询指定城市指定日期的天气情况"""
    if not date:
        # 使用当前日期
        date = datetime.datetime.now().strftime("%Y-%m-%d")
    return f"{date} {city} 的天气:晴,温度 5~15℃"


# 构建结构化工具
weather_tool = StructuredTool.from_function(
    func=weather_query,
    name="weather_query",
    description="查询指定城市指定日期的天气情况",
    args_schema=WeatherInput,
    return_direct=False  # 改为False,让链统一处理
)
(2)Tool 调用流程

Tool 本身不主动执行,需结合 LLM(支持工具调用的模型)或 Agent 完成调用:

python 复制代码
"""
工具函数注册与调用配置文件 tools.py
支持:基于LangChain v1.0+ 规范实现的数学计算、天气查询工具
功能:
1. 定义计算工具(支持加减乘除、幂运算、括号)
2. 定义天气查询工具(支持指定城市/日期,默认查询当日)
3. 实现标准化的工具调用流程(LLM生成调用指令 → 解析 → 执行工具)
4. 兼容单/多工具调用、自然语言直接回答等场景
"""
import json
import datetime
from typing import Optional, List, Dict, Any
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.runnables import RunnablePassthrough
from pydantic import BaseModel, Field
from langchain_core.tools import StructuredTool
from llm import qwen_llm


# ====================== 1. 定义工具 ======================
@tool
def calculate(expression: str) -> str:
    """
    计算数学表达式的结果,支持加减乘除、幂运算(^)、括号
    
    参数:
        expression: 数学表达式字符串,例如 "3 + 5 * (2 - 8)^2"
    """
    expr = expression.replace("^", "**")
    try:
        result = eval(expr)
        return f"计算结果:{float(result)}"
    except Exception as e:
        return f"计算失败:{str(e)}"


class WeatherInput(BaseModel):
    city: str = Field(description="城市名称,如北京、上海")
    date: Optional[str] = Field(default=None, description="查询日期,格式 YYYY-MM-DD")


def weather_query(city: str, date: Optional[str] = None) -> str:
    """查询指定城市指定日期的天气情况"""
    if not date:
        # 使用当前日期
        date = datetime.datetime.now().strftime("%Y-%m-%d")
    return f"{date} {city} 的天气:晴,温度 5~15℃"


# 构建结构化工具
weather_tool = StructuredTool.from_function(
    func=weather_query,
    name="weather_query",
    description="查询指定城市指定日期的天气情况",
    args_schema=WeatherInput,
    return_direct=False  # 改为False,让链统一处理
)


# ====================== 2. 工具注册 ======================
tools = [calculate, weather_tool]
tool_dict = {tool.name: tool for tool in tools}


# ====================== 3. 工具调用逻辑 ======================
def get_tool_description() -> str:
    """生成工具描述(供LLM参考)"""
    tool_descs = []
    for t in tools:
        desc = f"工具名称:{t.name}\n描述:{t.description}"
        if hasattr(t, 'args_schema') and t.args_schema:
            desc += f"\n参数:{t.args_schema.model_json_schema()}"
        else:
            desc += "\n参数:无"
        tool_descs.append(desc)
    return "\n\n".join(tool_descs)


prompt = ChatPromptTemplate.from_messages([
    ("system", """你是一个工具调用助手,请根据用户问题决定是否调用工具。
    
可用工具:
{tools}

调用格式说明:
1. 如果需要调用工具,请严格输出JSON格式的工具调用指令
2. 如果不需要调用工具,请直接返回自然语言答案

工具调用JSON格式:
{{"name": "工具名称", "arguments": {{参数名: 参数值}}}}

如果需要调用多个工具,输出JSON数组:
[{{"name": "工具1", "arguments": {{参数1: 值1}}}}, {{"name": "工具2", "arguments": {{参数2: 值2}}}}]"""),
    ("user", "{question}")
])


# 构建工具调用链
tool_call_chain = (
    RunnablePassthrough.assign(tools=lambda x: get_tool_description())
    | prompt
    | qwen_llm
    | JsonOutputParser()
)


def execute_tool_call(question: str) -> str:
    """执行工具调用"""
    try:
        # 1. 调用LLM生成工具调用指令
        tool_invocations = tool_call_chain.invoke({"question": question})
        
        # 2. 处理输出:可能是单个工具调用或工具调用数组
        if not isinstance(tool_invocations, list):
            tool_invocations = [tool_invocations]
        
        results = []
        for inv in tool_invocations:
            # 3. 检查是否是工具调用格式
            if isinstance(inv, dict) and "name" in inv and "arguments" in inv:
                tool_name = inv["name"]
                
                if tool_name not in tool_dict:
                    results.append(f"❌ 未知工具:{tool_name}")
                    continue
                
                # 4. 执行工具
                try:
                    tool = tool_dict[tool_name]
                    tool_input = inv["arguments"]
                    
                    if isinstance(tool_input, dict):
                        result = tool.invoke(tool_input)
                    else:
                        result = tool.invoke({"expression": str(tool_input)})
                    
                    results.append(f"✅ {tool_name} 执行结果:{result}")
                except Exception as e:
                    results.append(f"❌ {tool_name} 执行失败:{str(e)}")
            else:
                # 5. 如果不是工具调用格式,直接作为回答
                return str(inv)
        
        return "\n".join(results)
    
    except Exception as e:
        # 6. JSON解析失败,说明可能是自然语言回答
        # 直接调用LLM回答问题
        try:
            direct_prompt = ChatPromptTemplate.from_messages([
                ("system", "请直接回答用户的问题。"),
                ("human", "{question}")
            ])
            direct_chain = direct_prompt | qwen_llm
            return direct_chain.invoke({"question": question}).content
        except:
            return f"处理问题时发生错误:{str(e)}"


# ====================== 4. 调用示例 ======================
if __name__ == "__main__":
    # 示例1:调用计算工具
    result1 = execute_tool_call("计算 (10 + 20) * 3 的结果")
    print("【计算工具调用结果】")
    print(result1, "\n")

    # 示例2:调用天气工具
    result2 = execute_tool_call("查询上海2024-01-01的天气")
    print("【天气工具调用结果】")
    print(result2, "\n")

    # 示例3:天气工具默认日期
    result3 = execute_tool_call("今天北京的天气如何?")
    print("【天气工具默认日期调用结果】")
    print(result3, "\n")

    # 示例4:自然语言问题
    result4 = execute_tool_call("介绍一下你自己")
    print("【自然语言问题结果】")
    print(result4, "\n")

7. 智能体层:Agent

Agent 是 LangChain 中处理动态决策型任务的核心组件,本质是:

Agent = LLM(决策核心) + 推理循环 + Tool 调用策略

v1.0+ 重构了 Agent 体系,推荐使用预置 Agent 构造器,简化开发流程。

(1)核心 Agent 类型
Agent 类型 适用场景 构造器
OpenAI Tools Agent 基于 OpenAI 工具调用格式的 Agent create_openai_tools_agent
Anthropic Tools Agent 基于 Anthropic 工具调用格式的 Agent create_anthropic_tools_agent
Structured Chat Agent 结构化对话 Agent,支持复杂工具调用 create_structured_chat_agent
(2)Agent 开发示例
python 复制代码
"""
Agent 标准实现(create_agent 统一构造器) agent.py
核心:创建 Agent,适配模型 + 计算/天气工具
"""
# ====================== 1. 正确导入 ======================
from langchain.agents import create_agent 
from langchain_core.tools import StructuredTool, tool
from typing import Optional
import datetime
from pydantic import BaseModel, Field
import sys
import os
from llm import qwen_llm  

# ====================== 2. 定义工具(保持原有业务逻辑) ======================
@tool
def calculate(expression: str) -> str:
    """
    计算数学表达式的结果,支持加减乘除、幂运算(^)、括号
    
    参数:
        expression: 数学表达式字符串,例如 "15 - 5"
    """
    expr = expression.replace("^", "**")
    try:
        result = eval(expr)
        return f"计算结果:{float(result)}"
    except Exception as e:
        return f"计算失败:{str(e)}"

class WeatherInput(BaseModel):
    """天气查询工具参数校验模型"""
    city: str = Field(description="城市名称,如北京、上海")
    date: Optional[str] = Field(default=None, description="查询日期,格式 YYYY-MM-DD")

def weather_query(city: str, date: Optional[str] = None) -> str:
    """查询指定城市指定日期的天气情况,返回温度范围(如 5~15℃)"""
    if not date:
        date = datetime.datetime.now().strftime("%Y-%m-%d")
    return f"{date} {city} 的天气:晴,温度 5~15℃"

weather_tool = StructuredTool.from_function(
    func=weather_query,
    name="weather_query",
    description="查询指定城市指定日期的天气情况,返回结果包含温度范围(如 5~15℃)",
    args_schema=WeatherInput,
)

# 工具列表
tools = [calculate, weather_tool]

# ====================== 3. 创建 Agent ======================
agent = create_agent(
    model=qwen_llm, 
    tools=tools,     # 注册计算/天气工具
    system_prompt="""你是一个智能助手,严格按照以下规则使用工具:
1. 查询天气必须调用 weather_query 工具,计算必须调用 calculate 工具;
2. 计算温度差值时,先提取天气工具返回的最高温、最低温,生成减法表达式后调用计算工具;
3. 最终用自然语言汇总所有结果,无需返回工具调用指令。""",
    debug=False  # True 启用调试模式,打印详细执行过程
)

# ====================== 4. 调用 Agent ======================
if __name__ == "__main__":
    # 严格使用 messages 列表格式(兼容 anthropic 风格)
    inputs = {
        "messages": [
            {"role": "user", "content": "查询北京2025-01-10的天气,然后计算当天温度范围的差值(最高-最低)"}
        ]
    }
    
    # 使用 stream 方法获取执行过程和最终结果
    final_output = None
    for chunk in agent.stream(inputs, stream_mode="updates"):
        print(f"执行步骤: {chunk}")
    
    # 使用 invoke 获取最终结果
    result = agent.invoke(inputs)
    
    # 输出最终结果
    print("\n【最终结果】:", result["messages"][-1].content)
(3)Agent 适用场景与限制
适用场景 不适用场景
多步骤决策任务 固定流程任务(优先用 Chain)
需动态选择工具的任务 低延迟要求的任务
需探索性解决的问题 高确定性要求的任务

8. 记忆层:Memory

Memory 负责保存和管理对话历史,让 LLM 具备上下文记忆能力,v1.0+ 中 Memory 也实现了 Runnable 接口,可无缝集成到 LCEL 流程中。

(1)核心 Memory 类型
类型 特点 适用场景
ChatMessageHistory 基础内存记忆,存储所有对话消息 简单测试场景
BufferMemory 带缓存的记忆,可配置最大消息数 常规多轮对话
VectorStoreRetrieverMemory 基于向量检索的记忆,只召回相关历史 长对话、历史消息量大的场景
RedisChatMessageHistory 基于 Redis 的持久化记忆 分布式、多会话场景
(2)Memory 使用示例
python 复制代码
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate,MessagesPlaceholder
from llm import qwen_llm
# 1. 初始化基础链
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个健忘的助手,只根据对话历史回答问题"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{question}")
])
chain = prompt | qwen_llm | StrOutputParser()

# 2. 定义对话历史存储(生产环境可替换为 Redis 等持久化存储)
store = {}
def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

# 3. 为链添加记忆能力
chain_with_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="question",
    history_messages_key="history"
)

# 4. 多轮对话调用
# 第一轮
result1 = chain_with_history.invoke(
    {"question": "我的名字是张三"},
    config={"configurable": {"session_id": "user123"}}
)
print(result1)  # 输出:好的,我记住了你的名字是张三

# 第二轮(带历史)
result2 = chain_with_history.invoke(
    {"question": "我叫什么名字?"},
    config={"configurable": {"session_id": "user123"}}
)
print(result2)  # 输出:你叫张三

9. 检索层:Retriever

Retriever 负责从外部数据源检索相关信息,是 RAG(检索增强生成)的核心组件,v1.0+ 中 Retriever 同样实现了 Runnable 接口,可直接集成到 LCEL 流程。

(1)核心 Retriever 类型
类型 底层存储 特点
VectorStoreRetriever 向量数据库(FAISS/PGVector/Chroma) 语义检索,适配非结构化文本
BM25Retriever 倒排索引 关键词检索,速度快
ParentDocumentRetriever 向量数据库 + 文档拆分 支持召回长文档的相关片段
(2)RAG 核心流程示例
python 复制代码
from langchain_core.runnables import RunnablePassthrough
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.retrievers import RetrieverOutputParser

# 1. 初始化向量库和 Retriever(模拟数据)
embeddings = OpenAIEmbeddings()
texts = [
    "LangChain v1.0 核心是 Runnable",
    "LCEL 是声明式编排语言",
    "Agent 用于动态决策任务"
]
vectorstore = FAISS.from_texts(texts, embeddings)
retriever = vectorstore.as_retriever(k=2)  # 召回Top2相关文档

# 2. 构建 RAG 提示词
prompt = ChatPromptTemplate.from_messages([
    ("system", "根据以下上下文回答问题,只使用上下文中的信息:\n{context}"),
    ("human", "{question}")
])

# 3. 构建 RAG 链
rag_chain = (
    {
        "context": retriever | RetrieverOutputParser(),  # 检索并解析为文本
        "question": RunnablePassthrough()  # 透传用户问题
    }
    | prompt
    | llm
    | StrOutputParser()
)

# 4. 调用 RAG 链
result = rag_chain.invoke({"question": "LangChain v1.0 的核心是什么?"})
print(result)  # 输出:LangChain v1.0 的核心是 Runnable

四、LangChain v1.0+ 标准化开发模板

项目结构

复制代码
langchain-fastapi-template/
├── app/                     # 核心应用代码
│   ├── __init__.py
│   ├── api/                 # API 路由层
│   │   ├── __init__.py
│   │   ├── v1/              # 版本化路由
│   │   │   ├── __init__.py
│   │   │   ├── chat.py      # 对话/流式接口
│   │   │   └── rag.py       # RAG 接口
│   ├── core/                # 核心逻辑层
│   │   ├── __init__.py
│   │   ├── llm.py           # LLM 实例初始化(千问/OpenAI)
│   │   ├── agent.py         # Agent 构建(v1.1.0+ create_agent)
│   │   └── rag.py           # RAG 链构建
│   ├── tools/               # 自定义工具
│   │   ├── __init__.py
│   │   ├── calculate.py     # 计算工具
│   │   └── weather.py       # 天气工具
│   └── utils/               # 工具函数
│       ├── __init__.py
│       ├── streaming.py     # 流式输出工具
│       └── config.py        # 配置管理
├── config/                  # 配置文件
│   ├── __init__.py
│   └── settings.py          # 环境变量/模型配置
├── requirements.txt         # 依赖清单
├── main.py                  # FastAPI 入口文件
└── README.md                # 部署/使用说明

代码仓库:https://gitee.com/YHLG/yh_langchain-fastapi-template.git

五、常见问题与解决方案

问题 1:v0.x 代码迁移到 v1.0+ 报错

核心原因

  • v0.x 的 LLMChainChain.run() 已被废弃
  • PromptTemplate 使用方式不兼容
  • 工具调用、Agent 接口重构

解决方案

  1. 废弃 LLMChain,改用 Runnable + LCEL 重构流程

  2. 将字符串拼接的 Prompt 改为 ChatPromptTemplate

  3. Agent 改用 create_xxx_agent 构造器,而非直接实例化

  4. 替换示例:

    python 复制代码
    # v0.x 代码(废弃)
    from langchain.chains import LLMChain
    chain = LLMChain(llm=llm, prompt=prompt)
    result = chain.run(topic="LangChain")
    
    # v1.0+ 代码(推荐)
    chain = prompt | llm | StrOutputParser()
    result = chain.invoke({"topic": "LangChain"})

问题 2:Prompt 变量未传导致 KeyError

解决方案

  1. 使用 ChatPromptTemplateinput_variables 显式声明变量

  2. 初始化时开启 validate_template=True 校验模板

  3. 使用 RunnableParallel 做默认值处理:

    python 复制代码
    chain = (
        RunnableParallel({
            "topic": lambda x: x.get("topic", "默认主题"),  # 提供默认值
            "extra": lambda x: x.get("extra", "")
        })
        | prompt
        | llm
    )

问题 3:模型输出格式不稳定(JSON 解析失败)

解决方案

  1. 使用 RetryOutputParser 自动重试格式错误的输出

  2. 在 Prompt 中明确指定 JSON Schema,增强格式约束

  3. 使用模型的结构化输出能力(如 OpenAI 的 response_format):

    python 复制代码
    llm = ChatOpenAI(
        model="gpt-4o-mini",
        response_format={"type": "json_object"}  # 强制输出 JSON
    )

六、总结与最佳实践

核心总结

  1. 架构核心:LangChain v1.0+ 采用分层模块化架构,Runnable/LCEL 是所有组件的统一交互范式,实现了组件的声明式编排。
  2. 组件优先级:优先使用 Chain(固定流程)而非 Agent(动态流程),仅在需要动态决策时使用 Agent;Prompt 和 OutputParser 是生产级应用的必备组件。
  3. 开发范式 :通过 LCEL(| 运算符)组合 Runnable 构建流程,替代命令式代码,提升可读性和可维护性。
相关推荐
pen-ai2 小时前
PyTorch 张量维度处理详解
人工智能·pytorch·python
郝学胜-神的一滴2 小时前
Python对象的自省机制:深入探索对象的内心世界
开发语言·python·程序人生·算法
tjjucheng2 小时前
小程序定制开发哪家有数据支持
python
pen-ai2 小时前
【PyTorch】 nn.TransformerEncoderLayer 详解
人工智能·pytorch·python
山土成旧客2 小时前
【Python学习打卡-Day44】站在巨人的肩膀上:玩转PyTorch预训练模型与迁移学习
pytorch·python·学习
星河天欲瞩2 小时前
【深度学习Day1】环境配置(CUDA、PyTorch)
人工智能·pytorch·python·深度学习·学习·机器学习·conda
Irene.ll2 小时前
DAY32 官方文档的阅读
python
Pyeako2 小时前
Opencv计算机视觉--轮廓检测&模板匹配
人工智能·python·opencv·计算机视觉·边缘检测·轮廓检测·模板匹配
西柚小萌新2 小时前
【人工智能:Agent】--7.Langchain短期记忆
langchain