From 8c8e28264f3a3077c63fc5c02e9fae91dd5c2120 Mon Sep 17 00:00:00 2001 From: Zihao Xu Date: Mon, 5 Jan 2026 01:25:52 -0800 Subject: [PATCH] fix: handle null action_params from LLM response LLM sometimes returns null instead of {} for action_params when an action doesn't require parameters (e.g., ["Cultivate", null]). This caused AttributeError when calling .items() on None. Changes: - Add defensive check in ai.py to convert null to {} - Update prompt to explicitly require {} instead of null --- src/classes/ai.py | 5 +++-- src/sim/simulator.py | 4 ++++ static/templates/ai.txt | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/classes/ai.py b/src/classes/ai.py index 3122259..8dc6431 100644 --- a/src/classes/ai.py +++ b/src/classes/ai.py @@ -87,9 +87,10 @@ class LLMAI(AI): for p in raw_pairs: if isinstance(p, list) and len(p) == 2: - pairs.append((p[0], p[1])) + # LLM 可能返回 null 作为 params,需要转为空字典。 + pairs.append((p[0], p[1] or {})) elif isinstance(p, dict) and "action_name" in p and "action_params" in p: - pairs.append((p["action_name"], p["action_params"])) + pairs.append((p["action_name"], p["action_params"] or {})) else: continue diff --git a/src/sim/simulator.py b/src/sim/simulator.py index dfada3b..94dd8c2 100644 --- a/src/sim/simulator.py +++ b/src/sim/simulator.py @@ -126,6 +126,10 @@ class Simulator: async def _phase_execute_actions(self): """ 执行阶段:推进当前动作,支持同月链式抢占即时结算,返回期间产生的事件。 + + TODO: 为单个角色的 tick_action() 添加 try-except 处理。 + 当前如果任一角色的动作执行抛出异常,整个 step() 会失败, + 导致 month_stamp 不会推进,游戏卡在同一个月份无限循环。 """ events = [] MAX_LOCAL_ROUNDS = 3 diff --git a/static/templates/ai.txt b/static/templates/ai.txt index bd81141..478b39e 100644 --- a/static/templates/ai.txt +++ b/static/templates/ai.txt @@ -14,7 +14,7 @@ "avatar_thinking": ... // 从角色角度,以第一人称视角,简单清晰的描述想法 "current_emotion": ... // 从以下列表中选择一个最符合当前心情的词:平静、开心、愤怒、悲伤、恐惧、惊讶、期待、厌恶、疑惑、疲惫 "short_term_objective": ..., // 角色接下来一段时间的短期目标 - "action_name_params_pairs": list[Tuple[action_name, action_params]] // 一次性决定未来的5~10个动作,按顺序执行 + "action_name_params_pairs": list[Tuple[action_name, action_params]] // 一次性决定未来的5~10个动作,按顺序执行。action_params 必须是字典 {},不能是 null。 }} }}