基于 LangChain 构建 LLM Agent
LangChain 是一个强大的框架,支持构建应用程序,将外部数据源和计算源连接到大型语言模型(LLM)。本文将介绍如何从简单的 LLM 链开始,逐步构建检索链、对话检索链,并最终实现一个能够自主决定步骤的智能体(Agent)。
1. Agent 概述
在之前的示例中,我们创建的链每一步都是预先确定的。而 Agent(智能体)的核心在于 LLM 可以自主决定采取哪些步骤来完成任务。
简单来说,Agent 就是赋予 LLM 使用工具的能力。在这个示例中,我们将授予 Agent 对两个工具的访问权限:
- 文档检索工具:基于外部知识库(如百度百科)的电影信息。
- 数学计算工具:LangChain 内置的
llm-math工具,用于处理复杂的数学运算。
当用户询问电影相关问题时,Agent 会使用第一个工具;当涉及数学计算时,则调用第二个工具。
2. 环境准备与依赖安装
在开始之前,请确保已安装必要的 Python 库。可以使用 pip 进行安装:
pip install langchain langchain-community langchain-core faiss-cpu torch transformers
同时需要配置好环境变量或 API Key,特别是对于 HuggingFace 模型的使用。
3. 数据加载与向量化
Agent 需要访问外部知识,这通常通过 RAG(检索增强生成)技术实现。我们需要加载网页数据,将其切分,并通过嵌入模型转换为向量存储到向量数据库中。
3.1 初始化嵌入模型
首先加载词嵌入模型。根据硬件情况选择设备(CUDA, MPS 或 CPU)。
from langchain_community.document_loaders import WebBaseLoader
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
import torch
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 检测设备
EMBEDDING_DEVICE = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
# 初始化嵌入模型
embeddings = HuggingFaceEmbeddings(
model_name='m3e-base',
model_kwargs={'device': EMBEDDING_DEVICE}
)
3.2 加载与处理文档
加载外部文档并进行文本分割。合理的文本分割有助于提高检索精度。
# 加载外部文档
loader = WebBaseLoader("https://baike.baidu.com/item/%E8%AE%A9%E5%AD%90%E5%BC%B9%E9%A3%9E/5358?fr=ge_ala")
docs = loader.load()
# 文档向量化到 FAISS
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)
vector = FAISS.from_documents(documents, embeddings)
# 得到一个检索器
retriever = vector.as_retriever()
4. 创建工具
为了让 Agent 能够使用上述检索能力,我们需要将检索器封装为工具。
4.1 创建检索工具
from langchain.tools.retriever import create_retriever_tool
retriever_tool = create_retriever_tool(
retriever,
"rzdf_search",
"搜索有关电影《让子弹飞》的信息。对于任何关于《让子弹飞》的问题,你必须使用此工具!"
)
4.2 加载内置工具
LangChain 提供了一些内置工具,例如用于数学计算的 llm-math。
from langchain.agents import load_tools
# 注意:此处 llm 变量需提前初始化,例如使用 ChatOpenAI 或本地模型
# from langchain.chat_models import ChatOpenAI
# llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
tools = load_tools(['llm-math'], llm=llm)
4.3 组合工具列表
将自定义工具和内置工具合并。
tools.append(retriever_tool)
5. 构建与运行 Agent
现在我们可以创建一个代理来使用这些工具。这里我们使用 ReAct 模式,它结合了推理(Reasoning)和行动(Action)。
5.1 初始化 Agent
获取内置 Prompt 并创建 Agent Executor。
from langchain import hub
from langchain.agents import create_react_agent
from langchain.agents import AgentExecutor
# 获取内置 prompt
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
设置 verbose=True 可以查看 Agent 思考的中间过程(Chain of Thought),这对于调试和理解 Agent 行为非常重要。
5.2 单轮问答测试
调用代理回答关于电影导演的问题。
result = agent_executor.invoke({"input": "让子弹飞的导演是谁"})
print(result['output'])
输出结果示例:
{
'input': '让子弹飞的导演是谁',
'output': '《让子弹飞》的导演是姜文。'
}
5.3 复杂计算测试
测试 Agent 调用数学工具的能力。
result = agent_executor.invoke({"input": "8 的立方根是多少?乘以 13.27,然后减去 5。"})
print(result['output'])
输出结果示例:
{
'input': '8 的立方根是多少?乘以 13.27,然后减去 5。',
'output': '8 的立方根大约是 2,然后乘以 13.27 得到 26.54,减去 5 后得到 21.54。'
}
6. 多轮对话支持
Agent 可以通过传入聊天记录来实现上下文感知,从而进行多轮对话。
from langchain_core.messages import HumanMessage, AIMessage
chat_history = [
HumanMessage(content="让子弹飞是谁导演的"),
AIMessage(content="让子弹飞是姜文导演的。")
]
result = agent_executor.invoke({
"chat_history": chat_history,
"input": "这部电影什么时候上映的?"
})
输出结果示例:
{
'chat_history': [
HumanMessage(content='让子弹飞是谁导演的'),
AIMessage(content='让子弹飞是姜文导演的。')
],
'input': '这部电影什么时候上映的?',
'output': '电影《让子弹飞》上映于 2010 年 12 月 16 日。'
}
7. 总结与最佳实践
至此,我们已经成功设置了一个基本的 Agent。它结合了外部知识检索和数学计算能力,并能维护对话历史。
在实际生产环境中,建议关注以下几点:
- Prompt 优化:默认的 ReAct Prompt 可能不够精确,可根据具体业务场景微调 System Prompt。
- 工具描述:清晰定义工具的描述(Description),帮助 LLM 准确判断何时调用哪个工具。
- 错误处理:增加异常捕获机制,防止因工具调用失败导致整个流程中断。
- 性能监控:记录 Token 消耗和响应时间,以便优化成本。
高级用法包括自定义 Agent 类型(如 Plan-and-Execute)、更复杂的记忆管理以及与其他系统的集成等。掌握基础后,可进一步探索 LangChain 的高级特性以构建更复杂的 AI 应用。

