pycityagent 2.0.0a52__cp310-cp310-macosx_11_0_arm64.whl → 2.0.0a53__cp310-cp310-macosx_11_0_arm64.whl
Sign up to get free protection for your applications and to get access to all the features.
- pycityagent/agent/agent.py +48 -62
- pycityagent/agent/agent_base.py +66 -53
- pycityagent/cityagent/bankagent.py +5 -7
- pycityagent/cityagent/blocks/__init__.py +0 -2
- pycityagent/cityagent/blocks/cognition_block.py +149 -172
- pycityagent/cityagent/blocks/economy_block.py +90 -129
- pycityagent/cityagent/blocks/mobility_block.py +56 -29
- pycityagent/cityagent/blocks/needs_block.py +163 -145
- pycityagent/cityagent/blocks/other_block.py +17 -9
- pycityagent/cityagent/blocks/plan_block.py +44 -56
- pycityagent/cityagent/blocks/social_block.py +70 -51
- pycityagent/cityagent/blocks/utils.py +2 -0
- pycityagent/cityagent/firmagent.py +6 -7
- pycityagent/cityagent/governmentagent.py +7 -9
- pycityagent/cityagent/memory_config.py +48 -48
- pycityagent/cityagent/nbsagent.py +6 -29
- pycityagent/cityagent/societyagent.py +204 -119
- pycityagent/environment/sim/client.py +10 -1
- pycityagent/environment/sim/clock_service.py +2 -2
- pycityagent/environment/sim/pause_service.py +61 -0
- pycityagent/environment/simulator.py +17 -12
- pycityagent/llm/embeddings.py +0 -24
- pycityagent/memory/faiss_query.py +29 -26
- pycityagent/memory/memory.py +720 -272
- pycityagent/pycityagent-sim +0 -0
- pycityagent/simulation/agentgroup.py +92 -99
- pycityagent/simulation/simulation.py +115 -40
- pycityagent/tools/tool.py +7 -9
- pycityagent/workflow/block.py +11 -4
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/METADATA +1 -1
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/RECORD +35 -35
- pycityagent/cityagent/blocks/time_block.py +0 -116
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/top_level.txt +0 -0
@@ -1,54 +1,54 @@
|
|
1
1
|
import json
|
2
2
|
from pycityagent import Simulator
|
3
|
-
from pycityagent.memory
|
4
|
-
from pycityagent.llm
|
3
|
+
from pycityagent.memory import Memory
|
4
|
+
from pycityagent.llm import LLM
|
5
5
|
from pycityagent.workflow.block import Block
|
6
6
|
from pycityagent.workflow.prompt import FormatPrompt
|
7
7
|
import logging
|
8
8
|
logger = logging.getLogger("pycityagent")
|
9
9
|
|
10
|
-
INITIAL_NEEDS_PROMPT = """You are an intelligent agent
|
10
|
+
INITIAL_NEEDS_PROMPT = """You are an intelligent agent satisfaction initialization system. Based on the profile information below, please help initialize the agent's satisfaction levels and related parameters.
|
11
11
|
|
12
12
|
Profile Information:
|
13
13
|
- Gender: {gender}
|
14
|
-
- Education: {education}
|
14
|
+
- Education Level: {education}
|
15
15
|
- Consumption Level: {consumption}
|
16
16
|
- Occupation: {occupation}
|
17
17
|
- Age: {age}
|
18
18
|
- Monthly Income: {income}
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
|
20
|
+
Current Emotion: {emotion_types}
|
21
|
+
Current Thought: {thought}
|
22
22
|
|
23
23
|
Current Time: {now_time}
|
24
24
|
|
25
|
-
Please initialize the agent's
|
25
|
+
Please initialize the agent's satisfaction levels and parameters based on the profile above. Return the values in JSON format with the following structure:
|
26
26
|
|
27
|
-
1. Current
|
28
|
-
-
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
27
|
+
1. Current satisfaction levels (0-1 float values, lower means less satisfied):
|
28
|
+
- hunger_satisfaction: Hunger satisfaction level (Normally, the agent will be less satisfied with hunger at eating time)
|
29
|
+
- energy_satisfaction: Energy satisfaction level (Normally, at night, the agent will be less satisfied with energy)
|
30
|
+
- safety_satisfaction: Safety satisfaction level (Normally, the agent will be more satisfied with safety when they have high income and currency)
|
31
|
+
- social_satisfaction: Social satisfaction level
|
32
32
|
|
33
33
|
2. Natural decay rates per hour (0-1 float values):
|
34
34
|
- alpha_H: Hunger satisfaction decay rate
|
35
|
-
- alpha_D:
|
35
|
+
- alpha_D: Energy satisfaction decay rate
|
36
36
|
- alpha_P: Safety satisfaction decay rate
|
37
37
|
- alpha_C: Social satisfaction decay rate
|
38
38
|
|
39
39
|
3. Threshold values (0-1 float values, below which the agent will try to improve):
|
40
40
|
- T_H: Hunger satisfaction threshold
|
41
|
-
- T_D:
|
42
|
-
- T_S: Safety threshold
|
43
|
-
- T_C: Social threshold
|
41
|
+
- T_D: Energy satisfaction threshold
|
42
|
+
- T_S: Safety satisfaction threshold
|
43
|
+
- T_C: Social satisfaction threshold
|
44
44
|
|
45
45
|
Example response format (Do not return any other text):
|
46
46
|
{{
|
47
|
-
"
|
48
|
-
"
|
49
|
-
"
|
50
|
-
"
|
51
|
-
"
|
47
|
+
"current_satisfaction": {{
|
48
|
+
"hunger_satisfaction": 0.8,
|
49
|
+
"energy_satisfaction": 0.7,
|
50
|
+
"safety_satisfaction": 0.9,
|
51
|
+
"social_satisfaction": 0.6
|
52
52
|
}},
|
53
53
|
"decay_rates": {{
|
54
54
|
"alpha_H": 0.2,
|
@@ -68,15 +68,22 @@ Example response format (Do not return any other text):
|
|
68
68
|
EVALUATION_PROMPT = """You are an evaluation system for an intelligent agent. The agent has performed the following actions to satisfy the {current_need} need:
|
69
69
|
|
70
70
|
Goal: {plan_target}
|
71
|
-
Execution
|
71
|
+
Execution situation:
|
72
72
|
{evaluation_results}
|
73
73
|
|
74
|
-
Current
|
74
|
+
Current satisfaction:
|
75
|
+
- hunger_satisfaction: {hunger_satisfaction}
|
76
|
+
- energy_satisfaction: {energy_satisfaction}
|
77
|
+
- safety_satisfaction: {safety_satisfaction}
|
78
|
+
- social_satisfaction: {social_satisfaction}
|
79
|
+
|
80
|
+
Current Emotion: {emotion_types}
|
81
|
+
Current Thought: {thought}
|
75
82
|
|
76
|
-
Please evaluate and adjust the value of {current_need}
|
83
|
+
Please evaluate and adjust the value of {current_need} satisfaction based on the execution results above.
|
77
84
|
|
78
85
|
Notes:
|
79
|
-
1.
|
86
|
+
1. Satisfaction values range from 0-1, where:
|
80
87
|
- 1 means the need is fully satisfied
|
81
88
|
- 0 means the need is completely unsatisfied
|
82
89
|
- Higher values indicate greater need satisfaction
|
@@ -85,13 +92,13 @@ Notes:
|
|
85
92
|
|
86
93
|
Example response format for specific need (hungry here) adjustment (Do not return any other text):
|
87
94
|
{{
|
88
|
-
"
|
95
|
+
"hunger_satisfaction": new_need_value
|
89
96
|
}}
|
90
97
|
|
91
98
|
Example response format for whatever need adjustment (Do not return any other text):
|
92
99
|
{{
|
93
|
-
"
|
94
|
-
"
|
100
|
+
"safety_satisfaction": new_safe_value,
|
101
|
+
"social_satisfaction": new_social_value
|
95
102
|
}}
|
96
103
|
"""
|
97
104
|
|
@@ -100,50 +107,63 @@ class NeedsBlock(Block):
|
|
100
107
|
Generate needs
|
101
108
|
"""
|
102
109
|
def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
|
103
|
-
super().__init__("NeedsBlock", llm, memory, simulator)
|
110
|
+
super().__init__("NeedsBlock", llm=llm, memory=memory, simulator=simulator)
|
104
111
|
self.evaluation_prompt = FormatPrompt(EVALUATION_PROMPT)
|
105
112
|
self.initial_prompt = FormatPrompt(INITIAL_NEEDS_PROMPT)
|
113
|
+
self.need_work = True
|
114
|
+
self.now_day = -1
|
106
115
|
self.last_evaluation_time = None
|
107
116
|
self.trigger_time = 0
|
108
117
|
self.token_consumption = 0
|
109
118
|
self.initialized = False
|
110
|
-
self.alpha_H, self.alpha_D, self.alpha_P, self.alpha_C = 0.2, 0.08, 0.05, 0.03 #
|
111
|
-
self.T_H, self.T_D, self.T_P, self.T_C = 0.4, 0.2, 0.2, 0.2 #
|
119
|
+
self.alpha_H, self.alpha_D, self.alpha_P, self.alpha_C = 0.2, 0.08, 0.05, 0.03 # Hunger decay rate, Energy decay rate, Safety decay rate, Social decay rate
|
120
|
+
self.T_H, self.T_D, self.T_P, self.T_C = 0.4, 0.2, 0.2, 0.2 # Hunger threshold, Energy threshold, Safety threshold, Social threshold
|
112
121
|
|
113
122
|
async def initialize(self):
|
114
|
-
self.
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
age=await self.memory.get("age"),
|
120
|
-
income=await self.memory.get("income"),
|
121
|
-
race=await self.memory.get("race"),
|
122
|
-
religion=await self.memory.get("religion"),
|
123
|
-
skill=await self.memory.get("skill"),
|
124
|
-
now_time=await self.simulator.get_time(format_time=True)
|
125
|
-
)
|
126
|
-
response = await self.llm.atext_request(
|
127
|
-
self.initial_prompt.to_dialog()
|
128
|
-
)
|
129
|
-
response = self.clean_json_response(response)
|
130
|
-
logger.info(f"Needs Initialization: {response}")
|
131
|
-
try:
|
132
|
-
needs = json.loads(response)
|
133
|
-
await self.memory.update("needs", needs["current_needs"])
|
134
|
-
self.alpha_H, self.alpha_D, self.alpha_P, self.alpha_C = needs["decay_rates"].values()
|
135
|
-
self.T_H, self.T_D, self.T_P, self.T_C = needs["thresholds"].values()
|
136
|
-
except json.JSONDecodeError:
|
137
|
-
logger.warning(f"初始化响应不是有效的JSON格式: {response}")
|
138
|
-
self.initialized = True
|
139
|
-
|
140
|
-
async def forward(self):
|
141
|
-
self.trigger_time += 1
|
142
|
-
consumption_start = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
|
123
|
+
day = await self.simulator.get_simulator_day()
|
124
|
+
if day != self.now_day:
|
125
|
+
self.now_day = day
|
126
|
+
self.need_work = True
|
127
|
+
self.initialized = False
|
143
128
|
|
144
129
|
if not self.initialized:
|
145
|
-
|
130
|
+
self.initial_prompt.format(
|
131
|
+
gender=await self.memory.status.get("gender"),
|
132
|
+
education=await self.memory.status.get("education"),
|
133
|
+
consumption=await self.memory.status.get("consumption"),
|
134
|
+
occupation=await self.memory.status.get("occupation"),
|
135
|
+
age=await self.memory.status.get("age"),
|
136
|
+
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
|
+
now_time=await self.simulator.get_time(format_time=True)
|
140
|
+
)
|
141
|
+
response = await self.llm.atext_request(
|
142
|
+
self.initial_prompt.to_dialog()
|
143
|
+
)
|
144
|
+
response = self.clean_json_response(response)
|
145
|
+
try:
|
146
|
+
satisfaction = json.loads(response)
|
147
|
+
satisfactions = satisfaction["current_satisfaction"]
|
148
|
+
await self.memory.status.update("hunger_satisfaction", satisfactions["hunger_satisfaction"])
|
149
|
+
await self.memory.status.update("energy_satisfaction", satisfactions["energy_satisfaction"])
|
150
|
+
await self.memory.status.update("safety_satisfaction", satisfactions["safety_satisfaction"])
|
151
|
+
await self.memory.status.update("social_satisfaction", satisfactions["social_satisfaction"])
|
152
|
+
self.alpha_H, self.alpha_D, self.alpha_P, self.alpha_C = satisfaction["decay_rates"].values()
|
153
|
+
self.T_H, self.T_D, self.T_P, self.T_C = satisfaction["thresholds"].values()
|
154
|
+
except json.JSONDecodeError:
|
155
|
+
logger.warning(f"初始化响应不是有效的JSON格式: {response}")
|
156
|
+
|
157
|
+
current_plan = await self.memory.status.get("current_plan")
|
158
|
+
history = await self.memory.status.get("plan_history")
|
159
|
+
history.append(current_plan)
|
160
|
+
await self.memory.status.update("plan_history", history)
|
161
|
+
await self.memory.status.update("current_plan", None)
|
162
|
+
await self.memory.status.update("current_step", {"intention": "", "type": ""})
|
163
|
+
await self.memory.status.update("execution_context", {})
|
164
|
+
self.initialized = True
|
146
165
|
|
166
|
+
async def time_decay(self):
|
147
167
|
# 计算时间差
|
148
168
|
time_now = await self.simulator.get_time()
|
149
169
|
if self.last_evaluation_time is None:
|
@@ -153,103 +173,96 @@ class NeedsBlock(Block):
|
|
153
173
|
time_diff = (time_now - self.last_evaluation_time)/3600
|
154
174
|
self.last_evaluation_time = time_now
|
155
175
|
|
156
|
-
#
|
157
|
-
|
176
|
+
# 获取当前需求的满意度
|
177
|
+
hunger_satisfaction = await self.memory.status.get("hunger_satisfaction")
|
178
|
+
energy_satisfaction = await self.memory.status.get("energy_satisfaction")
|
179
|
+
safety_satisfaction = await self.memory.status.get("safety_satisfaction")
|
180
|
+
social_satisfaction = await self.memory.status.get("social_satisfaction")
|
158
181
|
|
159
182
|
# 根据经过的时间计算饥饿与疲劳的衰减
|
160
183
|
hungry_decay = self.alpha_H * time_diff
|
161
|
-
|
162
|
-
|
184
|
+
energy_decay = self.alpha_D * time_diff
|
185
|
+
safety_decay = self.alpha_P * time_diff
|
163
186
|
social_decay = self.alpha_C * time_diff
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
await self.memory.update("
|
187
|
+
hunger_satisfaction = max(0, hunger_satisfaction - hungry_decay)
|
188
|
+
energy_satisfaction = max(0, energy_satisfaction - energy_decay)
|
189
|
+
safety_satisfaction = max(0, safety_satisfaction - safety_decay)
|
190
|
+
social_satisfaction = max(0, social_satisfaction - social_decay)
|
191
|
+
|
192
|
+
# 更新满意度
|
193
|
+
await self.memory.status.update("hunger_satisfaction", hunger_satisfaction)
|
194
|
+
await self.memory.status.update("energy_satisfaction", energy_satisfaction)
|
195
|
+
await self.memory.status.update("safety_satisfaction", safety_satisfaction)
|
196
|
+
await self.memory.status.update("social_satisfaction", social_satisfaction)
|
174
197
|
|
198
|
+
async def update_when_plan_completed(self):
|
175
199
|
# 判断当前是否有正在执行的plan
|
176
|
-
current_plan = await self.memory.get("current_plan")
|
177
|
-
if current_plan and current_plan.get("completed"):
|
200
|
+
current_plan = await self.memory.status.get("current_plan")
|
201
|
+
if current_plan and (current_plan.get("completed") or current_plan.get("failed")):
|
178
202
|
# 评估计划执行过程并调整需求
|
179
203
|
await self.evaluate_and_adjust_needs(current_plan)
|
180
204
|
# 将完成的计划添加到历史记录
|
181
|
-
history = await self.memory.get("plan_history")
|
205
|
+
history = await self.memory.status.get("plan_history")
|
182
206
|
history.append(current_plan)
|
183
|
-
await self.memory.update("plan_history", history)
|
184
|
-
await self.memory.update("current_plan", None)
|
185
|
-
await self.memory.update("current_step", {"intention": "", "type": ""})
|
186
|
-
await self.memory.update("execution_context", {})
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
logger.info(f"Time elapsed: {time_diff:.2f} hours")
|
194
|
-
logger.info(f"Current state - Hungry: {hungry:.2f}, Tired: {tired:.2f}, Safe: {safe:.2f}, Social: {social:.2f}")
|
207
|
+
await self.memory.status.update("plan_history", history)
|
208
|
+
await self.memory.status.update("current_plan", None)
|
209
|
+
await self.memory.status.update("current_step", {"intention": "", "type": ""})
|
210
|
+
await self.memory.status.update("execution_context", {})
|
211
|
+
|
212
|
+
async def determine_current_need(self):
|
213
|
+
hunger_satisfaction = await self.memory.status.get("hunger_satisfaction")
|
214
|
+
energy_satisfaction = await self.memory.status.get("energy_satisfaction")
|
215
|
+
safety_satisfaction = await self.memory.status.get("safety_satisfaction")
|
216
|
+
social_satisfaction = await self.memory.status.get("social_satisfaction")
|
195
217
|
|
196
218
|
# 如果需要调整需求,更新当前需求
|
197
219
|
# 调整方案为,如果当前的需求为空,或有更高级的需求出现,则调整需求
|
198
|
-
|
220
|
+
current_plan = await self.memory.status.get("current_plan")
|
221
|
+
current_need = await self.memory.status.get("current_need")
|
199
222
|
|
200
223
|
# 当前没有计划或计划已执行完毕,获取所有需求值,按优先级检查各需求是否达到阈值
|
201
224
|
if not current_plan or current_plan.get("completed"):
|
202
225
|
# 按优先级顺序检查需求
|
203
|
-
if
|
204
|
-
await self.memory.update("current_need", "hungry")
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
elif
|
210
|
-
await self.memory.update("current_need", "
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
logger.info("Needs adjusted: Social")
|
226
|
+
if hunger_satisfaction <= self.T_H:
|
227
|
+
await self.memory.status.update("current_need", "hungry")
|
228
|
+
elif energy_satisfaction <= self.T_D:
|
229
|
+
await self.memory.status.update("current_need", "tired")
|
230
|
+
elif safety_satisfaction <= self.T_P:
|
231
|
+
await self.memory.status.update("current_need", "safe")
|
232
|
+
elif social_satisfaction <= self.T_C:
|
233
|
+
await self.memory.status.update("current_need", "social")
|
234
|
+
elif self.need_work:
|
235
|
+
await self.memory.status.update("current_need", "safe")
|
236
|
+
self.need_work = False
|
215
237
|
else:
|
216
|
-
await self.memory.update("current_need", "whatever")
|
217
|
-
logger.info("Needs adjusted: Whatever")
|
238
|
+
await self.memory.status.update("current_need", "whatever")
|
218
239
|
else:
|
219
240
|
# 有正在执行的计划时,只在出现更高优先级需求时调整
|
220
241
|
needs_changed = False
|
221
242
|
new_need = None
|
222
|
-
if
|
243
|
+
if hunger_satisfaction <= self.T_H and current_need not in ["hungry", "tired"]:
|
223
244
|
new_need = "hungry"
|
224
|
-
logger.info("Higher priority need detected, adjusted to: Hungry")
|
225
245
|
needs_changed = True
|
226
|
-
elif
|
246
|
+
elif energy_satisfaction <= self.T_D and current_need not in ["hungry", "tired"]:
|
227
247
|
new_need = "tired"
|
228
|
-
logger.info("Higher priority need detected, adjusted to: Tired")
|
229
248
|
needs_changed = True
|
230
|
-
elif
|
249
|
+
elif safety_satisfaction <= self.T_P and current_need not in ["hungry", "tired", "safe"]:
|
231
250
|
new_need = "safe"
|
232
|
-
logger.info("Higher priority need detected, adjusted to: Safe")
|
233
251
|
needs_changed = True
|
234
|
-
elif
|
252
|
+
elif social_satisfaction <= self.T_C and current_need not in ["hungry", "tired", "safe", "social"]:
|
235
253
|
new_need = "social"
|
236
|
-
logger.info("Higher priority need detected, adjusted to: Social")
|
237
254
|
needs_changed = True
|
238
255
|
|
239
256
|
# 如果需求发生变化,中断当前计划
|
240
257
|
if needs_changed:
|
241
258
|
await self.evaluate_and_adjust_needs(current_plan)
|
242
|
-
history = await self.memory.get("plan_history")
|
259
|
+
history = await self.memory.status.get("plan_history")
|
243
260
|
history.append(current_plan)
|
244
|
-
await self.memory.update("current_need", new_need)
|
245
|
-
await self.memory.update("plan_history", history)
|
246
|
-
await self.memory.update("current_plan", None)
|
247
|
-
await self.memory.update("current_step", {"intention": "", "type": ""})
|
248
|
-
await self.memory.update("execution_context", {})
|
249
|
-
logger.info("----Agent's plan has been interrupted due to need change----")
|
250
|
-
|
251
|
-
consumption_end = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
|
252
|
-
self.token_consumption += consumption_end - consumption_start
|
261
|
+
await self.memory.status.update("current_need", new_need)
|
262
|
+
await self.memory.status.update("plan_history", history)
|
263
|
+
await self.memory.status.update("current_plan", None)
|
264
|
+
await self.memory.status.update("current_step", {"intention": "", "type": ""})
|
265
|
+
await self.memory.status.update("execution_context", {})
|
253
266
|
|
254
267
|
async def evaluate_and_adjust_needs(self, completed_plan):
|
255
268
|
# 获取执行的计划和评估结果
|
@@ -258,41 +271,34 @@ class NeedsBlock(Block):
|
|
258
271
|
if 'evaluation' in step['evaluation']:
|
259
272
|
eva_ = step['evaluation']['evaluation']
|
260
273
|
else:
|
261
|
-
eva_ = 'Plan
|
274
|
+
eva_ = 'Plan failed, not completed'
|
262
275
|
evaluation_results.append(f"- {step['intention']} ({step['type']}): {eva_}")
|
263
276
|
evaluation_results = "\n".join(evaluation_results)
|
264
277
|
|
265
278
|
# 使用 LLM 进行评估
|
266
|
-
current_need = await self.memory.get("current_need")
|
279
|
+
current_need = await self.memory.status.get("current_need")
|
267
280
|
self.evaluation_prompt.format(
|
268
281
|
current_need=current_need,
|
269
282
|
plan_target=completed_plan["target"],
|
270
283
|
evaluation_results=evaluation_results,
|
271
|
-
|
284
|
+
hunger_satisfaction=await self.memory.status.get("hunger_satisfaction"),
|
285
|
+
energy_satisfaction=await self.memory.status.get("energy_satisfaction"),
|
286
|
+
safety_satisfaction=await self.memory.status.get("safety_satisfaction"),
|
287
|
+
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")
|
272
290
|
)
|
273
291
|
|
274
292
|
response = await self.llm.atext_request(
|
275
293
|
self.evaluation_prompt.to_dialog()
|
276
294
|
)
|
277
295
|
|
278
|
-
try:
|
279
|
-
|
280
|
-
logger.info(f"Evaluating need: {current_need}")
|
281
|
-
logger.info(f"Executing plan: {completed_plan['target']}")
|
282
|
-
logger.info("Execution results:")
|
283
|
-
logger.info(evaluation_results)
|
284
|
-
|
285
|
-
new_needs = json.loads(self.clean_json_response(response)) # type: ignore
|
296
|
+
try:
|
297
|
+
new_satisfaction = json.loads(self.clean_json_response(response)) # type: ignore
|
286
298
|
# 更新所有需求的数值
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
if need_type in needs:
|
291
|
-
old_value = needs[need_type]
|
292
|
-
needs[need_type] = new_value
|
293
|
-
logger.info(f"- {need_type}: {old_value} -> {new_value}")
|
294
|
-
await self.memory.update("needs", needs)
|
295
|
-
logger.info("===============\n")
|
299
|
+
for need_type, new_value in new_satisfaction.items():
|
300
|
+
if need_type in ['hunger_satisfaction', 'energy_satisfaction', 'safety_satisfaction', 'social_satisfaction']:
|
301
|
+
await self.memory.status.update(need_type, new_value)
|
296
302
|
except json.JSONDecodeError:
|
297
303
|
logger.warning(f"Evaluation response is not a valid JSON format: {response}")
|
298
304
|
except Exception as e:
|
@@ -302,4 +308,16 @@ class NeedsBlock(Block):
|
|
302
308
|
def clean_json_response(self, response: str) -> str:
|
303
309
|
"""清理LLM响应中的特殊字符"""
|
304
310
|
response = response.replace('```json', '').replace('```', '')
|
305
|
-
return response.strip()
|
311
|
+
return response.strip()
|
312
|
+
|
313
|
+
async def forward(self):
|
314
|
+
await self.initialize()
|
315
|
+
|
316
|
+
# satisfaction decay with time
|
317
|
+
await self.time_decay()
|
318
|
+
|
319
|
+
# update when plan completed
|
320
|
+
await self.update_when_plan_completed()
|
321
|
+
|
322
|
+
# determine current need
|
323
|
+
await self.determine_current_need()
|
@@ -12,30 +12,34 @@ logger = logging.getLogger("pycityagent")
|
|
12
12
|
|
13
13
|
class SleepBlock(Block):
|
14
14
|
def __init__(self, llm: LLM, memory: Memory):
|
15
|
-
super().__init__("SleepBlock", llm, memory)
|
15
|
+
super().__init__("SleepBlock", llm=llm, memory=memory)
|
16
16
|
self.description = "Sleep"
|
17
17
|
self.guidance_prompt = FormatPrompt(template=TIME_ESTIMATE_PROMPT)
|
18
18
|
|
19
19
|
async def forward(self, step, context):
|
20
20
|
self.guidance_prompt.format(
|
21
21
|
plan=context['plan'],
|
22
|
-
intention=step['intention']
|
22
|
+
intention=step['intention'],
|
23
|
+
emotion_types=await self.memory.status.get("emotion_types"),
|
23
24
|
)
|
24
25
|
result = await self.llm.atext_request(self.guidance_prompt.to_dialog())
|
25
26
|
result = clean_json_response(result)
|
27
|
+
node_id = await self.memory.stream.add_other(description=f"I slept")
|
26
28
|
try:
|
27
29
|
result = json.loads(result)
|
28
30
|
return {
|
29
31
|
'success': True,
|
30
32
|
'evaluation': f'Sleep: {step["intention"]}',
|
31
|
-
'consumed_time': result['time']
|
33
|
+
'consumed_time': result['time'],
|
34
|
+
'node_id': node_id
|
32
35
|
}
|
33
36
|
except Exception as e:
|
34
37
|
logger.warning(f"解析时间评估响应时发生错误: {str(e)}, 原始结果: {result}")
|
35
38
|
return {
|
36
39
|
'success': True,
|
37
40
|
'evaluation': f'Sleep: {step["intention"]}',
|
38
|
-
'consumed_time': random.randint(1, 10)*60
|
41
|
+
'consumed_time': random.randint(1, 10)*60,
|
42
|
+
'node_id': node_id
|
39
43
|
}
|
40
44
|
|
41
45
|
class OtherNoneBlock(Block):
|
@@ -44,30 +48,34 @@ class OtherNoneBlock(Block):
|
|
44
48
|
OtherNoneBlock
|
45
49
|
"""
|
46
50
|
def __init__(self, llm: LLM, memory: Memory):
|
47
|
-
super().__init__("OtherNoneBlock", llm, memory)
|
51
|
+
super().__init__("OtherNoneBlock", llm=llm, memory=memory)
|
48
52
|
self.description = "Used to handle other cases"
|
49
53
|
self.guidance_prompt = FormatPrompt(template=TIME_ESTIMATE_PROMPT)
|
50
54
|
|
51
55
|
async def forward(self, step, context):
|
52
56
|
self.guidance_prompt.format(
|
53
57
|
plan=context['plan'],
|
54
|
-
intention=step['intention']
|
58
|
+
intention=step['intention'],
|
59
|
+
emotion_types=await self.memory.status.get("emotion_types"),
|
55
60
|
)
|
56
61
|
result = await self.llm.atext_request(self.guidance_prompt.to_dialog())
|
57
62
|
result = clean_json_response(result)
|
63
|
+
node_id = await self.memory.stream.add_other(description=f"I {step['intention']}")
|
58
64
|
try:
|
59
65
|
result = json.loads(result)
|
60
66
|
return {
|
61
67
|
'success': True,
|
62
68
|
'evaluation': f'Finished executing {step["intention"]}',
|
63
|
-
'consumed_time': result['time']
|
69
|
+
'consumed_time': result['time'],
|
70
|
+
'node_id': node_id
|
64
71
|
}
|
65
72
|
except Exception as e:
|
66
73
|
logger.warning(f"解析时间评估响应时发生错误: {str(e)}, 原始结果: {result}")
|
67
74
|
return {
|
68
75
|
'success': True,
|
69
76
|
'evaluation': f'Finished executing {step["intention"]}',
|
70
|
-
'consumed_time': random.randint(1, 180)
|
77
|
+
'consumed_time': random.randint(1, 180),
|
78
|
+
'node_id': node_id
|
71
79
|
}
|
72
80
|
|
73
81
|
|
@@ -76,7 +84,7 @@ class OtherBlock(Block):
|
|
76
84
|
other_none_block: OtherNoneBlock
|
77
85
|
|
78
86
|
def __init__(self, llm: LLM, memory: Memory):
|
79
|
-
super().__init__("OtherBlock", llm, memory)
|
87
|
+
super().__init__("OtherBlock", llm=llm, memory=memory)
|
80
88
|
# 初始化所有块
|
81
89
|
self.sleep_block = SleepBlock(llm, memory)
|
82
90
|
self.other_none_block = OtherNoneBlock(llm, memory)
|