一、前言

 近年来,大语言模型(LLM)展现了惊人的能力,但在实际应用中,直接使用原生LLM往往会遇到一系列棘手的问题:

  • 幻觉问题:模型可能生成看似合理但实际错误的信息
  • 提示词不统一:不同场景需要反复调整提示词,缺乏标准化
  • 模型切换成本高:不同厂商的LLM接口差异大,迁移困难
  • 编码集成不便:开发者更希望通过结构化数据(JSON/XML等)接口获取能力,而非纯文本
  • 知识截止日期:模型训练数据有时间限制,无法获取实时信息
  • 专业领域知识薄弱:在医学、法律等垂直领域,模型结果仅能作为参考,可信度不足

解决方案
 上述问题的核心在于:大模型本身缺乏外部知识检索、工具调用和状态管理能力。目前主流解决思路包括:

  • RAG(检索增强生成):为模型提供外部知识库,减少幻觉
  • Agent(智能体):让模型能够主动调用工具、搜索网络、执行操作

 而要实现这些能力,需要一个强大的框架来协调模型、数据和工具——这就是 LangChain 和 LangGraph 诞生的背景。

1.解决痛点

 LangChain能解决提到的每一个痛点,具体如下:

痛点 LangChain 的解决方案
幻觉问题 通过 RAG(检索增强生成) 流程,将外部知识库(文档、数据库)接入模型,让模型在回答时参考真实数据,从而显著降低幻觉。LangChain 提供了完整的文档加载、分割、向量化、检索链,开箱即用。
提示词不统一 通过 SystemPrompt 模板提示词工程 的最佳实践,将提示词结构化(身份、指令、示例、上下文)。LangChain 的 ChatPromptTemplate 支持动态插入变量,便于在不同场景复用同一套提示词模板。
模型切换成本高 LangChain 提供了 统一的 API 接口(如 invoke、stream),所有模型(OpenAI、DeepSeek、Anthropic 等)都遵循相同调用方式。只需修改模型名称或配置,无需重构业务代码。
编码集成不便 LangChain 支持 结构化输出,通过 with_structured_output 或 output_parsers,可以强制模型返回 JSON、XML 或 Pydantic 对象。开发者可以直接操作结构化数据,而非解析纯文本。
知识截止日期 通过 工具(Tool) 机制,模型可以调用外部搜索工具(如 Tavily、Google Search),实时获取最新网络信息,突破训练数据的时间限制。
专业领域知识薄弱 结合 RAG + 领域知识库,将医学、法律等专业文档向量化后作为上下文注入模型,使模型基于权威资料作答。同时可通过 自定义工具 调用领域专用 API(如药品查询、法规检索),进一步提升可信度。

2.技术特点

 LangChain 的核心设计哲学是 组件化与可组合性。它将复杂的大模型应用拆解为多个标准化组件,并通过 链式(Chain) 的方式将这些组件串联起来,形成一个可执行的工作流。

  • 组件化:所有功能(模型、提示词、检索、工具、记忆)均封装为独立组件,可插拔替换。
  • 链式调用:通过 | 管道运算符或 Chain 类将组件串联,形成清晰的执行流程。
  • 标准化接口:所有组件都遵循 invoke、stream、batch 等统一方法,学习成本低。
  • 可观测性:支持回调机制(Callbacks),便于日志记录、监控和调试。
  • 生态丰富:内置大量文档加载器、向量数据库、工具、输出解析器,开箱即用。
  • 与 LangGraph 协同:LangChain 提供基础链式能力,LangGraph 在此基础上增加了状态管理和循环控制,适用于复杂 Agent 场景。

3.传统LLM与Agent的区别

特性 传统聊天机器人 / LLM AI Agent
交互模式 被动响应,问一句答一句 下达命令,自主执行
执行力 停留在文本生成层面 能操作软件、发送邮件、联网搜索
自主性 需要人类给出详细步骤 只需给定最终目标,自主寻找路径

二、LangChain

 LangChain 是一个专门用于开发由大语言模型驱动的应用程序的框架。它将自然语言处理(NLP)流程拆解为标准化组件,让开发者能够自由组合并高效定制工作流。

核心组件与工作流程
典型的RAG流程在LangChain中体现为以下步骤:

  • 读取文档:支持PDF、Word、网页等多种格式
  • 分割文本:将长文档切分为语义完整的块(Chunk)
  • 向量化(Embedding):将文本块转换为向量表示
  • 存储向量:存入向量数据库(如Chroma、FAISS)
  • 接收用户问题:将用户问题也转换为向量
  • 检索相关文本:通过相似度搜索找到最相关的文本块
  • 组合提示:将用户问题与检索到的上下文一起发送给LLM
  • 解析输出:提取并返回最终答案

1.模型调用

(1)invoke方式

【解释一句话】

from langchain.chat_models import ChatDeepSeek

model = ChatDeepSeek(model="deepseek-chat", temperature=0.9)

response = model.invoke([
    SystemMessage(content="你扮演火箭队的武藏。"),
    HumanMessage(content="你是谁?")
])
print(response.content)

(2)stream方式

【解释一句话】

for chunk in model.stream("你好,你是谁?"):
    print(chunk.content, end="", flush=True)

2.消息

 在 LangChain 中,发送给 LLM 的消息和 LLM 返回的消息都统一封装为 BaseMessage,它是智能体中基本的上下文单元。LangChain 已经根据角色(Role)创建了对应的子类:

  • SystemMessage:role=“system”,用于设定模型角色和交互背景。
  • HumanMessage:role=“user”,代表用户输入。
  • AIMessage:role=“assistant”,代表 LLM 生成的响应(包含文本、工具调用、元数据)。
  • ToolMessage:role=“tool”,代表工具调用时产生的结果。
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

# 定义工具
@tool
def get_weather(location: str) -> str:
    """
    Get the weather in a given location.
    Args:
        location: city name or coordinates
    """
    return f"Current weather in {location} is sunny"

# 创建 Agent
agent = create_agent(model="deepseek-chat", tools=[get_weather])

# 调用 Agent,发送消息
response = agent.invoke({
    "messages": [
        SystemMessage(content="请使用工具来获取天气信息。"),
        HumanMessage(content="你好,我是虎哥。"),
        AIMessage(content="你好,虎哥,很高兴认识你。"),
        HumanMessage(content="北京今天天气如何?")
    ]
})

print(response)

 除了文本消息,LangChain 也支持向模型发送多模态消息(图片、音频、视频等),但前提是模型本身支持多模态,例如:

  • qwen3.5-plus
  • gpt-5-nano
# 准备多模态消息
message = HumanMessage([
    {"type": "text", "text": "描述以下这张图片的内容。"},
    {"type": "image", "url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241022/emyria/dog_and_girl.jpeg"},
])

stream = agent.stream(
    {"messages": [message]},
    stream_mode="messages"
)

for chunk, metadata in stream:
    if chunk.content:
        print(chunk.content, end="", flush=True)

3.提示词

 在所有消息中,SystemMessage 最为重要,它设定了模型的角色和聊天背景,会影响后续所有对话。我们将其称为 系统提示词(System Prompt)。

 系统提示词示例

from langchain.agents import create_agent
from langchain.messages import HumanMessage

# 创建智能体,设定系统提示词
agent = create_agent(
    model="deepseek-chat",
    system_prompt="你以海盗的口吻来回答用户问题。"
)

# 流式调用
for token, metadata in agent.stream(
    {"messages": [HumanMessage(content="你是谁?")]},
    stream_mode="messages"
):
    print(token.content, end="", flush=True)

 提示词工程(Prompt Engineering):所谓提示词工程,就是通过优化提示词使模型输出的结果更符合业务需要的过程。

 一般来说,系统提示词会包含以下几个部分,建议按此顺序排列:

  • 身份角色(Identity):描述 AI 的职责、沟通风格和总体目标。
  • 指令说明(Instructions):指导模型如何生成响应,应遵循哪些规则,模型应该做什么以及绝对不能做什么。
  • 对话示例(Examples):提供可能的输入示例及期望的输出。
  • 背景信息(Context):提供生成响应所需的额外信息,例如 RAG 检索到的知识库数据。
  • 在编写系统提示词时,可以使用 Markdown 格式和 XML 标签 的组合来帮助模型理解逻辑边界:
  • Markdown 的标题和列表有助于标记提示的不同部分,并传达层级结构,同时提高可读性。
  • XML 标签(如 <context>、<example>)可以明确区分不同内容的起始和结束位置。
# 身份
你是一名资深的AI助教,擅长用通俗易懂的方式解释复杂概念。

# 指令
- 回答必须简洁、准确。
- 如果问题涉及实时数据,请告知用户需要查询最新信息。
- 禁止编造事实。

# 对话示例
用户:什么是RAG?
AI:RAG是检索增强生成,它通过在生成答案前先检索外部知识库来减少幻觉。

# 上下文
<context>
RAG全称Retrieval-Augmented Generation,由Facebook AI在2020年提出。
</context>

4.工具Tool

 所谓的工具(Tool),本质上是一个可调用的函数,但这个函数不是由我们直接调用,而是交给模型来调用。因此,除了定义函数本身,我们还需要清晰描述这个工具,让模型知道它的用途和用法。描述信息通常包括:

  • 工具名
  • 工具的作用
  • 工具需要的参数

(1)基于 @tool 装饰器直接描述

 在LangChain中,定义工具需要用到 @tool 装饰器,我们可以通过装饰器来定义工具名、工具的作用,

from langchain_core.tools import tool

@tool("square_root", description="Calculate the square root of a number")
def tool1(x: float) -> float:
    return x ** 0.5

(2)使用函数名和文档注释自动生成描述

 如果不 @tool 装饰器没有定义工具名和作用描述,此时:

  • 工具名:默认就是函数名
  • 工具所需的参数:默认就是函数的参数列表
  • 工具作用的描述:默认就是函数的文档注释
# 定义一个查询天气的tool
@tool
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
    """Get current weather and optional forecast"""
    Args:
        location: city name or coordinates
        units: unit of degrees
        include_forecast: does it include the weather forecast
    """
    temp = 22 if units == "celsius" else 72
    result = f"Current weather in {location}: {temp} degrees {units[0].upper()}"
    if include_forecast:
        result += "\nNext 5 days: Sunny"
    return result

(3)预定义工具

 LangChain中提供了很多预定义的Tool,方便我们使用。例如 tavily 就是一个用来做web搜索的工具,使用步骤如下,

  • 注册账号,创建API_KEY;
  • 配置环境变量:TAVILY_APIKEY;
  • 安装依赖:uv addlangchain-tavily;
  • 初始化工具并调用;
from langchain_tavily import TavilySearch

# 初始化搜索工具
search_tool = TavilySearch(
    max_results=5,
    topic="general",          # 可选:general, news, finance
    # include_answer=False,
    # include_raw_content=False,
    # include_images=False,
    # include_image_descriptions=False,
    # search_depth="basic",
    # time_range="day",
    # include_domains=None,
    # exclude_domains=None
)

# 直接调用
result = search_tool.invoke("蒸蚌是什么梗?")
print(result)
  • 直接调用
# 直接调用
result = search_tool.invoke("蒸蚌是什么梗?")
print(result)

5.记忆

 Agent的记忆(Memory)分两类:

  • 短期记忆(short-term memory):当前任务或会话的上下文
  • 长期记忆(long-term memory):跨任务或会话的经验与知识

(1)短期记忆

 在 LangChain 短期记忆是通过 Agentstate 实现的,而会话历史(也就是消息列表)是 AgentState 的一部分。

 LangChain提供了checkpointer对象来保存AgentState,每一次用户与AI的交互都会生成一个快照,记录为一个checkpoint。同一会话的多个 checkpoint 形成一个组,用同一个thread_id来标记。

在这里插入图片描述

  • 添加会话记忆(短期记忆)分为三步:
    • 导入并初始化 Checkpointer
    • 创建Agent,指定 Checkpointer
    • 调用Agent,指定 thread_id
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    "deepseek-chat",
    checkpointer=InMemorySaver()
)
from langchain.messages import HumanMessage

## 设定thread_id,作为会话标识
config = {"configurable": {"thread_id": "thread_1"}}

# 第一次调用,告知AI我的信息
response = agent.invoke(
    {"messages": [HumanMessage(content="你好,我叫虎哥,我最喜欢猫猫。")]},
    config # 调用时添加thread_id
)

print(response)
# 第二次调用,询问我的信息,这次带上thread_id,唤起记忆
response = agent.invoke(
    {"messages": [HumanMessage(content="我最喜欢的动物是什么?")]},
    config # 调用时添加thread_id
)

print(response)

(2)记忆的持久化存储

 内存型 checkpointer 在程序重启后会丢失数据。如果需要持久化存储,这里选择使用 Sqlite 作为后端。首先需要按照langgraph-checkpoint-sqlite依赖:

uv add langgraph-checkpoint-sqlite

 接着,按照以下步骤使用:

  • 导入依赖
  • 连接 SQLite 数据库并初始化 SqliteSaver
  • 执行 setup() 自动创建表结构。
  • 创建 Agent 时指定该 checkpointer。
import sqlite3
from langgraph.checkpoint.sqlite import SqliteSaver

# 连接sqlite
connection = sqlite3.connect("resources/checkpoint.db", check_same_thread=False)
# 初始化checkpointer
checkpointer = SqliteSaver(connection)
# 自动建表
checkpointer.setup()

# 创建agent
agent = create_agent(
    "deepseek-chat",
    checkpointer=checkpointer,
)
  • 使用方式与内存型一致
from langchain.messages import HumanMessage

# 设定thread_id,作为会话标识
config = {"configurable": {"thread_id": "thread_2"}}

# 第一次调用,告知AI我的信息
response = agent.invoke(
    {"messages": [HumanMessage(content="你好,我叫虎哥,我最喜欢猫猫。")]},
    config # 调用时添加thread_id
)

print(response)
# 第二次调用,询问我的信息,这次带上thread_id,唤起记忆
response = agent.invoke(
    {"messages": [HumanMessage(content="我最喜欢的动物是什么?")]},
    config # 调用时添加thread_id
)

print(response)

(3)记忆管理策略

 多轮对话会导致消息历史不断累积,可能超出模型的上下文长度限制(例如 DeepSeek 的上下文上限为 128K)。LangChain 提供了多种记忆管理策略来解决这一问题。

  • 修剪:保留最近的 N 条消息,丢弃更早的消息,但可能丢失重要历史信息;
  • 删除:直接删除某个 checkpoint 快照,无法回滚,但风险较大,不可恢复;
  • 总结摘要:对早期消息进行总结,生成摘要,替代原始消息,但摘要可能丢失部分细节;
  • 自定义:自定义策略,例如根据用户问题筛选历史消息

 下面以摘要中间件(SummarizationMiddleware) 为例,展示如何使用摘要策:

from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.runnables import RunnableConfig

# 初始化checkpointer
checkpointer = InMemorySaver()
# 初始化中间件
middleware = SummarizationMiddleware(
    model="deepseek-chat",
    trigger=("messages", 3), # 触发时机,当消息数超过3时,进行总结
    keep=("messages", 1) # 保留的会话数,超过2条
)
# 创建agent
agent = create_agent(
    model="deepseek-chat",
    middleware=[middleware],
    checkpointer=checkpointer,
)

config: RunnableConfig = {"configurable": {"thread_id": "thread_3"}}
# 制造长会话历史
agent.invoke({"messages": [HumanMessage(content="你好,我是虎哥。")]}, config)
agent.invoke({"messages": [HumanMessage(content="我最喜欢的运动是乒乓")]}, config)
agent.invoke({"messages": [HumanMessage(content="我最喜欢的动物是猫猫")]}, config)

# 测试效果
final_response = agent.invoke({"messages": HumanMessage(content="你还记得我吗?")}, config)
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐