在 LangChain 中,代理(Agents) 是一种高级组件,允许语言模型(LLM)通过动态推理和工具调用来处理复杂任务。代理通过结合语言模型的自然语言理解能力和外部工具(如搜索、计算、数据库查询等)的执行能力,能够根据用户输入自主选择合适的操作路径,执行多步骤任务并生成最终结果。代理是 LangChain 生态中实现交互性和智能自动化任务的核心模块,特别适合需要动态决策的场景。
以下是对 LangChain 代理的详细介绍,涵盖其定义、工作原理、类型、实现方式、应用场景、代码示例、优化建议以及与生态系统的结合。
1. 什么是 LangChain 的代理?
代理是一个智能系统,结合语言模型和工具,通过推理决定如何处理用户输入。它的核心功能是:
- 理解输入:解析用户查询,提取意图和任务要求。
- 动态决策:根据任务选择合适的工具或操作序列。
- 工具调用:执行外部功能(如搜索、计算)以获取数据或完成任务。
- 生成响应:整合工具结果和语言模型的推理,输出最终答案。
代理与 链(Chains) 的区别在于:
- 链是预定义的、固定的工作流,执行顺序确定。
- 代理是动态的,通过推理选择工具和操作路径,适合开放性任务。
代理的核心组件:
- 语言模型(LLM):提供推理和语言生成能力。
- 工具(Tools):提供外部功能(如搜索、数据库查询)。
- 代理执行器(AgentExecutor):管理推理循环,协调模型和工具的交互。
2. 代理的工作原理
代理的工作流程可以分为以下步骤:
- 输入解析:语言模型分析用户输入,理解任务目标。
- 推理规划:
- 使用推理框架(如 ReAct)生成操作计划。
- 决定是否调用工具、调用哪些工具以及调用顺序。
- 工具调用:
- 根据推理计划调用工具,传递输入并获取结果。
- 工具结果反馈给语言模型。
- 迭代推理:
- 语言模型根据工具结果更新推理,可能触发更多工具调用。
- 循环直到任务完成或达到终止条件。
- 输出生成:
- 语言模型综合所有信息,生成最终答案。
代理通常基于以下推理框架:
- ReAct(Reasoning + Acting):结合推理和行动,模型在每次迭代中思考(生成推理)并执行(调用工具)。
- OpenAI Functions:利用 OpenAI 的函数调用能力,结构化工具调用。
- Plan-and-Execute:先规划完整步骤,再逐一执行。
3. LangChain 代理的类型
LangChain 提供了多种代理类型,基于不同的推理框架和语言模型特性。以下是主要类型的详细介绍:
(1) Zero-shot ReAct
- 功能:基于 ReAct 框架,通过零样本提示(Zero-shot Prompting)推理和调用工具。
- 特点:
- 无需训练,直接根据工具描述选择工具。
- 适合通用任务,灵活性高。
- 依赖语言模型的推理能力。
- 适用场景:
- 通用问答。
- 动态任务处理(如搜索后计算)。
- 示例:
from langchain_openai import ChatOpenAI from langchain.agents import initialize_agent, AgentType from langchain_community.tools import DuckDuckGoSearchRun llm = ChatOpenAI(api_key="your-openai-key") tools = [DuckDuckGoSearchRun()] agent = initialize_agent( tools=tools, llm=llm, agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True ) result = agent.invoke("量子计算的最新进展是什么?") print(result)
(2) OpenAI Functions
- 功能:利用 OpenAI 的函数调用能力,结构化工具调用。
- 特点:
- 适合 OpenAI 模型(如 GPT-4)。
- 工具调用更可靠,输出结构化(JSON)。
- 适合复杂任务,需要明确工具参数。
- 适用场景:
- 结构化任务(如 API 调用)。
- 需要高可靠性工具调用。
- 示例:
from langchain_openai import ChatOpenAI from langchain.agents import initialize_agent, AgentType from langchain_core.tools import Tool def calculator(expression: str) -> str: return str(eval(expression)) tools = [Tool(name="Calculator", func=calculator, description="执行数学计算")] llm = ChatOpenAI(api_key="your-openai-key") agent = initialize_agent( tools=tools, llm=llm, agent_type=AgentType.OPENAI_FUNCTIONS, verbose=True ) result = agent.invoke("计算 5 + 3") print(result)
(3) Conversational Agent
- 功能:专为对话场景设计,结合记忆(Memory)维护上下文。
- 特点:
- 支持多轮对话,记录历史。
- 基于 ReAct 框架,适合交互式任务。
- 适用场景:
- 聊天机器人。
- 持续交互的任务。
- 示例:
from langchain_openai import ChatOpenAI from langchain.agents import initialize_agent, AgentType from langchain.memory import ConversationBufferMemory from langchain_community.tools import DuckDuckGoSearchRun llm = ChatOpenAI(api_key="your-openai-key") memory = ConversationBufferMemory(memory_key="chat_history") tools = [DuckDuckGoSearchRun()] agent = initialize_agent( tools=tools, llm=llm, agent_type=AgentType.CONVERSATIONAL_REACT_DESCRIPTION, memory=memory, verbose=True ) result = agent.invoke("量子计算是什么?") result = agent.invoke("有哪些最新进展?") print(result)
(4) Self-Ask with Search
- 功能:通过分解问题并使用搜索工具回答复杂问题。
- 特点:
- 适合需要分步推理的知识性问题。
- 依赖搜索工具(如 Google、DuckDuckGo)。
- 适用场景:
- 回答复杂的事实性问题。
- 需要外部知识的场景。
- 示例:
from langchain_openai import ChatOpenAI from langchain.agents import initialize_agent, AgentType from langchain_community.tools import DuckDuckGoSearchRun llm = ChatOpenAI(api_key="your-openai-key") tools = [DuckDuckGoSearchRun()] agent = initialize_agent( tools=tools, llm=llm, agent_type=AgentType.SELF_ASK_WITH_SEARCH, verbose=True ) result = agent.invoke("量子计算的最新进展是什么?") print(result)
(5) Structured Chat
- 功能:支持结构化工具调用,结合对话记忆。
- 特点:
- 适合需要多轮对话和复杂工具调用的场景。
- 支持结构化输入(如 JSON Schema)。
- 适用场景:
- 复杂交互式任务。
- 需要严格输入格式的工具调用。
- 示例:
from langchain_openai import ChatOpenAI from langchain.agents import initialize_agent, AgentType from langchain_core.tools import StructuredTool from pydantic import BaseModel class CalcInput(BaseModel): a: float b: float def add_numbers(input: CalcInput) -> float: return input.a + input.b tools = [StructuredTool.from_function( func=add_numbers, name="Adder", description="将两个数字相加" )] llm = ChatOpenAI(api_key="your-openai-key") agent = initialize_agent( tools=tools, llm=llm, agent_type=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True ) result = agent.invoke("将 5 和 3 相加") print(result)
(6) Custom Agent
- 功能:开发者可以自定义代理逻辑,适配特定推理框架或工具。
- 特点:
- 继承
BaseAgent
或使用 LangGraph 实现。 - 高度灵活,适合复杂场景。
- 继承
- 适用场景:
- 特定任务的定制推理逻辑。
- 集成非标准工具或工作流。
- 示例(简单自定义代理):
from langchain.agents import AgentExecutor, BaseSingleActionAgent from langchain_core.tools import Tool from langchain_openai import ChatOpenAI class CustomAgent(BaseSingleActionAgent): def plan(self, intermediate_steps, **kwargs): return {"tool": "Calculator", "tool_input": kwargs["input"]} def parse_output(self, output): return output def calculator(expression: str) -> str: return str(eval(expression)) tools = [Tool(name="Calculator", func=calculator, description="执行数学计算")] llm = ChatOpenAI(api_key="your-openai-key") agent = CustomAgent() executor = AgentExecutor(agent=agent, tools=tools, verbose=True) result = executor.invoke({"input": "2 + 2"}) print(result)
4. 代理的应用场景
代理在以下场景中广泛应用:
- 开放性问答:
- 回答需要外部数据的问题(如“今天的天气”)。
- 示例:结合
SerpAPI
或DuckDuckGoSearch
。
- 多步骤任务:
- 执行复杂任务(如“搜索最新论文并总结”)。
- 示例:结合
Arxiv
和语言模型。
- 交互式对话:
- 构建聊天机器人,维护上下文并调用工具。
- 示例:使用
Conversational Agent
。
- 自动化工作流:
- 触发外部操作(如发送邮件、更新数据库)。
- 示例:结合
ZapierToolkit
。
- 数学与计算:
- 解决数学或编程问题。
- 示例:使用
PythonREPLTool
。
- 研究与分析:
- 收集和处理外部数据。
- 示例:结合
WebResearchRetriever
和Wikipedia
。
5. 代理的实现与代码示例
综合示例:多工具代理
以下是一个代理结合搜索和计算工具的示例:
from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
from langchain_core.tools import Tool
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_core.callbacks import StdOutCallbackHandler
# 自定义计算工具
def calculator(expression: str) -> str:
return str(eval(expression))
calc_tool = Tool(
name="Calculator",
func=calculator,
description="执行数学计算,输入为数学表达(如 '2 + 2')。"
)
# 搜索工具
search_tool = DuckDuckGoSearchRun()
# 工具列表
tools = [calc_tool, search_tool]
# 初始化代理
llm = ChatOpenAI(api_key="your-openai-key")
agent = initialize_agent(
tools=tools,
llm=llm,
agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
callbacks=[StdOutCallbackHandler()]
)
# 执行任务
result = agent.invoke("计算 5 + 3 并搜索量子计算的最新进展")
print(result["output"])
输出:
[AgentExecutor] 正在执行...
[Thought] 需要先计算 5 + 3,然后搜索量子计算的最新进展。
[Action] 使用 Calculator 工具计算 5 + 3
[Tool Output] 8
[Action] 使用 DuckDuckGoSearch 工具搜索量子计算的最新进展
[Tool Output] 量子计算的最新研究...
[Final Answer] 计算结果为 8,量子计算的最新进展包括...
示例:带记忆的对话代理
from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
from langchain.memory import ConversationBufferMemory
from langchain_community.tools import DuckDuckGoSearchRun
llm = ChatOpenAI(api_key="your-openai-key")
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
tools = [DuckDuckGoSearchRun()]
agent = initialize_agent(
tools=tools,
llm=llm,
agent_type=AgentType.CONVERSATIONAL_REACT_DESCRIPTION,
memory=memory,
verbose=True
)
# 多轮对话
print(agent.invoke("量子计算是什么?")["output"])
print(agent.invoke("有哪些最新进展?")["output"])
6. 代理的优化建议
(1) 提高工具选择准确性
- 清晰的工具描述:
- 确保工具描述明确功能和输入格式。
- 示例:
description="搜索网页,返回最新信息。输入为查询字符串。"
。
- 限制工具数量:
- 通常少于 10 个工具,避免代理选择困难。
- 结构化工具:
- 使用
StructuredTool
提供明确的输入格式。
from pydantic import BaseModel class SearchInput(BaseModel): query: str def search(query: SearchInput) -> str: return DuckDuckGoSearchRun().run(query.query)
- 使用
(2) 提高性能
- 缓存工具结果:
- 使用 LangChain 的缓存机制。
from langchain.globals import set_llm_cache from langchain.cache import SQLiteCache set_llm_cache(SQLiteCache(database_path="cache.db"))
- 异步工具:
- 实现异步工具以支持高并发。
- 减少推理循环:
- 设置最大迭代次数(
max_iterations
)。
agent = initialize_agent(tools, llm, max_iterations=5)
- 设置最大迭代次数(
(3) 错误处理
- 回退机制:
- 为工具或代理配置回退。
from langchain_core.runnables import RunnableWithFallbacks search_tool_with_fallback = search_tool.with_fallbacks([DuckDuckGoSearchRun()])
- 异常捕获:
- 在工具中处理异常。
@tool def safe_calculator(expression: str) -> str: try: return str(eval(expression)) except Exception as e: return f"计算错误:{e}"
(4) 监控与调试
- 回调:
- 使用回调记录代理的推理和工具调用。
from langchain_core.callbacks import BaseCallbackHandler class AgentCallback(BaseCallbackHandler): def on_agent_action(self, action, **kwargs): print(f"代理动作:{action.tool},输入:{action.tool_input}")
- LangSmith:
- 分析代理的性能和工具选择。
from langsmith import Client agent.invoke(input, config={"callbacks": [Client(api_key="your-langsmith-key")]})
(5) 上下文管理
- 记忆优化:
- 使用
ConversationSummaryMemory
压缩对话历史,节省 token。
from langchain.memory import ConversationSummaryMemory memory = ConversationSummaryMemory(llm=llm)
- 使用
- 动态上下文:
- 使用检索器为代理提供外部知识。
from langchain.chains import ConversationalRetrievalChain qa_chain = ConversationalRetrievalChain.from_llm(llm, retriever, memory=memory)
7. 注意事项
- 推理能力:
- 代理的性能依赖语言模型的推理能力,选择强大的模型(如 GPT-4)。
- 弱模型可能导致工具选择错误或推理循环过多。
- 工具设计:
- 工具描述不清晰可能导致误选。
- 确保工具输出与代理期望兼容。
- 性能:
- 多次工具调用可能增加延迟,需优化工具执行。
- 设置
max_iterations
和max_execution_time
限制循环。
- 安全性:
- 避免执行不安全的工具(如未沙箱化的
eval
)。 - 限制工具的访问权限。
- 避免执行不安全的工具(如未沙箱化的
- 成本:
- 工具调用(如 SerpAPI)和模型推理可能产生费用。
- 使用缓存和低成本工具优化。
8. 学习资源
- 官方文档:https://python.langchain.com/docs/modules/agents
- GitHub 示例:https://github.com/langchain-ai/langchain
- LangSmith:用于调试代理(https://smith.langchain.com)。
- 社区教程:LangChain 官方博客、YouTube 视频。
9. 总结
- 定义:代理结合语言模型和工具,通过动态推理处理复杂任务。
- 类型:
Zero-shot ReAct
:通用推理。OpenAI Functions
:结构化工具调用。Conversational Agent
:对话场景。Self-Ask with Search
:复杂问题分解。Structured Chat
:结构化交互。- 自定义代理:特定需求。
- 工作原理:输入解析 → 推理规划 → 工具调用 → 迭代推理 → 输出生成。
- 应用场景:问答、多步骤任务、对话、自动化、计算、研究。
- 优化点:工具选择、性能、错误处理、上下文管理、监控。
- 注意事项:推理能力、工具设计、性能、安全性、成本。