# agno_map **Repository Path**: wolf6069/agno_map ## Basic Information - **Project Name**: agno_map - **Description**: 基于 Agno + FastAPI + OpenLayers / Cesium 的地图智能助手。 - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-22 - **Last Updated**: 2026-09-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: agnoe, openlayers, Cesium, skills, 地图智能助手 ## README # MapBrain 地图智能助手 > 基于 **Agno(最新 3.x)+ FastAPI + 本地 Ollama(qwen)+ OpenLayers / Cesium** 的地图智能助手。 > 浏览器端与服务端通过 **WebSocket** 交互:用户输入自然语言指令(可附 GeoJSON/CSV/图片等附件), > 服务端 **Agent 按 skills 拆解**成带依赖关系的步骤计划(JSON),前端**任务解释器**自动逐步执行, > 每步结果(成功 / 报错 / 产生的 **refId**)回传服务端;执行报错时 **Agent 重新调用 skill 修正参数重试**。 > 会话历史持久化到 **SQLite**;对象(layers/entity)**只缓存于浏览器**,服务端仅持有 **refId 引用字符串**。 - **作者**:wolf - **版本**:v1.0.2 - **设计原则**:**以维护 `skills/*.SKILL.md` 为主,尽量少写代码**——扩能力主要改 markdown,框架代码保持稳定。 - **流式思考**(v1.0.2 新增):规划时 Ollama 的**思考过程**经 WebSocket `thinking_delta` 帧**逐字流式**推送到对话框(打字机效果),规划完成后再一次性给出结构化 `Plan`。开关见 `config.OLLAMA_ENABLE_THINKING`。 --- ## 一、功能特性 | # | 诉求 | 实现 | |---|------|------| | 1 | Agno 最新框架 + FastAPI + 本地 Ollama + html 测试页 | `agno[sqlite]` 3.x + FastAPI + 原生 JS 页面 | | 2 | 服务端创建 OpenLayers / Cesium 的 skills | `skills/openlayers/SKILL.md`、`skills/cesium/SKILL.md` | | 3 | WS 连接、区分 sessionid | 每帧带 `session_id`,`SessionManager` 按会话隔离 | | 4 | 初始加载地图 + 浮动智能对话框(新增/停止/上传等) | 顶栏引擎切换 + 右上角浮动对话框 | | 5 | 双方需 WS 连接成功才能对话 | 握手门控:`hello→ready` 前拒绝 `user_message`(NOT_READY) | | 6 | 服务端分析指令,按 skills 拆解多步 | 规划 Agent(Agno + Ollama + Skills + output_schema) | | 7 | 返回步骤 JSON(并行/串行/请求 id/skill 名/参数) | `Plan` 契约:`request_id / steps[](depends_on/group/params)` | | 8 | 前端展示步骤状态并自动执行,回传结果 | `interpreter.js` 任务解释器(拓扑/并行/refId) | | 9 | 执行报错,Agent 重调 skill 修正参数重试 | `step_result(error)` → Agent 决策 → `step_retry` | | 10 | 会话换 db;对象 ID 注册表在前端、后端只传引用;浏览器缓存实体 | SqliteDb;服务端 registry 仅存 refId 视图;前端 `instanceCache` 存真实 layers/entity | --- ## 二、架构总览 ``` ┌──────────────────────────── 浏览器(前端 static/)─────────────────────────┐ │ index.html(顶栏切换 + 地图容器 + 浮动对话框) │ │ app.js WS 客户端 / UI / 附件解析 / 引擎切换 │ │ interpreter.js 任务解释器:依赖拓扑 + 并行波次 + refId + 重试/跳过(纯逻辑)│ │ skill_registry.js 执行对照表:skill→底层操作(SKILL.md 的执行侧) │ │ map_runtime.js 对象实例缓存 + refId 生成 + OpenLayers/Cesium 底层操作 │ └──────────────┬─────────────────────────────────────────────┬──────────────┘ │ 上行 user_message / step_result │ 下行 ready/plan/ │ stop │ step_retry/plan_done ╲ WebSocket ws://host:8000/ws(按 session_id 隔离)╱ ┌────────────────────────────── 服务端 FastAPI(server/)──────────────────────┐ │ main.py FastAPI app + /ws 端点 + 静态托管 + /api/version|skills │ │ ws.py SessionManager(会话/门控)+ RequestState + 依赖跳过传播 │ │ agent.py 规划 Agent:Ollama(qwen) + Skills(LocalSkills) + Plan(output_schema)│ │ db.py SqliteDb(会话历史持久化) │ │ config.py 集中配置(模型 tag / host / 端口 / 重试上限 …) │ └──────────────┬──────────────────────────────────────────────┬──────────────┘ Ollama(localhost:11434, qwen) SQLite(mapbrain.db) skills/openlayers/SKILL.md skills/cesium/SKILL.md ← 维护主战场 ``` **核心职责切分(务必理解)**: - **服务端只做规划**,永不持有地图对象实体; - **前端只做执行**,真实 layers/entity 只活在浏览器 `instanceCache`; - 二者靠「`<能力域>.<操作>` + 参数 + **refId 引用字符串**」这套契约解耦。 --- ## 三、目录结构 ``` agno_map/ ├── README.md # 本文件 ├── requirements.txt # Python 依赖 ├── config.py # 集中配置(模型/服务/行为) ├── run.py # 启动入口(uvicorn) ├── server/ │ ├── __init__.py │ ├── main.py # FastAPI + WebSocket 端点 + 静态托管 │ ├── ws.py # 会话管理 / 协议分发 / 门控 / 请求状态机 │ ├── agent.py # 规划 Agent + Plan/Step/StepFix 契约 │ └── db.py # SQLite 会话持久化 ├── skills/ # ← 能力维护主战场(改这里扩能力) │ ├── openlayers/SKILL.md │ └── cesium/SKILL.md ├── static/ # 前端 │ ├── index.html / style.css # 顶部含天地图 token 常量 │ ├── app.js interpreter.js # UI / 任务解释器 │ ├── skill_registry.js # 执行对照表核心(通用) │ ├── map_runtime.js # 通用内核 + 引擎注册表 │ └── engines/ # 每引擎一个独立文件(可整删) │ ├── openlayers.js # OL 引擎实现(自注册) │ ├── registry_openlayers.js │ ├── cesium.js # Cesium 引擎实现(可整删) │ └── registry_cesium.js # Cesium 执行器绑定(可整删) ├── tests/ │ ├── conftest.py │ ├── test_backend.py # pytest:schema / 门控 / 编排集成(FakePlanner) │ └── test_frontend.js # node:任务解释器 + 执行对照表 └── docs/superpowers/specs/2026-09-20-mapbrain-design.md # 设计规格 ``` --- ## 四、环境准备 ### 1. Python 环境(本仓库以 conda `py313` 为例,Python 3.13.12) ```powershell conda activate py313 # 如不是 3.13,可用任意 Python >= 3.11(Agno 3.x 官方支持 3.9~3.13) python -m pip install -r requirements.txt ``` > 依赖说明:`agno[sqlite]`(含 aiosqlite,供 SqliteDb)、`fastapi`、`uvicorn[standard]`、`ollama`、`pydantic`、`pytest`。 ### 2. 本地 Ollama(qwen 模型) 1. 安装并启动 Ollama: ```powershell ollama serve # 若未常驻后台 ``` 2. 拉取模型。默认 tag 为 `qwen3.8:27b-bf16`(见 `config.py` 的 `OLLAMA_MODEL_TAG`),**需与本地实际一致**: ```powershell ollama list # 查看本地已有模型 tag ollama pull qwen3:32b # 若本地用的是其它 qwen,请改 config.OLLAMA_MODEL_TAG 后 pull ``` > 27B/32B 需 ≥16G 显存或内存。若资源有限,可临时改用 `qwen3:8b`、`qwen2.5:7b` 等小模型, > 只需改 `config.py` 的 `OLLAMA_MODEL_TAG`,**无需改其它代码**。 3. 验证 Ollama 在线: ```powershell ollama list # 能看到模型即可 ``` --- ## 五、启动 ```powershell conda activate py313 cd agno_map python run.py ``` 启动后: | 地址 | 说明 | |------|------| | http://127.0.0.1:8000/ | 前端测试页(地图 + 智能对话框) | | ws://127.0.0.1:8000/ws | WebSocket 端点 | | http://127.0.0.1:8000/api/version | 版本/配置自检 | | http://127.0.0.1:8000/api/skills | 已加载能力域 | 打开前端页面后: 1. 顶栏选择引擎(默认 **OpenLayers 2D**,可切 **Cesium 3D**); 2. 在右下浮动对话框输入指令,如: > “在地图上加一个卫星图层,并在北京(116.404,39.915)打一个标注” 3. 观察对话框**逐步展示步骤与状态**,每步结果自动回传服务端; 4. 出错时若 Ollama 决策重试,会看到 **`step_retry`**(修正参数后重跑)。 --- ## 六、WebSocket 协议 每帧为 JSON,均含 `type` 与 `session_id`。 ### 上行(浏览器 → 服务端) | type | 关键字段 | 说明 | |------|----------|------| | `hello` | `engine?` | 建立会话握手 | | `user_message` | `input`, `attachments[]` | 用户指令(附件含 `refId/kind/name`) | | `step_result` | `request_id`,`step_id`,`status`,`refId?`,`error?` | 单步结果:success/error/skipped/stopped | | `stop` | `request_id` | 中止当前计划 | | `bye` | — | 主动断开 | ### 下行(服务端 → 浏览器) | type | 关键字段 | 说明 | |------|----------|------| | `ready` | `session_id`,`map_engine`,`skills[]` | 握手成功,可对话 | | `planning` | — | 规划中(前端显示 spinner) | | `thinking_delta` | `delta` | **v1.0.2**:思考过程增量,`planning` 后 `plan` 前逐字下发(打字机效果) | | `plan` | `request_id`,`goal`,`steps[]`,`thinking` | 完整步骤计划(思考已流式下发,`thinking` 字段用于去重/回补一次性展示) | | `step_retry` | `request_id`,`step_id`(_rN),`skill`,`op`,`params`,`reason` | 修正参数后重跑某步 | | `step_abandon` | `request_id`,`step_id`,`reason` | 放弃某步(其下游被跳过) | | `plan_done` | `request_id`,`ok`,`summary`,`registry` | 计划终结(附 refId 注册表视图) | | `error` | `code`,`message` | 协议/会话错误(含 `NOT_READY`、`PLAN_FAILED`) | > **流式思考时序**:`user_message` → `planning` → `thinking_delta`×N(思考逐字流出)→ `plan`(结构化计划一次到位)→ 前端解释器自动执行 → `step_result` → … 。 > 若 `config.OLLAMA_ENABLE_THINKING=False` 或模型未吐 thinking,则跳过 `thinking_delta`,直接 `plan`(前端改用 `plan.thinking` 一次性展示,体验不降级)。 **步骤计划 JSON 示例(`plan` 帧)**: ```json { "type": "plan", "request_id": "req_a1b2", "goal": "加卫星图层并标注北京", "steps": [ { "step_id": "s1", "engine": "openlayers", "skill": "openlayers.add_layer", "op": "add_layer", "title": "添加卫星图层", "depends_on": [], "group": "parallel-1", "params": { "source": "google_sat" }, "expect_ref_type": "layer" }, { "step_id": "s2", "engine": "openlayers", "skill": "openlayers.add_marker", "op": "add_marker", "title": "标注北京", "depends_on": ["s1"], "group": "serial", "params": { "coords": [116.404, 39.915], "label": "北京" }, "expect_ref_type": "marker" } ] } ``` - `depends_on` → 串行依赖;同 `group` 且互不依赖 → 并行。 - 步骤引用前序产物**只能用 refId 字符串**(如 `layer_ref:"layer_1"`),不传对象实体。 --- ## 七、维护指南(以 skills 为主) ### 扩一个「新地图操作」(最常见) 1. **改 `skills/<能力域>/SKILL.md`**:新增一节 `### `,声明参数、返回 refId 类型、依赖与失败重试提示。(LLM 规划靠此) 2. **前端补执行函数**(仅当是全新操作时): - `static/map_runtime.js` 里对应 `ctx.ops.`(做真实地图操作并 `return refId`); - `static/skill_registry.js` 的 `EXECUTORS` 加一行 `"能力域.": makeExecutor("能力域","")`。 3. 若只是**改参数语义/描述/示例/取值范围**:只改 `SKILL.md` 即可,前端通常无需动。 ### 换模型 / 改行为 - 换模型 tag、Ollama 地址、温度、keep_alive → 改 `config.py`。 - 改重试上限、单计划最大步数、附件大小上限 → 改 `config.py`。 - **开关流式思考**(v1.0.2):改 `config.py` 的 `OLLAMA_ENABLE_THINKING`(默认 `True`)。 关闭后不再注入 `think` 参数、不发 `thinking_delta` 帧,前端改用 `plan.thinking` 一次性展示,**体验不降级**。 > 注意:思考流式只对支持 thinking 的模型(如 `qwen3`、`deepseek-r1` 系列)生效; > 换到不吐 thinking 的模型时,链路会自动退化到"只展示 `plan.thinking` 文本",不会报错。 ### 会话数据库 - 会话历史存于 `agno_map/mapbrain.db`(首次运行自动创建)。删除该文件即清空会话记忆。 --- ## 八、扩展底图数据源(天地图 / ArcGIS 等) 系统已内置 13 个 OpenLayers 底图源 + 8 个 Cesium 影像 provider,**大部分开箱即用**,仅天地图需配 token。 ### 1. 开箱即用的源(无需任何配置) | 能力域 | source / provider | 说明 | |---|---|---| | OpenLayers | `osm` | OpenStreetMap 世界底图(默认) | | OpenLayers / Cesium | `google_sat` / `google_road` | Google 卫星/道路 | | OpenLayers / Cesium | `arcgis_world_imagery` | Esri 世界卫星影像(Esri 官方公开,无需 key) | | OpenLayers / Cesium | `arcgis_world_topo` | Esri 世界地形图 | | OpenLayers / Cesium | `arcgis_world_streets` | Esri 世界街道 | | OpenLayers | `arcgis_world_ocean` | Esri 世界海洋 | | Cesium | `osm` | OSM(三维场景默认回退) | ### 2. 天地图(Tianditu,需 token) 天地图是中国国家测绘地理信息局的官方源,提供 **矢量底图 / 矢量注记 / 影像底图 / 影像注记** 四层组合: | source | 语义 | 用法 | |---|---|---| | `tianditu_vec` | 矢量底图(含道路/中文地名) | 单用 | | `tianditu_cva` | 矢量注记(地名叠加) | 叠加在 `tianditu_vec` 上 | | `tianditu_img` | 卫星影像底图 | 单用 | | `tianditu_cia` | 影像注记(地名叠加) | 叠加在 `tianditu_img` 上 | **★ 三种设置 token 的方式(优先级从高到低)★**: | # | 方式 | 位置 | 适用场景 | |---|------|------|---------| | 1 | **页面常量** `window.MB_TIANDITU_TOKEN` | `static/index.html` 顶部(醒目注释块) | **推荐**,一次配置长期生效 | | 2 | URL 参数 `?tk=xxx` | 浏览器地址栏 `http://127.0.0.1:8000/?tk=你的token` | 临时调试 / 分享链接 | | 3 | localStorage | 浏览器控制台 `localStorage['tianditu_token'] = '你的token'` | JS 里临时改 | **推荐用第 1 种**:打开 `static/index.html`,在 `` 起始处找到这段: ```html ``` 把 `""` 改成 `"<你的token>"` 即可。**v0.1.2 起,配置了 token 后默认底图会自动加载「天地图影像 (`tianditu_img`) + 影像注记 (`tianditu_cia`)」两层叠加**,没配置则回退 OSM(控制台会 warn,不会白屏)。 申请地址:[天地图开发者平台](https://console.tianditu.gov.cn/api/key.html)(免费注册,个人开发者额度足够本地开发)。 > **未配置 token 时**:Agent 生成 `tianditu_*` 步骤 → 前端执行 → 抛"缺 token"错误 → Agent 会自动回退 `osm`(在 SKILL.md 的重试提示里写死了这个策略),**不会卡死**。 ### 3. Cesium ion token(可选) 3D 端若要用 **Bing 影像** / **Cesium 真实地形**,需要免费 ion token: 1. 到 [Cesium ion](https://ion.cesium.com/) 注册,拿到 token。 2. 在浏览器控制台执行 `Cesium.Ion.defaultAccessToken = '你的token';`,或 3. 改 `static/map_runtime.js` 的 `createCesiumCtx.ensureLoaded()` 里的 `Cesium.Ion.defaultAccessToken = ...`。 无 token 时:Bing/地形会**自动回退 OSM / 椭球地形**(在 `addImagery` 里 try/catch),不会白屏。 ### 4. 想加一个自己公司/第三方的底图(例如内网瓦片服务) 只需 **两处** 改动(**不用改后端**!): 1. 在 `static/map_runtime.js` 的 `TILER` 映射表里加一个 name: ```javascript my_internal_wms: { url: "http://my.map/wms?SERVICE=WMTS&...&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}", attrib: "MyMap" }, ``` 2. 在 `skills/openlayers/SKILL.md` 的 `add_layer.source` 枚举里加一行说明: ```markdown - `my_internal_wms` (内网企业瓦片,需内网访问) ``` 后端 Agent 会自动从 SKILL.md 读到这个新名字并可用。Cesium 侧对应位置是 `CESIUM_PROVIDERS` 映射表 + `skills/cesium/SKILL.md` 的 `add_imagery.provider` 枚举。 --- ## 九、如何添加一个新能力或自定义功能(完整案例:五角星图标 + 定位天安门) > 下面以"用户想在天安门广场定位并加一个**五角星图标**"为例,完整走一遍「需求 → 设计 → 改 SKILL.md → 改前端 → 验证」的流程。 > **读完这一节,你就能自己加任何新能力了。** ### 场景 用户输入:**"定位到天安门广场,并在中心加个五角星"。** 系统应能自动规划出:`add_marker`(icon=star,北京坐标)→ `fly_to`(放大到 17 级)。 ### 第 1 步:拆解需求 → 决定改哪里 先问自己:**这是「新底图源」、还是「新操作」、还是「新参数」?** - 新底图源 → 改 `TILER` 映射 + SKILL.md 枚举 - 新操作(如新增 `add_route`) → 改 `TILER` 或 `ops` + `SKILL.md` 新增 `### add_route` 一节 + `skill_registry.js` 加一行 - 新参数(本次就是这种) → 改 `SKILL.md` 参数 schema + 前端对应函数加分支 五角星属于**新参数**:`add_marker` 已存在,只是要支持 `icon=star`。所以只改两处 + 文档。 ### 第 2 步:改 `skills/openlayers/SKILL.md`(让 Agent 知道有这个参数) 在 `### add_marker` 的 `参数:` 段里加(本项目已实现,你照着改自己的参数即可): ```markdown - `icon`: enum,图标样式(可选,默认 `pin`): - `pin` 默认地图图钉样式(蓝色圆点+白边) - `star` **五角星**(红色填充,常用于地标/重点位置) - `circle` 实心圆 - `cross` 十字准星 - `size`: number,图标渲染尺寸像素(可选,默认 32)。 - `color`: str,主色 hex(可选,默认按 icon 类型取合理默认)。 ``` **关键**:写清楚 ①取值范围 ②语义 ③默认值。Agent 会依据这段生成 `params`。 ### 第 3 步:改前端 `static/map_runtime.js`(真正画出来的地方) 在 `createOlCtx` 里已有两个工厂函数:**`ICON_SVG`**(SVG 定义)与 **`buildMarkerStyle`**(按 icon 名建 style)。 - 若只是**新加一个 SVG 图标**(本次五角星就是):在 `ICON_SVG` 里加一行,例如 ```javascript star: '', ``` `{COLOR}` 会被 `buildMarkerStyle` 里的 `.replace(/\{COLOR\}/g, color)` 替换为实际颜色。 - 若**新图标不是 SVG 而是别的图形**(比如圆形、矩形):在 `buildMarkerStyle` 里加 `if (icon === 'circle')` 分支,用 `ol.style.Circle` 等构造。 `feature.setStyle(buildMarkerStyle(params, ol))` 已在 `addMarker` 里写好,**无需**改 `addMarker`。 ### 第 4 步:加一个 Few-Shot 示例(让 Agent 更稳) 在 SKILL.md 末尾的「典型组合示例」节里加: ```json { "goal": "定位到天安门广场并在广场中心加五角星图标", "steps": [ { "step_id": "s1", "skill": "openlayers.add_marker", "params": { "coords": [116.397026, 39.908690], "icon": "star", "label": "天安门广场", "color": "#e53935", "size": 40 }, "depends_on": [], "group": "serial", "expect_ref_type": "marker" }, { "step_id": "s2", "skill": "openlayers.fly_to", "params": { "center": [116.397026, 39.908690], "zoom": 17 }, "depends_on": ["s1"], "group": "serial", "expect_ref_type": null } ] } ``` LLM 对这类"地标 + 特殊图标"的组合,看到示例后能稳定输出同样的结构。示例越贴用户原话,效果越好。 ### 第 5 步:本地验证(无需真实地图) 在 `tests/test_frontend.js` 里用 `runtime._internals.buildMarkerStyle` 直接单测,**不必加载 OpenLayers**: ```javascript const style = olCtx._internals.buildMarkerStyle({ icon: "star", color: "#e53935" }, fakeOl); // 断言 style.image.src 是 dataURL,且含红色 assert(style.image.src.includes("#e53935")); ``` ### 第 6 步:端到端验证(有浏览器/Ollama 时) 1. `python run.py` 启动服务 2. 浏览器打开 http://127.0.0.1:8000/ 3. 对话框输入:"定位到天安门广场,并在中心加个五角星" 4. 观察:`add_marker(icon=star)` 步骤执行 → 地图上出现红色五角星 → `fly_to` 放大到 17 级 → `plan_done summary=全部步骤执行成功`。 ### 总结(一张表) | 新增能力类型 | 改 SKILL.md | 改 frontend | 改 backend | 验证 | |---|---|---|---|---| | 新底图源 | `add_layer.source` 加 name | `TILER` 加一行 | ❌ | 单测 buildSource + 端到端 | | 新参数(icon 等) | `add_marker` 参数段加分项 | 对应工厂函数(ICON_SVG / buildMarkerStyle)加分支 | ❌ | 单测 buildMarkerStyle + 端到端 | | 新操作(add_route 等) | 新增 `### add_route` 一节 | `ctx.ops` 加函数 + `skill_registry.js` 加一行 | ❌ | 单测 + 端到端 | | 新能力域(如三维激光扫描) | 新建 `skills/xxx/SKILL.md` | 新建 `static/xxx_runtime.js` + 注册 | Agent 自动识别 | 全链路 | **核心心法**:**后端 Agent 只读 SKILL.md**,所以只要 SKILL.md 写清 "参数 schema + 语义 + Few-Shot",Agent 就能规划出正确 Plan; 前端只需在对应工厂函数里补上**渲染实现**即可,两层解耦得非常干净。 --- ## 十、测试 ```powershell conda activate py313 cd agno_map # 后端(pytest):schema 校验 / 握手门控 / 编排集成(FakePlanner,不真调 Ollama) python -m pytest tests/test_backend.py -v # 前端(node):任务解释器 / 执行对照表 纯逻辑 node tests/test_frontend.js ``` 两者均不依赖真实 Ollama / 浏览器,可快速回归。 (前端 14 项含:任务解释器拓扑/重试/停止、引擎自注册、天地图 token 三级优先级、 天地图 source 不做投影干预(坐标系由 View 统一声明)、五角星 SVG 等。) --- ## 十(附)、只保留 OpenLayers、删除 Cesium(独立维护指南) > v0.1.2 起,OpenLayers 与 Cesium 的代码**已完全解耦**为独立文件,可按需整删。 ### 目录结构(v0.1.2 起) ``` static/ map_runtime.js # 通用内核 + 引擎注册表(保留) skill_registry.js # 执行对照表核心(保留) interpreter.js # 任务解释器(保留) app.js # WS 客户端 + UI(保留) index.html # 页面骨架(保留,注释两行引擎脚本即可) style.css # 样式(保留) engines/ # ← 引擎独立文件(可整删其中任意一个引擎) openlayers.js # OpenLayers 引擎实现(自注册) registry_openlayers.js # OpenLayers skill→执行器 绑定 cesium.js # Cesium 引擎实现(自注册,可删) registry_cesium.js # Cesium skill→执行器 绑定(可删) skills/ openlayers/SKILL.md # Agent 读的能力声明(推荐保留) cesium/SKILL.md # Agent 读的能力声明(可删,见下方步骤 4) ``` ### 3 步删除 Cesium(若你只用 OpenLayers) 1. **删除引擎实现文件**: ```powershell Remove-Item static/engines/cesium.js ``` 2. **删除执行器绑定文件**: ```powershell Remove-Item static/engines/registry_cesium.js ``` 3. **注释/删除 `static/index.html` 里的两行**: ```html ``` 同时建议注释掉 Cesium 顶栏按钮和容器 div: ```html ``` 4. **(可选)删除 `skills/cesium/SKILL.md`**: - 不删:Agent 仍可能规划出 `cesium.*` 步骤;前端执行时会报 **"引擎 cesium 未加载"**,解释器自动上报 `step_result(error)`,Agent 会决策重试或放弃 —— **不会卡死、不会白屏**。 - 删了:Agent 的 SKILL.md 里就不再有 cesium 能力,**不会主动生成 cesium 步骤**(更干净)。 ### 为什么这样拆分? **核心心法**: - **引擎文件自注册** —— 每个 `engines/.js` 加载时调 `runtime.registerEngine("", factory)`,不依赖加载顺序。 - **执行器惰性解析** —— `skill_registry.js` 里 `resolve(step)` 不预先建闭包,执行时才 `rt.ctx(engine)`。因此即使引擎文件被删,`resolve` 仍会返回执行器(因为 skill 名仍注册在 `registry_cesium.js` 里),只是执行时报清晰错误。 - **删引擎 = 删文件 + 注释 `