88from mineland import Action
99
1010from .base_agent import BaseAgent
11+ from src .plugins .minecraft .state .analyzers import StateAnalyzer
1112
1213
1314class SimpleAgent (BaseAgent ):
@@ -23,33 +24,7 @@ def __init__(self):
2324 self .max_memory_size : int = 10
2425 self .logger = logging .getLogger (__name__ )
2526 self ._is_initialized = False
26-
27- # API验证集合
28- self .valid_bot_methods = {
29- "chat" ,
30- "look" ,
31- "lookAt" ,
32- "dig" ,
33- "placeBlock" ,
34- "activateBlock" ,
35- "setControlState" ,
36- "clearControlStates" ,
37- "equip" ,
38- "unequip" ,
39- "toss" ,
40- "tossStack" ,
41- "consume" ,
42- "activateItem" ,
43- "attack" ,
44- "mount" ,
45- "dismount" ,
46- "setQuickBarSlot" ,
47- "waitForTicks" ,
48- "craft" ,
49- "sleep" ,
50- "wake" ,
51- "respawn" ,
52- }
27+ self .state_analyzer : Optional [StateAnalyzer ] = None
5328
5429 async def initialize (self , config : Dict [str , Any ]) -> None :
5530 """初始化简单智能体"""
@@ -105,6 +80,13 @@ async def run(
10580 raise RuntimeError ("简单智能体未初始化" )
10681
10782 try :
83+ # 初始化或更新状态分析器
84+ if obs :
85+ if self .state_analyzer is None :
86+ self .state_analyzer = StateAnalyzer (obs = obs , config = self .config )
87+ else :
88+ self .state_analyzer .set_observation (obs )
89+
10890 # 构建上下文
10991 context = self ._build_context (obs , code_info , done , task_info , maicore_command )
11092
@@ -125,7 +107,7 @@ async def run(
125107
126108 except Exception as e :
127109 self .logger .error (f"简单智能体执行错误: { e } " )
128- return Action (type = Action .NEW , code = "// 等待下一步 " )
110+ return Action (type = Action .RESUME , code = "" )
129111
130112 def _validate_and_fix_action (self , action_code : str ) -> str :
131113 """验证并修复动作代码"""
@@ -158,99 +140,38 @@ def _build_context(
158140 task_info : Optional [Dict ],
159141 maicore_command : Optional [str ],
160142 ) -> str :
161- """构建决策上下文 - 集成状态分析器的环境感知 """
143+ """构建决策上下文 - 使用状态分析器获取环境感知 """
162144 context_parts = []
163145
164146 # === 环境感知部分 (优先级最高) ===
165- if obs :
166- # 使用状态分析器提供的环境分析
167- if "environment_analysis" in obs :
168- env_analysis = obs ["environment_analysis" ]
169- if "summary" in env_analysis and env_analysis ["summary" ]:
170- context_parts .append ("=== 环境分析 ===" )
171- context_parts .extend (env_analysis ["summary" ])
172- context_parts .append ("" ) # 空行分隔
173-
174- # 详细的环境信息
175- if "detailed_environment" in obs :
176- detailed_env = obs ["detailed_environment" ]
177-
178- # 生命状态
179- if "life_stats" in detailed_env and detailed_env ["life_stats" ]:
180- context_parts .append ("=== 生命状态 ===" )
181- context_parts .extend (detailed_env ["life_stats" ])
182- context_parts .append ("" )
183-
184- # 周围方块环境
185- if "environment" in detailed_env and detailed_env ["environment" ]:
186- context_parts .append ("=== 周围环境 ===" )
187- context_parts .extend (detailed_env ["environment" ])
188- context_parts .append ("" )
189-
190- # 位置和方向
191- if "position" in detailed_env and detailed_env ["position" ]:
192- context_parts .append ("=== 位置信息 ===" )
193- context_parts .extend (detailed_env ["position" ])
194- if "direction" in detailed_env and detailed_env ["direction" ]:
195- context_parts .extend (detailed_env ["direction" ])
196- context_parts .append ("" )
197-
198- # 移动障碍
199- if "collision" in detailed_env and detailed_env ["collision" ]:
200- context_parts .append ("=== 移动状况 ===" )
201- context_parts .extend (detailed_env ["collision" ])
202- if "facing_wall" in detailed_env and detailed_env ["facing_wall" ]:
203- context_parts .extend (detailed_env ["facing_wall" ])
204- context_parts .append ("" )
205-
206- # 装备和物品
207- if "equipment" in detailed_env and detailed_env ["equipment" ]:
208- context_parts .append ("=== 装备状态 ===" )
209- context_parts .extend (detailed_env ["equipment" ])
210- context_parts .append ("" )
211-
212- if "inventory" in detailed_env and detailed_env ["inventory" ]:
213- context_parts .append ("=== 物品栏 ===" )
214- context_parts .extend (detailed_env ["inventory" ])
215- context_parts .append ("" )
216-
217- # 时间和天气
218- if "time" in detailed_env and detailed_env ["time" ]:
219- context_parts .append ("=== 游戏时间 ===" )
220- context_parts .extend (detailed_env ["time" ])
221- if "weather" in detailed_env and detailed_env ["weather" ]:
222- context_parts .extend (detailed_env ["weather" ])
223- context_parts .append ("" )
224-
225- # 如果没有状态分析器数据,使用原始观察数据
226- if not any (key in obs for key in ["environment_analysis" , "detailed_environment" ]):
227- # 基础状态信息
228- health = obs .get ("health" , "未知" )
229- food = obs .get ("food" , "未知" )
230- position = obs .get ("position" , "未知" )
231- if health != "未知" or food != "未知" or position != "未知" :
232- context_parts .append (f"=== 基础状态 ===" )
233- context_parts .append (f"生命值: { health } , 饥饿值: { food } , 位置: { position } " )
234- context_parts .append ("" )
147+ if obs and self .state_analyzer :
148+ # 使用状态分析器提供的详细环境分析
149+ analysis_result = self .state_analyzer .analyze_all ()
150+ if isinstance (analysis_result , list ):
151+ context_parts .extend (analysis_result )
152+ else :
153+ context_parts .append (str (analysis_result ))
235154
236155 # === 代码执行状态 ===
237156 if code_info :
238157 if code_info .get ("code_error" ):
239158 error_info = code_info ["code_error" ]
240- context_parts .append ("=== 执行错误 ===" )
241- context_parts .append (f"上次代码执行失败: { error_info .get ('error_message' , '未知错误' )} " )
242- context_parts .append ("" )
159+ context_parts .extend (
160+ (
161+ "=== 执行错误 ===" ,
162+ f"上次代码执行失败: { error_info .get ('error_message' , '未知错误' )} " ,
163+ "" ,
164+ )
165+ )
243166 elif code_info .get ("is_ready" ):
244- context_parts .append ("=== 执行状态 ===" )
245- context_parts .append ("代码执行完成,准备下一个动作" )
246- context_parts .append ("" )
247-
167+ context_parts .extend (("=== 执行状态 ===" , "代码执行完成,准备下一个动作" , "" ))
248168 # === 历史记忆 ===
249169 if self .memory :
250170 recent_memory = self .memory [- 2 :] # 最近2次记忆
251171 context_parts .append ("=== 最近动作 ===" )
252- for i , memory in enumerate (recent_memory , 1 ):
253- context_parts .append (f"{ i } . { memory .get ('action' , '未知动作' )} " )
172+ context_parts .extend (
173+ f"{ i } . { memory .get ('action' , '未知动作' )} " for i , memory in enumerate (recent_memory , 1 )
174+ )
254175 context_parts .append ("" )
255176
256177 # === MaiCore指令 (优先级最高) ===
@@ -273,16 +194,10 @@ def _build_context(
273194
274195 # === 任务信息 ===
275196 if task_info :
276- context_parts .append ("=== 任务信息 ===" )
277- context_parts .append (f"任务: { task_info } " )
278- context_parts .append ("" )
279-
197+ context_parts .extend (("=== 任务信息 ===" , f"任务: { task_info } " , "" ))
280198 # 当前目标
281199 if self .current_goal :
282- context_parts .append (f"=== 当前目标 ===" )
283- context_parts .append (f"目标: { self .current_goal } " )
284- context_parts .append ("" )
285-
200+ context_parts .extend (("=== 当前目标 ===" , f"目标: { self .current_goal } " , "" ))
286201 return "\n " .join (context_parts )
287202
288203 def _parse_maicore_command (self , command : str ) -> Optional [str ]:
@@ -307,18 +222,13 @@ def _parse_maicore_command(self, command: str) -> Optional[str]:
307222 self .logger .info (f"从MaiCore指令中提取到动作: { actions } " )
308223 return actions .strip ()
309224 except json .JSONDecodeError :
310- # 如果不是JSON格式,尝试用正则表达式提取actions字段
311- actions_match = re .search (r'"actions":\s*"([^"]+)"' , command_clean )
312- if actions_match :
225+ if actions_match := re .search (r'"actions":\s*"([^"]+)"' , command_clean ):
313226 actions = actions_match .group (1 )
314227 self .logger .info (f"通过正则表达式提取到动作: { actions } " )
315228 return actions
316229
317- # 尝试提取不带引号的actions
318- actions_match = re .search (r'"actions":\s*([^,}]+)' , command_clean )
319- if actions_match :
320- actions = actions_match .group (1 ).strip ().strip ('"' )
321- if actions :
230+ if actions_match := re .search (r'"actions":\s*([^,}]+)' , command_clean ):
231+ if actions := actions_match .group (1 ).strip ().strip ('"' ):
322232 self .logger .info (f"通过正则表达式提取到动作(无引号): { actions } " )
323233 return actions
324234
@@ -340,10 +250,7 @@ async def _llm_decision(self, context: str) -> str:
340250 messages = [SystemMessage (content = self ._get_system_prompt ()), HumanMessage (content = context )]
341251
342252 response = await self .llm .ainvoke (messages )
343- action_code = self ._parse_action_from_response (str (response .content ))
344-
345- return action_code
346-
253+ return self ._parse_action_from_response (str (response .content ))
347254 except Exception as e :
348255 self .logger .error (f"LLM决策错误: { e } " )
349256 return "// 等待"
@@ -386,92 +293,53 @@ def _rule_based_decision(self, obs: Dict, maicore_command: Optional[str]) -> str
386293
387294 def _get_system_prompt (self ) -> str :
388295 """获取系统提示 - 增强环境感知能力"""
389- return """你是一个Minecraft智能体,能够感知和分析周围环境。根据详细的环境分析信息和当前状态,生成合适的动作代码。
390-
391- ## 环境感知能力
392- 你会收到以下类型的环境分析信息:
393- - **环境分析**: 周围方块的分布、开阔程度、墙壁位置等
394- - **生命状态**: 生命值、饥饿值、氧气值等
395- - **位置信息**: 当前坐标、朝向、移动速度等
396- - **移动状况**: 是否碰撞、前方是否有墙等
397- - **装备状态**: 当前装备的工具和防具
398- - **物品栏**: 拥有的物品和数量
399- - **游戏时间**: 白天/夜晚、天气状况
400-
401- ## 动作指南
402- 根据环境分析信息做出智能决策:
403-
404- ### 移动决策
405- - 如果"前方有墙",考虑挖掘或转向
406- - 如果"处于开阔区域",可以自由移动探索
407- - 如果"处于封闭空间",注意寻找出口
408-
409- ### 挖掘决策
410- - 根据"周围方块"信息选择挖掘目标
411- - 如果看到有价值的矿物,优先挖掘
412- - 如果被困,挖掘脚下或上方的方块
413-
414- ### 生存决策
415- - 根据"生命状态"调整行动策略
416- - 生命值低时寻找食物或避开危险
417- - 夜晚时寻找安全的地方
418-
419- ## 正确的API使用
420- 使用以下正确的mineflayer API:
421-
422- ### 移动控制
423- ```javascript
424- // 移动
425- bot.setControlState("forward", true) // 前进
426- bot.setControlState("back", true) // 后退
427- bot.setControlState("left", true) // 左移
428- bot.setControlState("right", true) // 右移
429- bot.setControlState("jump", true) // 跳跃
430- bot.clearControlStates() // 停止所有移动
431-
432- // 转向
433- bot.look(bot.entity.yaw + Math.PI/2, bot.entity.pitch) // 右转90度
434- bot.look(bot.entity.yaw - Math.PI/2, bot.entity.pitch) // 左转90度
435- bot.look(bot.entity.yaw + Math.PI, bot.entity.pitch) // 转身180度
436- ```
437-
438- ### 方块操作
439- ```javascript
440- // 挖掘
441- bot.dig(bot.blockAt(bot.entity.position.offset(0, -1, 0))) // 挖脚下
442- bot.dig(bot.blockAt(bot.entity.position.offset(0, 1, 0))) // 挖上方
443- bot.dig(bot.blockAt(bot.entity.position.offset(0, 0, 1))) // 挖前方
444-
445- // 放置方块
446- bot.placeBlock(bot.blockAt(bot.entity.position.offset(0, -1, 0)), new Vec3(0, 1, 0))
447- ```
448-
449- ### 物品操作
450- ```javascript
451- // 装备物品
452- bot.equip(bot.inventory.slots[36], 'hand') // 装备到手中
453- bot.unequip('hand') // 卸下手中物品
454-
455- // 使用物品
456- bot.activateItem(false) // 右键使用物品
457- bot.consume() // 消耗物品(如食物)
458- ```
459-
460- ## 决策流程
461- 1. **分析环境**: 仔细阅读环境分析信息
462- 2. **评估状态**: 检查生命值、物品等状态
463- 3. **制定策略**: 根据环境和状态确定行动方案
464- 4. **选择动作**: 生成相应的API调用代码
465- 5. **确保语法**: 使用正确的JavaScript语法
296+ return """你是一个Minecraft智能体,任务是根据环境信息生成单行或多行的JavaScript动作代码。
297+
298+ ## 决策指南
299+ - **分析环境**: 你会收到关于生命、位置、周围方块、物品栏等的详细信息。
300+ - **生存**: 当生命值或饥饿值低时,优先寻找食物或避开危险。夜晚时寻找安全之处。
301+ - **移动**:
302+ - 前方有墙时,考虑转向或挖掘。
303+ - 在开阔地带可以自由探索。
304+ - 在水里时,使用 `swimToLand` 游到岸边。
305+ - **挖掘**:
306+ - 根据周围方块信息,挖掘有价值的矿物(如 `diamond_ore`)或必要的材料(如 `oak_log`)。
307+ - 被困时,尝试挖掘出路。
308+
309+ ## API参考
310+ **重要**: 只能使用下面列出的API。确保API名称和参数正确。
311+
312+ ### 基础
313+ - `bot.chat("消息")`: 发送聊天消息 (请使用中文)。
314+ - `// 注释`: 用于写注释或表示"等待"。
315+
316+ ### 移动
317+ - `bot.setControlState("状态", true/false)`: 设置移动状态。状态可以是 `forward`, `back`, `left`, `right`, `jump`, `sprint`。
318+ - `bot.clearControlStates()`: 停止所有移动。
319+ - `bot.look(yaw, pitch)`: 转向。示例:
320+ - `bot.look(bot.entity.yaw + Math.PI/2, bot.entity.pitch)`: 右转90度。
321+ - `bot.look(bot.entity.yaw - Math.PI/2, bot.entity.pitch)`: 左转90度。
322+ - `followPlayer(bot, "玩家名")`: 跟随玩家。
323+ - `swimToLand(bot)`: 游到最近的岸边。
324+
325+ ### 方块
326+ - `mineBlock(bot, "方块名", 数量)`: 挖掘并收集指定数量的方块。
327+ - **注意**: 方块名必须正确,例如挖铁矿石是 `iron_ore`,而不是 `raw_iron`。
328+ - `placeItem(bot, "物品名", position)`: 在指定位置放置方块。
329+
330+ ### 物品
331+ - `bot.equip(item, "位置")`: 装备物品到指定位置(如 'hand', 'head')。需要先在物品栏找到物品对象(item)。
332+ - `bot.unequip("位置")`: 卸下指定位置的装备。
333+ - `bot.activateItem(offhand)`: 使用手上的物品(`offhand`=false表示主手)。
334+ - `bot.consume()`: 消耗物品(例如吃食物)。
466335
467336## 输出格式
468- 直接返回JavaScript代码,可以多行,例如:
469- - `bot.setControlState("forward", true)`
470- - `bot.dig(bot.blockAt(bot.entity.position.offset(0, -1, 0)))`
471- - `bot.look(bot.entity.yaw + Math.PI/2, bot.entity.pitch)`
472- - `// 等待观察环境`
473-
474- 不要包含解释或其他文本,只返回代码。"""
337+ - **只返回代码**: 不要包含任何解释、markdown标记(```)或多余的文本。
338+ - **代码示例**:
339+ - `bot.setControlState("forward", true);`
340+ - `mineBlock(bot, "oak_log", 1);`
341+ - `// 正在观察...`
342+ """
475343
476344 def _parse_action_from_response (self , response : str ) -> str :
477345 """从LLM响应中解析动作代码"""
0 commit comments