3、LangChain核心概念:Chain、Agent、Tool、Memory、Callback机制详解

说实话,LangChain 刚火起来那会儿,我第一反应是:这不就是个套壳的 Prompt 工程吗?

后来我在一个实际项目里,需要让 LLM 去查数据库、调 API、还要记住用户上一轮说了啥。嗯,自己硬写的话,代码会变得又臭又长。这时候我才真正体会到,LangChain 这套抽象,确实帮了大忙。

这一章,咱们就把它的五个核心概念掰开揉碎。你理解透了,后面集成 vLLM 就会顺手很多。

3.1 Chain:把多个步骤串起来

Chain 是 LangChain 里最基本的构建块。说白了,它就是「把一件事拆成几步,然后按顺序执行」。

我习惯把 Chain 想象成一条流水线。原料进去,经过几个工位,最后出来成品。每个工位可能是一个 LLM 调用,也可能是一个数据处理函数。

核心要点: Chain 不一定要用 LLM。你可以把普通函数也包装成 Chain,然后跟 LLM Chain 组合使用。

举个最简单的例子——LLMChain。它就是把 Prompt Template 和 LLM 绑在一起:

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI

prompt = PromptTemplate(
    input_variables=["product"],
    template="请为 {product} 写一句广告语。"
)

chain = LLMChain(llm=OpenAI(), prompt=prompt)
result = chain.run("智能水杯")
print(result)

你看,就这么几行。但实际项目中,我们往往需要更复杂的流程。比如 SequentialChain,它可以把多个 Chain 串成一条线,前一个的输出作为后一个的输入。

我在项目中遇到过一个场景:先让 LLM 提取用户问题中的关键词,再根据关键词去数据库查数据,最后让 LLM 把查到的数据整理成自然语言回复。用 SequentialChain 来组织,代码清晰多了。

我的建议: 刚开始用 Chain 时,别贪多。先从一个 LLMChain 开始,跑通了再加 SequentialChain。一步到位容易出 bug,排查起来也麻烦。

3.2 Agent:让 LLM 自己决定下一步

Chain 是固定的流水线,但 Agent 不一样。Agent 让 LLM 自己决定「下一步该调用什么工具」。你想想看,这就像给 LLM 配了一个工具箱,它自己判断什么时候该用扳手,什么时候该用螺丝刀。

Agent 的核心逻辑是 ReAct 模式——Reasoning + Acting。LLM 先思考(Reasoning),然后行动(Acting),观察结果后再思考,循环直到任务完成。

from langchain.agents import initialize_agent, Tool
from langchain.llms import OpenAI
from langchain.agents import AgentType

# 定义工具
def search_weather(city):
    return f"{city} 今天气温 25°C,晴。"

tools = [
    Tool(
        name="天气查询",
        func=search_weather,
        description="查询某个城市的天气"
    )
]

# 初始化 Agent
llm = OpenAI(temperature=0)
agent = initialize_agent(
    tools, llm, 
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

agent.run("北京今天天气怎么样?适合跑步吗?")

这里有个坑,我曾经踩过:Agent 的 description 字段非常重要。LLM 就是靠这个描述来判断什么时候该用这个工具。如果你写得太模糊,LLM 可能根本不会调用它。

避坑指南: 给 Tool 写 description 时,要站在 LLM 的角度想。比如「天气查询」这个工具,description 写成「当用户询问某个城市的天气情况时使用」,比写成「查询天气」要准确得多。

3.3 Tool:给 LLM 装个外挂

Tool 是 Agent 的「手」和「眼睛」。LLM 本身只有语言能力,但通过 Tool,它可以做计算、查数据库、调用 API、甚至控制硬件。

LangChain 内置了很多 Tool,比如:

  • 计算器:处理数学运算,避免 LLM 算错数
  • 搜索引擎:获取实时信息
  • 文件读写:读取本地文件内容
  • Python REPL:执行 Python 代码

但实际项目中,我们更多需要自定义 Tool。比如我做过一个客服系统,需要 Tool 去查询订单状态:

from langchain.tools import BaseTool

class OrderQueryTool(BaseTool):
    name = "订单查询"
    description = "根据订单号查询订单状态和物流信息"

    def _run(self, order_id: str) -> str:
        # 这里调用真实的订单系统 API
        return f"订单 {order_id} 状态:已发货,预计明天到达。"

    async def _arun(self, order_id: str) -> str:
        # 异步版本
        return self._run(order_id)

注意看,我实现了两个方法:_run 是同步的,_arun 是异步的。LangChain 会优先调用异步版本,如果你的 Tool 只支持同步,记得把 _arun 也实现一下,否则会报错。

个人经验: 自定义 Tool 时,尽量让 description 包含「何时使用」和「输入格式」两个信息。比如「当用户提供订单号时,查询该订单的当前状态。输入应为纯数字订单号。」这样 LLM 不容易用错。

3.4 Memory:让 LLM 记住上下文

LLM 本身是无状态的。你问它一句,它答一句。但对话场景下,我们需要它记住之前说过什么。这就是 Memory 的作用。

LangChain 提供了好几种 Memory 实现:

类型 特点 适用场景
ConversationBufferMemory 完整保存所有对话历史 简单对话,历史不长
ConversationSummaryMemory 用 LLM 总结历史,只存摘要 长对话,节省 Token
VectorStoreMemory 基于向量数据库,检索相关历史 超长对话,需要精准回忆
ConversationBufferWindowMemory 只保留最近 k 轮对话 控制 Token 消耗

我记得有一次,我用 ConversationBufferMemory 做了一个聊天机器人。用户聊了 50 轮之后,每次请求的 Token 数暴涨,响应速度慢得离谱。后来换成 ConversationSummaryMemory,让 LLM 每 5 轮总结一次历史,问题就解决了。

from langchain.memory import ConversationSummaryMemory
from langchain.chains import ConversationChain

memory = ConversationSummaryMemory(
    llm=OpenAI(),
    max_token_limit=500
)

conversation = ConversationChain(
    llm=OpenAI(),
    memory=memory
)

conversation.predict(input="你好,我叫小明")
conversation.predict(input="我刚才说了什么?")
小技巧: 用 ConversationSummaryMemory 时,记得给 summary 设置一个合理的 max_token_limit。我一般设 300-500,既能保留关键信息,又不会太贵。

3.5 Callback:监控和调试的利器

Callback 机制,说白了就是「钩子」。你可以在 Chain 或 Agent 执行的各个阶段插入自定义逻辑,比如打日志、算耗时、发通知。

LangChain 定义了一系列回调事件:

  • on_llm_start / on_llm_end:LLM 调用前后
  • on_chain_start / on_chain_end:Chain 执行前后
  • on_tool_start / on_tool_end:Tool 调用前后
  • on_agent_action:Agent 决定采取某个动作时
  • on_agent_finish:Agent 完成最终输出时

我经常用 Callback 来做两件事:一是统计每次请求的 Token 消耗,二是记录 Agent 的思考过程方便调试。

from langchain.callbacks.base import BaseCallbackHandler

class TokenCounterHandler(BaseCallbackHandler):
    def __init__(self):
        self.total_tokens = 0

    def on_llm_end(self, response, **kwargs):
        if hasattr(response, 'llm_output'):
            tokens = response.llm_output.get('token_usage', {})
            self.total_tokens += tokens.get('total_tokens', 0)
            print(f"本轮消耗 Token: {tokens.get('total_tokens', 0)}")
            print(f"累计消耗 Token: {self.total_tokens}")

# 使用
handler = TokenCounterHandler()
chain = LLMChain(llm=OpenAI(), prompt=prompt, callbacks=[handler])
chain.run("智能水杯")
注意: Callback 是同步执行的。如果你的回调函数里有耗时操作(比如写数据库),会影响主流程的响应速度。建议把耗时操作放到异步回调里,或者用消息队列异步处理。

3.6 知识体系总览

这五个概念的关系,我画了一张图帮你理解:

LangChain 核心概念关系图 Chain 执行流程编排 Agent 自主决策执行 Tool 外部能力扩展 Memory 状态与记忆 Callback 监控与钩子 可包含 可包含 可绑定 调用 可绑定 全部可监听 Chain 是骨架,Agent 是大脑,Tool 是手脚,Memory 是记忆,Callback 是神经 实线:直接调用/包含 虚线:可选绑定/包含

你看,Chain 是骨架,负责把流程串起来。Agent 是大脑,决定什么时候该做什么。Tool 是手脚,帮 LLM 完成具体任务。Memory 是记忆,让对话有上下文。Callback 是神经,让你能感知到系统内部发生了什么。

这五个概念,你掌握好了,LangChain 的基本功就算打扎实了。下一节我们会把这些概念跟 vLLM 结合起来,看看怎么在实际项目中落地。

一句话总结: Chain 管流程,Agent 管决策,Tool 管执行,Memory 管记忆,Callback 管监控。五者配合,才能构建出真正可用的 LLM 应用。

公众号:蓝海资料掘金营,微信deep3321