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 os
|
||||||
import time
|
import time
|
||||||
import operator
|
import operator
|
||||||
@@ -11,7 +12,12 @@ from langchain_core.messages import HumanMessage
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
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 = {'天气查询模块': '输入一个城市和日期,查询当日的天气状况',
|
MEMBERS = {'天气查询模块': '输入一个城市和日期,查询当日的天气状况',
|
||||||
'网络查询模块': '在网上搜索指定的内容',
|
'网络查询模块': '在网上搜索指定的内容',
|
||||||
@@ -41,31 +47,53 @@ def planner(state: AgentState):
|
|||||||
])
|
])
|
||||||
planner_chain = (planner_prompt | llm)
|
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请各模块按照上述计划执行任务,并在完成后汇总信息。'}
|
llm_resp = planner_chain.invoke({'query': [('user', user_query)]})
|
||||||
|
return {'plan': llm_resp.content}
|
||||||
return result_dict
|
|
||||||
# llm_resp = planner_chain.invoke({'query': [('user', user_query)]})
|
|
||||||
# return {'plan': llm_resp.content}
|
|
||||||
|
|
||||||
|
|
||||||
def decision_node(state: AgentState):
|
def decision_node(state: AgentState):
|
||||||
class NextStep(BaseModel):
|
|
||||||
next_agent: str = Field(description='下一步应该交给哪个模块来完成')
|
|
||||||
action: str = Field(description='下一步应该执行的行动计划是什么')
|
|
||||||
|
|
||||||
members = state.get('members', {})
|
members = state.get('members', {})
|
||||||
member_keys = list(members.keys())
|
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([
|
decision_prompt = ChatPromptTemplate.from_messages([
|
||||||
('system', f'你负责针对一个给定的任务计划,以及当前的任务执行状态,制定下一步应该由谁来执行什么内容。可以在这些模块中进行选择:{", ".join(member_keys)}。'),
|
('system', f'你负责针对一个给定的任务计划,以及当前的任务执行状态,制定下一步应该由谁来执行什么内容。'
|
||||||
|
f'可以在这些模块中进行选择:{", ".join(member_keys)}。'),
|
||||||
('user', f'当前的计划是:'),
|
('user', f'当前的计划是:'),
|
||||||
MessagesPlaceholder(variable_name="plan"),
|
MessagesPlaceholder(variable_name="plan"),
|
||||||
('user', '以下是各个模块之间的消息记录'),
|
('user', '以下是各个模块之间的消息记录'),
|
||||||
MessagesPlaceholder(variable_name="messages")
|
MessagesPlaceholder(variable_name="messages")
|
||||||
])
|
])
|
||||||
decision_chain = (decision_prompt | llm.with_structured_output(NextStep))
|
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
|
next_agent = llm_resp.next_agent
|
||||||
action = llm_resp.action
|
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}
|
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):
|
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)]}
|
return {'messages': [HumanMessage(content=result)]}
|
||||||
|
|
||||||
|
|
||||||
def websearch_node(state: AgentState):
|
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):
|
def composer_node(state: AgentState):
|
||||||
@@ -100,7 +140,7 @@ def composer_node(state: AgentState):
|
|||||||
|
|
||||||
|
|
||||||
def end_node(state: AgentState):
|
def end_node(state: AgentState):
|
||||||
print('placeholder')
|
print('任务完成')
|
||||||
|
|
||||||
|
|
||||||
workflow = StateGraph(AgentState)
|
workflow = StateGraph(AgentState)
|
||||||
@@ -134,12 +174,14 @@ workflow.add_edge('结束节点', END)
|
|||||||
workflow.set_entry_point('planner')
|
workflow.set_entry_point('planner')
|
||||||
|
|
||||||
graph = workflow.compile()
|
graph = workflow.compile()
|
||||||
|
|
||||||
|
if '__main__' == __name__:
|
||||||
print(graph.get_graph().draw_ascii())
|
print(graph.get_graph().draw_ascii())
|
||||||
|
|
||||||
enter = {'user_query': "查询2024年中国GDP最高的城市,以这个城市今天的天气,创作一首诗",
|
user_query = '查询2024年中国GDP最高的城市,以这个城市今天的天气,创作一首诗'
|
||||||
"members": MEMBERS}
|
enter = {'user_query': user_query, "members": MEMBERS}
|
||||||
for s in graph.stream(enter):
|
for s in graph.stream(enter):
|
||||||
if "__end__" not in s:
|
if "__end__" not in s and 'router' not in s:
|
||||||
print(s)
|
print(s)
|
||||||
print('-'*80)
|
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
|
import requests
|
||||||
|
|
||||||
|
from src.multi_agent.config import tavily_key
|
||||||
|
|
||||||
query = '乔布斯是谁'
|
|
||||||
|
def do_search(query):
|
||||||
|
# query = '乔布斯是谁'
|
||||||
|
|
||||||
base_url = 'https://api.tavily.com/search'
|
base_url = 'https://api.tavily.com/search'
|
||||||
json = {
|
json = {
|
||||||
'api_key': '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',
|
'api_key': tavily_key,
|
||||||
'query': query,
|
'query': query,
|
||||||
'search_depth': 'basic',
|
'search_depth': 'basic',
|
||||||
'include_answer': False,
|
'include_answer': False,
|
||||||
@@ -23,5 +25,6 @@ if response.status_code == 200:
|
|||||||
search_result = response.json()
|
search_result = response.json()
|
||||||
else:
|
else:
|
||||||
raise Exception(f'Error: {response.status_code}: {response.reason}')
|
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