LangChain从入门到精通(1)

目录

  1. AI应用的发展与LangChain的定位
  2. LangChain核心组件
  3. Agent智能体开发
  4. Middleware中间件机制
  5. RAG检索增强生成

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从入门到精通(下):工作流与架构进阶

相关推荐
leeyi2 小时前
Workflow 编排:字段映射、数据流分离
langchain·workflow·graphql
倾颜2 小时前
从手写 Runner 到 LangGraph:受控 Agent 接入 LangGraph
前端·后端·langchain
wuhen_n2 小时前
从零到一!前端搭建本地轻量化 RAG 问答系统
前端·langchain·ai编程
Solis程序员6 小时前
LangChain从入门到精通(2)
langchain
kishu_iOS&AI6 小时前
LLM —— LangChain
人工智能·langchain
老梁agent7 小时前
Agent 返回 JSON 而不是闲聊:LangChain4j 结构化输出实战
物联网·langchain
打小就很皮...9 小时前
基于 Python + LangChain + React 实现智能发票识别与验真系统实战
前端·react.js·langchain·ocr·发票识别
颜酱1 天前
让 Agent 不再失忆:LangChain 短期记忆实战
langchain·agent
装不满的克莱因瓶1 天前
了解 LangChain 中的 LLM 与 ChatModel 的差异
人工智能·python·ai·langchain·llm·agent·chatmodel