docs: 深度优化 Token 消耗,精简查找与层级获取载荷,补充相关文档与安全守则

This commit is contained in:
火焰库拉
2026-02-24 16:22:45 +08:00
parent 127fc684ca
commit 655335483c
5 changed files with 1202 additions and 1098 deletions

View File

@@ -105,8 +105,11 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.j
### 4. get_scene_hierarchy
- **描述**: 获取当前场景的完整节点树结构(包括 UUID、名称和层级关系
- **参数**:
- **描述**: 获取当前场景的完整节点树结构(支持分页避免长数据截断)。如果要查询具体组件属性请配合 manage_components。
- **参数**:
- `nodeId`: 指定的根节点 UUID。如果不传则获取整个场景的根 (可选)。
- `depth`: 遍历的深度限制,默认为 2。用来防止过大场景导致返回数据超长 (可选)。
- `includeDetails`: 是否包含坐标、缩放等杂项详情,默认为 false (可选)。
### 5. update_node_transform
@@ -223,14 +226,13 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.j
### 15. find_gameobjects
- **描述**: 查找游戏对象
- **描述**: 按条件在场景中搜索游戏对象。返回匹配节点的轻量级结构 (UUID, name, active, components 等)。若要获取完整的详细组件属性,请进一步对目标使用 `manage_components`
- **参数**:
- `conditions`: 查找条件
- `name`: 节点名称(包含匹配)
- `tag`: 节点标签
- `component`: 组件类型
- `active`: 激活状态
- `recursive`: 是否递归查找默认true
- `name`: 节点名称(包含模糊匹配)
- `component`: 包含的组件类名(如 `cc.Sprite`
- `active`: 布尔值,节点的激活状态
- `recursive`: 是否递归查找所有的子节点默认true
### 16. manage_material

View File

@@ -120,3 +120,32 @@
- **优化预制体创建稳定性 (`create_node` + `prefab_management`)**:
- 在创建物理目录后强制执行 `Editor.assetdb.refresh`,确保 AssetDB 即时同步。
- 将节点重命名与预制体创建指令之间的安全延迟从 100ms 增加至 300ms消除了重命名未完成导致创建失败的竞态条件。
---
## 八、 Token 消耗深度优化 (2026-02-24)
### 1. 工具描述精简 (`main.js`)
- **问题**: `globalPrecautions` (AI 安全守则) 被硬编码到所有工具的 `description` 中,导致每次环境初始化或查阅工具列表时浪费约 2200 个 CJK Token。
- **优化**: 收束安全守则的广播范围。目前仅针对高风险的**写操作**(如 `manage_components`, `update_node_transform`, `manage_material`, `create_node` 等)保留警告,低风险或只读分析类工具(如 `get_scene_hierarchy`, `get_selected_node`)已悉数移除该文本。
- **效果**: `/list-tools` 整体负载字符数缩减近 40%。
### 2. 长数据截断保护 (`scene-script.js`)
- **问题**: `manage_components(get)` 会完整序列化多边形坐标集、曲线数据数组以及 Base64 图片,产生极其庞大且对 AI 无用的 JSON 负载。
- **优化**:
- **数组截断**: 长度超过 10 的数组直接返回 `[Array(length)]`,彻底杜绝数据雪崩。
- **字符串截断**: 长度超过 200 的字符串限制为截断显示并附带 `...[Truncated, total length: X]` 提示。
### 3. 层级树获取瘦身与分页 (`get_scene_hierarchy`)
- **问题**: 请求场景层级时会一次性返回完整 1000+ 节点的深层结构,包括所有变换矩阵。
- **优化**:
- 支持 `depth` 深度限制(默认 2 层)。
- 支持 `nodeId` 参数,允许 AI 缩小作用域,从指定根节点向下探测。
- 添加 `includeDetails` 参数。默认关闭,此时剥离坐标、缩放与尺寸指标,且将冗长的组件详细结构浓缩成简化的名称数组(如 `["Sprite", "Button"]`)。
### 4. 查找结果精简 (`find_gameobjects`)
- **优化**: 将原本包含 Transform位移/缩放/尺寸)全量数据的匹配回传,精简为仅包含核心识别特征的基础集 (`uuid`, `name`, `active`, `components`, `childrenCount`),极大释放了同名大批量查找时的 Token 压力。
### 5. 底层鲁棒性大修
- **问题**: 上述优化在应用过程中暴露出遍历未命名根节点(如 `cc.Scene`)时遭遇 `undefined.startsWith` 报错并引发 IPC 悬挂的致命隐患。
- **修复**: 在 `dumpNodes``searchNode` 中增设前置安全屏障,并修复 `cc.js.getClassName(c)` 替代底层的 `__typename` 来兼容 2.4 获取有效类名。修复了 `main.js` 中关于 `get_scene_hierarchy` 的参数传递脱节问题。

44
main.js
View File

@@ -173,7 +173,7 @@ const getToolsList = () => {
return [
{
name: "get_selected_node",
description: `${globalPrecautions} 获取当前编辑器中选中的节点 ID。建议获取后立即调用 get_scene_hierarchy 确认该节点是否仍存在于当前场景中。`,
description: `获取当前编辑器中选中的节点 ID。建议获取后立即调用 get_scene_hierarchy 确认该节点是否仍存在于当前场景中。`,
inputSchema: { type: "object", properties: {} },
},
{
@@ -190,13 +190,20 @@ const getToolsList = () => {
},
{
name: "save_scene",
description: `${globalPrecautions} 保存当前场景的修改`,
description: `保存当前场景的修改`,
inputSchema: { type: "object", properties: {} },
},
{
name: "get_scene_hierarchy",
description: `${globalPrecautions} 获取当前场景的完整节点树结构(包 UUID、名称和层级关系)`,
inputSchema: { type: "object", properties: {} },
description: `获取当前场景的节点树结构(包 UUID、名称、子节点数)。若要查询节点组件详情等,请使用 manage_components。`,
inputSchema: {
type: "object",
properties: {
nodeId: { type: "string", description: "指定的根节点 UUID。如果不传则获取整个场景的根。" },
depth: { type: "number", description: "遍历的深度限制,默认为 2。用来防止过大场景导致返回数据超长。" },
includeDetails: { type: "boolean", description: "是否包含坐标、缩放等杂项详情,默认为 false。" }
}
},
},
{
name: "update_node_transform",
@@ -218,7 +225,7 @@ const getToolsList = () => {
},
{
name: "create_scene",
description: `${globalPrecautions} 在 assets 目录下创建一个新的场景文件。创建并通过 open_scene 打开后,请务必初始化基础节点(如 Canvas 和 Camera`,
description: `在 assets 目录下创建一个新的场景文件。创建并通过 open_scene 打开后,请务必初始化基础节点(如 Canvas 和 Camera`,
inputSchema: {
type: "object",
properties: {
@@ -241,7 +248,7 @@ const getToolsList = () => {
},
{
name: "open_scene",
description: `${globalPrecautions} 打开场景文件。注意这是一个异步且耗时的操作打开后请等待几秒。重要如果是新创建或空的场景请务必先创建并初始化基础节点Canvas/Camera`,
description: `打开场景文件。注意这是一个异步且耗时的操作打开后请等待几秒。重要如果是新创建或空的场景请务必先创建并初始化基础节点Canvas/Camera`,
inputSchema: {
type: "object",
properties: {
@@ -255,7 +262,7 @@ const getToolsList = () => {
},
{
name: "open_prefab",
description: `${globalPrecautions} 在编辑器中打开预制体文件进入编辑模式。注意:这是一个异步操作,打开后请等待几秒。`,
description: `在编辑器中打开预制体文件进入编辑模式。注意:这是一个异步操作,打开后请等待几秒。`,
inputSchema: {
type: "object",
properties: {
@@ -424,12 +431,15 @@ const getToolsList = () => {
},
{
name: "find_gameobjects",
description: `${globalPrecautions} 查找游戏对象`,
description: `按条件在场景中搜索游戏对象。返回匹配节点的轻量级结构 (UUID, name, active, components 等)。若要获取完整的详细组件属性,请进一步对目标使用 manage_components。`,
inputSchema: {
type: "object",
properties: {
conditions: { type: "object", description: "查找条件" },
recursive: { type: "boolean", default: true, description: "是否递归查找" },
conditions: {
type: "object",
description: "查找条件。支持的属性name (节点名称,支持模糊匹配), component (包含的组件类名,如 'cc.Sprite'), active (布尔值,节点的激活状态)。"
},
recursive: { type: "boolean", default: true, description: "是否递归查找所有子节点" },
},
required: ["conditions"],
},
@@ -538,7 +548,7 @@ const getToolsList = () => {
},
{
name: "read_console",
description: `${globalPrecautions} 读取控制台`,
description: `读取控制台`,
inputSchema: {
type: "object",
properties: {
@@ -553,7 +563,7 @@ const getToolsList = () => {
},
{
name: "validate_script",
description: `${globalPrecautions} 验证脚本`,
description: `验证脚本`,
inputSchema: {
type: "object",
properties: {
@@ -564,7 +574,7 @@ const getToolsList = () => {
},
{
name: "search_project",
description: `${globalPrecautions} 搜索项目文件。支持三种模式1. 'content' (默认): 搜索文件内容支持正则表达式2. 'file_name': 在指定目录下搜索匹配的文件名3. 'dir_name': 在指定目录下搜索匹配的文件夹名。`,
description: `搜索项目文件。支持三种模式1. 'content' (默认): 搜索文件内容支持正则表达式2. 'file_name': 在指定目录下搜索匹配的文件名3. 'dir_name': 在指定目录下搜索匹配的文件夹名。`,
inputSchema: {
type: "object",
properties: {
@@ -650,7 +660,7 @@ const getToolsList = () => {
},
{
name: "get_sha",
description: `${globalPrecautions} 获取指定文件的 SHA-256 哈希值`,
description: `获取指定文件的 SHA-256 哈希值`,
inputSchema: {
type: "object",
properties: {
@@ -999,7 +1009,7 @@ module.exports = {
break;
case "get_scene_hierarchy":
callSceneScriptWithTimeout("mcp-bridge", "get-hierarchy", null, callback);
callSceneScriptWithTimeout("mcp-bridge", "get-hierarchy", args, callback);
break;
case "update_node_transform":
@@ -1209,7 +1219,7 @@ module.exports = {
Editor.assetdb.create(
scriptPath,
content ||
`const { ccclass, property } = cc._decorator;
`const { ccclass, property } = cc._decorator;
@ccclass
export default class NewScript extends cc.Component {
@@ -2385,7 +2395,7 @@ CCProgram fs %{
} else {
props[key] = typeof val;
}
} catch (e) {}
} catch (e) { }
});
return { name, exists: true, props };
};

File diff suppressed because it is too large Load Diff

View File

@@ -128,3 +128,20 @@
- **背景**`Editor.Scene.callSceneScript` 的回调依赖 Scene 面板响应 IPC 消息。如果主线程阻塞Scene 面板无法处理消息,导致 callback 永远不返回HTTP 连接堆积。
- **解决方案**:所有 `callSceneScript` 调用均通过 `callSceneScriptWithTimeout` 包装,默认 15 秒超时。超时后自动返回错误,释放 HTTP 连接和队列位置。
- **日志标识**:超时会记录 `[超时] callSceneScript "方法名" 超过 15000ms 未响应`
---
## 10. Token 消耗与长数据保护防爆机制
### 10.1 `get_scene_hierarchy` 深度与层级限制
- **背景**:在一两千个节点的大型 UI 场景中,无限制地获取全场景树会瞬间消耗十万以上的 Token导致 AI 丢失上下文甚至触发截断报错。
- **最佳实践**
- **默认使用 `depth: 2`** (默认限制) 来逐步探查。
- **结合 `nodeId` 参数**:找到关键模块(例如 `Canvas/LoginPanel`)的 UUID 后,再单独向该 `nodeId` 请求下一层的结构,而非每次从根部拉取。
### 10.2 大对象与长数组截断
- **背景**在读取某些特定组件数据如多边形顶点坐标、Sprite 曲线数据或序列化的内联 Base64 图片JSON 可能会异常庞大。
- **保护机制**
- `scene-script.js` 内部在执行 `manage_components(get)` 序列化时,对于**长度超过 10 的 Array** 会强制截断,返回字面量字符串 `"[Array(X)]"`
- 对于**长度大于 200 的长字符串**,也会强制缩略并追加 `...[Truncated, total length: X]`
- **应对策略**:如果 AI 看到截断提示,这意味着此处为海量无语义数据,**请勿**尝试盲目通过 `update` 覆盖或还原被截断的字段,极易导致源数据被破坏。请仅修改自己能够完全看清的轻量级属性(如 `name`, `x`, `scale` 等)。