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
架构层级说明
- 用户交互层:应用的入口与出口,负责接收用户输入(文本、参数)并返回处理结果,常见形式包括 API 接口、CLI 终端、前端界面等。
- 编排层:LangChain 的核心调度层,通过 Runnable/LCEL 定义组件的执行流程,Chains 处理固定流程编排,Agents 处理动态决策流程。
- 核心能力层:构建 LLM 应用的基础能力组件,涵盖模型调用、提示词管理、工具调用、记忆、检索、输出解析等核心能力。
- 基础设施层:底层依赖组件,负责对接外部系统(模型供应商、数据库、第三方工具),并提供可观测性、缓存等支撑能力。
架构核心特点:
- 组件化:所有能力拆分为独立组件,可按需组合、替换(如替换不同 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 的
LLMChain、Chain.run()已被废弃 PromptTemplate使用方式不兼容- 工具调用、Agent 接口重构
解决方案:
-
废弃
LLMChain,改用Runnable + LCEL重构流程 -
将字符串拼接的 Prompt 改为
ChatPromptTemplate -
Agent 改用
create_xxx_agent构造器,而非直接实例化 -
替换示例:
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
解决方案:
-
使用
ChatPromptTemplate的input_variables显式声明变量 -
初始化时开启
validate_template=True校验模板 -
使用
RunnableParallel做默认值处理:pythonchain = ( RunnableParallel({ "topic": lambda x: x.get("topic", "默认主题"), # 提供默认值 "extra": lambda x: x.get("extra", "") }) | prompt | llm )
问题 3:模型输出格式不稳定(JSON 解析失败)
解决方案:
-
使用
RetryOutputParser自动重试格式错误的输出 -
在 Prompt 中明确指定 JSON Schema,增强格式约束
-
使用模型的结构化输出能力(如 OpenAI 的
response_format):pythonllm = ChatOpenAI( model="gpt-4o-mini", response_format={"type": "json_object"} # 强制输出 JSON )
六、总结与最佳实践
核心总结
- 架构核心:LangChain v1.0+ 采用分层模块化架构,Runnable/LCEL 是所有组件的统一交互范式,实现了组件的声明式编排。
- 组件优先级:优先使用 Chain(固定流程)而非 Agent(动态流程),仅在需要动态决策时使用 Agent;Prompt 和 OutputParser 是生产级应用的必备组件。
- 开发范式 :通过 LCEL(
|运算符)组合 Runnable 构建流程,替代命令式代码,提升可读性和可维护性。