Skip to content

Commit

Permalink
update to a65
Browse files Browse the repository at this point in the history
  • Loading branch information
PinkGranite committed Jan 18, 2025
1 parent d61ce84 commit 88f1fce
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 24 deletions.
6 changes: 1 addition & 5 deletions pycityagent/cityagent/blocks/cognition_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,6 @@ async def forward(self):

async def emotion_update(self, incident):
"""Cognition - emotion update workflow"""
whether_trigger = await self.check_trigger()
if not whether_trigger:
return
print(f"Updating emotion for {incident}")
description_prompt = """
You are a {gender}, aged {age}, belonging to the {race} race and identifying as {religion}.
Your marital status is {marital_status}, and you currently reside in a {residence} area.
Expand All @@ -228,7 +224,7 @@ async def emotion_update(self, incident):
question_prompt = """
Please reconsider your emotion intensities:
sadness, joy, fear, disgust, anger, surprise (0 meaning not at all, 10 meaning very much).
Return in JSON format, e.g. {{"sadness": 5, "joy": 5, "fear": 5, "disgust": 5, "anger": 5, "surprise": 5, "conclusion": "I feel ..."}}"""
Return in JSON format, e.g. {{"sadness": 5, "joy": 5, "fear": 5, "disgust": 5, "anger": 5, "surprise": 5, "conclusion": "I feel ...", "word": "Relief"}}"""
question_prompt = description_prompt + incident_prompt + question_prompt
question_prompt = FormatPrompt(question_prompt)
emotion = await self.memory.status.get("emotion")
Expand Down
11 changes: 5 additions & 6 deletions pycityagent/cityagent/blocks/mobility_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

RADIUS_PROMPT = """As an intelligent decision system, please determine the maximum travel radius (in meters) based on the current emotional state.
Current weather: {weather}
Current temperature: {temperature}
Your current emotion: {emotion_types}
Your current thought: {thought}
Expand Down Expand Up @@ -82,7 +84,9 @@ async def forward(self, step, context):
center = (center['xy_position']['x'], center['xy_position']['y'])
self.radiusPrompt.format(
emotion_types=await self.memory.status.get("emotion_types"),
thought=await self.memory.status.get("thought")
thought=await self.memory.status.get("thought"),
weather=self.simulator.sence("weather"),
temperature=self.simulator.sence("temperature")
)
radius = int(await self.llm.atext_request(self.radiusPrompt.to_dialog())) # type: ignore
try:
Expand Down Expand Up @@ -158,7 +162,6 @@ async def forward(self, step, context):
return {
'success': True,
'evaluation': f'Successfully returned home (already at home)',
'from_place': home,
'to_place': home,
'consumed_time': 0,
'node_id': node_id
Expand All @@ -170,7 +173,6 @@ async def forward(self, step, context):
return {
'success': True,
'evaluation': f'Successfully returned home',
'from_place': nowPlace['aoi_position']['aoi_id'],
'to_place': home,
'consumed_time': 45,
'node_id': node_id
Expand All @@ -185,7 +187,6 @@ async def forward(self, step, context):
return {
'success': True,
'evaluation': f'Successfully reached the workplace (already at the workplace)',
'from_place': work,
'to_place': work,
'consumed_time': 0,
'node_id': node_id
Expand All @@ -197,7 +198,6 @@ async def forward(self, step, context):
return {
'success': True,
'evaluation': f'Successfully reached the workplace',
'from_place': nowPlace['aoi_position']['aoi_id'],
'to_place': work,
'consumed_time': 45,
'node_id': node_id
Expand Down Expand Up @@ -227,7 +227,6 @@ async def forward(self, step, context):
return {
'success': True,
'evaluation': f'Successfully reached the destination: {next_place}',
'from_place': nowPlace['aoi_position']['aoi_id'],
'to_place': next_place[1],
'consumed_time': 45,
'node_id': node_id
Expand Down
12 changes: 10 additions & 2 deletions pycityagent/cityagent/blocks/plan_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
GUIDANCE_SELECTION_PROMPT = """As an intelligent agent's decision system, please select the most suitable option from the following choices to satisfy the current need.
The Environment will influence the choice of steps.
Current weather: {weather}
Current temperature: {temperature}
Current need: Need to satisfy {current_need}
Available options: {options}
Current location: {current_location}
Current time: {current_time}
Current Environment: {environment}
Your emotion: {emotion_types}
Your thought: {thought}
Expand All @@ -40,10 +42,12 @@

DETAILED_PLAN_PROMPT = """Generate specific execution steps based on the selected guidance plan. The Environment will influence the choice of steps.
Current weather: {weather}
Current temperature: {temperature}
Selected plan: {selected_option}
Current location: {current_location}
Current time: {current_time}
Current Environment: {environment}
Your emotion: {emotion_types}
Your thought: {thought}
Expand Down Expand Up @@ -191,6 +195,8 @@ async def select_guidance(self, current_need: str) -> Dict:
environment = await self.memory.status.get("environment")
options = self.guidance_options.get(current_need, [])
self.guidance_prompt.format(
weather=self.simulator.sence("weather"),
temperature=self.simulator.sence("temperature"),
current_need=current_need,
options=options,
current_location=current_location,
Expand Down Expand Up @@ -224,6 +230,8 @@ async def generate_detailed_plan(self, current_need: str, selected_option: str)
current_time = await self.simulator.get_time(format_time=True)
environment = await self.memory.status.get("environment")
self.detail_prompt.format(
weather=self.simulator.sence("weather"),
temperature=self.simulator.sence("temperature"),
selected_option=selected_option,
current_location=current_location,
current_time=current_time,
Expand Down
15 changes: 12 additions & 3 deletions pycityagent/cityagent/initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,33 @@ async def bind_agent_info(simulation):
infos = await simulation.gather("id")
citizen_uuids = await simulation.filter(types=[SocietyAgent])
firm_uuids = await simulation.filter(types=[FirmAgent])
locations = await simulation.gather("location", firm_uuids)
locations_plain = {}
for info in locations:
for k, v in info.items():
locations_plain[k] = v
government_uuids = await simulation.filter(types=[GovernmentAgent])
bank_uuids = await simulation.filter(types=[BankAgent])
nbs_uuids = await simulation.filter(types=[NBSAgent])
citizen_agent_ids = []
firm_ids = []
for info in infos:
for k, v in info.items():
if k in citizen_uuids:
citizen_agent_ids.append(v)
elif k in firm_uuids:
firm_id = v
firm_ids.append(v)
elif k in government_uuids:
government_id = v
elif k in bank_uuids:
bank_id = v
elif k in nbs_uuids:
nbs_id = v
for citizen_uuid in citizen_uuids:
await simulation.update(citizen_uuid, "firm_id", firm_id)
random_firm_id = random.choice(firm_ids)
location = locations_plain[random_firm_id]
await simulation.update(citizen_uuid, "firm_id", random_firm_id)
await simulation.update(citizen_uuid, "work", location)
await simulation.update(citizen_uuid, "government_id", government_id)
await simulation.update(citizen_uuid, "bank_id", bank_id)
await simulation.update(citizen_uuid, "nbs_id", nbs_id)
Expand All @@ -104,5 +113,5 @@ async def bind_agent_info(simulation):
await simulation.update(bank_uuid, "citizens", citizen_uuids)
await simulation.update(bank_uuid, "citizens_agent_id", citizen_agent_ids)
for nbs_uuid in nbs_uuids:
await simulation.update(nbs_uuid, "firm_id", firm_id)
await simulation.update(nbs_uuid, "firm_id", random.choice(firm_ids))
print("Agent info binding completed!")
3 changes: 3 additions & 0 deletions pycityagent/cityagent/memory_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ def memory_config_societyagent():
def memory_config_firm():
EXTRA_ATTRIBUTES = {
"type": (int, economyv2.ORG_TYPE_FIRM),
"location": {
"aoi_position": {"aoi_id": AOI_START_ID + random.randint(1000, 10000)}
},
"price": (float, float(np.mean(agent_skills))),
"inventory": (int, 0),
"employees": (list, []),
Expand Down
4 changes: 1 addition & 3 deletions pycityagent/cityagent/societyagent.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ async def step_execution(self):
elif step_type == "other":
result = await self.otherBlock.forward(current_step, execution_context)
if result != None:
logger.warning(f"Execution result: {result}")
current_step["evaluation"] = result

# Update current_step, plan, and execution_context information
Expand Down Expand Up @@ -210,7 +209,7 @@ def __init__(
self.enable_mobility = True
self.enable_social = True
self.enable_economy = True

self.mindBlock = MindBlock(
llm=self.llm, memory=self.memory, simulator=self.simulator
)
Expand All @@ -231,7 +230,6 @@ def __init__(
# Main workflow
async def forward(self):
self.step_count += 1
logger.info(f"Agent {self._uuid} forward [step_count: {self.step_count}]")
# sync agent status with simulator
await self.update_with_sim()

Expand Down
14 changes: 14 additions & 0 deletions pycityagent/environment/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ def __init__(self, config: dict, secure: bool = False) -> None:
self.poi_id_2_aoi_id: dict[int, int] = {
poi["id"]: poi["aoi_id"] for _, poi in self.map.pois.items()
}
self._environment_prompt:dict[str, str] = {}

@property
def environment(self):
return self._environment_prompt

def set_environment(self, environment: dict[str, str]):
self._environment_prompt = environment

def sence(self, key: str):
return self._environment_prompt.get(key, "")

def update_environment(self, key: str, value: str):
self._environment_prompt[key] = value

# * Agent相关
def find_agents_by_area(self, req: dict, status=None):
Expand Down
6 changes: 5 additions & 1 deletion pycityagent/simulation/agentgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __init__(
embedding_model: Embeddings,
logging_level: int,
agent_config_file: Optional[dict[type[Agent], str]] = None,
environment: Optional[dict[str, str]] = None,
):
logger.setLevel(logging_level)
self._uuid = str(uuid.uuid4())
Expand Down Expand Up @@ -116,7 +117,7 @@ def __init__(
logger.info(f"-----Creating Simulator in AgentGroup {self._uuid} ...")
self.simulator = Simulator(config["simulator_request"])
self.projector = pyproj.Proj(self.simulator.map.header["projection"])

self.simulator.set_environment(environment)
# prepare Economy client
logger.info(f"-----Creating Economy client in AgentGroup {self._uuid} ...")
self.economy_client = EconomyClient(
Expand Down Expand Up @@ -355,6 +356,9 @@ async def update(self, target_agent_uuid: str, target_key: str, content: Any):
agent = self.id2agent[target_agent_uuid]
await agent.status.update(target_key, content)

async def update_environment(self, key: str, value: str):
self.simulator.update_environment(key, value)

async def message_dispatch(self):
logger.debug(f"-----Starting message dispatch for group {self._uuid}")
while True:
Expand Down
27 changes: 24 additions & 3 deletions pycityagent/simulation/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ async def run_from_config(cls, config: dict):
- number_of_government: required, int
- number_of_bank: required, int
- number_of_nbs: required, int
- environment: Optional[dict[str, str]]
- default: {'weather': 'The weather is normal', 'crime': 'The crime rate is low', 'pollution': 'The pollution level is low', 'temperature': 'The temperature is normal'}
- workflow:
- list[Step]
- Step:
Expand Down Expand Up @@ -261,6 +263,16 @@ async def run_from_config(cls, config: dict):
exp_name=config.get("exp_name", "default_experiment"),
logging_level=config.get("logging_level", logging.WARNING),
)
environment = config.get(
"environment",
{
"weather": "The weather is normal",
"crime": "The crime rate is low",
"pollution": "The pollution level is low",
"temperature": "The temperature is normal"
}
)
simulation._simulator.set_environment(environment)
logger.info("Initializing Agents...")
agent_count = []
agent_count.append(config["agent_config"]["number_of_citizen"])
Expand Down Expand Up @@ -308,6 +320,7 @@ async def run_from_config(cls, config: dict):
),
memory_config_func=config["agent_config"].get("memory_config_func", None),
**_message_intercept_kwargs,
environment=environment,
)
logger.info("Running Init Functions...")
for init_func in config["agent_config"].get(
Expand Down Expand Up @@ -461,6 +474,7 @@ async def init_agents(
message_listener: Optional[MessageBlockListenerBase] = None,
embedding_model: Embeddings = SimpleEmbedding(),
memory_config_func: Optional[dict[type[Agent], Callable]] = None,
environment: Optional[dict[str, str]] = None,
) -> None:
"""初始化智能体
Expand All @@ -470,6 +484,7 @@ async def init_agents(
pg_sql_writers: 独立的PgSQL writer数量
message_interceptors: message拦截器数量
memory_config_func: 返回Memory配置的函数,需要返回(EXTRA_ATTRIBUTES, PROFILE, BASE)元组, 每个元素表示一个智能体类创建的Memory配置函数
environment: 环境变量,用于更新模拟器的环境变量
"""
if not isinstance(agent_count, list):
agent_count = [agent_count]
Expand Down Expand Up @@ -657,6 +672,7 @@ async def init_agents(
embedding_model,
self.logging_level,
config_file,
environment,
)
creation_tasks.append((group_name, group))

Expand Down Expand Up @@ -727,6 +743,11 @@ async def filter(
filtered_uuids.extend(await group.filter.remote(types))
return filtered_uuids

async def update_environment(self, key: str, value: str):
self._simulator.update_environment(key, value)
for group in self._groups.values():
await group.update_environment.remote(key, value)

async def update(self, target_agent_uuid: str, target_key: str, content: Any):
"""更新指定智能体的记忆"""
group = self._agent_uuid2group[target_agent_uuid]
Expand Down Expand Up @@ -802,9 +823,6 @@ async def step(self):
try:
# check whether insert agents
simulator_day = await self._simulator.get_simulator_day()
print(
f"simulator_day: {simulator_day}, self._simulator_day: {self._simulator_day}"
)
need_insert_agents = False
if simulator_day > self._simulator_day:
need_insert_agents = True
Expand All @@ -817,6 +835,9 @@ async def step(self):
await asyncio.gather(*insert_tasks)

# step
simulator_day = await self._simulator.get_simulator_day()
simulator_time = int(await self._simulator.get_time())
logger.info(f"Start simulation day {simulator_day} at {simulator_time}, step {self._total_steps}")
tasks = []
for group in self._groups.values():
tasks.append(group.step.remote())
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "pycityagent"
version = "2.0.0a64" # change it for each release
version = "2.0.0a65" # change it for each release
description = "LLM-based city environment agent building library"
authors = [
{ name = "Yuwei Yan", email = "[email protected]" },
Expand Down

0 comments on commit 88f1fce

Please sign in to comment.