diff --git a/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs b/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs
new file mode 100644
index 00000000..c102018d
--- /dev/null
+++ b/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs
@@ -0,0 +1,96 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+using BaseGames.AI;
+using BaseGames.Enemies;
+
+namespace BaseGames.Editor.AI
+{
+ ///
+ /// EnemyAiBrain 的检视器:把「配方资产 / AiScript 定义 id」二选一的不变量提前到编辑期,
+ /// 并把定义 id 从裸字符串换成下拉(取自 AiDefinitionRegistry)。
+ /// 不做任何自动修正——配错就明确报出来,由作者选一条路(CLAUDE.md 第 6 条)。
+ ///
+ [CustomEditor(typeof(EnemyAiBrain))]
+ [CanEditMultipleObjects]
+ public sealed class EnemyAiBrainEditor : UnityEditor.Editor
+ {
+ const string NoneLabel = "(不用此路径)";
+
+ SerializedProperty _recipe;
+ SerializedProperty _definitionId;
+
+ void OnEnable()
+ {
+ _recipe = serializedObject.FindProperty("_recipe");
+ _definitionId = serializedObject.FindProperty("_definitionId");
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.Update();
+
+ EditorGUILayout.PropertyField(_recipe);
+ DrawDefinitionIdDropdown();
+
+ DrawInvariantHelp();
+
+ // 其余字段(若将来新增)照常绘制
+ DrawPropertiesExcluding(serializedObject, "m_Script", "_recipe", "_definitionId");
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ void DrawDefinitionIdDropdown()
+ {
+ var ids = new List { NoneLabel };
+ ids.AddRange(AiDefinitionRegistry.Ids.OrderBy(x => x));
+
+ string current = _definitionId.stringValue;
+ int index = string.IsNullOrEmpty(current) ? 0 : ids.IndexOf(current);
+
+ // 已配的 id 在注册表里找不到(脚本被删/改名)——保留原值并显式标出,不静默清空
+ bool missing = index < 0;
+ if (missing)
+ {
+ ids.Add($"{current} ⚠ 注册表中不存在");
+ index = ids.Count - 1;
+ }
+
+ using (new EditorGUI.DisabledScope(_recipe.objectReferenceValue != null))
+ {
+ int picked = EditorGUILayout.Popup(
+ new GUIContent("定制脚本 id", "[AiDefinition(id)] 的 AiScript 子类 id。与配方资产二选一"),
+ index, ids.Select(s => new GUIContent(s)).ToArray());
+
+ if (picked != index)
+ _definitionId.stringValue = picked == 0 ? string.Empty : ids[picked];
+ }
+
+ if (missing)
+ EditorGUILayout.HelpBox(
+ $"定义 id '{current}' 在 AiDefinitionRegistry 中不存在。" +
+ "对应的 [AiDefinition] AiScript 子类可能已被删除或改名。", MessageType.Error);
+ }
+
+ void DrawInvariantHelp()
+ {
+ if (_recipe.hasMultipleDifferentValues || _definitionId.hasMultipleDifferentValues)
+ return; // 多选且不一致时不下断言
+
+ bool hasRecipe = _recipe.objectReferenceValue != null;
+ bool hasId = !string.IsNullOrEmpty(_definitionId.stringValue);
+
+ if (hasRecipe && hasId)
+ EditorGUILayout.HelpBox(
+ "配方资产与定制脚本 id 同时配置了。二者互斥,运行时 Awake 会报错并禁用本组件。" +
+ "请清掉其中一项。", MessageType.Error);
+ else if (!hasRecipe && !hasId)
+ EditorGUILayout.HelpBox(
+ "尚未配置 AI 来源。约 95% 的敌人应指定配方资产(用菜单 " +
+ "BaseGames/AI/Enemy AI Recipe Wizard 创建);有独门机制的敌人才写 " +
+ "[AiDefinition] 的 AiScript 子类并在此选它的 id。", MessageType.Error);
+ }
+ }
+}
diff --git a/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs.meta b/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs.meta
new file mode 100644
index 00000000..f8982c89
--- /dev/null
+++ b/Assets/_Game/Scripts/Editor/AI/EnemyAiBrainEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1916dc03357f54d48a974ff1bbd377ba
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: