pycityagent 2.0.0a64__cp39-cp39-macosx_11_0_arm64.whl → 2.0.0a66__cp39-cp39-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycityagent/cityagent/blocks/cognition_block.py +1 -5
- pycityagent/cityagent/blocks/mobility_block.py +88 -15
- pycityagent/cityagent/blocks/needs_block.py +0 -10
- pycityagent/cityagent/blocks/plan_block.py +10 -2
- pycityagent/cityagent/blocks/social_block.py +0 -10
- pycityagent/cityagent/initial.py +7 -3
- pycityagent/cityagent/memory_config.py +17 -5
- pycityagent/cityagent/societyagent.py +3 -4
- pycityagent/environment/simulator.py +14 -0
- pycityagent/llm/llm.py +64 -42
- pycityagent/memory/memory.py +1 -1
- pycityagent/simulation/agentgroup.py +10 -3
- pycityagent/simulation/simulation.py +64 -28
- {pycityagent-2.0.0a64.dist-info → pycityagent-2.0.0a66.dist-info}/METADATA +1 -1
- {pycityagent-2.0.0a64.dist-info → pycityagent-2.0.0a66.dist-info}/RECORD +19 -19
- {pycityagent-2.0.0a64.dist-info → pycityagent-2.0.0a66.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a64.dist-info → pycityagent-2.0.0a66.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a64.dist-info → pycityagent-2.0.0a66.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a64.dist-info → pycityagent-2.0.0a66.dist-info}/top_level.txt +0 -0
@@ -207,10 +207,6 @@ class CognitionBlock(Block):
|
|
207
207
|
|
208
208
|
async def emotion_update(self, incident):
|
209
209
|
"""Cognition - emotion update workflow"""
|
210
|
-
whether_trigger = await self.check_trigger()
|
211
|
-
if not whether_trigger:
|
212
|
-
return
|
213
|
-
print(f"Updating emotion for {incident}")
|
214
210
|
description_prompt = """
|
215
211
|
You are a {gender}, aged {age}, belonging to the {race} race and identifying as {religion}.
|
216
212
|
Your marital status is {marital_status}, and you currently reside in a {residence} area.
|
@@ -228,7 +224,7 @@ class CognitionBlock(Block):
|
|
228
224
|
question_prompt = """
|
229
225
|
Please reconsider your emotion intensities:
|
230
226
|
sadness, joy, fear, disgust, anger, surprise (0 meaning not at all, 10 meaning very much).
|
231
|
-
Return in JSON format, e.g. {{"sadness": 5, "joy": 5, "fear": 5, "disgust": 5, "anger": 5, "surprise": 5, "conclusion": "I feel ..."}}"""
|
227
|
+
Return in JSON format, e.g. {{"sadness": 5, "joy": 5, "fear": 5, "disgust": 5, "anger": 5, "surprise": 5, "conclusion": "I feel ...", "word": "Relief"}}"""
|
232
228
|
question_prompt = description_prompt + incident_prompt + question_prompt
|
233
229
|
question_prompt = FormatPrompt(question_prompt)
|
234
230
|
emotion = await self.memory.status.get("emotion")
|
@@ -1,9 +1,12 @@
|
|
1
|
+
import math
|
1
2
|
from typing import List
|
2
3
|
from .dispatcher import BlockDispatcher
|
3
4
|
from pycityagent.environment.simulator import Simulator
|
4
5
|
from pycityagent.llm import LLM
|
5
6
|
from pycityagent.memory import Memory
|
6
7
|
from pycityagent.workflow.block import Block
|
8
|
+
import numpy as np
|
9
|
+
from operator import itemgetter
|
7
10
|
import random
|
8
11
|
import logging
|
9
12
|
logger = logging.getLogger("pycityagent")
|
@@ -33,21 +36,88 @@ Your output must be a single selection from ['home', 'workplace', 'other'] witho
|
|
33
36
|
|
34
37
|
RADIUS_PROMPT = """As an intelligent decision system, please determine the maximum travel radius (in meters) based on the current emotional state.
|
35
38
|
|
39
|
+
Current weather: {weather}
|
40
|
+
Current temperature: {temperature}
|
36
41
|
Your current emotion: {emotion_types}
|
37
42
|
Your current thought: {thought}
|
38
43
|
|
39
|
-
Please analyze how these emotions would affect travel willingness and return only a single integer number between
|
44
|
+
Please analyze how these emotions would affect travel willingness and return only a single integer number between 3000-100000 representing the maximum travel radius in meters. A more positive emotional state generally leads to greater willingness to travel further.
|
40
45
|
|
41
46
|
Return only the integer number without any additional text or explanation."""
|
42
47
|
|
48
|
+
def gravity_model(pois):
|
49
|
+
N = len(pois)
|
50
|
+
pois_Dis = {
|
51
|
+
"1k": [],
|
52
|
+
"2k": [],
|
53
|
+
"3k": [],
|
54
|
+
"4k": [],
|
55
|
+
"5k": [],
|
56
|
+
"6k": [],
|
57
|
+
"7k": [],
|
58
|
+
"8k": [],
|
59
|
+
"9k": [],
|
60
|
+
"10k": [],
|
61
|
+
"more": [],
|
62
|
+
}
|
63
|
+
for poi in pois:
|
64
|
+
iflt10k = True
|
65
|
+
for d in range(1, 11):
|
66
|
+
if (d - 1) * 1000 <= poi[1] < d * 1000:
|
67
|
+
pois_Dis["{}k".format(d)].append(poi)
|
68
|
+
iflt10k = False
|
69
|
+
break
|
70
|
+
if iflt10k:
|
71
|
+
pois_Dis["more"].append(poi)
|
72
|
+
|
73
|
+
res = []
|
74
|
+
distanceProb = []
|
75
|
+
for poi in pois:
|
76
|
+
iflt10k = True
|
77
|
+
for d in range(1, 11):
|
78
|
+
if (d - 1) * 1000 <= poi[1] < d * 1000:
|
79
|
+
n = len(pois_Dis["{}k".format(d)])
|
80
|
+
S = math.pi * ((d * 1000) ** 2 - ((d - 1) * 1000) ** 2)
|
81
|
+
density = n / S
|
82
|
+
distance = poi[1]
|
83
|
+
distance = distance if distance > 1 else 1
|
84
|
+
|
85
|
+
# distance decay coefficient, use the square of distance to calculate, so that distant places are less likely to be selected
|
86
|
+
weight = density / (distance**2) # the original weight is reasonable
|
87
|
+
res.append((poi[0]["name"], poi[0]["id"], weight, distance))
|
88
|
+
distanceProb.append(
|
89
|
+
1 / (math.sqrt(distance))
|
90
|
+
)
|
91
|
+
iflt10k = False
|
92
|
+
break
|
93
|
+
|
94
|
+
distanceProb = np.array(distanceProb)
|
95
|
+
distanceProb = distanceProb / np.sum(distanceProb)
|
96
|
+
distanceProb = list(distanceProb)
|
97
|
+
|
98
|
+
options = list(range(len(res)))
|
99
|
+
sample = list(
|
100
|
+
np.random.choice(options, size=50, p=distanceProb)
|
101
|
+
) # sample based on the probability value
|
102
|
+
|
103
|
+
get_elements = itemgetter(*sample)
|
104
|
+
random_elements = get_elements(res)
|
105
|
+
|
106
|
+
# normalize the weight to become the true probability value
|
107
|
+
weightSum = sum(item[2] for item in random_elements)
|
108
|
+
final = [
|
109
|
+
(item[0], item[1], item[2] / weightSum, item[3]) for item in random_elements
|
110
|
+
]
|
111
|
+
return final
|
112
|
+
|
43
113
|
class PlaceSelectionBlock(Block):
|
44
114
|
"""
|
45
|
-
|
115
|
+
Select destination
|
46
116
|
PlaceSelectionBlock
|
47
117
|
"""
|
48
118
|
configurable_fields: List[str] = ["search_limit"]
|
49
119
|
default_values = {
|
50
|
-
"search_limit":
|
120
|
+
"search_limit": 10000
|
51
121
|
}
|
52
122
|
|
53
123
|
def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
|
@@ -57,7 +127,7 @@ class PlaceSelectionBlock(Block):
|
|
57
127
|
self.secondTypeSelectionPrompt = FormatPrompt(PLACE_SECOND_TYPE_SELECTION_PROMPT)
|
58
128
|
self.radiusPrompt = FormatPrompt(RADIUS_PROMPT)
|
59
129
|
# configurable fields
|
60
|
-
self.search_limit =
|
130
|
+
self.search_limit = 10000
|
61
131
|
|
62
132
|
async def forward(self, step, context):
|
63
133
|
self.typeSelectionPrompt.format(
|
@@ -82,7 +152,9 @@ class PlaceSelectionBlock(Block):
|
|
82
152
|
center = (center['xy_position']['x'], center['xy_position']['y'])
|
83
153
|
self.radiusPrompt.format(
|
84
154
|
emotion_types=await self.memory.status.get("emotion_types"),
|
85
|
-
thought=await self.memory.status.get("thought")
|
155
|
+
thought=await self.memory.status.get("thought"),
|
156
|
+
weather=self.simulator.sence("weather"),
|
157
|
+
temperature=self.simulator.sence("temperature")
|
86
158
|
)
|
87
159
|
radius = int(await self.llm.atext_request(self.radiusPrompt.to_dialog())) # type: ignore
|
88
160
|
try:
|
@@ -102,9 +174,15 @@ class PlaceSelectionBlock(Block):
|
|
102
174
|
limit=self.search_limit
|
103
175
|
)
|
104
176
|
if len(pois) > 0:
|
105
|
-
|
106
|
-
|
107
|
-
|
177
|
+
pois = gravity_model(pois)
|
178
|
+
probabilities = [item[2] for item in pois]
|
179
|
+
options = list(range(len(pois)))
|
180
|
+
sample = np.random.choice(
|
181
|
+
options, size=1, p=probabilities
|
182
|
+
) # sample based on the probability value
|
183
|
+
nextPlace = pois[sample[0]]
|
184
|
+
nextPlace = (nextPlace[0], nextPlace[1])
|
185
|
+
# save the destination to context
|
108
186
|
context['next_place'] = nextPlace
|
109
187
|
node_id = await self.memory.stream.add_mobility(description=f"For {step['intention']}, I selected the destination: {nextPlace}")
|
110
188
|
return {
|
@@ -117,7 +195,7 @@ class PlaceSelectionBlock(Block):
|
|
117
195
|
simmap = self.simulator.map
|
118
196
|
poi = random.choice(list(simmap.pois.values()))
|
119
197
|
nextPlace = (poi['name'], poi['aoi_id'])
|
120
|
-
#
|
198
|
+
# save the destination to context
|
121
199
|
context['next_place'] = nextPlace
|
122
200
|
node_id = await self.memory.stream.add_mobility(description=f"For {step['intention']}, I selected the destination: {nextPlace}")
|
123
201
|
return {
|
@@ -129,7 +207,7 @@ class PlaceSelectionBlock(Block):
|
|
129
207
|
|
130
208
|
class MoveBlock(Block):
|
131
209
|
"""
|
132
|
-
|
210
|
+
Execute mobility operations
|
133
211
|
MoveBlock
|
134
212
|
"""
|
135
213
|
def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
|
@@ -158,7 +236,6 @@ class MoveBlock(Block):
|
|
158
236
|
return {
|
159
237
|
'success': True,
|
160
238
|
'evaluation': f'Successfully returned home (already at home)',
|
161
|
-
'from_place': home,
|
162
239
|
'to_place': home,
|
163
240
|
'consumed_time': 0,
|
164
241
|
'node_id': node_id
|
@@ -170,7 +247,6 @@ class MoveBlock(Block):
|
|
170
247
|
return {
|
171
248
|
'success': True,
|
172
249
|
'evaluation': f'Successfully returned home',
|
173
|
-
'from_place': nowPlace['aoi_position']['aoi_id'],
|
174
250
|
'to_place': home,
|
175
251
|
'consumed_time': 45,
|
176
252
|
'node_id': node_id
|
@@ -185,7 +261,6 @@ class MoveBlock(Block):
|
|
185
261
|
return {
|
186
262
|
'success': True,
|
187
263
|
'evaluation': f'Successfully reached the workplace (already at the workplace)',
|
188
|
-
'from_place': work,
|
189
264
|
'to_place': work,
|
190
265
|
'consumed_time': 0,
|
191
266
|
'node_id': node_id
|
@@ -197,7 +272,6 @@ class MoveBlock(Block):
|
|
197
272
|
return {
|
198
273
|
'success': True,
|
199
274
|
'evaluation': f'Successfully reached the workplace',
|
200
|
-
'from_place': nowPlace['aoi_position']['aoi_id'],
|
201
275
|
'to_place': work,
|
202
276
|
'consumed_time': 45,
|
203
277
|
'node_id': node_id
|
@@ -227,7 +301,6 @@ class MoveBlock(Block):
|
|
227
301
|
return {
|
228
302
|
'success': True,
|
229
303
|
'evaluation': f'Successfully reached the destination: {next_place}',
|
230
|
-
'from_place': nowPlace['aoi_position']['aoi_id'],
|
231
304
|
'to_place': next_place[1],
|
232
305
|
'consumed_time': 45,
|
233
306
|
'node_id': node_id
|
@@ -17,9 +17,6 @@ Profile Information:
|
|
17
17
|
- Age: {age}
|
18
18
|
- Monthly Income: {income}
|
19
19
|
|
20
|
-
Current Emotion: {emotion_types}
|
21
|
-
Current Thought: {thought}
|
22
|
-
|
23
20
|
Current Time: {now_time}
|
24
21
|
|
25
22
|
Please initialize the agent's satisfaction levels and parameters based on the profile above. Return the values in JSON format with the following structure:
|
@@ -77,9 +74,6 @@ Current satisfaction:
|
|
77
74
|
- safety_satisfaction: {safety_satisfaction}
|
78
75
|
- social_satisfaction: {social_satisfaction}
|
79
76
|
|
80
|
-
Current Emotion: {emotion_types}
|
81
|
-
Current Thought: {thought}
|
82
|
-
|
83
77
|
Please evaluate and adjust the value of {current_need} satisfaction based on the execution results above.
|
84
78
|
|
85
79
|
Notes:
|
@@ -134,8 +128,6 @@ class NeedsBlock(Block):
|
|
134
128
|
occupation=await self.memory.status.get("occupation"),
|
135
129
|
age=await self.memory.status.get("age"),
|
136
130
|
income=await self.memory.status.get("income"),
|
137
|
-
emotion_types=await self.memory.status.get("emotion_types"),
|
138
|
-
thought=await self.memory.status.get("thought"),
|
139
131
|
now_time=await self.simulator.get_time(format_time=True)
|
140
132
|
)
|
141
133
|
response = await self.llm.atext_request(
|
@@ -285,8 +277,6 @@ class NeedsBlock(Block):
|
|
285
277
|
energy_satisfaction=await self.memory.status.get("energy_satisfaction"),
|
286
278
|
safety_satisfaction=await self.memory.status.get("safety_satisfaction"),
|
287
279
|
social_satisfaction=await self.memory.status.get("social_satisfaction"),
|
288
|
-
emotion_types=await self.memory.status.get("emotion_types"),
|
289
|
-
thought=await self.memory.status.get("thought")
|
290
280
|
)
|
291
281
|
|
292
282
|
response = await self.llm.atext_request(
|
@@ -13,11 +13,13 @@ logger = logging.getLogger("pycityagent")
|
|
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.
|
14
14
|
The Environment will influence the choice of steps.
|
15
15
|
|
16
|
+
Current weather: {weather}
|
17
|
+
Current temperature: {temperature}
|
18
|
+
|
16
19
|
Current need: Need to satisfy {current_need}
|
17
20
|
Available options: {options}
|
18
21
|
Current location: {current_location}
|
19
22
|
Current time: {current_time}
|
20
|
-
Current Environment: {environment}
|
21
23
|
Your emotion: {emotion_types}
|
22
24
|
Your thought: {thought}
|
23
25
|
|
@@ -40,10 +42,12 @@ Please return the evaluation results in JSON format (Do not return any other tex
|
|
40
42
|
|
41
43
|
DETAILED_PLAN_PROMPT = """Generate specific execution steps based on the selected guidance plan. The Environment will influence the choice of steps.
|
42
44
|
|
45
|
+
Current weather: {weather}
|
46
|
+
Current temperature: {temperature}
|
47
|
+
|
43
48
|
Selected plan: {selected_option}
|
44
49
|
Current location: {current_location}
|
45
50
|
Current time: {current_time}
|
46
|
-
Current Environment: {environment}
|
47
51
|
Your emotion: {emotion_types}
|
48
52
|
Your thought: {thought}
|
49
53
|
|
@@ -191,6 +195,8 @@ class PlanBlock(Block):
|
|
191
195
|
environment = await self.memory.status.get("environment")
|
192
196
|
options = self.guidance_options.get(current_need, [])
|
193
197
|
self.guidance_prompt.format(
|
198
|
+
weather=self.simulator.sence("weather"),
|
199
|
+
temperature=self.simulator.sence("temperature"),
|
194
200
|
current_need=current_need,
|
195
201
|
options=options,
|
196
202
|
current_location=current_location,
|
@@ -224,6 +230,8 @@ class PlanBlock(Block):
|
|
224
230
|
current_time = await self.simulator.get_time(format_time=True)
|
225
231
|
environment = await self.memory.status.get("environment")
|
226
232
|
self.detail_prompt.format(
|
233
|
+
weather=self.simulator.sence("weather"),
|
234
|
+
temperature=self.simulator.sence("temperature"),
|
227
235
|
selected_option=selected_option,
|
228
236
|
current_location=current_location,
|
229
237
|
current_time=current_time,
|
@@ -210,16 +210,6 @@ class FindPersonBlock(Block):
|
|
210
210
|
|
211
211
|
class MessageBlock(Block):
|
212
212
|
"""生成并发送消息"""
|
213
|
-
configurable_fields: List[str] = ["default_message_template", "to_discuss"]
|
214
|
-
default_values = {
|
215
|
-
"default_message_template": """
|
216
|
-
As a {gender} {occupation} with {education} education and {personality} personality,
|
217
|
-
generate a message for a friend (relationship strength: {relationship_score}/100)
|
218
|
-
about {intention}.
|
219
|
-
""",
|
220
|
-
"to_discuss": []
|
221
|
-
}
|
222
|
-
|
223
213
|
def __init__(self, agent, llm: LLM, memory: Memory, simulator: Simulator):
|
224
214
|
super().__init__("MessageBlock", llm=llm, memory=memory, simulator=simulator)
|
225
215
|
self.agent = agent
|
pycityagent/cityagent/initial.py
CHANGED
@@ -77,12 +77,15 @@ async def bind_agent_info(simulation):
|
|
77
77
|
bank_uuids = await simulation.filter(types=[BankAgent])
|
78
78
|
nbs_uuids = await simulation.filter(types=[NBSAgent])
|
79
79
|
citizen_agent_ids = []
|
80
|
+
firm_ids = []
|
81
|
+
id2uuid = {}
|
80
82
|
for info in infos:
|
81
83
|
for k, v in info.items():
|
82
84
|
if k in citizen_uuids:
|
83
85
|
citizen_agent_ids.append(v)
|
84
86
|
elif k in firm_uuids:
|
85
|
-
|
87
|
+
firm_ids.append(v)
|
88
|
+
id2uuid[v] = k
|
86
89
|
elif k in government_uuids:
|
87
90
|
government_id = v
|
88
91
|
elif k in bank_uuids:
|
@@ -90,7 +93,8 @@ async def bind_agent_info(simulation):
|
|
90
93
|
elif k in nbs_uuids:
|
91
94
|
nbs_id = v
|
92
95
|
for citizen_uuid in citizen_uuids:
|
93
|
-
|
96
|
+
random_firm_id = random.choice(firm_ids)
|
97
|
+
await simulation.update(citizen_uuid, "firm_id", random_firm_id)
|
94
98
|
await simulation.update(citizen_uuid, "government_id", government_id)
|
95
99
|
await simulation.update(citizen_uuid, "bank_id", bank_id)
|
96
100
|
await simulation.update(citizen_uuid, "nbs_id", nbs_id)
|
@@ -104,5 +108,5 @@ async def bind_agent_info(simulation):
|
|
104
108
|
await simulation.update(bank_uuid, "citizens", citizen_uuids)
|
105
109
|
await simulation.update(bank_uuid, "citizens_agent_id", citizen_agent_ids)
|
106
110
|
for nbs_uuid in nbs_uuids:
|
107
|
-
await simulation.update(nbs_uuid, "firm_id",
|
111
|
+
await simulation.update(nbs_uuid, "firm_id", random.choice(firm_ids))
|
108
112
|
print("Agent info binding completed!")
|
@@ -5,6 +5,7 @@ import numpy as np
|
|
5
5
|
import pycityproto.city.economy.v2.economy_pb2 as economyv2
|
6
6
|
from mosstool.map._map_util.const import AOI_START_ID
|
7
7
|
|
8
|
+
from .firmagent import FirmAgent
|
8
9
|
pareto_param = 8
|
9
10
|
payment_max_skill_multiplier = 950
|
10
11
|
payment_max_skill_multiplier = float(payment_max_skill_multiplier)
|
@@ -14,17 +15,24 @@ clipped_skills = np.minimum(pmsm, (pmsm - 1) * pareto_samples + 1)
|
|
14
15
|
sorted_clipped_skills = np.sort(clipped_skills, axis=1)
|
15
16
|
agent_skills = list(sorted_clipped_skills.mean(axis=0))
|
16
17
|
|
18
|
+
work_locations = [AOI_START_ID + random.randint(1000, 10000) for _ in range(1000)]
|
19
|
+
|
20
|
+
async def memory_config_init(simulation):
|
21
|
+
global work_locations
|
22
|
+
number_of_firm = simulation.agent_count[FirmAgent]
|
23
|
+
work_locations = [AOI_START_ID + random.randint(1000, 10000) for _ in range(number_of_firm)]
|
17
24
|
|
18
25
|
def memory_config_societyagent():
|
26
|
+
global work_locations
|
19
27
|
EXTRA_ATTRIBUTES = {
|
20
28
|
"type": (str, "citizen"),
|
21
29
|
"city": (str, "New York", True),
|
22
30
|
|
23
31
|
# Needs Model
|
24
|
-
"hunger_satisfaction": (float, random.random(), True), #
|
25
|
-
"energy_satisfaction": (float, random.random(), True), #
|
26
|
-
"safety_satisfaction": (float, random.random(), True), #
|
27
|
-
"social_satisfaction": (float, random.random(), True), #
|
32
|
+
"hunger_satisfaction": (float, random.random(), True), # hunger satisfaction
|
33
|
+
"energy_satisfaction": (float, random.random(), True), # energy satisfaction
|
34
|
+
"safety_satisfaction": (float, random.random(), True), # safety satisfaction
|
35
|
+
"social_satisfaction": (float, random.random(), True), # social satisfaction
|
28
36
|
"current_need": (str, "none", True),
|
29
37
|
|
30
38
|
# Plan Behavior Model
|
@@ -186,7 +194,7 @@ def memory_config_societyagent():
|
|
186
194
|
"aoi_position": {"aoi_id": AOI_START_ID + random.randint(1000, 10000)}
|
187
195
|
},
|
188
196
|
"work": {
|
189
|
-
"aoi_position": {"aoi_id":
|
197
|
+
"aoi_position": {"aoi_id": random.choice(work_locations)}
|
190
198
|
},
|
191
199
|
}
|
192
200
|
|
@@ -194,8 +202,12 @@ def memory_config_societyagent():
|
|
194
202
|
|
195
203
|
|
196
204
|
def memory_config_firm():
|
205
|
+
global work_locations
|
197
206
|
EXTRA_ATTRIBUTES = {
|
198
207
|
"type": (int, economyv2.ORG_TYPE_FIRM),
|
208
|
+
"location": {
|
209
|
+
"aoi_position": {"aoi_id": random.choice(work_locations)}
|
210
|
+
},
|
199
211
|
"price": (float, float(np.mean(agent_skills))),
|
200
212
|
"inventory": (int, 0),
|
201
213
|
"employees": (list, []),
|
@@ -121,7 +121,6 @@ class PlanAndActionBlock(Block):
|
|
121
121
|
elif step_type == "other":
|
122
122
|
result = await self.otherBlock.forward(current_step, execution_context)
|
123
123
|
if result != None:
|
124
|
-
logger.warning(f"Execution result: {result}")
|
125
124
|
current_step["evaluation"] = result
|
126
125
|
|
127
126
|
# Update current_step, plan, and execution_context information
|
@@ -210,7 +209,7 @@ class SocietyAgent(CitizenAgent):
|
|
210
209
|
self.enable_mobility = True
|
211
210
|
self.enable_social = True
|
212
211
|
self.enable_economy = True
|
213
|
-
|
212
|
+
|
214
213
|
self.mindBlock = MindBlock(
|
215
214
|
llm=self.llm, memory=self.memory, simulator=self.simulator
|
216
215
|
)
|
@@ -231,12 +230,12 @@ class SocietyAgent(CitizenAgent):
|
|
231
230
|
# Main workflow
|
232
231
|
async def forward(self):
|
233
232
|
self.step_count += 1
|
234
|
-
logger.info(f"Agent {self._uuid} forward [step_count: {self.step_count}]")
|
235
233
|
# sync agent status with simulator
|
236
234
|
await self.update_with_sim()
|
237
235
|
|
238
236
|
# check last step
|
239
|
-
|
237
|
+
ifpass = await self.check_and_update_step()
|
238
|
+
if not ifpass:
|
240
239
|
return
|
241
240
|
|
242
241
|
await self.planAndActionBlock.forward()
|
@@ -105,6 +105,20 @@ class Simulator:
|
|
105
105
|
self.poi_id_2_aoi_id: dict[int, int] = {
|
106
106
|
poi["id"]: poi["aoi_id"] for _, poi in self.map.pois.items()
|
107
107
|
}
|
108
|
+
self._environment_prompt:dict[str, str] = {}
|
109
|
+
|
110
|
+
@property
|
111
|
+
def environment(self):
|
112
|
+
return self._environment_prompt
|
113
|
+
|
114
|
+
def set_environment(self, environment: dict[str, str]):
|
115
|
+
self._environment_prompt = environment
|
116
|
+
|
117
|
+
def sence(self, key: str):
|
118
|
+
return self._environment_prompt.get(key, "")
|
119
|
+
|
120
|
+
def update_environment(self, key: str, value: str):
|
121
|
+
self._environment_prompt[key] = value
|
108
122
|
|
109
123
|
# * Agent相关
|
110
124
|
def find_agents_by_area(self, req: dict, status=None):
|
pycityagent/llm/llm.py
CHANGED
@@ -24,7 +24,6 @@ from .utils import *
|
|
24
24
|
|
25
25
|
os.environ["GRPC_VERBOSITY"] = "ERROR"
|
26
26
|
|
27
|
-
|
28
27
|
class LLM:
|
29
28
|
"""
|
30
29
|
大语言模型对象
|
@@ -46,6 +45,7 @@ class LLM:
|
|
46
45
|
api_keys = [api_keys]
|
47
46
|
|
48
47
|
self._aclients = []
|
48
|
+
self._client_usage = []
|
49
49
|
|
50
50
|
for api_key in api_keys:
|
51
51
|
if self.config.text["request_type"] == "openai":
|
@@ -69,6 +69,11 @@ class LLM:
|
|
69
69
|
f"Unsupported `request_type` {self.config.text['request_type']}!"
|
70
70
|
)
|
71
71
|
self._aclients.append(client)
|
72
|
+
self._client_usage.append({
|
73
|
+
"prompt_tokens": 0,
|
74
|
+
"completion_tokens": 0,
|
75
|
+
"request_number": 0
|
76
|
+
})
|
72
77
|
|
73
78
|
def set_semaphore(self, number_of_coroutine: int):
|
74
79
|
self.semaphore = asyncio.Semaphore(number_of_coroutine)
|
@@ -81,45 +86,62 @@ class LLM:
|
|
81
86
|
clear the storage of used tokens to start a new log message
|
82
87
|
Only support OpenAI category API right now, including OpenAI, Deepseek
|
83
88
|
"""
|
84
|
-
self.
|
85
|
-
|
86
|
-
|
89
|
+
for usage in self._client_usage:
|
90
|
+
usage["prompt_tokens"] = 0
|
91
|
+
usage["completion_tokens"] = 0
|
92
|
+
usage["request_number"] = 0
|
93
|
+
|
94
|
+
def get_consumption(self):
|
95
|
+
consumption = {}
|
96
|
+
for i, usage in enumerate(self._client_usage):
|
97
|
+
consumption[f"api-key-{i+1}"] = {
|
98
|
+
"total_tokens": usage["prompt_tokens"] + usage["completion_tokens"],
|
99
|
+
"request_number": usage["request_number"]
|
100
|
+
}
|
101
|
+
return consumption
|
87
102
|
|
88
103
|
def show_consumption(
|
89
104
|
self, input_price: Optional[float] = None, output_price: Optional[float] = None
|
90
105
|
):
|
91
106
|
"""
|
92
|
-
|
107
|
+
Show consumption for each API key separately
|
93
108
|
"""
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
if self.request_number != 0:
|
100
|
-
TcA = total_token / self.request_number
|
101
|
-
else:
|
102
|
-
TcA = "nan"
|
103
|
-
out = f"""Request Number: {self.request_number}
|
104
|
-
Token Usage:
|
105
|
-
- Total tokens: {total_token}
|
106
|
-
- Prompt tokens: {self.prompt_tokens_used}
|
107
|
-
- Completion tokens: {self.completion_tokens_used}
|
108
|
-
- Token per request: {TcA}
|
109
|
-
- Prompt:Completion ratio: {rate}:1"""
|
110
|
-
if input_price != None and output_price != None:
|
111
|
-
consumption = (
|
112
|
-
self.prompt_tokens_used / 1000000 * input_price
|
113
|
-
+ self.completion_tokens_used / 1000000 * output_price
|
114
|
-
)
|
115
|
-
out += f"\n - Cost Estimation: {consumption}"
|
116
|
-
print(out)
|
117
|
-
return {
|
118
|
-
"total": total_token,
|
119
|
-
"prompt": self.prompt_tokens_used,
|
120
|
-
"completion": self.completion_tokens_used,
|
121
|
-
"ratio": rate,
|
109
|
+
total_stats = {
|
110
|
+
"total": 0,
|
111
|
+
"prompt": 0,
|
112
|
+
"completion": 0,
|
113
|
+
"requests": 0
|
122
114
|
}
|
115
|
+
|
116
|
+
for i, usage in enumerate(self._client_usage):
|
117
|
+
prompt_tokens = usage["prompt_tokens"]
|
118
|
+
completion_tokens = usage["completion_tokens"]
|
119
|
+
requests = usage["request_number"]
|
120
|
+
total_tokens = prompt_tokens + completion_tokens
|
121
|
+
|
122
|
+
total_stats["total"] += total_tokens
|
123
|
+
total_stats["prompt"] += prompt_tokens
|
124
|
+
total_stats["completion"] += completion_tokens
|
125
|
+
total_stats["requests"] += requests
|
126
|
+
|
127
|
+
rate = prompt_tokens / completion_tokens if completion_tokens != 0 else "nan"
|
128
|
+
tokens_per_request = total_tokens / requests if requests != 0 else "nan"
|
129
|
+
|
130
|
+
print(f"\nAPI Key #{i+1}:")
|
131
|
+
print(f"Request Number: {requests}")
|
132
|
+
print("Token Usage:")
|
133
|
+
print(f" - Total tokens: {total_tokens}")
|
134
|
+
print(f" - Prompt tokens: {prompt_tokens}")
|
135
|
+
print(f" - Completion tokens: {completion_tokens}")
|
136
|
+
print(f" - Token per request: {tokens_per_request}")
|
137
|
+
print(f" - Prompt:Completion ratio: {rate}:1")
|
138
|
+
|
139
|
+
if input_price is not None and output_price is not None:
|
140
|
+
consumption = (prompt_tokens / 1000000 * input_price +
|
141
|
+
completion_tokens / 1000000 * output_price)
|
142
|
+
print(f" - Cost Estimation: {consumption}")
|
143
|
+
|
144
|
+
return total_stats
|
123
145
|
|
124
146
|
def _get_next_client(self):
|
125
147
|
"""获取下一个要使用的客户端"""
|
@@ -168,9 +190,9 @@ Token Usage:
|
|
168
190
|
tools=tools,
|
169
191
|
tool_choice=tool_choice,
|
170
192
|
) # type: ignore
|
171
|
-
self.
|
172
|
-
self.
|
173
|
-
self.request_number += 1
|
193
|
+
self._client_usage[self._current_client_index]["prompt_tokens"] += response.usage.prompt_tokens # type: ignore
|
194
|
+
self._client_usage[self._current_client_index]["completion_tokens"] += response.usage.completion_tokens # type: ignore
|
195
|
+
self._client_usage[self._current_client_index]["request_number"] += 1
|
174
196
|
if tools and response.choices[0].message.tool_calls:
|
175
197
|
return json.loads(
|
176
198
|
response.choices[0]
|
@@ -193,9 +215,9 @@ Token Usage:
|
|
193
215
|
tools=tools,
|
194
216
|
tool_choice=tool_choice,
|
195
217
|
) # type: ignore
|
196
|
-
self.
|
197
|
-
self.
|
198
|
-
self.request_number += 1
|
218
|
+
self._client_usage[self._current_client_index]["prompt_tokens"] += response.usage.prompt_tokens # type: ignore
|
219
|
+
self._client_usage[self._current_client_index]["completion_tokens"] += response.usage.completion_tokens # type: ignore
|
220
|
+
self._client_usage[self._current_client_index]["request_number"] += 1
|
199
221
|
if tools and response.choices[0].message.tool_calls:
|
200
222
|
return json.loads(
|
201
223
|
response.choices[0]
|
@@ -248,9 +270,9 @@ Token Usage:
|
|
248
270
|
if task_status != "SUCCESS":
|
249
271
|
raise Exception(f"Task failed with status: {task_status}")
|
250
272
|
|
251
|
-
self.
|
252
|
-
self.
|
253
|
-
self.request_number += 1
|
273
|
+
self._client_usage[self._current_client_index]["prompt_tokens"] += result_response.usage.prompt_tokens # type: ignore
|
274
|
+
self._client_usage[self._current_client_index]["completion_tokens"] += result_response.usage.completion_tokens # type: ignore
|
275
|
+
self._client_usage[self._current_client_index]["request_number"] += 1
|
254
276
|
if tools and result_response.choices[0].message.tool_calls: # type: ignore
|
255
277
|
return json.loads(
|
256
278
|
result_response.choices[0] # type: ignore
|
pycityagent/memory/memory.py
CHANGED
@@ -47,6 +47,7 @@ class AgentGroup:
|
|
47
47
|
embedding_model: Embeddings,
|
48
48
|
logging_level: int,
|
49
49
|
agent_config_file: Optional[dict[type[Agent], str]] = None,
|
50
|
+
environment: Optional[dict[str, str]] = None,
|
50
51
|
):
|
51
52
|
logger.setLevel(logging_level)
|
52
53
|
self._uuid = str(uuid.uuid4())
|
@@ -116,7 +117,7 @@ class AgentGroup:
|
|
116
117
|
logger.info(f"-----Creating Simulator in AgentGroup {self._uuid} ...")
|
117
118
|
self.simulator = Simulator(config["simulator_request"])
|
118
119
|
self.projector = pyproj.Proj(self.simulator.map.header["projection"])
|
119
|
-
|
120
|
+
self.simulator.set_environment(environment)
|
120
121
|
# prepare Economy client
|
121
122
|
logger.info(f"-----Creating Economy client in AgentGroup {self._uuid} ...")
|
122
123
|
self.economy_client = EconomyClient(
|
@@ -185,7 +186,7 @@ class AgentGroup:
|
|
185
186
|
self.message_dispatch_task.cancel() # type: ignore
|
186
187
|
await asyncio.gather(self.message_dispatch_task, return_exceptions=True) # type: ignore
|
187
188
|
|
188
|
-
async def
|
189
|
+
async def insert_agent(self):
|
189
190
|
bind_tasks = []
|
190
191
|
for agent in self.agents:
|
191
192
|
bind_tasks.append(agent.bind_to_simulator()) # type: ignore
|
@@ -199,7 +200,7 @@ class AgentGroup:
|
|
199
200
|
if day == 0:
|
200
201
|
break
|
201
202
|
await asyncio.sleep(1)
|
202
|
-
await self.
|
203
|
+
await self.insert_agent()
|
203
204
|
self.id2agent = {agent._uuid: agent for agent in self.agents}
|
204
205
|
logger.debug(f"-----Binding Agents to Messager in AgentGroup {self._uuid} ...")
|
205
206
|
assert self.messager is not None
|
@@ -355,6 +356,9 @@ class AgentGroup:
|
|
355
356
|
agent = self.id2agent[target_agent_uuid]
|
356
357
|
await agent.status.update(target_key, content)
|
357
358
|
|
359
|
+
async def update_environment(self, key: str, value: str):
|
360
|
+
self.simulator.update_environment(key, value)
|
361
|
+
|
358
362
|
async def message_dispatch(self):
|
359
363
|
logger.debug(f"-----Starting message dispatch for group {self._uuid}")
|
360
364
|
while True:
|
@@ -701,6 +705,9 @@ class AgentGroup:
|
|
701
705
|
)
|
702
706
|
)
|
703
707
|
|
708
|
+
def get_llm_consumption(self):
|
709
|
+
return self.llm.get_consumption()
|
710
|
+
|
704
711
|
async def step(self):
|
705
712
|
try:
|
706
713
|
tasks = [agent.run() for agent in self.agents]
|
@@ -14,9 +14,10 @@ from langchain_core.embeddings import Embeddings
|
|
14
14
|
|
15
15
|
from ..agent import Agent, InstitutionAgent
|
16
16
|
from ..cityagent import (BankAgent, FirmAgent, GovernmentAgent, NBSAgent,
|
17
|
-
SocietyAgent
|
17
|
+
SocietyAgent)
|
18
|
+
from ..cityagent.memory_config import (memory_config_bank, memory_config_firm,
|
18
19
|
memory_config_government, memory_config_nbs,
|
19
|
-
memory_config_societyagent)
|
20
|
+
memory_config_societyagent, memory_config_init)
|
20
21
|
from ..cityagent.initial import bind_agent_info, initialize_social_network
|
21
22
|
from ..cityagent.message_intercept import (EdgeMessageBlock,
|
22
23
|
MessageBlockListener,
|
@@ -35,16 +36,15 @@ from .storage.pg import PgWriter, create_pg_tables
|
|
35
36
|
|
36
37
|
logger = logging.getLogger("pycityagent")
|
37
38
|
|
38
|
-
|
39
39
|
class AgentSimulation:
|
40
|
-
"""
|
40
|
+
"""Agent Simulation"""
|
41
41
|
|
42
42
|
def __init__(
|
43
43
|
self,
|
44
44
|
config: dict,
|
45
45
|
agent_class: Union[None, type[Agent], list[type[Agent]]] = None,
|
46
46
|
agent_config_file: Optional[dict] = None,
|
47
|
-
|
47
|
+
metric_extractors: Optional[list[tuple[int, Callable]]] = None,
|
48
48
|
enable_institution: bool = True,
|
49
49
|
agent_prefix: str = "agent_",
|
50
50
|
exp_name: str = "default_experiment",
|
@@ -52,10 +52,14 @@ class AgentSimulation:
|
|
52
52
|
):
|
53
53
|
"""
|
54
54
|
Args:
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
config: Configuration
|
56
|
+
agent_class: Agent class
|
57
|
+
agent_config_file: Agent configuration file
|
58
|
+
metric_extractors: Metric extractor
|
59
|
+
enable_institution: Whether to enable institution
|
60
|
+
agent_prefix: Agent name prefix
|
61
|
+
exp_name: Experiment name
|
62
|
+
logging_level: Logging level
|
59
63
|
"""
|
60
64
|
self.exp_id = str(uuid.uuid4())
|
61
65
|
if isinstance(agent_class, list):
|
@@ -166,11 +170,12 @@ class AgentSimulation:
|
|
166
170
|
experiment_name=exp_name,
|
167
171
|
run_id=mlflow_run_id,
|
168
172
|
)
|
169
|
-
|
173
|
+
if metric_extractors is not None:
|
174
|
+
self.metric_extractors = metric_extractors
|
170
175
|
else:
|
171
176
|
logger.warning("Mlflow is not enabled, NO MLFLOW STORAGE")
|
172
177
|
self.mlflow_client = None
|
173
|
-
self.
|
178
|
+
self.metric_extractors = None
|
174
179
|
|
175
180
|
# pg
|
176
181
|
_pgsql_config: dict[str, Any] = _storage_config.get("pgsql", {})
|
@@ -216,8 +221,9 @@ class AgentSimulation:
|
|
216
221
|
- enable_institution: bool, default is True
|
217
222
|
- agent_config:
|
218
223
|
- agent_config_file: Optional[dict[type[Agent], str]]
|
224
|
+
- memory_config_init_func: Optional[Callable]
|
219
225
|
- memory_config_func: Optional[dict[type[Agent], Callable]]
|
220
|
-
-
|
226
|
+
- metric_extractors: Optional[list[tuple[int, Callable]]]
|
221
227
|
- init_func: Optional[list[Callable[AgentSimulation, None]]]
|
222
228
|
- group_size: Optional[int]
|
223
229
|
- embedding_model: Optional[EmbeddingModel]
|
@@ -226,6 +232,8 @@ class AgentSimulation:
|
|
226
232
|
- number_of_government: required, int
|
227
233
|
- number_of_bank: required, int
|
228
234
|
- number_of_nbs: required, int
|
235
|
+
- environment: Optional[dict[str, str]]
|
236
|
+
- default: {'weather': 'The weather is normal', 'crime': 'The crime rate is low', 'pollution': 'The pollution level is low', 'temperature': 'The temperature is normal'}
|
229
237
|
- workflow:
|
230
238
|
- list[Step]
|
231
239
|
- Step:
|
@@ -256,18 +264,32 @@ class AgentSimulation:
|
|
256
264
|
simulation = cls(
|
257
265
|
config=simulation_config,
|
258
266
|
agent_config_file=config["agent_config"].get("agent_config_file", None),
|
259
|
-
|
267
|
+
metric_extractors=config["agent_config"].get("metric_extractors", None),
|
260
268
|
enable_institution=config.get("enable_institution", True),
|
261
269
|
exp_name=config.get("exp_name", "default_experiment"),
|
262
270
|
logging_level=config.get("logging_level", logging.WARNING),
|
263
271
|
)
|
272
|
+
environment = config.get(
|
273
|
+
"environment",
|
274
|
+
{
|
275
|
+
"weather": "The weather is normal",
|
276
|
+
"crime": "The crime rate is low",
|
277
|
+
"pollution": "The pollution level is low",
|
278
|
+
"temperature": "The temperature is normal"
|
279
|
+
}
|
280
|
+
)
|
281
|
+
simulation._simulator.set_environment(environment)
|
264
282
|
logger.info("Initializing Agents...")
|
265
|
-
agent_count =
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
283
|
+
agent_count = {
|
284
|
+
SocietyAgent: config["agent_config"].get("number_of_citizen", 0),
|
285
|
+
FirmAgent: config["agent_config"].get("number_of_firm", 0),
|
286
|
+
GovernmentAgent: config["agent_config"].get("number_of_government", 0),
|
287
|
+
BankAgent: config["agent_config"].get("number_of_bank", 0),
|
288
|
+
NBSAgent: config["agent_config"].get("number_of_nbs", 0),
|
289
|
+
}
|
290
|
+
if agent_count.get(SocietyAgent, 0) == 0:
|
291
|
+
raise ValueError("number_of_citizen is required")
|
292
|
+
|
271
293
|
# support MessageInterceptor
|
272
294
|
if "message_intercept" in config:
|
273
295
|
_intercept_config = config["message_intercept"]
|
@@ -306,8 +328,10 @@ class AgentSimulation:
|
|
306
328
|
embedding_model=config["agent_config"].get(
|
307
329
|
"embedding_model", SimpleEmbedding()
|
308
330
|
),
|
309
|
-
memory_config_func=config["agent_config"].get("memory_config_func", None),
|
331
|
+
memory_config_func=config["agent_config"].get("memory_config_func", None),
|
332
|
+
memory_config_init_func=config["agent_config"].get("memory_config_init_func", None),
|
310
333
|
**_message_intercept_kwargs,
|
334
|
+
environment=environment,
|
311
335
|
)
|
312
336
|
logger.info("Running Init Functions...")
|
313
337
|
for init_func in config["agent_config"].get(
|
@@ -452,7 +476,7 @@ class AgentSimulation:
|
|
452
476
|
|
453
477
|
async def init_agents(
|
454
478
|
self,
|
455
|
-
agent_count:
|
479
|
+
agent_count: dict[type[Agent], int],
|
456
480
|
group_size: int = 10000,
|
457
481
|
pg_sql_writers: int = 32,
|
458
482
|
message_interceptors: int = 1,
|
@@ -460,7 +484,9 @@ class AgentSimulation:
|
|
460
484
|
social_black_list: Optional[list[tuple[str, str]]] = None,
|
461
485
|
message_listener: Optional[MessageBlockListenerBase] = None,
|
462
486
|
embedding_model: Embeddings = SimpleEmbedding(),
|
487
|
+
memory_config_init_func: Optional[Callable] = None,
|
463
488
|
memory_config_func: Optional[dict[type[Agent], Callable]] = None,
|
489
|
+
environment: Optional[dict[str, str]] = None,
|
464
490
|
) -> None:
|
465
491
|
"""初始化智能体
|
466
492
|
|
@@ -470,13 +496,15 @@ class AgentSimulation:
|
|
470
496
|
pg_sql_writers: 独立的PgSQL writer数量
|
471
497
|
message_interceptors: message拦截器数量
|
472
498
|
memory_config_func: 返回Memory配置的函数,需要返回(EXTRA_ATTRIBUTES, PROFILE, BASE)元组, 每个元素表示一个智能体类创建的Memory配置函数
|
499
|
+
environment: 环境变量,用于更新模拟器的环境变量
|
473
500
|
"""
|
474
|
-
|
475
|
-
agent_count = [agent_count]
|
501
|
+
self.agent_count = agent_count
|
476
502
|
|
477
503
|
if len(self.agent_class) != len(agent_count):
|
478
|
-
raise ValueError("agent_class
|
504
|
+
raise ValueError("The length of agent_class and agent_count does not match")
|
479
505
|
|
506
|
+
if memory_config_init_func is not None:
|
507
|
+
await memory_config_init(self)
|
480
508
|
if memory_config_func is None:
|
481
509
|
memory_config_func = self.default_memory_config_func # type:ignore
|
482
510
|
|
@@ -488,9 +516,11 @@ class AgentSimulation:
|
|
488
516
|
citizen_params = []
|
489
517
|
|
490
518
|
# 收集所有参数
|
519
|
+
print(self.agent_class)
|
520
|
+
print(agent_count)
|
491
521
|
for i in range(len(self.agent_class)):
|
492
522
|
agent_class = self.agent_class[i]
|
493
|
-
agent_count_i = agent_count[
|
523
|
+
agent_count_i = agent_count[agent_class]
|
494
524
|
assert memory_config_func is not None
|
495
525
|
memory_config_func_i = memory_config_func.get(
|
496
526
|
agent_class, self.default_memory_config_func[agent_class] # type:ignore
|
@@ -657,6 +687,7 @@ class AgentSimulation:
|
|
657
687
|
embedding_model,
|
658
688
|
self.logging_level,
|
659
689
|
config_file,
|
690
|
+
environment,
|
660
691
|
)
|
661
692
|
creation_tasks.append((group_name, group))
|
662
693
|
|
@@ -727,6 +758,11 @@ class AgentSimulation:
|
|
727
758
|
filtered_uuids.extend(await group.filter.remote(types))
|
728
759
|
return filtered_uuids
|
729
760
|
|
761
|
+
async def update_environment(self, key: str, value: str):
|
762
|
+
self._simulator.update_environment(key, value)
|
763
|
+
for group in self._groups.values():
|
764
|
+
await group.update_environment.remote(key, value)
|
765
|
+
|
730
766
|
async def update(self, target_agent_uuid: str, target_key: str, content: Any):
|
731
767
|
"""更新指定智能体的记忆"""
|
732
768
|
group = self._agent_uuid2group[target_agent_uuid]
|
@@ -802,9 +838,6 @@ class AgentSimulation:
|
|
802
838
|
try:
|
803
839
|
# check whether insert agents
|
804
840
|
simulator_day = await self._simulator.get_simulator_day()
|
805
|
-
print(
|
806
|
-
f"simulator_day: {simulator_day}, self._simulator_day: {self._simulator_day}"
|
807
|
-
)
|
808
841
|
need_insert_agents = False
|
809
842
|
if simulator_day > self._simulator_day:
|
810
843
|
need_insert_agents = True
|
@@ -817,6 +850,9 @@ class AgentSimulation:
|
|
817
850
|
await asyncio.gather(*insert_tasks)
|
818
851
|
|
819
852
|
# step
|
853
|
+
simulator_day = await self._simulator.get_simulator_day()
|
854
|
+
simulator_time = int(await self._simulator.get_time())
|
855
|
+
logger.info(f"Start simulation day {simulator_day} at {simulator_time}, step {self._total_steps}")
|
820
856
|
tasks = []
|
821
857
|
for group in self._groups.values():
|
822
858
|
tasks.append(group.step.remote())
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pycityagent
|
3
|
-
Version: 2.0.
|
3
|
+
Version: 2.0.0a66
|
4
4
|
Summary: LLM-based city environment agent building library
|
5
5
|
Author-email: Yuwei Yan <pinkgranite86@gmail.com>, Junbo Yan <yanjb20thu@gmali.com>, Jun Zhang <zhangjun990222@gmali.com>
|
6
6
|
License: MIT License
|
@@ -1,3 +1,9 @@
|
|
1
|
+
pycityagent-2.0.0a66.dist-info/RECORD,,
|
2
|
+
pycityagent-2.0.0a66.dist-info/LICENSE,sha256=n2HPXiupinpyHMnIkbCf3OTYd3KMqbmldu1e7av0CAU,1084
|
3
|
+
pycityagent-2.0.0a66.dist-info/WHEEL,sha256=md3JO_ifs5j508p3TDNMgtQVtnQblpGEt_Wo4W56l8Y,107
|
4
|
+
pycityagent-2.0.0a66.dist-info/entry_points.txt,sha256=BZcne49AAIFv-hawxGnPbblea7X3MtAtoPyDX8L4OC4,132
|
5
|
+
pycityagent-2.0.0a66.dist-info/top_level.txt,sha256=yOmeu6cSXmiUtScu53a3s0p7BGtLMaV0aff83EHCTic,43
|
6
|
+
pycityagent-2.0.0a66.dist-info/METADATA,sha256=Gd-mcYNBdEIpmg-DYNadjFxVQicXesWi6GK71M85Gfs,9110
|
1
7
|
pycityagent/pycityagent-sim,sha256=vskCJGHJEh0B2dUfmYlVyrcy3sDZ3kBNwjqcYUZpmO8,35449490
|
2
8
|
pycityagent/__init__.py,sha256=PUKWTXc-xdMG7px8oTNclodsILUgypANj2Z647sY63k,808
|
3
9
|
pycityagent/pycityagent-ui,sha256=K2XXJhxIoIk4QWty5i-0FuzZJekkFlbeqrJgPX3tbdE,41225346
|
@@ -10,10 +16,10 @@ pycityagent/tools/__init__.py,sha256=XtdtGyWeFyK1YOUvWkykBWxemtmwQjWUIuuyU1-gosQ
|
|
10
16
|
pycityagent/tools/tool.py,sha256=D-ESFlX7EESm5mcvs2zRlGEQTzXbVfQc8G7Vpz8TmAw,8651
|
11
17
|
pycityagent/llm/llmconfig.py,sha256=4Ylf4OFSBEFy8jrOneeX0HvPhWEaF5jGvy1HkXK08Ro,436
|
12
18
|
pycityagent/llm/__init__.py,sha256=iWs6FLgrbRVIiqOf4ILS89gkVCTvS7HFC3vG-MWuyko,205
|
13
|
-
pycityagent/llm/llm.py,sha256=
|
19
|
+
pycityagent/llm/llm.py,sha256=upm246fUurltONXies4I4oiZ7NkG0Xk8nj4xVRTNV9o,17215
|
14
20
|
pycityagent/llm/embeddings.py,sha256=2_P4TWm3sJKFdGDx2Q1a2AEapFopDctIXsGuntvmP6E,6816
|
15
21
|
pycityagent/llm/utils.py,sha256=hoNPhvomb1u6lhFX0GctFipw74hVKb7bvUBDqwBzBYw,160
|
16
|
-
pycityagent/memory/memory.py,sha256
|
22
|
+
pycityagent/memory/memory.py,sha256=-o_W0uC_cOPyWPxdXiCLmU9XiTHF82DQYb53RQyYgeg,34588
|
17
23
|
pycityagent/memory/profile.py,sha256=q8ZS9IBmHCg_X1GONUvXK85P6tCepTKQgXKuvuXYNXw,5203
|
18
24
|
pycityagent/memory/__init__.py,sha256=_Vfdo1HcLWsuuz34_i8e91nnLVYADpMlHHSVaB3xgIk,297
|
19
25
|
pycityagent/memory/memory_base.py,sha256=QG_j3BxZvkadFEeE3uBR_kjl_xcXD1aHUVs8GEF3d6w,5654
|
@@ -22,9 +28,9 @@ pycityagent/memory/utils.py,sha256=oJWLdPeJy_jcdKcDTo9JAH9kDZhqjoQhhv_zT9qWC0w,8
|
|
22
28
|
pycityagent/memory/const.py,sha256=6zpJPJXWoH9-yf4RARYYff586agCoud9BRn7sPERB1g,932
|
23
29
|
pycityagent/memory/faiss_query.py,sha256=V3rIw6d1_xcpNqZBbAYz3qfjVNE7NfJ7xOS5SibPtVU,13180
|
24
30
|
pycityagent/memory/state.py,sha256=TYItiyDtehMEQaSBN7PpNrnNxdDM5jGppr9R9Ufv3kA,5134
|
25
|
-
pycityagent/simulation/simulation.py,sha256=
|
31
|
+
pycityagent/simulation/simulation.py,sha256=QRD994g4fRzDTbuCEmYGFdyFxix5a5XnXikgy4L19oc,37765
|
26
32
|
pycityagent/simulation/__init__.py,sha256=P5czbcg2d8S0nbbnsQXFIhwzO4CennAhZM8OmKvAeYw,194
|
27
|
-
pycityagent/simulation/agentgroup.py,sha256=
|
33
|
+
pycityagent/simulation/agentgroup.py,sha256=BpUWmN_CWR7-PJhq9e4pSsVjXZWcoW3Wt-gh5MIxQjQ,31674
|
28
34
|
pycityagent/simulation/storage/pg.py,sha256=xRshSOGttW-p0re0fNBOjOpb-nQ5msIE2LsdT79_E_Y,8425
|
29
35
|
pycityagent/message/message_interceptor.py,sha256=w8XTyZStQtMjILpeAX3VMhAWcYAuaxCgSMwXQU1OryM,8951
|
30
36
|
pycityagent/message/__init__.py,sha256=f5QH7DKPqEAMyfSlBMnl3uouOKlsoel909STlIe7nUk,276
|
@@ -47,7 +53,7 @@ pycityagent/workflow/prompt.py,sha256=6jI0Rq54JLv3-IXqZLYug62vse10wTI83xvf4ZX42n
|
|
47
53
|
pycityagent/workflow/block.py,sha256=4QufS8XnyP6SYp8g1gDODW-H0nAHA7lvivrPGUq1p-w,9922
|
48
54
|
pycityagent/workflow/trigger.py,sha256=Df-MOBEDWBbM-v0dFLQLXteLsipymT4n8vqexmK2GiQ,5643
|
49
55
|
pycityagent/environment/__init__.py,sha256=MyZBwsweDIHOKSX2iSZs748foNtaiyEcyg6sc747T2g,263
|
50
|
-
pycityagent/environment/simulator.py,sha256=
|
56
|
+
pycityagent/environment/simulator.py,sha256=QMmxL7xT7zgdJDxINNb1Li1iZsLdqtH2rbqhJhZc14Y,12878
|
51
57
|
pycityagent/environment/message/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
58
|
pycityagent/environment/utils/port.py,sha256=3OM6kSUt3PxvDUOlgyiendBtETaWU8Mzk_8H0TzTmYg,295
|
53
59
|
pycityagent/environment/utils/grpc.py,sha256=6EJwKXXktIWb1NcUiJzIRmfrY0S03QAXXGcCDHqAT00,1998
|
@@ -75,31 +81,25 @@ pycityagent/environment/sim/clock_service.py,sha256=gBUujvX_vIFMKVfcLRyk1GcpRRL6
|
|
75
81
|
pycityagent/environment/sim/road_service.py,sha256=bKyn3_me0sGmaJVyF6eNeFbdU-9C1yWsa9L7pieDJzg,1285
|
76
82
|
pycityagent/environment/interact/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
77
83
|
pycityagent/environment/interact/interact.py,sha256=ifxPPzuHeqLHIZ_6zvfXMoBOnBsXNIP4bYp7OJ7pnEQ,6588
|
78
|
-
pycityagent/cityagent/memory_config.py,sha256=
|
84
|
+
pycityagent/cityagent/memory_config.py,sha256=nBUkLbxmiNtw4J4s34n4brgyFXnhpNYvQxws0c2n-ho,11356
|
79
85
|
pycityagent/cityagent/bankagent.py,sha256=lr4GEcqt-iwA7DXoDry0WXkV6benmdaAyLpswqSpKlY,2120
|
80
86
|
pycityagent/cityagent/__init__.py,sha256=gcBQ-a50XegFtjigQ7xDXRBZrywBKqifiQFSRnEF8gM,572
|
81
87
|
pycityagent/cityagent/firmagent.py,sha256=UVlNN0lpa4cC4PZVqYzQhbc5VJ2oGsA1731mhbCjnR8,4109
|
82
88
|
pycityagent/cityagent/nbsagent.py,sha256=WIXW__6dZ5IrqBqDCjvGbrCshpXzuFRV3Ww6gkYw7p4,4387
|
83
|
-
pycityagent/cityagent/initial.py,sha256=
|
84
|
-
pycityagent/cityagent/societyagent.py,sha256=
|
89
|
+
pycityagent/cityagent/initial.py,sha256=k9iolPtDj5KiOvg_FaDWPpqhLCpP19T8gmGTKLISa40,4694
|
90
|
+
pycityagent/cityagent/societyagent.py,sha256=REGEBWGT7ScKVS9o-x8iJMWSoAPXrMRpBZhAxxYuxS4,20312
|
85
91
|
pycityagent/cityagent/message_intercept.py,sha256=1YMOs6-6bbAaTt7RfMn-ALVIcp0frHN7oqGUkWRy5xE,4519
|
86
92
|
pycityagent/cityagent/governmentagent.py,sha256=HJLuhvEmllu_1KnFEJsYCIasaBJT0BV9Cn_4Y2QGPqg,2791
|
87
93
|
pycityagent/cityagent/blocks/dispatcher.py,sha256=mEa1r3tRS3KI1BMZR_w_sbUGzOj6aUJuiUrsHv1n2n0,2943
|
88
|
-
pycityagent/cityagent/blocks/needs_block.py,sha256=
|
89
|
-
pycityagent/cityagent/blocks/cognition_block.py,sha256=
|
90
|
-
pycityagent/cityagent/blocks/social_block.py,sha256=
|
94
|
+
pycityagent/cityagent/blocks/needs_block.py,sha256=ZAf1cQq1N73YBBPEejYF2vAfEkXXTAVUcvqHIy-9Rhs,14935
|
95
|
+
pycityagent/cityagent/blocks/cognition_block.py,sha256=zDbyyLh5GEqje9INJUJA1gMSDPW0wX5lt6yNu97XXn0,14818
|
96
|
+
pycityagent/cityagent/blocks/social_block.py,sha256=Dust9Tpu145h24gbJzEyy_a-IzbnZ0KtTNwTvteVb6w,15138
|
91
97
|
pycityagent/cityagent/blocks/__init__.py,sha256=wydR0s-cCRWgdvQetkfQnD_PU8vC3eTmt2zntcb4fSA,452
|
92
98
|
pycityagent/cityagent/blocks/economy_block.py,sha256=m5B67cgGZ9nKWtrYeak5gxMoCoKlRbATAsXpFajYKyg,19129
|
93
99
|
pycityagent/cityagent/blocks/utils.py,sha256=8O5p1B8JlreIJTGXKAP03rTcn7MvFSR8qJ1_hhszboU,2065
|
94
100
|
pycityagent/cityagent/blocks/other_block.py,sha256=NnDwxQAO5XZ7Uxe-n3qtrfNItHlwFYk2MQsh2GYDKMQ,4338
|
95
|
-
pycityagent/cityagent/blocks/plan_block.py,sha256=
|
96
|
-
pycityagent/cityagent/blocks/mobility_block.py,sha256=
|
101
|
+
pycityagent/cityagent/blocks/plan_block.py,sha256=v04ePs-6b86TyaP3fl9HPMwWh3_lHp4cjyoEQBHkoDU,11280
|
102
|
+
pycityagent/cityagent/blocks/mobility_block.py,sha256=rFRqyVnZG-BMXU0VNAkyrpHFYLv0_QUv4o8vI1wdG5A,15042
|
97
103
|
pycityagent/survey/models.py,sha256=YE50UUt5qJ0O_lIUsSY6XFCGUTkJVNu_L1gAhaCJ2fs,3546
|
98
104
|
pycityagent/survey/__init__.py,sha256=rxwou8U9KeFSP7rMzXtmtp2fVFZxK4Trzi-psx9LPIs,153
|
99
105
|
pycityagent/survey/manager.py,sha256=S5IkwTdelsdtZETChRcfCEczzwSrry_Fly9MY4s3rbk,1681
|
100
|
-
pycityagent-2.0.0a64.dist-info/RECORD,,
|
101
|
-
pycityagent-2.0.0a64.dist-info/LICENSE,sha256=n2HPXiupinpyHMnIkbCf3OTYd3KMqbmldu1e7av0CAU,1084
|
102
|
-
pycityagent-2.0.0a64.dist-info/WHEEL,sha256=md3JO_ifs5j508p3TDNMgtQVtnQblpGEt_Wo4W56l8Y,107
|
103
|
-
pycityagent-2.0.0a64.dist-info/entry_points.txt,sha256=BZcne49AAIFv-hawxGnPbblea7X3MtAtoPyDX8L4OC4,132
|
104
|
-
pycityagent-2.0.0a64.dist-info/top_level.txt,sha256=yOmeu6cSXmiUtScu53a3s0p7BGtLMaV0aff83EHCTic,43
|
105
|
-
pycityagent-2.0.0a64.dist-info/METADATA,sha256=Y5jk3ZxwATSr1K6QdN8hLQV-XUhcMNtPRJiXNDdniC4,9110
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|