欢迎光临
我们一直在努力

AI 智能体如何把「一句话」变成一张分析图

AI 智能体如何把「一句话」变成一张分析图

目录

1 引言:空间分析的能力供给与使用门槛

1.1 问题的工程化表述

1.2 解法:把「人话」翻译成「地图操作」

2 总体架构:从对话到成图的四层链路

3 核心技术拆解

3.1 意图理解与工具调用

3.2 字段语义层:翻译与防臆造校验

3.3 低代码场景引擎:能力注册与编排

3.4 空间计算内核

3.5 数据链路与持久化

3.6 状态与反馈模型

4 端到端链路:县域企业影响分析(平度市案例)

5 代码示例:HeatmapAgent 的「感知—决策—执行—汇报」模式

6 与常规 GIS 二次开发的对比

7 工程取舍与可观测的边界

8 结语


产业分析真正的难点,不在数据,而在「从数据到地图」之间的那道鸿沟。本文从技术视角拆解——一个以 AI 智能体与低代码场景引擎为核心的空间分析:它如何把一句句自然语言需求,解析为可执行的图层、样式、分析与组件操作,并实时呈现在地图上。全文以一次真实的县域产业分析为例,覆盖意图理解、字段校验、能力编排、空间计算、数据持久化等关键链路。

1 引言:空间分析的能力供给与使用门槛

1.1 问题的工程化表述

「做业务的人不懂 GIS,懂 GIS 的人不懂业务」,是政务、园区、招商团队中常年存在的分工困境。从工程视角看,一次空间分析交付至少包含五类环节:数据准备、坐标基准对齐、图层组织、空间分析与统计、结果表达,每一环都对应独立的专业工具与技能要求。

以「龙头企业影响圈覆盖了多少上下游企业」这类问题为例,完整链路包括坐标转换、图层叠加、缓冲区分析、覆盖统计与结果汇总。在常规工作流中,这些环节需要数据工程师、GIS 工程师与业务人员多轮协作:找数据、导出 Excel、提交开发、等待排期、反复沟通样式与口径,最终拿到的往往还是一张可能已经过时的图。

1.2 解法:把「人话」翻译成「地图操作」

不要求业务人员学习 GIS,也不依赖开发排期,而是把空间分析能力封装为可编排的能力原子,由 AI 智能体将自然语言需求翻译为能力调用序列,在低代码场景引擎中逐一执行并实时呈现。用户的核心动作只有一个——像聊天一样,把分析需求说出来。

2 总体架构:从对话到成图的四层链路

不是把 GIS 操作搬上对话框,而是一套「会干活」的智能体。整体架构可抽象为四层:

交互层:对话输入与地图画布双通道。用户以自然语言下达指令,所有操作结果实时呈现在地图上;发现偏差时,用一句话即可纠正。

意图理解层:将中文需求解析为结构化操作指令,包括意图识别、槽位抽取与参数映射,输出标准化的工具调用序列。

能力编排层:按需组合图层、样式、分析、组件等十余项开箱即用能力,复杂需求自动拆解为多步操作序列。

数据与执行层:低代码场景引擎执行操作,支撑图层入库、字段查询、空间计算与数据库访问;支持对话生成 SQL,直接查询业务数据。

四个层面共同保证一条设计原则:每一步操作都可解释、可纠正、可持久化——工具调用过程在对话面板中可见,操作结果即时上图,最终成果可保存为场景与图层资产。

3 核心技术拆解

3.1 意图理解与工具调用

将 GIS 操作封装为一组带参数的工具,智能体通过工具调用完成「一句话 → 操作序列」的翻译。以界面中可见的调用为例:

修改图层样式:update_layer_style,参数包括 fullColor、borderColor、borderWidth、opacity;

多条件过滤:filter_layer_data,参数为图层 ID 与 conditions 数组,多个条件以 AND 连接;

覆盖分析:analyze_buffer_coverage,可指定统计字段完成汇总。

对于「过滤出注册资本大于 500、2025 年以后成立的企业」这类需求,智能体将其拆解为两个条件(注册资本大于 500 且成立日期不早于 2025),以 AND 组合后调用 filter_layer_data。条件中的字段名与比较符由字段语义层提供,而非模型自由生成。

3.2 字段语义层:翻译与防臆造校验

自然语言中的业务字段(如「注册资本」「成立日期」)与数据表中的真实字段(如 REGCAP、idate)并非一一对应。若让模型直接生成字段名,极易出现「臆造字段」。智能体的应对方式是字段先翻译、再校验:

解析上传文件时识别字段清单,维护字段元数据;

工具调用前先经 list_layer_fields 预取目标图层的字段编码;

将需求中的业务字段映射为真实字段,并在调用前校验参数合法性,杜绝臆造字段名。

这一机制同时服务两类场景:过滤条件的构建,以及覆盖分析中统计字段(sumFields)的指定。

3.3 低代码场景引擎:能力注册与编排

低代码场景引擎沉淀了四类能力,见表1。

表1  智能体核心能力清单

能力类

包含能力

图层类

图层列表、创建图层入库、向已有图层追加数据、字段清单翻译

样式类

属性修改、图标与位图替代、数据标签、分级分类着色

地理分析类

缓冲区分析、面转点、坐标系转换、缓冲区覆盖分析

筛选与组件

多条件过滤、属性框组件、图层数据过滤

引擎按「能力注册表 + 组合编排」工作:每条指令被解析为一个或多个能力调用,能力之间可串联。例如覆盖分析并非单次调用:需要先获取字段编码(list_layer_fields),再执行 analyze_buffer_coverage 并指定统计字段,复杂分析因此可以被逐步执行、逐步确认。

3.4 空间计算内核

空间计算内核提供基础几何算子与分析算子两类能力:

坐标系转换:支持 GCJ02 与 WGS84 等坐标系互转。企业坐标从 GCJ02 转成 WGS84 后,点位与底图精准对齐,解决「漂移」问题;

缓冲区分析:以指定要素为中心、按半径生成缓冲区(如 10 千米影响圈),并支持保存为独立图层;

缓冲区覆盖分析:统计缓冲区覆盖范围内的要素数量与字段汇总(覆盖几个乡镇、多少企业、注册资本合计);

面转中心点:将面要素(如乡镇行政区划)转换为中心点图层,供后续分析使用;

分级分类着色:按字段值分档映射色阶(如按注册资本分 5 档:绿、黄、蓝、橙、紫),也支持按行政区编码分档着色;

热力渲染:将点要素渲染为热力分布,直观呈现区域密度差异。

3.5 数据链路与持久化

文件解析与入库:上传 CSV 或 Excel 后,智能体解析数据条数、识别要素类型(点或面)与字段清单;数据量较大时,地图预览仅渲染部分点位,入库时以后端解析的全量数据为准,保证统计口径完整。

图层资产:操作生成的临时图层(如影响圈、中心点)不会自动入库;经用户确认后,可保存为正式图层入库并返回图层 ID,成为可复用的图层资产。

场景存档:场景记录图层集合、初始视图(经纬度与层级)与配置,保存后整体复用,下次分析从「继承」开始。

对话式 SQL:智能体可直接生成 SQL 查询数据库,打通「数据—地图—分析—决策」整条链路。

3.6 状态与反馈模型

「前端暂存 + 显式持久化」的状态模型:样式、过滤等配置暂存于前端,点击「保存场景」后才持久化到后端。这一设计让操作具备即时的可逆性与可见性——每一步操作都在地图上即时呈现,发现偏差可以用一句话纠正,最终成果经确认后统一落库。

4 端到端链路:县域企业影响分析(平度市案例)

以平度市为例,将企业数据导入,完整演示一次企业影响分析。全过程由对话驱动,九步的指令、底层动作与呈现效果见表2。

表2  九步分析的技术链路映射

步骤

用户指令(节选)

底层动作

地图呈现

1 数据一键上图

「把上传的文件生成新图层,图层名称:平度企业」

文件解析(4096 条点数据)、字段识别、创建图层入库

企业点位图层叠加行政底图

2 数据真实叠加

「企业坐标从 GCJ02 转成 WGS84」

坐标系转换算子

点位与底图精准对齐

3 企业热力分布

「生成热力图」

热力渲染

热力图层,密度分布一目了然

4 资本格局

「按注册资本分 5 档上色」

分级分类着色(5 档色阶)

资本集聚格局一眼看清

5 重点企业画像

「注册资本大于 500、成立日期 ≥ 2025」

filter_layer_data 多条件过滤(AND 组合)

新设重点企业被单独圈出

6 点选看详情

点击任意企业

属性框组件绑定要素查询

工商信息卡片随点随看

7 龙头企业影响圈

以龙头公司为中心生成影响圈

缓冲区分析(示例半径 10 千米)

辐射圈瞬间生成

8 龙头带动能力量化

「统计影响圈覆盖几个乡镇、多少企业,汇总注册资本」

list_layer_fields + analyze_buffer_coverage

覆盖统计结果量化呈现

9 成果固化复用

「保存影响圈为正式图层」「面转中心点」「保存场景」

临时图层转正式图层入库、面转点、场景序列化

图层资产与场景存档

步骤1 数据一键上图:上传企业数据后,智能体解析并识别为点数据,同时列出字段清单;一句「把上传的文件生成新图层,图层名称:平度企业」即完成图层创建与上图,再上传乡镇行政区划,行政底图就位。

图1  数据解析与图层管理

步骤2 数据真实叠加:上传数据的坐标若为 GCJ02,与 WGS84 底图存在偏移;一句「企业坐标从 GCJ02 转成 WGS84」完成坐标系转换,点位与底图精准对齐,不再漂移。

步骤3 企业热力分布:「生成热力图」将点位渲染为热力分布,企业密集区与稀疏区一眼看清;图中右侧可见 update_layer_style 工具调用的参数(fullColor、opacity 等)。

图2  热力分布与样式工具调用

步骤4 资本格局:「按注册资本分 5 档上色」,绿、黄、蓝、橙、紫五档色阶呈现资本规模集聚格局;乡镇层面再按行政编码分档着色,区域差异一目了然。

步骤5 重点企业画像:通过多条件过滤「注册资本大于 500」且「成立日期 ≥ 2025」,新设重点企业被单独圈出。条件以 AND 组合,由 filter_layer_data 执行。

图3  多条件过滤

步骤6 点选看详情:点击任意企业,属性框自动弹出名称、注册资本、成立日、经营范围,工商信息随点随看,无需翻库。

图4  点选详情

步骤7 龙头企业影响圈:以龙头公司为中心生成指定半径影响圈,缓冲区分析瞬间给出辐射范围。

步骤8 龙头带动能力量化:「统计影响圈覆盖几个乡镇、多少企业,汇总注册资本」,覆盖分析自动统计并给出结果——覆盖多少家、分布在哪些乡镇、注册资本合计多少,龙头带动能力被量化成一张可汇报的图。

图5  覆盖分析

步骤9 成果固化复用:「把影响圈保存为正式图层」「乡镇面转中心点」「保存场景」,分析结果沉淀为图层资产并随场景存档,下次分析从「继承」开始。

图6  场景保存与图层入库

5 代码示例:HeatmapAgent 的「感知—决策—执行—汇报」模式

热力渲染是分析链路中最常用的能力之一。下面以一个基于高德地图(AMap)的 HeatmapAgent 为例,说明智能体代码的组织方式:run() 作为总入口,内部按「感知(取数)—决策(统计与分级)—执行(渲染)—汇报(日志与状态)」四段式组织,与智能体智能体的执行范式一致。

class HeatmapAgent {

    constructor(){

        this.map = null;        // AMap 实例

        this.markers = [];      // 散点覆盖物

        this.heat = null;       // 热力层

        this.mode = 'scatter';  // scatter | heat | both

        this.radius = 5;        // 基础点半径

        this.seed = 20261013;

        this.stats = null;

    }

    /* —— 总入口 —— */

    async run(count, seed, fit){

        const t0 = performance.now();

        this.setPill('running', '运行中');

        this.log('感知', '读取数据源:' + fmtNum(count) + ' 个点位,' + CLUSTERS.length + ' 个聚类中心', '');

        const points = this.perceive(count, seed);

        this.log('决策', '强度归一化 → 5 级分档(绿/黄/紫/蓝/深紫)', '');

        const plan = this.decide(points);

        this.log('执行', '模式=' + this.modeLabel() + ',基础半径=' + this.radius + 'px' + (fit ? ',自适应取景' : ''), '');

        const err = await this.act(plan, fit);

        const cost = Math.round(performance.now() – t0);

        if(err){

            this.setPill('fail', '失败');

            this.log('汇报', '执行失败:' + err.message, 'err');

            return { ok:false, error: err.message };

        }

        this.stats = Object.assign(plan.stats, { cost });

        this.report();

        this.renderStats();

        this.setPill('done', '完成');

        this.log('汇报', '已完成:' + fmtNum(points.length) + ' 点 / 聚类 ' + plan.stats.clusterUsed + ' / 耗时 ' + cost + 'ms', 'ok');

        return { ok:true };

    }

    /* —— 感知:取数(此处为模拟数据,可替换真实数据源) —— */

    perceive(count, seed){

        this.seed = seed;

        return generatePoints(count, seed);

    }

    /* —— 决策:统计 + 分级 —— */

    decide(points){

        const levelCount = [0, 0, 0, 0, 0];

        let minLng = Infinity, maxLng = -Infinity, minLat = Infinity, maxLat = -Infinity;

        const clusters = new Set();

        for(const p of points){

            const lv = levelOf(p.intensity);

            levelCount[lv.idx]++;

            clusters.add(p.cluster);

            if(p.lng < minLng) minLng = p.lng;

            if(p.lng > maxLng) maxLng = p.lng;

            if(p.lat < minLat) minLat = p.lat;

            if(p.lat > maxLat) maxLat = p.lat;

        }

        const cLng = (minLng + maxLng) / 2, cLat = (minLat + maxLat) / 2;

        const kmPerDegLng = 111.32 * Math.cos(cLat * Math.PI / 180);

        const rangeKm = Math.round(Math.hypot((maxLng – minLng) * kmPerDegLng, (maxLat – minLat) * 111.32) / 2);

        return { points, stats: {

            count: points.length,

            clusterUsed: clusters.size,

            rangeKm,

            center: [cLng, cLat],

            levelCount,

            bounds: { minLng, maxLng, minLat, maxLat },

        }};

    }

    /* —— 执行:渲染到高德地图(演示模式走 Canvas) —— */

    async act(plan, fit){

        try{

            if(this.demoMode){ this._demoDraw(plan); return null; }

            if(!this.map) await this._initMap();

            this.clearLayers();

            if(this.mode !== 'heat') this._addScatter(plan);

            if(this.mode !== 'scatter') this._addHeat(plan);

            if(fit) this._fitView(plan.stats.bounds);

            return null;

        }catch(e){

            return e;

        }

    }

    async _initMap(){

        await loadAMap();

        this.map = new AMap.Map('map', {

            zoom: 10,

            center: [120.10, 36.60],

            mapStyle: 'amap://styles/whitesmoke', // 浅色底图,贴近原图米色风格

        });

        this.map.addControl(new AMap.Scale());

        this.map.addControl(new AMap.ToolBar({ position: { right: '10px', top: '10px' } }));

    }

    clearLayers(){

        if(this.markers.length){ this.map.remove(this.markers); this.markers = []; }

        if(this.heat){

            try{ this.heat.destroy(); }catch(e){ try{ this.heat.hide(); }catch(e2){} }

            this.heat = null;

        }

    }

    _addScatter(plan){

        const arr = [];

        for(const p of plan.points){

            const lv = levelOf(p.intensity);

            const r = Math.max(2.5, this.radius * (0.85 + lv.idx * 0.22));

            arr.push(new AMap.CircleMarker({

                center: [p.lng, p.lat],

                radius: r,

                fillColor: lv.color,

                fillOpacity: 0.82,

                strokeColor: '#ffffff',

                strokeWeight: 0.8,

                strokeOpacity: 0.65,

                zIndex: 40 + lv.idx,

            }));

        }

        this.map.add(arr);

        this.markers = arr;

    }

    _addHeat(plan){

        this.heat = new AMap.HeatMap(this.map, {

            radius: 26,

            opacity: [0, 0.72],

            gradient: {

                0.0: '#1fae62', 0.25: '#f2b31a', 0.5: '#9c5fb8', 0.75: '#2e86de', 1.0: '#5e2f8e',

            },

        });

        const data = plan.points.map(p => ({ lng: p.lng, lat: p.lat, count: Math.round(1 + p.intensity * 9) }));

        this.heat.setDataSet({ data, max: 10 });

    }

    _fitView(b){

        const sw = new AMap.LngLat(b.minLng, b.minLat);

        const ne = new AMap.LngLat(b.maxLng, b.maxLat);

        this.map.setBounds(new AMap.Bounds(sw, ne), false, [48, 48, 48, 48]);

    }

    /* —— 汇报:写日志与状态徽标 —— */

    report(){

        const s = this.stats;

        $('mapBadge').innerHTML =

            '<b>HeatmapAgent</b> · ' + fmtNum(s.count) + ' 个点位 / ' + s.clusterUsed + ' 个聚类' +

            '<br>覆盖半径约 ' + s.rangeKm + ' km · 模式 ' + this.modeLabel() + ' · 耗时 ' + s.cost + 'ms';

    }

    renderStats(){

        const s = this.stats;

        if(!s) return;

        $('stCount').textContent = fmtNum(s.count);

        $('stCluster').textContent = s.clusterUsed;

        $('stRange').textContent = '~' + s.rangeKm + ' km';

        $('stCost').textContent = s.cost + ' ms';

    }

    modeLabel(){

        return { scatter: '散点', heat: '热力', both: '混合' }[this.mode] || this.mode;

    }

    /* —— UI 辅助 —— */

    setPill(state, text){

        const pill = $('agentPill');

        pill.classList.remove('running', 'done', 'fail');

        if(state !== 'idle') pill.classList.add(state);

        $('agentState').textContent = text;

    }

    log(tag, msg, cls){

        const ln = document.createElement('div');

        ln.className = 'ln' + (cls ? ' ' + cls : '');

        const t = new Date().toTimeString().slice(0, 8);

        ln.innerHTML = '<span class="tag">' + tag + '</span>' +

            '<span class="time">' + t + '</span>' +

            '<span class="msg"></span>';

        ln.querySelector('.msg').textContent = msg;

        $('log').appendChild(ln);

        $('log').scrollTop = $('log').scrollHeight;

    }

}

代码要点:perceive 负责数据源读取,本示例使用模拟数据,可替换为真实数据源;decide 完成强度归一化、5 级分档与范围统计;act 根据模式(散点、热力、混合)渲染到地图,支持自适应取景;report 输出点位数量、聚类数、覆盖半径与耗时,形成可观测的执行结果。

6 与常规 GIS 二次开发的对比

表3  常规 GIS 二次开发与智能体模式对比

对比维度

常规 GIS 二次开发

智能体模式

需求到成图

需求评审—设计—开发—联调—发布

对话直出,实时成图

技术门槛

需 GIS 与开发技能

自然语言即可

变更成本

需求变更重新排期

一句话调整

空间分析能力

需自行集成算法与算子

引擎内置缓冲区、覆盖分析、坐标转换等算子

成果复用

项目内定制,复用成本高

图层资产 + 场景存档,随取随用

数据接入

ETL、服务发布

文件上传解析、对话式 SQL

适配对象

开发团队

业务、规划、招商一线人员

7 工程取舍与可观测的边界

从实现细节可以观察到几处明确的工程取舍:

渲染与入库解耦:大数据量下地图预览采用抽样渲染,入库与统计以后端全量数据为准,取舍在于交互流畅性与数据完整性的平衡;

前端暂存、显式持久化:操作配置先落前端,保存场景后才写后端,换取操作的即时可逆性,代价是需要显式提交;

字段校验兜底:通过预取字段清单约束模型输出,降低大模型幻觉对数据语义的影响,属于以确定性约束非确定性的典型做法;

歧义依赖对话澄清:当指令存在多义性(如多个同名图层实例)时,智能体需要选择或向用户确认,说明自然语言驱动在复杂指令下仍有交互成本。

在演进方向上,值得关注更大数据量下的空间索引与聚合渲染、多轮任务的执行状态管理、图层与场景的权限与数据安全治理(本节为作者基于可观测实现的分析,不代表产品承诺)。

8 结语

这场企业影响分析,从上传数据到保存场景,全流程由对话驱动完成。当「做图」不再依赖开发排期、不再要求 GIS 技能,空间分析这件事就从「工程」变成了「对话」。门槛的降低并非能力的降级——专业能力被封装进可编排的场景引擎,由智能体按需调用,这正是 AI 低代码的核心价值。

延伸阅读:

让 AI 写地图代码,装个官方技能包值不值?

赞(0)
未经允许不得转载:171主机测评 » AI 智能体如何把「一句话」变成一张分析图
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址