callanwu's picture
init
200916c
# coding=utf-8
# Copyright 2023 The AIWaves Inc. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""LLM autonoumous agent"""
from LLM.base_LLM import *
from Component import *
from Action import Action
from Prompt import *
headers = {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"X-Accel-Buffering": "no",
}
class Agent:
"""
Auto agent, input the JSON of SOP.
"""
# Agent should have args: agents,states
def __init__(self, name, agent_state_roles, **kwargs) -> None:
self.state_roles = agent_state_roles
self.name = name
self.style = kwargs["style"]
self.LLMs = kwargs["LLMs"]
self.LLM = None
self.is_user = kwargs["is_user"]
self.begins = kwargs["begins"] if "begins" in kwargs else False
self.current_role = ""
self.long_term_memory = []
self.short_term_memory = ""
self.current_state = None
self.first_speak = True
self.environment = None
@classmethod
def from_config(cls, config_path):
"""
Initialize agents based on json file
Return:
agents(dict) : key:agent_name;value:class(Agent)
names_to_roles(dict) : key:state_name value:(dict; (key:agent_name ; value:agent_role))
roles_to_names(dict) : key:state_name value:(dict; (key:agent_role ; value:agent_name))
"""
with open(config_path) as f:
config = json.load(f)
roles_to_names = {}
names_to_roles = {}
agents = {}
user_names = json.loads(os.environ["User_Names"]) if "User_Names" in os.environ else []
for agent_name, agent_dict in config["agents"].items():
agent_state_roles = {}
agent_LLMs = {}
agent_begins = {}
for state_name, agent_role in agent_dict["roles"].items():
agent_begins[state_name] = {}
if state_name not in roles_to_names:
roles_to_names[state_name] = {}
if state_name not in names_to_roles:
names_to_roles[state_name] = {}
roles_to_names[state_name][agent_role] = agent_name
names_to_roles[state_name][agent_name] = agent_role
agent_state_roles[state_name] = agent_role
current_state = config["states"][state_name]
current_state["roles"] = list(current_state["agent_states"].keys()) if "roles" not in current_state else current_state["roles"]
current_state_begin_role = current_state["begin_role"] if "begin_role" in current_state else current_state["roles"][0]
agent_begins[state_name]["is_begin"] = current_state_begin_role==agent_role if "begin_role" in current_state else False
agent_begins[state_name]["begin_query"] = current_state["begin_query"] if "begin_query" in current_state else " "
agent_LLMs[state_name] = init_LLM("logs"+os.sep+f"{agent_name}",**current_state["agent_states"][agent_role])
agents[agent_name] = cls(
agent_name,
agent_state_roles,
LLMs=agent_LLMs,
is_user=agent_name in user_names,
style = agent_dict["style"],
begins = agent_begins
)
assert len(config["agents"].keys()) != 2 or (roles_to_names[config["root"]][config["states"][config["root"]]["begin_role"]] not in user_names and "begin_query" in config["states"][config["root"]]),"In a single-agent scenario, there must be an opening statement and it must be the agent"
return agents, roles_to_names, names_to_roles
def step(self, current_state,input=""):
"""
return actions by current state and environment
Return: action(Action)
"""
current_state.chat_nums +=1
state_begin = current_state.is_begin
agent_begin = self.begins[current_state.name]["is_begin"]
self.begins[current_state.name]["is_begin"] = False
current_state.is_begin = False
environment = self.environment
self.current_state = current_state
# 先根据当前环境更新信息
# First update the information according to the current environment
response = " "
res_dict = {}
if self.is_user:
response = f"{self.name}:{input}"
else:
if len(environment.shared_memory["long_term_memory"])>0:
current_history = self.observe()
self.long_term_memory.append(current_history)
if agent_begin:
response = (char for char in self.begins[current_state.name]["begin_query"])
else:
response,res_dict = self.act()
action_dict = {
"response": response,
"res_dict": res_dict,
"role": self.state_roles[current_state.name],
"name": self.name,
"state_begin" : state_begin,
"agent_begin" : agent_begin,
"is_user" : self.is_user
}
return Action(**action_dict)
def act(self):
"""
return actions by the current state
"""
current_state = self.current_state
chat_history = self.long_term_memory
current_LLM = self.LLMs[current_state.name]
system_prompt, last_prompt, res_dict = self.compile()
response = current_LLM.get_response(
chat_history, system_prompt, last_prompt, stream=True
)
return response,res_dict
def update_memory(self, memory):
self.long_term_memory.append(
{"role": "assistant", "content": memory.content}
)
MAX_CHAT_HISTORY = eval(os.environ["MAX_CHAT_HISTORY"])
environment = self.environment
current_chat_history_idx = environment.current_chat_history_idx if environment.environment_type == "competive" else 0
current_long_term_memory = environment.shared_memory["long_term_memory"][current_chat_history_idx:]
last_conversation_idx = environment._get_agent_last_conversation_idx(self,current_long_term_memory)
if len(current_long_term_memory)-last_conversation_idx >= MAX_CHAT_HISTORY:
current_state = self.current_state
current_role = self.state_roles[current_state.name]
current_component_dict = current_state.components[current_role]
# get chat history from new conversation
conversations = environment._get_agent_new_memory(self,current_long_term_memory)
# get summary
summary_prompt = (
current_state.summary_prompt[current_role]
if current_state.summary_prompt
else f"""your name is {self.name},your role is{current_component_dict["style"].role},your task is {current_component_dict["task"].task}.\n"""
)
summary_prompt =eval(Agent_summary_system_prompt)
summary = self.LLMs[current_state.name].get_response(None, summary_prompt,stream = False)
self.short_term_memory = summary
def compile(self):
"""
get prompt from state depend on your role
Return:
system_prompt:system_prompt for agents's LLM
last_prompt:last_prompt for agents's LLM
res_dict(dict): Other return from tool component.For example: search engine results
"""
current_state = self.current_state
self.current_roles = self.state_roles[current_state.name]
current_state_name = current_state.name
self.LLM = self.LLMs[current_state_name]
components = current_state.components[self.state_roles[current_state_name]]
system_prompt = self.current_state.environment_prompt
last_prompt = ""
res_dict = {}
for component in components.values():
if isinstance(component, (OutputComponent, LastComponent)):
last_prompt = last_prompt + "\n" + component.get_prompt(self)
elif isinstance(component, PromptComponent):
system_prompt = (
system_prompt + "\n" + component.get_prompt(self)
)
elif isinstance(component, ToolComponent):
response = component.func(self)
if "prompt" in response and response["prompt"]:
last_prompt = last_prompt + "\n" + response["prompt"]
res_dict.update(response)
name = self.name
query = self.environment.shared_memory["long_term_memory"][-1] if len(self.environment.shared_memory["long_term_memory"]) else ""
last_prompt = eval(Agent_last_prompt)
system_prompt = eval(Agent_system_prompt)
return system_prompt, last_prompt, res_dict
def observe(self):
"""
Update one's own memory according to the current environment, including: updating short-term memory; updating long-term memory
"""
return self.environment._observe(self)
def generate_sop(self):
pass
def reflection(self):
pass