GIS智能体
把 GIS 做成对话:一个本地空间信息智能体的工程化实践
过去很多 GIS 系统都像一间工具仓库:功能很全,但每一步都要用户知道按钮在哪里、参数怎么填、数据是什么坐标系、结果应该怎么导出。真正的问题不是 GIS 不强,而是它太像“专业软件”,不太像“工作伙伴”。
这次做的空间信息智能体,目标很直接:让用户只需要做两件事。
第一,在地图上框一个范围。
第二,用自然语言说出任务。
剩下的事情交给系统:理解任务、查找本地数据、生成分析代码、受控执行、保存结果、回到地图上展示。
它不是一个只能回答问题的聊天框,也不是一个套了皮的地图页面,而是一个面向地理空间数据处理的本地智能执行系统。
为什么要重做 GIS 交互
传统 GIS 工作流里,用户经常在这些细节里消耗精力:
- 数据在哪里?
- 当前范围有没有传给后端?
- 用哪个波段算 NDVI、NDWI、EVI、SAVI?
- 面积到底该用经纬度算,还是先投影?
- 结果是 GeoJSON、TIF、PNG 还是 CSV?
- 代码执行失败后,用户要不要自己看 traceback?
这些问题本质上不是用户真正想做的事。用户真正想说的是:
“计算这个区域面积。”
“给这个范围算一下水体指数。”
“把这个区域外扩 5000 米显示出来。”
“计算 EVI,并把结果叠到地图上。”
所以这个原型的核心不是多做几个按钮,而是把 GIS 的操作入口从“菜单驱动”变成“意图驱动”。
最终形态:地图是画布,对话是入口
前端被压到非常简单:
- 全屏地图作为主画布。
- 加载昌吉遥感 WMS 底图。
- 只保留矩形和多边形框选。
- 左下角一个悬浮对话框。
- 结果自动叠加到地图。
- 文件自动保存并提供下载。
没有复杂菜单,没有大段说明,没有一堆调试按钮。用户不需要理解系统内部有多少模块,只需要知道:先圈范围,再说任务。
这个交互看起来很轻,但背后其实有完整的数据流:
自然语言任务 -> 任务理解 -> 数据目录检索 -> 受控 Python 代码生成 -> 沙箱执行 -> GeoJSON / PNG / TIF / CSV 输出 -> OpenLayers 地图叠加 -> 聊天区摘要反馈后端不是固定工具菜单,而是受控执行系统
早期版本最大的问题,是工具能力太死。系统只知道几个固定工具时,用户稍微换个说法,就会得到“当前不支持”的回复。这不是智能体,更像一个比较礼貌的菜单。
最终版本换了思路:固定 GIS 函数不再是唯一入口,而是作为稳定底座。智能层根据用户意图生成 Python 分析代码,后端负责校验、执行和兜底。
换句话说:
- 用户不用记工具名。
- 智能层可以组合
geopandas、rasterio、shapely、pyproj、GDAL等本地 GIS 能力。 - 后端不盲信生成代码,而是用沙箱约束读写范围、禁危险调用、限制网络和系统命令。
- 常见 GIS 操作提供稳定 helper,避免每次都从零写复杂栅格处理代码。
这让系统既有动态能力,又不会变成一个不受控的脚本执行器。
沙箱:让智能体能动手,但不能乱动
空间分析一旦允许动态代码执行,安全边界必须先设计好。这个原型里,代码执行遵循几条硬规则:
- 只能写入当前任务的
outputs/{run_id}目录。 - 只能读取项目数据目录和任务输出目录。
- 禁止系统命令、网络访问、任意进程调用。
- 禁止越权路径。
- 自动注入当前 AOI、数据目录、输出目录等上下文。
- 自动捕获 stdout、stderr 和 traceback。
- 执行失败后可把错误反馈给智能层进行修复。
同时,系统也没有把沙箱做成“什么都不让用”。例如open()并不是简单禁掉,而是替换成safe_open():允许在任务输出目录内安全读写,越权时才拒绝。
这很关键。因为真正的工程系统不能只靠“禁用一切”来获得安全,那会让正常任务也没法完成。好的沙箱应该是:能做事,但只能在允许范围内做事。
结果协议:不要让用户看 traceback
一个可用的空间智能体,不能把错误原样甩给用户。最终版本对结果输出做了一层协议:
{"assistant_message":"分析完成。","summary":{},"metrics":{},"layers":[],"files":[]}智能代码应该调用write_result()写出这个协议。即使代码忘了写,后端也会扫描输出目录,自动整理已生成的GeoJSON、PNG、TIF、CSV,尽量生成一个可展示的结果。
这解决了一个非常现实的问题:智能代码经常能把文件算出来,但忘了告诉前端“结果在哪里”。现在即使它忘了,系统也能兜底。
指数计算:从 NDVI 到 SAVI
遥感指数是这个原型里最适合展示智能体能力的一类任务。
目前系统已经能稳定处理:
- NDVI:植被指数
- NDWI:水体指数
- EVI:增强植被指数
- SAVI:土壤调节植被指数
用户不需要输入公式,只需要说:
计算 EVI或者:
给这个区域计算水体指数系统会根据本地多波段影像的波段约定选择参数。例如当前昌吉多波段影像默认:
Band 1 = Blue Band 2 = Green Band 3 = Red Band 4 = NIR因此:
NDWI = (Green - NIR) / (Green + NIR) EVI = 2.5 * (NIR - Red) / (NIR + 6*Red - 7.5*Blue + 1) SAVI = (NIR - Red) * (1 + L) / (NIR + Red + L)这些指数并不是只返回一个数字。系统会输出:
- 栅格结果 TIF
- 地图预览 PNG
- 统计 CSV
- 前端地图叠加图层
- 聊天区关键指标摘要
例如一次 SAVI 分析可以返回:
SAVI 均值:0.6371 SAVI 最小值:-0.0918 SAVI 最大值:0.8297 有效像元:293,670这比“生成了一个文件,请自己去找”更接近真实工作流。
面积、缓冲区和矢量分析
矢量任务同样走自然语言。
用户说:
计算面积系统会把 AOI 转到适合当地的米制投影坐标系,再计算面积,避免直接在经纬度下算出不靠谱的结果。
用户说:
这个区域的 5000 米缓冲区显示出来系统会自动生成缓冲区 GeoJSON,并叠加到地图上。
这里的重点不是“写了一个 buffer 函数”,而是把用户意图、空间范围、坐标转换、结果导出和地图展示串成了闭环。
数据目录:让系统知道自己有什么
空间智能体不能凭空分析数据。它必须知道本地有哪些数据、每份数据是什么类型、坐标系是什么、范围在哪里、字段有哪些。
因此后端会扫描数据目录,形成数据 catalog:
- 昌吉 RGB 影像
- 昌吉多波段影像
- 乡镇边界矢量数据
- 已发布 WMS 底图
- 自动扫描到的其他栅格或矢量数据
智能层在生成代码前会看到这个 catalog。它不能假装有不存在的数据,也不能随便访问项目外路径。
这让系统具备了一个重要能力:不是只会“泛泛而谈”,而是围绕本机真实数据做分析。
工程上最重要的三个兜底
这个项目最有价值的地方,不是某一次成功演示,而是逐步补上的工程兜底。
第一,坏 JSON 自动修复。
智能层输出非法 JSON 时,系统不会马上失败,而是把原始输出和解析错误送回去修复为合法结构。
第二,代码失败自动修复。
Python 执行失败时,系统会把 traceback、stdout、stderr 和上一版代码反馈回去,让智能层重新生成修复代码。
第三,结果缺失自动整理。
代码执行成功但忘记写result.json时,后端会扫描输出目录,把已有文件整理成标准结果。
这三层兜底,让系统从“能演示”迈向“能反复用”。
这不是聊天机器人,是空间工作流操作系统的雏形
这个原型真正有意思的地方在于,它把 GIS 操作拆成了三个层次:
- 交互层:地图框选 + 自然语言。
- 智能层:理解任务并生成分析逻辑。
- 执行层:受控运行 GIS 代码并输出标准结果。
传统 GIS 把用户暴露在工具参数里。
这个系统则试图把用户拉回任务本身。
用户只需要表达目标:
计算这个区域的 SAVI 指数系统负责把目标变成:
选择多波段影像 读取 AOI 裁剪栅格窗口 计算指数 生成 TIF 生成 PNG 预览 写 CSV 统计 回传地图图层 展示关键指标这就是空间信息智能体最迷人的地方:它不是把专业能力隐藏掉,而是把专业能力变得可对话、可组合、可执行。
下一步
这个版本已经跑通了本地空间智能体的核心闭环,但还有很多值得继续推进的方向:
- 增加更多遥感指数和分类算法。
- 支持用户上传临时数据。
- 允许多轮任务基于上一次结果继续分析。
- 增加图层管理和结果历史。
- 支持更复杂的矢量叠加、裁剪、空间连接。
- 把结果发布为服务,而不仅仅是文件。
- 接入更完整的数据治理和任务审计。
但最关键的一步已经完成:GIS 不再只是菜单、参数和工具箱,而是开始变成一个能听懂任务、能自己动手、能把结果放回地图上的工作伙伴。
这就是这个原型真正的价值。