LangChain Agents 实战:从零构建智能助手的深度指南
如果你曾经尝试过让大语言模型帮你查询实时信息、执行计算或者操作数据库,可能会发现它经常“一本正经地胡说八道”。模型本身并不知道2024年的新闻,也不会做数学计算,更无法直接访问你的私有数据。这就是 LangChain Agents 要解决的问题——让语言模型学会“使用工具”,从而突破自身的局限。
我在实际项目中构建过多个基于Agent的生产系统,从简单的客服机器人到复杂的多步骤数据分析助手。最让我印象深刻的是,一个设计良好的Agent系统能够将模型的准确率从60%提升到95%以上。这不仅仅是技术上的提升,更是用户体验的质变。
1. Agent核心概念:从静态响应到动态执行
传统的大语言模型应用就像是一个知识渊博但行动不便的学者——它知道很多,但无法主动获取新信息或执行具体操作。而Agent系统则给这位学者配上了“手”和“脚”,让它能够主动探索、查询、计算,最终给出更准确、更实用的答案。
1.1 Agent的基本架构
一个典型的LangChain Agent由四个核心组件构成:
语言模型(LLM):这是Agent的“大脑”,负责理解用户意图、制定计划、做出决策。你可以选择OpenAI的GPT系列、Anthropic的Claude、Google的Gemini,或者开源的Llama、Qwen等模型。
工具(Tools):这是Agent的“手”,是它能够执行的具体操作。每个工具都是一个函数,可以执行特定的任务,比如:
- 搜索网络信息
- 查询数据库
- 执行数学计算
- 调用外部API
- 读写文件系统
代理执行器(Agent Executor):这是Agent的“协调中心”,负责管理整个执行流程。它会:
- 接收用户输入
- 调用语言模型决定下一步行动
- 执行选定的工具
- 将工具结果反馈给语言模型
- 重复2-4步直到任务完成
记忆(Memory):这是Agent的“短期记忆”,让它能够记住对话历史,实现多轮对话的连贯性。
下面是一个最简单的Agent创建示例:
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import Tool
from langchain_community.llms import OpenAI
# 定义工具
def search_wikipedia(query: str) -> str:
"""搜索维基百科并返回摘要"""
# 这里简化实现,实际项目中会调用维基百科API
return f"关于'{query}'的搜索结果:这是从维基百科获取的信息摘要。"
# 创建工具实例
tools = [
Tool(
name="Wikipedia Search",
func=search_wikipedia,
description="用于搜索维基百科获取事实性信息"
)
]
# 初始化语言模型
llm = OpenAI(temperature=0)
# 创建Agent
agent = create_react_agent(llm, tools)
# 创建执行器
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 显示详细执行过程
max_iterations=5 # 限制最大迭代次数,防止无限循环
)
# 执行查询
result = agent_executor.invoke({
"input": "量子计算的主要应用领域有哪些?"
})
提示:在实际项目中,我强烈建议将
max_iterations设置为一个合理的值(通常5-10次),这可以防止Agent陷入无限循环。我曾经遇到过因为没有设置限制,Agent在一个简单问题上循环了50多次的情况。
1.2 Agent的工作流程:ReAct模式
ReAct(Reasoning + Acting)是Agent最常用的工作模式,它让模型在“思考”和“行动”之间交替进行:
用户问题 → 思考 → 行动 → 观察结果 → 再思考 → 再行动 → ... → 最终答案
让我用一个具体的例子来说明这个过程。假设用户问:“特斯拉2023年的营收是多少?比2022年增长了多少百分比?”
第一步:思考 模型分析问题:“我需要找到特斯拉2023年的营收数据,还需要2022年的数据来计算增长率。我应该先搜索最新的财务报告。”
第二步:行动 调用搜索工具,查询“特斯拉2023年营收”。
第三步:观察 工具返回:“特斯拉2023年总营收为967.7亿美元。”
第四步:再思考 “现在我需要2022年的数据来计算增长率。继续搜索特斯拉2022年营收。”
第五步:再行动 调用搜索工具,查询“特斯拉2022年营收”。
第六步:再观察 工具返回:“特斯拉2022年总营收为814.6亿美元。”
第七步:计算思考 “现在我有两个数据:2023年967.7亿,2022年814.6亿。需要计算增长率。应该使用计算工具。”
第八步:计算行动 调用计算工具,计算(967.7 - 814.6) / 814.6 * 100。
第九步:最终回答 “特斯拉2023年营收为967.7亿美元,相比2022年的814.6亿美元,增长了约18.8%。”
这个流程的关键在于,Agent不是一次性给出答案,而是通过多次“思考-行动”循环,逐步收集信息、验证数据、进行计算,最终得出准确答案。
2. 工具系统:扩展Agent的能力边界
工具是Agent能力的核心扩展点。一个设计良好的工具系统可以让Agent完成几乎任何任务。在实际项目中,我通常将工具分为几个类别:
2.1 内置工具与自定义工具
LangChain提供了丰富的内置工具,但很多时候你需要创建自定义工具来满足特定需求。下面是一个完整的自定义工具创建示例:
from langchain.tools import BaseTool
from typing import Type, Optional
from pydantic import BaseModel, Field
import requests
import json
# 定义工具的输入模式
class StockPriceInput(BaseModel):
symbol: str = Field(description="股票代码,如AAPL、TSLA")
date: Optional[str] = Field(
default=None,
description="查询日期,格式为YYYY-MM-DD,默认为最新交易日"
)
class StockPriceTool(BaseTool):
name = "get_stock_price"
description = "获取指定股票在特定日期的收盘价"
args_schema: Type[BaseModel] = StockPriceInput
def _run(self, symbol: str, date: Optional[str] = None) -> str:
"""实际执行工具逻辑"""
try:
# 这里使用模拟数据,实际项目中会调用金融数据API
# 例如Alpha Vantage、Yahoo Finance等
if symbol.upper() == "AAPL":
price = 185.92
elif symbol.upper() == "TSLA":
price = 245.18
elif symbol.upper() == "MSFT":
price = 407.81
else:
return f"未找到股票{symbol}的价格数据"
date_str = date if date else "最新交易日"
return f"{symbol}在{date_str}的收盘价为${price}"
except Exception as e:
return f"获取股票价格时出错:{str(e)}"
async def _arun(self, symbol: str, date: Optional[str] = None) -> str:
"""异步版本"""
return self._run(symbol, date)
# 创建工具实例
stock_tool = StockPriceTool()
# 工具使用示例
result = stock_tool.run({"symbol": "AAPL", "date": "2024-01-15"})
print(result) # 输出:AAPL在2024-01-15的收盘价为$185.92
注意:创建自定义工具时,
description字段非常重要。Agent会根据这个描述来决定何时使用该工具。描述应该清晰说明工具的用途、输入格式和输出内容。
2.2 工具包:相关工具的集合
对于复杂的任务,通常需要多个工具协同工作。LangChain提供了工具包(Toolkits)的概念,将相关工具组织在一起。下面是一个数据分析工具包的示例:
from langchain.agents.agent_toolkits import BaseToolkit
from langchain.tools import BaseTool
from typing import List
import pandas as pd
import numpy as np
class DataAnalysisToolkit(BaseToolkit):
"""数据分析工具包,包含常用的数据处理和分析工具"""
def __init__(self, df: pd.DataFrame):
self.df = df
def get_tools(self) -> List[BaseTool]:
return [
self._create_describe_tool(),
self._create_filter_tool(),
self._create_aggregate_tool(),
self._create_correlation_tool()
]
def _create_describe_tool(self) -> BaseTool:
"""数据描述工具"""
def describe_data(columns: str = "") -> str:
if columns:
selected_cols = [col.strip() for col in columns.split(",")]
subset_df = self.df[selected_cols]
else:
subset_df = self.df
stats = subset_df.describe(include='all').to_string()
return f"数据统计信息:\n{stats}"
return Tool(
name="data_describe",
func=describe_data,
description="获取数据的统计描述信息。输入:可选的要分析的列名,用逗号分隔"
)
def _create_filter_tool(self) -> BaseTool:
"""数据筛选工具"""
def filter_data(condition: str) -> str:
try:
# 注意:实际项目中需要更严格的安全检查
filtered_df = self.df.query(condition)
return f"筛选后数据形状:{filtered_df.shape}\n前5行:\n{filtered_df.head().to_string()}"
except Exception as e:
return f"筛选数据时出错:{str(e)}"
return Tool(
name="data_filter",
func=filter_data,
description="根据条件筛选数据。输入:Pandas查询条件字符串"
)
def _create_aggregate_tool(self) -> BaseTool:
"""数据聚合工具"""
def aggregate_data(group_by: str, agg_column: str, agg_func: str = "mean") -> str:
try:
if agg_func == "mean":
result = self.df.groupby(group_by)[agg_column].mean()
elif agg_func == "sum":
result = self.df.groupby(group_by)[agg_column].sum()
elif agg_func == "count":
result = self.df.groupby(group_by)[agg_column].count()
else:
return f"不支持的聚合函数:{agg_func},支持:mean, sum, count"
return f"聚合结果:\n{result.to_string()}"
except Exception as e:
return f"聚合数据时出错:{str(e)}"
return Tool(
name="data_aggregate",
func=aggregate_data,
description="按指定列分组并聚合数据。输入:分组列名,聚合列名,聚合函数(mean/sum/count)"
)
def _create_correlation_tool(self) -> BaseTool:
"""相关性分析工具"""
def calculate_correlation(col1: str, col2: str) -> str:
try:
correlation = self.df[col1].corr(self.df[col2])
return f"{col1}和{col2}的相关系数为:{correlation:.4f}"
except Exception as e:
return f"计算相关性时出错:{str(e)}"
return Tool(
name="data_correlation",
func=calculate_correlation,
description="计算两列数据的相关系数。输入:两个列名"
)
# 使用示例
import pandas as pd
# 创建示例数据
data = {
'category': ['A', 'A', 'B', 'B', 'A', 'B', 'A', 'B'],
'value': [10, 15, 20, 25, 30, 35, 40, 45],
'score': [85, 90, 78, 92, 88, 95, 82, 89]
}
df = pd.DataFrame(data)
# 创建工具包
toolkit = DataAnalysisToolkit(df)
tools = toolkit.get_tools()
# 现在可以将这些tools传递给Agent
这个工具包展示了如何将相关的数据分析功能组织在一起


被折叠的 条评论
为什么被折叠?



