如何使用Autogen或LangGraph实现GenAI代理

2024年08月05日 由 alex 发表 116 0

GenAI 模型擅长文本摘要、问题解答和代码生成等少数任务。如果你的业务流程可以分解为一系列步骤,其中一个或多个步骤涉及到 GenAI 的这些超级能力之一,那么你就可以使用 GenAI 实现业务流程的部分自动化。我们将自动执行此类步骤的软件应用程序称为代理。


虽然代理使用 LLMs 只是为了处理文本和生成响应,但这种基本能力可以提供相当高级的行为,例如自主调用后端服务的能力。


某个地点的当前天气

假设你想构建一个能回答 "芝加哥在下雨吗?"等问题的代理。仅仅使用 LLM 是无法回答这样的问题的,因为这不是从大量文本中记忆模式就能完成的任务。相反,要回答这个问题,你需要联系实时天气信息源。


美国国家气象局(NWS)有一个开放和免费的 API,可以提供某个地点的短期天气预报。不过,使用该 API 回答 "芝加哥下雨了吗?"这样的问题还需要几个额外的步骤(见图 1):


10

图1


  1. 我们需要建立一个代理框架来协调其余步骤。
  2. 用户对哪个地点感兴趣?我们例句中的答案是 "芝加哥"。如果用户问 "Is Orca Island hot today?",那么用户感兴趣的地点就是 " Orca Island"。由于从问题中提取位置需要能够理解自然语言,因此可以提示 LLM 识别用户感兴趣的位置。
  3. NWS API 基于经纬度运行。如果你想知道芝加哥的天气情况,就必须将 "芝加哥 "字符串转换为一个点的经纬度,然后调用 API。这就是所谓的地理编码。谷歌地图有一个 Geocoder API,只要给定一个地名(如 "芝加哥"),它就会给出经纬度。告诉代理使用该工具获取位置坐标。
  4. 将位置坐标发送到 NWS 天气 API。你将得到一个包含天气数据的 JSON 对象。
  5. 告诉 LLM 提取相应的天气预报(例如,如果问题涉及现在、今晚或下周一),并将其添加到问题的上下文中。
  6. 根据这个丰富的上下文,代理就能最终回答用户的问题了。


下面让我们逐一介绍这些步骤。


步骤 1:设置 Autogen

首先,我们将使用 Autogen,这是微软创建的一个开源代理框架。请克隆我的 Git 仓库,根据 Google Cloud 和 OpenAI 提供的说明获取 API 密钥。切换到 genai_agents 文件夹,用你的密钥更新 keys.env 文件。


GOOGLE_API_KEY=AI…
OPENAI_API_KEY=sk-…


接下来,使用 pip 安装所需的 Python 模块:


pip install -r requirements.txt


这将为谷歌地图和 OpenAI 安装 autogen 模块和客户端库。


Autogen 将代理任务视为代理之间的对话。因此,Autogen 的第一步是创建执行各个步骤的代理。其中一个代理将作为最终用户的代理。它将发起与人工智能代理的聊天,我们将其称为 "助理":


user_proxy = UserProxyAgent("user_proxy","user_proxy",
code_execution_config={"work_dir": "coding", "use_docker": False},
is_termination_msg=lambda x: autogen.code_utils.content_str(x.get("content")).find("TERMINATE") >= 0,
human_input_mode="NEVER",
)


关于上述用户代理,有三点需要注意:


  1. 如果助理回复了代码,用户代理可以在沙盒中执行该代码。
  2. 如果助手的回复中包含 "终止"(TERMINATE)字样,用户代理就会终止对话。这就是 LLM 告诉我们用户问题已得到完整回答的方式。让 LLM 这样做是 Autogen 发送给 LLM 的隐藏系统提示的一部分。
  3. 用户代理从未向最终用户提出任何后续问题。如果有后续问题,我们会指定在何种情况下要求用户输入更多信息。


尽管 Autogen 来自微软,但它并不局限于 Azure OpenAI。人工智能助手可以使用 OpenAI:


openai_config = {
"config_list": [
{
"model": "gpt-4",
"api_key": os.environ.get("OPENAI_API_KEY")
}
]
}


或Gemini:


gemini_config = {
"config_list": [
{
"model": "gemini-1.5-flash",
"api_key": os.environ.get("GOOGLE_API_KEY"),
"api_type": "google"
}
],
}


还支持 Anthropic 和 Ollama。


提供适当的 LLM 配置以创建助手:


assistant = AssistantAgent(
"Assistant",
llm_config=gemini_config,
max_consecutive_auto_reply=3
)


在为代理框架的其他部分布线之前,我们先让助理回答我们的示例查询。


response = user_proxy.initiate_chat(
assistant, message=f"Is it raining in Chicago?""Is it raining in Chicago?"
)
print(response)


助手会用这段代码响应现有的 Google 网络服务,并刮取响应:


```python
# filename: weather.py
import requests
from bs4 import BeautifulSoup
url = "https://www.google.com/search?q=weather+chicago"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
weather_info = soup.find('div', {'id': 'wob_tm'})
print(weather_info.text)


这就体现了由前沿基础模型驱动的代理框架的威力--助理已经自主地找出了一个能提供所需功能的网络服务,并利用其代码生成和执行能力提供了类似于所需功能的东西!然而,这并不完全是我们想要的--我们问是否下雨了,得到的不是想要的答案,而是完整的网站。


其次,自主功能并不能真正满足我们的教学需求。我们用这个例子来说明企业用例,法律硕士不太可能知道你的内部应用程序接口和工具,从而能够自主使用它们。因此,让我们继续构建图 1 所示的框架,以调用我们想要使用的特定 API。


步骤2:提取位置

由于从问题中提取位置只是一种文本处理,因此只需提示 LLM 即可。让我们以单枪匹马为例进行说明:


SYSTEM_MESSAGE_1 = """
In the question below, what location is the user asking about?
Example:
Question: What's the weather in Kalamazoo, Michigan?
Answer: Kalamazoo, Michigan.
Question:
"""


现在,当我们开始聊天,询问芝加哥是否下雨时:


response1 = user_proxy.initiate_chat(
assistant, message=f"{SYSTEM_MESSAGE_1} Is it raining in Chicago?"
)
print(response1)


我们得到:


Answer: Chicago.
TERMINATE


这样,图 1 的第 2 步就完成了。


步骤 3:对位置进行地理编码

第 3 步是获取用户感兴趣的位置的经纬度坐标。编写一个 Python 函数,调用 Google 地图 API 并提取所需的坐标:


def geocoder(location: str) -> (float, float):geocoder(location: str) -> (float, float):
geocode_result = gmaps.geocode(location)
return (round(geocode_result[0]['geometry']['location']['lat'], 4),
round(geocode_result[0]['geometry']['location']['lng'], 4))


接下来,注册该函数,这样助理就能在生成的代码中调用它,用户代理也能在沙盒中执行它:


autogen.register_function(
geocoder,
caller=assistant, # The assistant agent can suggest calls to the geocoder.# The assistant agent can suggest calls to the geocoder.
executor=user_proxy, # The user proxy agent can execute the geocder calls.
name="geocoder", # By default, the function name is used as the tool name.
description="Finds the latitude and longitude of a location or landmark", # A description of the tool.
)


请注意,在撰写本文时,Autogen 仅支持 GPT-4 模型的函数调用。


我们现在扩展提示中的示例,以包括地理编码步骤:


SYSTEM_MESSAGE_2 = """
In the question below, what latitude and longitude is the user asking about?
Example:
Question: What's the weather in Kalamazoo, Michigan?
Step 1: The user is asking about Kalamazoo, Michigan.
Step 2: Use the geocoder tool to get the latitude and longitude of Kalmazoo, Michigan.
Answer: (42.2917, -85.5872)
Question:
"""


现在,当我们开始聊天,询问芝加哥是否下雨时:


response2 = user_proxy.initiate_chat(
assistant, message=f"{SYSTEM_MESSAGE_2} Is it raining in Chicago?"
)
print(response2)


我们就会得到:


Answer: (41.8781, -87.6298)
TERMINATE


步骤 4-6:获取最终答案

有了经纬度坐标,我们就可以调用 NWS API 获取天气数据了。第 4 步,获取天气数据,与地理编码类似,只是我们调用的是不同的 API,并从网络服务响应中提取不同的对象。


结果是,系统提示扩展到了代理应用程序的所有步骤:


SYSTEM_MESSAGE_3 = """
Follow the steps in the example below to retrieve the weather information requested.
Example:
Question: What's the weather in Kalamazoo, Michigan?
Step 1: The user is asking about Kalamazoo, Michigan.
Step 2: Use the geocoder tool to get the latitude and longitude of Kalmazoo, Michigan.
Step 3: latitude, longitude is (42.2917, -85.5872)
Step 4: Use the get_weather_from_nws tool to get the weather from the National Weather Service at the latitude, longitude
Step 5: The detailed forecast for tonight reads 'Showers and thunderstorms before 8pm, then showers and thunderstorms likely. Some of the storms could produce heavy rain. Mostly cloudy. Low around 68, with temperatures rising to around 70 overnight. West southwest wind 5 to 8 mph. Chance of precipitation is 80%. New rainfall amounts between 1 and 2 inches possible.'
Answer: It will rain tonight. Temperature is around 70F.
Question:
"""


根据这一提示,对芝加哥天气问题的回答提取了正确的信息,并正确回答了问题。


在本例中,我们允许 Autogen 在对话中自主选择下一位发言人。我们还可以指定不同的下一位发言人选择策略:特别是,将其设置为 "手动 "时,就会在循环中插入一位人工,并允许人工选择工作流程中的下一位代理。


LangGraph 中的代理工作流

Autogen 将代理工作流视为对话,而 LangGraph 则是一个开源框架,它允许你将工作流视为图形来构建代理。其灵感来源于将数据处理管道表示为有向无环图(DAG)的悠久历史。


在图范式中,我们的气象代理将如图 2 所示。


11

图2


图 1(Autogen)和图 2(LangGraph)之间有一些主要区别:

  • 在 Autogen 中,每个代理都是会话代理。工作流程被视为代理之间的对话,代理之间可以相互交谈。当代理认为 "轮到自己了",就会跳入对话。在 LangGraph 中,工作流被视为一个图,工作流根据我们指定的规则循环经过图中的节点。
  • 在 Autogen 中,人工智能助手无法执行代码;相反,助手会生成代码,而执行代码的是用户代理。在 LangGraph 中,有一个特殊的工具节点(ToolsNode),其中包含了可供助手使用的功能。


我们通过创建工作流程图来设置 LangGraph。我们的图由两个节点组成:助理节点(Assistant Node)和工具节点(ToolsNode)。工作流内的通信通过共享状态进行。


workflow = StateGraph(MessagesState)
workflow.add_node("assistant", call_model)"assistant", call_model)
workflow.add_node("tools", ToolNode(tools))


这些工具都是 Python 函数:


@tool
def latlon_geocoder(location: str) -> (float, float):
  """Converts a place name such as "Kalamazoo, Michigan" to latitude and longitude coordinates"""
  geocode_result = gmaps.geocode(location)
  return (round(geocode_result[0]['geometry']['location']['lat'], 4),
  round(geocode_result[0]['geometry']['location']['lng'], 4))
  tools = [latlon_geocoder, get_weather_from_nws]


Assistant会调用语言模型:


model = ChatOpenAI(model='gpt-3.5-turbo', temperature=0).bind_tools(tools)'gpt-3.5-turbo', temperature=0).bind_tools(tools)
def call_model(state: MessagesState):
  messages = state['messages']
  response = model.invoke(messages)
  # This message will get appended to the existing list
  return {"messages": [response]}


LangGraph 使用 langchain,因此更改模型提供程序非常简单。要使用 Gemini,可以使用以下方法创建模型:


model = ChatGoogleGenerativeAI(model='gemini-1.5-flash',
temperature=0).bind_tools(tools)


接下来,我们定义图的边:


workflow.set_entry_point("assistant")"assistant")
workflow.add_conditional_edges("assistant", assistant_next_node)
workflow.add_edge("tools", "assistant")


上面的第一行和最后一行不言自明:工作流程从向助手发送问题开始。任何时候调用工具,工作流中的下一个节点就是助理,它将使用工具的结果。中间一行在工作流程中设置了一个条件边,因为助理之后的下一个节点并不固定。相反,助理会根据最后一条信息的内容调用工具或结束工作流:


def assistant_next_node(state: MessagesState) -> Literal["tools", END]:
  messages = state['messages']
  last_message = messages[-1]
  # If the LLM makes a tool call, then we route to the "tools" node
  if last_message.tool_calls:
    return "tools"
  # Otherwise, we stop (reply to the user)
  return END


创建工作流程后,编译图形,然后通过传递问题来运行它:


app = workflow.compile()
final_state = app.invoke(
{"messages": [HumanMessage(content=f"{system_message} {question}")]}
)


系统信息和问题正是我们在 Autogen 中使用的:


system_message = """
Follow the steps in the example below to retrieve the weather information requested.
Example:
Question: What's the weather in Kalamazoo, Michigan?
Step 1: The user is asking about Kalamazoo, Michigan.
Step 2: Use the latlon_geocoder tool to get the latitude and longitude of Kalmazoo, Michigan.
Step 3: latitude, longitude is (42.2917, -85.5872)
Step 4: Use the get_weather_from_nws tool to get the weather from the National Weather Service at the latitude, longitude
Step 5: The detailed forecast for tonight reads 'Showers and thunderstorms before 8pm, then showers and thunderstorms likely. Some of the storms could produce heavy rain. Mostly cloudy. Low around 68, with temperatures rising to around 70 overnight. West southwest wind 5 to 8 mph. Chance of precipitation is 80%. New rainfall amounts between 1 and 2 inches possible.'
Answer: It will rain tonight. Temperature is around 70F.
Question:
"""
question="Is it raining in Chicago?"


其结果是,代理框架利用这些步骤为我们的问题提供了答案:


Step 1: The user is asking about Chicago.1: The user is asking about Chicago.
Step 2: Use the latlon_geocoder tool to get the latitude and longitude of Chicago.
[41.8781, -87.6298]
[{"number": 1, "name": "This Afternoon", "startTime": "2024–07–30T14:00:00–05:00", "endTime": "2024–07–30T18:00:00–05:00", "isDaytime": true, …]
There is a chance of showers and thunderstorms after 8pm tonight. The low will be around 73 degrees.


在 Autogen 和 LangGraph 之间做出选择

在 Autogen 和 LangGraph 之间,你应该选择哪一个?几点注意事项:


12


当然,在你读到这篇文章时,Autogen 对非 OpenAI 模型和其他工具的支持水平可能会有所提高。LangGraph 可以添加自主功能,而 Autogen 可以为你提供更精细的控制。代理空间正在快速发展!




文章来源:https://medium.com/towards-data-science/how-to-implement-a-genai-agent-using-autogen-or-langgraph-929135afd34d
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
写评论取消
回复取消