介绍
前文的案例基于researcher agent的输出自动路由消息。
我们也可以选择使用LLM来编排不同的Agent。
下文我们将创建Agent组用一个Agent管理者来帮助委派任务。
为了简化每个Agent node中的代码,我们将使用 LangChain 中的 AgentExecutor 类。本方案和其他“advanced agent”方案旨在展示如何在 LangGraph 中实现某些设计模式。如果该模式满足您的需求,我们建议将其与文档其他地方描述的一些其他基本模式结合起来,以获得最佳性能。
环境配置代码省略,见前文。
创建工具
在这个案例中,你要用搜索引擎创建一个Agent做web研究,并创建一个Agent用于绘图。下文定义他们需要使用的工具:
import os
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_experimental.tools import PythonREPLTool
from common.common import TAVILY_API_KEY
# 提前通过 https://app.tavily.com/home 申请
os.environ["TAVILY_API_KEY"] = TAVILY_API_KEY
tavily_tool = TavilySearchResults(max_results=5)
# This executes code locally, which can be unsafe
python_repl_tool = PythonREPLTool()
辅助工具
定义辅助函数,使得添加新的Agent work nodes更容易。
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
def create_agent(llm: ChatOpenAI, tools: list, system_prompt: str):
# Each worker node will be given a name and some tools.
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
system_prompt,
),
MessagesPlaceholder(variable_name="messages"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)
return executor
我们还可以定义一个函数,用作图中的节点 - 它负责将Agent响应转换为人工消息。这很重要,因为这就是我们将其添加到graph的全局状态的方式。
创建Agent管理
它将使用函数调用来选择下一个工作节点或完成处理。
from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
from common.common import API_KEY, PROXY_URL
members = ["Researcher", "Coder"]
system_prompt = (
"你是负责管理以下workers之间对话的主管: {members}。"
"给定以下用户请求,请与worker一起响应以执行下一步操作。"
"每个worker都将执行一项task,并以其结果和状态作出响应。"
"完成后,回复FINISH。"
)
# 我们的团队管理是LLM节点。它只是选择下一个代理进行处理并决定工作何时完成
options = ["FINISH"] + members
# 使用openai函数调用可以使我们更容易地进行输出解析
function_def = {
"name": "route",
"description": "选择下一个角色",
"parameters": {
"title": "routeSchema",
"type": "object",
"properties": {
"next": {
"title": "Next",
"anyOf": [
{"enum": options},
],
}
},
"required": ["next"],
},
}
prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
MessagesPlaceholder(variable_name="messages"),
(
"system",
"鉴于上述对话,下一步谁应该采取行动?"
"还是应该结束?选择其中一个: {options}",
),
]
).partial(options=str(options), members=", ".join(members))
llm = ChatOpenAI(model_name="gpt-4o", api_key=API_KEY, base_url=PROXY_URL)
supervisor_chain = (
prompt
| llm.bind_functions(functions=[function_def], function_call="route")
| JsonOutputFunctionsParser()
)
构图
我们准备好开始构建graph了。下面,使用我们刚刚定义的tool定义state和worker nodes。
import functools
import operator
from typing import Sequence, TypedDict, Annotated
from langchain_core.messages import BaseMessage
from langgraph.graph import StateGraph
from agent_supervisor import llm, supervisor_chain
from ctools import tavily_tool, python_repl_tool
from utilities import create_agent, agent_node
# The agent state is the input to each node in the graph
class AgentState(TypedDict):
# The annotation tells the graph that new messages will always
# be added to the current states
messages: Annotated[Sequence[BaseMessage], operator.add]
# The 'next' field indicates where to route to next
next: str
research_agent = create_agent(llm, [tavily_tool], "你是一个web研究员.")
research_node = functools.partial(agent_node, agent=research_agent, name="Researcher")
# NOTE: THIS PERFORMS ARBITRARY CODE EXECUTION. PROCEED WITH CAUTION
code_agent = create_agent(
llm,
[python_repl_tool],
"你需要生成安全的python代码来分析数据并使用matplotlib生成图表。",
)
code_node = functools.partial(agent_node, agent=code_agent, name="Coder")
workflow = StateGraph(AgentState)
workflow.add_node("Researcher", research_node)
workflow.add_node("Coder", code_node)
workflow.add_node("supervisor", supervisor_chain)
然后连接在图中连接所有的边:
调用
创建图表后,我们现在可以调用它并查看它的执行情况!
from langchain_core.messages import HumanMessage
from cgraph import graph
for s in graph.stream(
{
"messages": [
HumanMessage(content="编码 hello 并打印到终端")
]
}
):
if "__end__" not in s:
print(s)
print("----")
reference
- https://langchain-ai.github.io/langgraph/tutorials/multi_agent/agent_supervisor/#agent-supervisor