目录
1. AI应用的发展与LangChain的定位
1.1 从简单调用到智能体
AI应用的发展经历了三个标志性阶段:
第一阶段:简单LLM应用
最初的AI应用仅仅是封装大语言模型(LLM)的API调用。这类应用能力有限------无法调用外部工具、无法访问私有数据、无法执行多步骤任务。本质上是一个"增强版的问答机器"。
第二阶段:链式应用(Chain)
为突破LLM的能力边界,开发者开始在其前后编排辅助步骤:调用前进行知识检索 (Retrieval),调用后进行工具调用 (Tool Calls)。整个流程形成一条固定的链(Chain)------这既是LangChain命名的来源,也是AI应用走向工程化的第一步。
链式应用的特点在于确定性(Deterministic) :无论执行多少次,流程完全一致。但其缺陷也恰在于此------缺乏自适应性(Agentic),无法根据上下文动态调整策略。
第三阶段:智能体(Agent)
Agent的核心理念是让LLM自主决定执行流程。不再固守预设的链条,而是由LLM在运行时动态规划下一步操作。这带来了Agent开发中的根本矛盾:自主性(Autonomy)与稳定性(Stability)是一对不可调和的张力。自主控制的程度越高,系统的不可预测性就越强。工程实践的核心,就是在两者之间找到恰当的平衡点。
1.2 智能产生的三要素
在大规模语言模型的语境下,所谓"智能"来源于三个核心要素的协同:
| 要素 | 作用 | 说明 |
|---|---|---|
| 模型算法 | 大脑 | 以Transformer为代表的神经网络架构,决定模型的基础推理能力 |
| 海量数据 | 知识 | 万亿级token的训练数据(互联网文本、书籍、代码库) |
| 超级算力 | 燃料 | 数千块GPU连续数周的训练,算力需求每数月翻一番 |
三者缺一不可。20世纪AI进展缓慢的根源,正是这三座大山同时制约着技术的发展。直到近十年,三者先后跨越临界点,AI能力才真正呈现爆发式增长。
1.3 LangChain与LangGraph的定位
LangChain 是面向AI应用开发的基础框架,提供模型调用、工具集成、记忆管理、RAG等统一API,简化Agent的快速构建。
LangGraph 是基于图结构的工作流编排引擎,让开发者精确控制Agent的执行流程,在保持自主性的同时提升稳定性。它有别于传统Chain的线性结构,支持分支、循环、并行和人工介入。
自LangChain 1.x起,Agent底层已全面迁移至LangGraph。两者的关系并非"二选一",而是搭档------LangChain提供能力,LangGraph编排流程。
| 维度 | LangChain | LangGraph |
|---|---|---|
| 定位 | AI应用开发框架 | 工作流编排框架 |
| 控制粒度 | API级别 | Node/Edge级别 |
| 适用场景 | 简单LLM调用、快捷Agent开发 | 复杂工作流、需要精细控制 |
| 学习曲线 | 低 | 较高 |
| 底层依赖 | 上层封装,底层调用LangGraph | 基础编排层 |
2. LangChain核心组件
LangChain的架构按层次划分,从数据流自下而上理解最为清晰。
2.1 模型层(Model)
LangChain通过 init_chat_model 提供统一的模型初始化接口,屏蔽了不同提供商(OpenAI、DeepSeek、Qwen等)的API差异:
python
from langchain.chat_models import init_chat_model
model = init_chat_model(
model="deepseek-chat",
model_provider="openai",
base_url=os.getenv("DASHSCOPE_BASE_URL"),
api_key=os.getenv("DASHSCOPE_API_KEY")
)
模型层支持多模态输入(文本、图片、音频),可配合 with_structured_output 实现结构化工件(如JSON Schema约束的输出)。
2.2 消息系统(Messages)
消息系统是LangChain数据流转的基石。所有Agent调用、模型交互均通过消息对象完成:
| 消息类型 | 用途 | 示例场景 |
|---|---|---|
HumanMessage |
封装用户输入 | 用户提问、指令 |
AIMessage |
封装模型回复 | 模型回答、工具调用请求 |
SystemMessage |
设定行为规范 | Agent人格设定、系统提示词 |
ToolMessage |
封装工具返回 | 搜索结果、API响应 |
多模态消息示例:
python
from langchain.messages import HumanMessage
multimodal_message = HumanMessage(
content=[
{"type": "image", "url": "https://oss.example.com/photo.jpg"},
{"type": "text", "text": "请识别这些食材并推荐食谱"}
]
)
最佳实践:多模态场景下优先使用对象存储URL而非base64编码,以避免Token浪费和内存压力。
2.3 工具系统(Tools)
工具是Agent与外部世界交互的通道。LangChain支持两种定义方式:
装饰器方式(推荐):
python
from langchain.tools import tool
@tool
def get_weather(location: str) -> str:
"""查询指定城市的当前天气"""
# 函数签名和文档字符串自动生成Tool Schema
return f"{location}:晴,25℃"
类继承方式(适合复杂工具):
python
from langchain.tools import BaseTool
class WeatherTool(BaseTool):
name: str = "get_weather"
description: str = "查询指定城市的当前天气"
def _run(self, location: str) -> str:
# 实际的查询逻辑
return f"{location}:晴,25℃"
LangChain还集成了大量第三方工具,如Tavily(Web搜索)、SQLDatabase(数据库操作)等,简化了工具的接入成本。
2.4 记忆管理(Checkpointer)
Agent需要持久化对话历史,才能进行连贯的多轮交互。LangGraph的 Checkpointer 机制实现了细粒度的记忆管理------在每个Node执行完毕后生成检查点,支持故障恢复、人机暂停和状态回溯。
python
from langgraph.checkpoint.sqlite import SqliteSaver
import sqlite3
connection = sqlite3.connect("agent_memory.db", check_same_thread=False)
checkpointer = SqliteSaver(connection)
checkpointer.setup() # 自动建表
| Checkpointer | 适用场景 | 特点 |
|---|---|---|
InMemorySaver |
开发/测试 | 进程内存储,数据不持久 |
SqliteSaver |
单机部署 | 轻量级,无需额外服务 |
PostgresSaver |
生产环境 | 高可用,支持分布式 |
2.5 结构化输出(Structured Output)
将LLM的文本输出约束为预定义的Pydantic模型,是构建可靠Agent的关键技术:
python
from pydantic import BaseModel, Field
from typing import Literal
class RouteDecision(BaseModel):
step: Literal["weather", "translate", "chat"] = Field(
..., description="路由决策"
)
reason: str = Field(..., description="决策理由")
# 绑定结构化输出
router = llm.with_structured_output(RouteDecision)
result = router.invoke("今天北京天气怎么样?")
# result.step == "weather"
with_structured_output 会自动将Pydantic模型转换为JSON Schema,利用LLM的function calling能力返回结构化数据,无需手工解析。
2.6 Runtime运行时
Runtime是Agent执行时的上下文环境,承载运行时状态和配置。通过Runtime,开发者可在不修改Agent代码的前提下动态调整行为:
python
from dataclasses import dataclass
@dataclass
class UserContext:
reasoning: bool = False
user_role: str = "guest"
# 调用时传入运行时上下文
response = agent.invoke(
{"messages": [HumanMessage("Hello")]},
config,
context=UserContext(reasoning=True)
)
Runtime的一个典型应用场景是中间件中的条件路由------根据运行时上下文切换模型、工具或行为策略。
3. Agent智能体开发
3.1 Agent的核心构成
一个标准的Agent由三个要素组成:
- 模型(Model):作为"大脑",负责理解、规划和决策
- 工具(Tools):作为"感官与四肢",负责与外部环境交互
- 系统提示词(System Prompt):作为"人格与行为准则",定义Agent的角色边界
创建Agent的API经过LangChain 1.x重构后高度简化:
python
from langchain.agents import create_agent
agent = create_agent(
model=model,
tools=[web_search, get_weather],
system_prompt="你是一名旅游助手...",
checkpointer=checkpointer
)
3.2 创建和调用Agent
同步调用:
python
response = agent.invoke(
{"messages": [HumanMessage(content="你好")]},
config={"configurable": {"thread_id": "session-001"}}
)
流式调用(推荐用于交互式场景):
python
for chunk, metadata in agent.stream(
{"messages": [HumanMessage(content="你好")]},
stream_mode="messages"
):
if isinstance(chunk, AIMessage) and chunk.content:
print(chunk.content, end="", flush=True)
流式调用的优势在于:用户可以实时看到Agent的思考过程和工具调用结果,显著提升交互体验。
3.3 LangSmith调试与部署
LangSmith是LangChain官方提供的全生命周期管理平台,涵盖开发调试、测试评估和生产监控。
properties
# .env 配置
LANGSMITH_API_KEY=your-api-key
LANGSMITH_TRACING=true
LANGSMITH_PROJECT=your-project-name
LangSmith Studio提供以下能力:
- 执行追踪:可视化每一步的输入、输出、Token消耗和延迟
- 交互式测试:在GUI中直接测试Agent,实时观察行为
- 性能监控:聚合指标看板,识别瓶颈和异常
- 云部署:基于测试通过的Agent一键部署为RESTful API
4. Middleware中间件机制
Middleware(中间件)是LangChain中控制Agent内部运行的关键设施。它在Agent运行的关键节点预留钩子(Hook),允许开发者嵌入自定义逻辑,实现对Agent执行过程的精细控制。
4.1 中间件类型
中间件分为两大类,按执行时机和使用方式区分:
Node-style hooks(节点钩子): 在Agent节点的特定生命周期触发
| 钩子 | 触发时机 | 典型用途 |
|---|---|---|
before_agent |
Agent执行前 | 输入校验、审计日志 |
before_model |
模型调用前 | 动态切换模型、注入上下文 |
after_model |
模型调用后 | 输出校验、内容过滤 |
after_agent |
Agent执行后 | 结果持久化、性能指标采集 |
Wrap-style hooks(环绕钩子): 包裹模型调用和工具调用
| 钩子 | 用途 |
|---|---|
wrap_model_call |
统一控制模型调用的前后处理 |
wrap_tool_call |
统一控制工具调用的前后处理 |
4.2 预定义中间件
LangChain提供多个开箱即用的企业级中间件:
PII脱敏中间件------自动识别并遮蔽个人敏感信息:
python
from langchain.agents.middleware import PIIMiddleware
pii_middleware = PIIMiddleware(
"email", # 敏感信息类型
strategy="redact", # 替换为 [REDACTED_EMAIL]
apply_to_input=False, # 输入不清洗
apply_to_output=True # 输出自动脱敏
)
模型降级中间件------主模型异常时自动切换到备用模型,提升可用性:
python
from langchain.agents.middleware import ModelFallbackMiddleware
model_fallback = ModelFallbackMiddleware(
"gpt-4o-mini", # 主模型
"deepseek-chat" # 备用模型
)
人工审核中间件(HITL)------在敏感操作前暂停执行,等待人工确认:
python
from langchain.agents.middleware import HumanInTheLoopMiddleware
human_in_loop = HumanInTheLoopMiddleware(
interrupt_on={
"transfer_money": {
"description": "请确认转账操作",
"allowed_decisions": ["approve", "reject", "edit"]
}
}
)
4.3 自定义中间件
装饰器方式------快速创建简单中间件:
python
from langchain.agents.middleware import after_model
@after_model(state_schema=CustomAgentState)
def increment_counter(state: CustomAgentState, runtime: Runtime) -> dict:
"""每次模型调用后计数加1"""
current_count = state.get("model_call_count", 0)
return {"model_call_count": current_count + 1}
类方式------创建复杂中间件,支持多重钩子:
python
from langchain.agents.middleware import AgentMiddleware
class LoggingMiddleware(AgentMiddleware):
def wrap_model_call(self, request, handler):
print(f"[Model] 调用模型,消息数: {len(request.messages)}")
return handler(request)
def wrap_tool_call(self, request, handler):
print(f"[Tool] 调用工具: {request.tool_call.get('name', 'unknown')}")
return handler(request)
4.4 高级用法
动态修改请求------根据运行时上下文切换模型:
python
@wrap_model_call
def dynamic_model_selector(request, handler):
is_reasoning = getattr(request.runtime.context, 'reasoning', False)
selected = reasoning_model if is_reasoning else chat_model
modified = request.override(model=selected)
return handler(modified)
条件跳转------满足条件时跳过模型调用,直接跳转到终止节点:
python
def before_model(self, state, runtime):
if state.get("call_count", 0) > self.max_limit:
return {
"jump_to": "end",
"messages": [AIMessage("调用次数已达上限")]
}
条件跳转是实现Agent"熔断"策略的有效手段,在Agent陷入无限循环时能自动终止流程。
5. RAG检索增强生成
RAG(Retrieval-Augmented Generation)通过在LLM调用前检索相关知识库,将检索结果作为上下文注入提示词,从根本上解决了LLM的知识局限性 (训练数据的截止时间)和领域局限性(通用模型对专有领域知识的匮乏)。
5.1 知识库构建
一个完整的RAG系统包含两大部分:知识库构建 和检索生成。知识库构建是RAG的基石,其完整流程如下:
文档加载 → 文本切分 → 向量化(Embedding) → 存入向量数据库
文档加载
LangChain通过统一的 BaseLoader 接口,支持数十种文档加载器:
| 加载器 | 用途 | 依赖 |
|---|---|---|
TextLoader |
纯文本文件 | 无 |
PyPDFLoader |
PDF文档 | pypdf |
WebBaseLoader |
网页内容 | 无 |
CSVLoader |
CSV表格数据 | 无 |
所有加载器将原始数据转换为统一的 Document 对象,包含 page_content(文档内容)和 metadata(来源、页码等元数据)。
文本切分
切分策略直接决定检索质量。LangChain提供多种切分器:
python
from langchain_text_splitters import RecursiveCharacterTextSplitter, MarkdownHeaderTextSplitter
# 按语义结构切分(适合Markdown文档)
markdown_splitter = MarkdownHeaderTextSplitter([
("#", "H1"), ("##", "H2"), ("###", "H3")
])
# 递归字符切分(适合普通文本)
recursive_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50, # 重叠窗口,保持上下文连贯
separators=["\n\n", "\n", "。", ","] # 优先级从高到低
)
切分原则:chunk_size应当与Embedding模型的上下文窗口匹配;chunk_overlap用于缓解切分边界的信息断裂;优先使用基于文档结构的切分器(如MarkdownHeaderTextSplitter)。
向量化存储
python
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
embeddings = DashScopeEmbeddings(
model="text-embedding-v3",
dashscope_api_key=os.getenv("DASHSCOPE_API_KEY")
)
vectorstore = InMemoryVectorStore(embeddings)
vectorstore.add_documents(docs)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
对于复杂结构的PDF(分栏、表格、图片扫描件),可选用 Docling(IBM/MIT协议) 、MinerU(上海AI实验室) 或 Unstructured 等专业工具进行预处理。
5.2 RAG系统架构
RAG系统有两种主流架构,适用于不同场景:
| 架构 | 决策主体 | 特点 | 适用场景 |
|---|---|---|---|
| 2-Step RAG | 开发者固定 | 每次调用前都检索,流程确定 | FAQ、文档问答机器人 |
| Agentic RAG | LLM自主决定 | 按需检索,支持多轮迭代 | 研究助手、复杂问答 |
2-Step RAG实现 ------利用 @dynamic_prompt 中间件注入检索上下文:
python
@dynamic_prompt
def prompt_with_context(request: ModelRequest) -> str:
last_query = request.state["messages"][-1].text
retrieved_docs = retriever.invoke(last_query)
context = "\n\n".join(
f"来源: {doc.metadata}\n{doc.page_content}" for doc in retrieved_docs
)
return f"请基于以下上下文回答问题:\n\n{context}"
Agentic RAG实现------将检索器封装为Tool,由Agent自主决定调用时机:
python
@tool
def search_knowledge_base(query: str) -> str:
"""搜索知识库,获取相关知识。需要查找资料时调用。"""
docs = retriever.invoke(query)
return "\n\n".join(
f"来源: {doc.metadata}\n{doc.page_content}" for doc in docs
)
agent = create_agent(
model="deepseek-chat",
tools=[search_knowledge_base],
system_prompt="你可以使用知识库搜索工具..."
)
Agentic RAG的优势在于按需检索------仅在需要时搜索,避免每次检索的资源浪费,同时支持多次搜索和多轮交互迭代。
5.3 检索优化策略
工业级RAG系统必须解决一个核心矛盾:检索精度与召回率之间的权衡。以下是经过验证的优化策略体系:
查询优化------让用户的模糊问题变得"可检索"
| 策略 | 原理 | 效果 |
|---|---|---|
| 查询重写 | LLM将口语化问题改写为规范检索词 | 提升命中率 |
| HyDE(虚构文档嵌入) | 先让LLM生成"假设答案",用答案作为向量检索 | 大幅提升语义匹配 |
| Multi-Hop拆分 | 复杂问题拆为多个子问题分别检索后聚合 | 解决多跳推理 |
HyDE实现示例:
python
# 第一步:让LLM基于问题生成假设性答案
rewrite_prompt = f"请根据你的知识,生成一个可能的50字以内的答案:{query}"
fake_answer = model.invoke(rewrite_prompt).content
# 第二步:用假设答案作为查询向量进行检索
retrieved_docs = vectorstore.similarity_search(fake_answer, k=3)
HyDE的直觉是:答案比问题在语义空间中更接近相关文档,因此用"虚拟答案"检索比用原始问题检索效果更好。
多路召回------稠密与稀疏的互补
单一的向量检索(稠密)对语义相似度高但关键词不同的查询表现好,但对专有名词、精确匹配场景效果不佳。方案是多路召回 + 融合排序:
python
# 稠密检索(向量语义)
dense_results = vectorstore.similarity_search(query, k=5)
# 稀疏检索(BM25关键词)
sparse_results = bm25_search(query, k=5)
# RRF融合
def reciprocal_rank_fusion(ranked_lists, k=60):
rrf_scores = {}
for rank_list in ranked_lists:
for rank, doc in enumerate(rank_list, start=1):
doc_id = doc.id
rrf_scores[doc_id] = rrf_scores.get(doc_id, 0) + 1.0 / (k + rank)
return sorted(rrf_scores.items(), key=lambda x: x[1], reverse=True)
RRF公式 : R R F ( d ) = ∑ r = 1 n 1 k + r a n k r ( d ) RRF(d) = \sum_{r=1}^{n}\frac{1}{k + rank_r(d)} RRF(d)=r=1∑nk+rankr(d)1
其中 k k k 通常取60, r a n k r ( d ) rank_r(d) rankr(d) 是文档 d d d 在第 r r r 个检索结果中的排名。RRF的优点是无需训练数据即可将多个排序结果融合为一个高质量排序。
重排序------精排打分的最后一道关卡
检索初排(粗排)后,使用Cross-Encoder对Top-K结果进行精确打分重排:
python
from langchain.retrievers.document_compressors import CrossEncoderReranker
# 使用Cross Encoder模型进行重排序
reranker = CrossEncoderReranker(
model_name="BAAI/bge-reranker-v2-m3",
top_n=3
)
reranked_docs = reranker.compress_documents(
documents=initial_results,
query=query
)
常用的Re-rank模型:Qwen3-Reranker、bge-reranker-v2-m3、Cohere rerank。
完整RAG流水线
用户问题
↓
查询重写 / HyDE / Multi-Hop(查询优化)
↓
稠密检索(向量) ──→ RRF融合 ←── 稀疏检索(BM25)
↓
Cross-Encoder重排序
↓
上下文注入 → LLM生成 → 最终回答
5.4 RAG评估
构建RAG系统后,必须从两个维度进行量化评估:
评估维度
| 维度 | 指标 | 目标值 | 说明 |
|---|---|---|---|
| 检索质量 | Context Precision | ≥ 0.85 | 检索结果中相关文档的比例及排名 |
| Context Recall | ≥ 0.70 | 标准答案中的信息被检索覆盖的比例 | |
| Context Entities Recall | ≥ 0.70 | 标准答案中的实体被检索覆盖的比例 | |
| 生成质量 | Faithfulness | ≥ 0.90 | 回答中的事实是否都有检索文档支持(反幻觉) |
| Response Relevancy | ≥ 0.88 | 回答是否紧扣用户问题 | |
| Noise Sensitivity | ≤ 0.10 | 回答中被噪声文档误导的错误比例(越低越好) |
核心指标详解
Faithfulness(忠实度)------衡量"幻觉"的关键指标:
Faithfulness = 检索文档能支持的陈述数 回答中的总陈述数 \text{Faithfulness} = \frac{\text{检索文档能支持的陈述数}}{\text{回答中的总陈述数}} Faithfulness=回答中的总陈述数检索文档能支持的陈述数
例如,检索文档包含"A",但模型回答包含了"A、B、C"三个陈述,只有"A"有文档支撑,则Faithfulness = 1/3。
Context Precision(上下文精度)------关注排名位置:
Context Precision @ K = ∑ i = 1 K ( relevant i × ∣ { relevant in top i } ∣ i ) ∣ { total relevant documents } ∣ \text{Context Precision}@K = \frac{\sum_{i=1}^{K} (\text{relevant}_i \times \frac{|\{\text{relevant in top } i\}|}{i})}{|\{\text{total relevant documents}\}|} Context Precision@K=∣{total relevant documents}∣∑i=1K(relevanti×i∣{relevant in top i}∣)
相关文档排得越靠前,贡献越大。排在第1位的文档贡献权重1,第3位权重1/3。
评估工具:RAGAS
RAGAS是社区最广泛使用的RAG评估框架:
python
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
result = evaluate(
dataset=test_dataset, # 包含 question/answer/contexts/ground_truth
metrics=[faithfulness, answer_relevancy, context_precision, context_recall]
)
print(result)
下篇 :以上,我们完成了从LangChain核心组件、Agent开发、Middleware中间件到RAG检索增强生成的完整基础能力构建。至此,你已经可以构建具备"信息增强"能力的AI应用。然而,真实世界的业务往往更加复杂------需要分支、循环、并行、人工介入,还需要连接外部MCP服务、协调多个Agent协作。下篇将深入LangGraph的图编排能力,带你掌握从"线性链"到"图工作流"的进阶之路。
下一篇:LangChain从入门到精通(下):工作流与架构进阶