update
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
from langchain_ollama import ChatOllama
|
||||
|
||||
LLM = ChatOllama(model='qwen2.5:14b', api_key="1145141919810", base_url='http://192.168.195.158:11434')
|
||||
# LLM = ChatOpenAI(model="gpt-4o", openai_api_key='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')
|
||||
|
||||
tavily_key = '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'
|
||||
|
||||
gaode_key = '00fd082df2414f75c6efb64896819451'
|
||||
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import operator
|
||||
@@ -11,7 +12,12 @@ from langchain_core.messages import HumanMessage
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
llm = ChatOpenAI(model="gpt-4o", temperature=0.1, openai_api_key='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')
|
||||
from src.multi_agent.util.tools import formatted_json
|
||||
from src.multi_agent.util.web_search import do_search
|
||||
from src.multi_agent.config import LLM
|
||||
from src.multi_agent.weather_agent import weather_chain
|
||||
|
||||
llm = LLM
|
||||
|
||||
MEMBERS = {'天气查询模块': '输入一个城市和日期,查询当日的天气状况',
|
||||
'网络查询模块': '在网上搜索指定的内容',
|
||||
@@ -41,31 +47,53 @@ def planner(state: AgentState):
|
||||
])
|
||||
planner_chain = (planner_prompt | llm)
|
||||
|
||||
result_dict = {'plan': '为了完成这个任务,我们需要按照以下步骤进行:\n\n1. **网络查询模块**:\n - 任务:查询2024年中国GDP最高的城市。\n - 行动:在网上搜索2024年中国GDP最高的城市的信息。\n\n2. **天气查询模块**:\n - 任务:查询该城市今天的天气状况。\n - 行动:使用天气查询模块,输入城市名称和当前日期,获取该城市的天气信息。\n\n3. **诗歌创作模块**:\n - 任务:根据查询到的城市名称和天气状况,创作一首诗。\n - 行动:利用诗歌创作模块,结合城市的特点和天气状况,创作一首诗。\n\n请各模块按照上述计划执行任务,并在完成后汇总信息。'}
|
||||
|
||||
return result_dict
|
||||
# llm_resp = planner_chain.invoke({'query': [('user', user_query)]})
|
||||
# return {'plan': llm_resp.content}
|
||||
llm_resp = planner_chain.invoke({'query': [('user', user_query)]})
|
||||
return {'plan': llm_resp.content}
|
||||
|
||||
|
||||
def decision_node(state: AgentState):
|
||||
class NextStep(BaseModel):
|
||||
next_agent: str = Field(description='下一步应该交给哪个模块来完成')
|
||||
action: str = Field(description='下一步应该执行的行动计划是什么')
|
||||
|
||||
members = state.get('members', {})
|
||||
member_keys = list(members.keys())
|
||||
if isinstance(llm, ChatOpenAI):
|
||||
class NextStep(BaseModel):
|
||||
next_agent: str = Field(description='下一步应该交给哪个模块来完成')
|
||||
action: str = Field(description='下一步应该执行的行动计划是什么。如果已经执行所有的任务,则填入执行结果')
|
||||
|
||||
decision_prompt = ChatPromptTemplate.from_messages([
|
||||
('system', f'你负责针对一个给定的任务计划,以及当前的任务执行状态,制定下一步应该由谁来执行什么内容。可以在这些模块中进行选择:{", ".join(member_keys)}。'),
|
||||
('system', f'你负责针对一个给定的任务计划,以及当前的任务执行状态,制定下一步应该由谁来执行什么内容。'
|
||||
f'可以在这些模块中进行选择:{", ".join(member_keys)}。'),
|
||||
('user', f'当前的计划是:'),
|
||||
MessagesPlaceholder(variable_name="plan"),
|
||||
('user', '以下是各个模块之间的消息记录'),
|
||||
MessagesPlaceholder(variable_name="messages")
|
||||
])
|
||||
decision_chain = (decision_prompt | llm.with_structured_output(NextStep))
|
||||
llm_resp = decision_chain.invoke({'plan': [('user', state.get('plan', ''))], 'messages': state.get('messages', [])})
|
||||
llm_resp = decision_chain.invoke({'plan': [('user', state.get('plan', ''))],
|
||||
'messages': state.get('messages', [])})
|
||||
next_agent = llm_resp.next_agent
|
||||
action = llm_resp.action
|
||||
else:
|
||||
decision_prompt = ChatPromptTemplate.from_messages([
|
||||
('system',
|
||||
f'你负责针对一个给定的任务计划,以及当前的任务执行状态,制定下一步应该由谁来执行什么内容。'
|
||||
f'可以在这些模块中进行选择:{", ".join(member_keys)}。你的输出必须只能是一个json字符串,'
|
||||
f'必须包含next_agent和action两个字段。其中next_agent是下一步应该交给哪个模块来完成,'
|
||||
f'action是下一步应该执行的行动计划是什么,如果已经执行完成所有的任务,则在action中填入执行结果'
|
||||
f'你只需要输出这个json即可,不需要给出任何解释'),
|
||||
('user', f'当前的计划是:'),
|
||||
MessagesPlaceholder(variable_name="plan"),
|
||||
('user', '以下是各个模块之间的消息记录'),
|
||||
MessagesPlaceholder(variable_name="messages")
|
||||
])
|
||||
decision_chain = (decision_prompt | llm)
|
||||
llm_resp = decision_chain.invoke(
|
||||
{'plan': [('user', state.get('plan', ''))], 'messages': state.get('messages', [])})
|
||||
llm_resp_str = formatted_json(llm_resp.content)
|
||||
resp_dict = json.loads(llm_resp_str)
|
||||
next_agent = resp_dict.get('next_agent')
|
||||
action = resp_dict.get('action')
|
||||
if not (next_agent and action):
|
||||
raise ValueError('模型返回异常')
|
||||
return {'messages': [HumanMessage(content=f'接下来由{next_agent}来执行{action}')], 'next_agent': next_agent, 'next_plan': action}
|
||||
|
||||
|
||||
@@ -79,13 +107,25 @@ def router_node(state: AgentState):
|
||||
|
||||
|
||||
def weather_node(state: AgentState):
|
||||
result = '上海的天气是25℃,下雨'
|
||||
# result = '上海的天气是25℃,下雨'
|
||||
agent_resp = weather_chain.invoke({'next_plan': state.get('next_plan')})
|
||||
result = agent_resp.get('result')
|
||||
return {'messages': [HumanMessage(content=result)]}
|
||||
|
||||
|
||||
def websearch_node(state: AgentState):
|
||||
result = '2024年中国GDP最高的城市是上海'
|
||||
return {'messages': [HumanMessage(content=result)]}
|
||||
|
||||
next_plan = state.get('next_plan', '')
|
||||
websearch_prompt = ChatPromptTemplate.from_messages([
|
||||
('system', f'你是一个网络搜索Agent,你需要根据用户的问题,从中提取出用于在网络搜索引擎上搜索的关键字。只需要回答关键字即可,不需要进行解释'),
|
||||
('user', f'当前的用户问题是:'),
|
||||
MessagesPlaceholder(variable_name="next_plan"),
|
||||
])
|
||||
websearch_chain = (websearch_prompt | llm)
|
||||
llm_resp = websearch_chain.invoke({'next_plan': [('user', next_plan)]})
|
||||
search_result = do_search(llm_resp.content)
|
||||
result_resp = llm.invoke(f'请根据搜索结果进行回答我的问题。\n我的问题是:{next_plan}\n\n搜索结果为:{search_result}')
|
||||
return {'messages': [HumanMessage(content=result_resp.content)]}
|
||||
|
||||
|
||||
def composer_node(state: AgentState):
|
||||
@@ -100,7 +140,7 @@ def composer_node(state: AgentState):
|
||||
|
||||
|
||||
def end_node(state: AgentState):
|
||||
print('placeholder')
|
||||
print('任务完成')
|
||||
|
||||
|
||||
workflow = StateGraph(AgentState)
|
||||
@@ -134,12 +174,14 @@ workflow.add_edge('结束节点', END)
|
||||
workflow.set_entry_point('planner')
|
||||
|
||||
graph = workflow.compile()
|
||||
print(graph.get_graph().draw_ascii())
|
||||
|
||||
enter = {'user_query': "查询2024年中国GDP最高的城市,以这个城市今天的天气,创作一首诗",
|
||||
"members": MEMBERS}
|
||||
for s in graph.stream(enter):
|
||||
if "__end__" not in s:
|
||||
if '__main__' == __name__:
|
||||
print(graph.get_graph().draw_ascii())
|
||||
|
||||
user_query = '查询2024年中国GDP最高的城市,以这个城市今天的天气,创作一首诗'
|
||||
enter = {'user_query': user_query, "members": MEMBERS}
|
||||
for s in graph.stream(enter):
|
||||
if "__end__" not in s and 'router' not in s:
|
||||
print(s)
|
||||
print('-'*80)
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import json
|
||||
|
||||
|
||||
def formatted_json(input_str: str):
|
||||
if input_str.startswith("```"):
|
||||
input_str = input_str[3::]
|
||||
if input_str.endswith("```"):
|
||||
input_str = input_str[:-3:]
|
||||
if input_str.startswith("'''"):
|
||||
input_str = input_str[3::]
|
||||
if input_str.endswith("'''"):
|
||||
input_str = input_str[:-3:]
|
||||
while input_str.startswith('\n'):
|
||||
input_str = input_str[1::]
|
||||
if input_str.startswith('json'):
|
||||
input_str = input_str[4::]
|
||||
return input_str
|
||||
@@ -0,0 +1,28 @@
|
||||
import requests
|
||||
|
||||
from src.multi_agent.config import gaode_key
|
||||
|
||||
|
||||
def search_weather(area_str):
|
||||
district_code_url = 'https://restapi.amap.com/v3/config/district?parameters'
|
||||
weather_url = 'https://restapi.amap.com/v3/weather/weatherInfo?parameters'
|
||||
|
||||
# area_str = '上海市'
|
||||
|
||||
response = requests.get(district_code_url, params={'key': gaode_key, 'keywords': area_str})
|
||||
district_code_list = response.json().get('districts')
|
||||
|
||||
if not district_code_list:
|
||||
raise Exception('查询失败')
|
||||
|
||||
district_code = district_code_list[0].get('adcode')
|
||||
|
||||
response = requests.get(weather_url, params={'key': gaode_key, 'city': district_code})
|
||||
weather_list = response.json().get('lives')
|
||||
if not weather_list:
|
||||
raise Exception('查询失败')
|
||||
|
||||
weather = weather_list[0]
|
||||
|
||||
result = f'{area_str}现在{weather["weather"]},{weather["temperature"]}摄氏度,湿度{weather["humidity"]}%,{weather["winddirection"]}风{weather["windpower"]}级'
|
||||
return result
|
||||
@@ -1,12 +1,14 @@
|
||||
from tavily import TavilyClient
|
||||
import requests
|
||||
|
||||
from src.multi_agent.config import tavily_key
|
||||
|
||||
query = '乔布斯是谁'
|
||||
|
||||
base_url = 'https://api.tavily.com/search'
|
||||
json = {
|
||||
'api_key': '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',
|
||||
def do_search(query):
|
||||
# query = '乔布斯是谁'
|
||||
|
||||
base_url = 'https://api.tavily.com/search'
|
||||
json = {
|
||||
'api_key': tavily_key,
|
||||
'query': query,
|
||||
'search_depth': 'basic',
|
||||
'include_answer': False,
|
||||
@@ -15,13 +17,14 @@ json = {
|
||||
'max_results': 5,
|
||||
'include_domains': [],
|
||||
'exclude_domains': []
|
||||
}
|
||||
}
|
||||
|
||||
response = requests.post(base_url, json=json, verify=False)
|
||||
response = requests.post(base_url, json=json, verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
if response.status_code == 200:
|
||||
search_result = response.json()
|
||||
else:
|
||||
else:
|
||||
raise Exception(f'Error: {response.status_code}: {response.reason}')
|
||||
return search_result
|
||||
|
||||
|
||||
print('done')
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import operator
|
||||
|
||||
from typing import TypedDict, List, Annotated
|
||||
from langgraph.graph import END, StateGraph
|
||||
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||||
|
||||
from src.multi_agent.config import LLM
|
||||
from src.multi_agent.util.weather_search import search_weather
|
||||
|
||||
llm = LLM
|
||||
|
||||
|
||||
class WeatherState(TypedDict):
|
||||
user_request: str
|
||||
city: str
|
||||
result: str
|
||||
|
||||
|
||||
def requirement_analysis(state: WeatherState):
|
||||
user_request = state.get('user_request')
|
||||
analysis_prompt = ChatPromptTemplate([
|
||||
('system', '你是一个天气查询agent,你负责从用户的需求中提取出需要查询天气的城市或地区,你只需要输出这个地名,不需要输出其他任何内容'),
|
||||
('user', f'当前的用户需求是:'),
|
||||
MessagesPlaceholder(variable_name="user_request"),
|
||||
])
|
||||
analysis_chain = analysis_prompt | llm
|
||||
llm_resp = analysis_chain.invoke({'user_request': [("user", user_request)]})
|
||||
return {'city': llm_resp.content}
|
||||
|
||||
|
||||
def get_weather_data(state: WeatherState):
|
||||
city = state.get('city')
|
||||
weather_data = search_weather(city)
|
||||
return {'result': weather_data}
|
||||
|
||||
|
||||
def enter_chain(input_data: dict):
|
||||
return {'user_request': input_data['next_plan']}
|
||||
|
||||
|
||||
workflow = StateGraph(WeatherState)
|
||||
# 其实完全没必要使用子agent,但演示一下子agent如何并网
|
||||
|
||||
workflow.add_node('需求分析', requirement_analysis)
|
||||
workflow.add_node('获取天气', get_weather_data)
|
||||
|
||||
workflow.set_entry_point('需求分析')
|
||||
|
||||
workflow.add_edge('需求分析', '获取天气')
|
||||
workflow.add_edge('获取天气', END)
|
||||
|
||||
weather_graph = workflow.compile()
|
||||
weather_chain = enter_chain | weather_graph
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
requirement_analysis({})
|
||||
Reference in New Issue
Block a user