概述
Agent 是一种能够基于接收到的输入,利用自身的决策逻辑和可用的工具,动态地规划并执行一系列操作,以达成特定任务的程序或系统。它在与外界交互过程中,会根据实时情况灵活调整策略,而不是按照固定的预设流程执行任务。
核心组成部分
Agent 是由大型语言模型(LLM)驱动的智能系统,通过调用外部工具(Tools)自主决策完成任务。其核心组件包括:
-
LLM(大脑):负责推理决策(例如是否调用工具)。
-
Tools(工具箱):外部功能接口(如搜索、计算、API调用)。工具需明确定义名称、描述和参数结构。
-
Prompt(指令模板):指导 LLM 的思考模式(如 ReAct 框架的 "Thought-Action-Observation" 循环)。
-
Output Parser(输出解析器):解析 LLM 输出,判断调用工具或返回最终答案。
-
AgentExecutor(执行器):管理执行循环,直到任务完成
工作流程
-
接收输入:Agent 接收用户提出的任务或问题。例如,用户输入“查询苹果公司最新款手机的价格,并计算其在打 8 折后的售价”。
-
分析理解:语言模型对输入进行分析和理解,明确任务的核心目标和关键信息。在上述例子中,语言模型会识别出需要查询手机价格并进行折扣计算这两个关键任务。
-
决策规划:决策逻辑根据分析结果,确定完成任务所需的工具和操作步骤。在这个例子中,会先选择搜索引擎工具查询苹果公司最新款手机的价格,再选择数学计算工具计算打折后的售价。
-
执行操作:按照规划好的步骤,依次调用相应的工具执行任务。首先调用搜索引擎工具获取手机价格信息,然后将价格信息传递给数学计算工具进行打折计算。
-
输出结果:将最终的处理结果反馈给用户。在这个例子中,会将计算得出的打折后售价返回给用户。
工具
langchain_community.agent_toolkits提供了丰富多样的工具包,这些工具包可以帮助开发者更方便地构建功能强大的智能代理。地址Tools | 🦜️🔗 LangChain,有很多免费的工具可以用
可以通过如下代码查询工具列表:
from langchain_community.agent_toolkits.load_tools import load_tools, get_all_tool_names
#查询所有提供的工具
tool_names = get_all_tool_names()
print(tool_names)
加载工具:
from langchain_community.agent_toolkits.load_tools import load_tools, get_all_tool_names
#加载工具 arxiv 用于搜索arxiv上的论文 llm-math让 LLM 执行数学计算任务(结合计算器)
tools = load_tools(["arxiv", "llm-math"], llm=deepseek_llm)
常用的创建方式
1. 使用`initialize_agent`函数(来自`langchain.agents`)并指定AgentType(如ZERO_SHOT_REACT_DESCRIPTION)。
2. 使用`create_react_agent`(针对ReAct类型的Agent)配合AgentExecutor。
3. 使用`create_openai_tools_agent`(针对OpenAI函数调用类型的Agent)。
4. 使用`create_json_chat_agent`(针对使用JSON格式的聊天Agent)。
5. 使用`create_structured_chat_agent`(针对结构化聊天Agent)。
6.使用`create_tool_calling_agent
`(仅适用于原生支持工具调用的模型)这种方式直接利用模型的原生工具调用能力,通常比 ReAct 代理更高效可靠。
Agent 类型
LangChain 提供了多种 Agent 类型
1. ZERO_SHOT_REACT_DESCRIPTION
-
含义:这是一种零样本学习的 Agent,在采取行动之前会进行推理步骤。所谓零样本学习,意味着该 Agent 不需要针对特定任务进行额外的训练,就可以根据工具的描述来使用工具解决问题。
-
工作原理:当接收到用户的输入时,它会先对问题进行推理分析,确定需要使用哪些工具以及如何使用这些工具,然后再执行相应的操作。例如,在面对一个需要查询数据并进行计算的问题时,它会先思考应该调用搜索引擎工具获取数据,再调用计算工具进行计算。
2. REACT_DOCSTORE
-
含义:同样是一种在行动前进行推理的零样本 Agent,但它可以访问一个文档存储库。这个文档存储库允许 Agent 查找与回答问题相关的信息。
-
工作原理:在处理问题时,它不仅会进行推理分析,还会利用文档存储库中的信息来辅助解决问题。例如,当用户询问关于某个历史事件的详细信息时,它可以在文档存储库中查找相关的历史文献、资料等,结合推理过程给出更准确的答案。
3. SELF_ASK_WITH_SEARCH
-
含义:这种 Agent 会将一个复杂的问题分解为一系列更简单的问题,然后使用搜索工具查找这些简单问题的答案,最终根据这些答案来回答原始的复杂问题。
-
工作原理:当接收到一个复杂问题时,它会首先分析问题的结构,将其拆分成多个简单的子问题。然后,依次使用搜索工具查找每个子问题的答案。最后,将这些子问题的答案整合起来,形成对原始复杂问题的回答。例如,对于“如何制作一道复杂的菜肴”这个问题,它可能会将其拆分为“这道菜需要哪些食材”“每种食材的处理方法”“烹饪的步骤和时间”等子问题,分别进行搜索并整合答案。
4. CONVERSATIONAL_REACT_DESCRIPTION
-
含义:从名称推测,这是一种适用于对话场景的 Agent,在行动前会进行推理。它能够在多轮对话中保持上下文的连贯性,根据之前的对话内容和当前的输入进行推理和行动。
-
工作原理:在对话过程中,它会维护对话历史,理解每一轮对话的上下文信息。当用户输入新的内容时,它会结合上下文进行推理分析,选择合适的工具和操作来做出回应。例如,在一个关于旅游规划的对话中,用户先询问了某个旅游景点的信息,之后又询问如何到达该景点,它会根据之前关于景点的对话内容,调用地图搜索工具等给出到达景点的路线建议。
5. CHAT_ZERO_SHOT_REACT_DESCRIPTION
-
含义:这是一种专为聊天场景设计的零样本 Agent,在行动前进行推理。它结合了零样本学习的能力和聊天场景的特点,能够在没有针对特定聊天任务进行训练的情况下,处理聊天中的各种问题。
-
工作原理:在聊天过程中,它会根据用户的输入进行推理,判断需要使用哪些工具来满足用户的需求。例如,在聊天中用户提到了想要了解某部电影的信息,它会推理出需要调用电影数据库 API 来获取相关信息。
6. CHAT_CONVERSATIONAL_REACT_DESCRIPTION
-
含义:这是一种针对聊天场景优化的、适用于多轮对话的 Agent,在行动前进行推理。它综合了聊天场景和多轮对话的特性,能够更好地处理复杂的聊天交互。
-
工作原理:在多轮对话中,它会持续跟踪对话的上下文,根据用户的最新输入和之前的对话历史进行推理分析。例如,在一个关于购物的聊天中,用户先询问了某类商品的价格,之后又询问该商品的优惠活动,它会结合之前关于价格的对话内容,调用电商平台的 API 来获取优惠信息。
7. STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION
-
含义:这是一种针对聊天模型优化的零样本反应 Agent,能够调用具有多个输入的工具。它在聊天场景中,即使面对需要多个参数输入的工具,也能准确地进行调用和处理。
-
工作原理:在聊天过程中,当遇到需要使用具有多个输入的工具时,它会根据工具的描述和用户的输入,准确地组织和提供所需的输入参数。例如,在一个关于旅游规划的聊天中,用户想要查询从一个城市到另一个城市的航班信息,它可以调用航班查询 API,并根据用户提供的出发地、目的地、出发时间等多个参数进行查询。
8. OPENAI_FUNCTIONS
-
含义:这是一种针对使用 OpenAI 函数进行优化的 Agent。OpenAI 提供了一些函数调用的机制,该 Agent 能够高效地利用这些函数来完成特定的任务。
-
工作原理:它会根据用户的输入和任务需求,调用 OpenAI 提供的相关函数。例如,在处理文本生成任务时,它可以调用 OpenAI 的文本生成函数,根据用户的要求生成符合特定风格和内容的文本。
9. OPENAI_MULTI_FUNCTIONS
-
含义:从名称推测,这是一种能够调用多个 OpenAI 函数的 Agent。它可以根据任务的复杂性,灵活地组合和调用多个 OpenAI 函数来完成任务。
-
工作原理:在面对复杂任务时,它会分析任务的需求,选择合适的多个 OpenAI 函数,并按照一定的顺序和逻辑进行调用。例如,在一个需要进行文本分析和生成的任务中,它可以先调用 OpenAI 的文本分析函数对输入文本进行分析,然后根据分析结果调用文本生成函数生成相关的回复。
initialize_agent
initialize_agent
是 LangChain 中最常用的创建 Agent 的函数,它提供了一种简单的方式来初始化不同类型的 Agent。可以根据需要选择不同的 Agent 类型和工具。
from langchain.agents import initialize_agent, AgentType
from langchain_community.agent_toolkits.load_tools import load_tools, get_all_tool_names
from model.deepseek import deepseek_llm
#查询所有提供的工具
#tool_names = get_all_tool_names()
#print(tool_names)
#加载工具 arxiv 用于搜索arxiv上的论文 llm-math让 LLM 执行数学计算任务(结合计算器)
tools = load_tools(["arxiv", "llm-math"], llm=deepseek_llm)
agent = initialize_agent(
tools,
deepseek_llm,
agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, #使用的agent类型
handle_parsing_errors=True, #如果解析报错继续
verbose=True, #输出的信息不要太多
)
resp = agent.invoke({"input": "人工智能领域最新的论文是什么?请问中文回答"})
print(resp)
create_react_agent
create_react_agent
函数用于创建一个基于 ReACT(Reasoning + Acting in a Cycle)框架的智能代理(Agent)。ReACT 框架通过结合推理和行动,使得代理能够更好地与环境交互,完成复杂任务。
from langchain import hub
from langchain.agents import create_react_agent, AgentExecutor
from langchain_community.agent_toolkits.load_tools import load_tools
from model.bailian import bailian_llm
from model.deepseek import deepseek_llm
prompt = hub.pull("hwchase17/react")
tools = load_tools(["arxiv", "llm-math"], llm=deepseek_llm)
agent = create_react_agent(
llm=bailian_llm,
tools=tools,
prompt=prompt
)
agent_executor = AgentExecutor(agent=agent, tools=tools, handle_parsing_errors=False, verbose=True)
result = agent_executor.invoke({"input": "What is the latest paper about Artificial Intelligence?"})
print(result)
create_structured_chat_agent
create_structured_chat_agent
是一个重要的函数,它用于创建具备结构化输出能力的聊天代理(Agent)。这个代理能够处理复杂的输入参数,并以结构化的形式输出结果,在面对复杂任务时表现出色。
LangSmith上提供了一些常用的提示词可以直接使用
使用方式:prompt = hub.pull("hwchase17/structured-chat-agent")
from langchain import hub
from langchain.agents import create_structured_chat_agent, AgentExecutor
from langchain_community.agent_toolkits.load_tools import load_tools
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field
from langchain.agents import tool
from model.deepseek import deepseek_llm
"""
使用@tool装饰器定义一个搜索模拟工具
@tool装饰器可以将一个函数转换成一个工具
return_direct=True表示直接返回函数的结果,不需要再进行思考
args_schema=SearchInput表示输入的参数类型是SearchInput
"""
class SearchInput(BaseModel):
keyword: str = Field(description="搜索的关键词")
@tool("这是一个搜索的工具", return_direct=True, args_schema=SearchInput)
def search(keyword: str) -> str:
"""
这是一个搜索电脑上的数据的工具
"""
return f'我是一个搜索工具{keyword}'
"""
使用StructuredTool.from_function定义一个排序工具
StructuredTool.from_function可以将一个函数转换成一个工具
return_direct=True表示直接返回函数的结果,不需要再进行思考·
args_schema=SortToolInput表示输入的参数类型是SortToolInput
"""
def sort_num(numString: str):
"""
这是一个工具,对所有的数字排序
"""
return sorted(eval(numString))
class SortToolInput(BaseModel):
num: str = Field(description="搜索的关键词")
#结构化工具
sort_tool = StructuredTool.from_function(
func=sort_num,
name='sort_tool',
description='这是一个工具,对所有的数字排序',
args_schema=SortToolInput,
return_direct=True
)
"""
使用StructuredTool.from_function定义一个计算字符串长度的工具
StructuredTool.from_function可以将一个函数转换成一个工具
return_direct=True表示直接返回函数的结果,不需要再进行思考
args_schema=ArgsInput表示输入的参数类型是ArgsInput
"""
class ArgsInput(BaseModel):
a: str = Field(description="第一个字符串")
b: str = Field(description="第二个字符串")
def count_str(a: str, b: str) -> int:
return len(a) + len(b)
count_tool = StructuredTool.from_function(
func=count_str,
name='count_tool',
description='这是一个工具,计算两个字符串的长度',
args_schema=ArgsInput,
return_direct=True
)
#加载官方工具 arxiv 用于搜索arxiv上的论文 llm-math让 LLM 执行数学计算任务(结合计算器)
tools = load_tools(["arxiv", "llm-math"], llm=deepseek_llm)
#自定义工具
tools = [search, sort_tool, count_tool] + tools
#使用提示器模版
prompt = hub.pull("hwchase17/structured-chat-agent")
agent = create_structured_chat_agent(deepseek_llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
resp = agent_executor.invoke(
# {"input": "‘bbccdd’的字符串长度加上‘abc’字符串长度是多少"}
{"input": "最新关于ai的论文"}
)
print(resp)
create_tool_calling_agent
create_tool_calling_agent
是 LangChain 中另一种非常重要的 Agent 创建方式,特别针对支持原生工具调用(tool calling)功能的模型(如 OpenAI 的 GPT-3.5-turbo 和 GPT-4 系列)。这种方式比结构化聊天代理更高效、更可靠。
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
from pydantic import Field, BaseModel
from model.zhipu import zhipu_llm
class AddInput(BaseModel):
num1: int = Field(description="计算的第一个数字")
num2: int = Field(description="计算的第二个数字")
@tool("add_num", args_schema=AddInput, description="求两个数字的和")
def add_num(num1: int, num2: int) -> int:
"""求两个数字的和"""
print(f"工具被调用:num1: {num1}, num2: {num2}")
return num1 + num2
prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一个智能助手,尽可能的调用工具回答用户的问题"),
MessagesPlaceholder(variable_name="chat_history", optional=True),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad", optional=True),
]
)
agent = create_tool_calling_agent(zhipu_llm, [add_num], prompt)
executor = AgentExecutor(agent=agent, tools=[add_num])
result = executor.invoke({"input": "我昨天赚了100,今天赚了200, 总共赚了多少?"})
print(result)