夜雨聆风学习资料网

ARTICLE · 1304191

把插件能力做成 Agent 的手:28 个工具的契约、线程与权限——《地质灾害风险评估方法探索》· 智能篇 · 02

把插件能力做成 Agent 的手:28 个工具的契约、线程与权限——《地质灾害风险评估方法探索》· 智能篇 · 02

上一篇搭好了 Agent 的地基:vendor 内核、纯标准库模型客户端、权限门控的骨架。但一个只会聊天、不会动手的 Agent 没有价值——本篇讲工具化:怎么把插件已有的能力(PyQGIS 操作、SWAT 数据准备、建模链条、Processing 算法)翻译成模型能读懂、能调用、调用完还能自动呈现的东西。这个专题的所有设计都围绕一个判断:工具层是模型与插件之间唯一的翻译层,它值得被认真设计。

工具全景:14 个 QGIS 通用工具 + 14 个领域工具 + 6 个可直达的 Processing 算法。

一、工具契约:五面一体的注册表

每个工具向注册表登记五样东西,缺一不可:

契约面——name / description / input_schema(JSON Schema)。这是给模型看的全部:模型不知道函数签名,只认描述。所以描述不是注释,是文档——"把 CMADS 数据仓目录转换为 SWAT2012 气象目录(按研究区 bbox 筛站,换研究区自动补解压缺失站文件)。产物 weather_dir 供 swat_import_weather 使用",最后半句把下游依赖也写进去,模型才知道输出往哪送。

校验面——注册时查重;调用前做必填项与类型粗查。设计取舍在"严格程度"上:额外参数不拦截,交给模型自纠(模型偶尔会多传一个参数,直接报错会让它卡死,忽略则无害)。

执行面——统一的 execute(args) -> (ok, payload) 签名,payload 必须可 JSON 序列化(QgsRectangle 一律转 [xmin, ymin, xmax, ymax])。

呈现面——给模型的契约剥离 execute 本体,模型看得见的只有描述与参数。

权限面——read_only 与 needs_approval 标志,第四节展开。

新增一个能力的成本因此被压到最低:注册一个契约 + 写一个 execute 函数,校验、权限、线程派发、确认弹窗、日志、图层加载全部复用既有设施。

二、两族工具的分工

QGIS 通用工具族(14 个)让模型"看得见、动得了"当前工程:list_layers / layer_info / get_extent / zoom_to_layer / query_features 是只读侦察兵;load_layer / remove_layer / set_layer_opacity / reorder_layers 管工程操作;set_raster_style / set_vector_style / set_labels 管符号化(栅格伪彩色内置 5 种色带、min/max 缺省 2%~98% 累计截断);最后两个是通用兜底——run_processing 能跑任何 QGIS Processing 算法,run_pyqgis 能执行任意 PyQGIS 代码(预置 iface/QgsProject/processing 与 qgis.core 全符号,末尾表达式或 result 变量作为返回值,print 被收集回传)。

领域工具族(14 个)把插件的核心投入暴露出来:数据准备链 search_region → fetch_region → swat_acquire_data → swat_convert_weather(市名 → adcode → 边界 → 四件套 → 气象目录);建模链 swat_check_engine → swat_prep_data → swat_delineate → swat_import_weather → swat_write_files → swat_run → swat_read_outputs → swat_render_maps;外加只读查状态的 swat_project_status / swat_data_report。另外 6 个地灾分析算法(guangxi:static_susceptibility 等)通过 run_processing 直达——算法 id 写进了 Agent 指令,模型不需要猜。

三、执行线程双通道:最重要的一个设计决策

QGIS 插件做 Agent 有一个绕不开的物理约束:PyQGIS 只能在主线程调用,而 agent 循环跑在工作线程。第一直觉是"所有工具都发回主线程执行"——这也确实是 QGIS 工具族的做法。但领域工具的真身是核心函数:纯 Python、文件 I/O、子进程、sqlite,一个 Qt 对象都不碰。把一个要跑十分钟的 TauDEM 划界发回主线程,QGIS 整个冻住——完全没有必要。

exec 字段声明执行线程,派发器统一处理。能后台的后台,必须主线程的明说。

于是工具契约多了一个字段 exec:

  • exec="worker"(领域工具缺省)
    ——在 agent 线程直接调用核心函数。这个正确性的证据来自无头测试:整条 SWAT 链(含 QSWAT+ 划界)可以在无 GUI 环境用注入的 FakeIface 跑通。核心函数原生支持 progress 与 cancel 回调,接上之后进度实时刷状态栏、停止按钮即时取消。
  • exec="main"(PyQGIS 工具与 swat_delineate)
    ——信号回主线程执行。qswat_drive 驱动 QSWAT+ 插件需要真 iface,与建模面板手工执行同线程,行为完全一致。

必须诚实记录为什么 swat_delineate 没有走 worker 通道:无头测试证明的是"逻辑上不依赖 GUI",但 GUI 进程里主线程的事件循环是活着的,qswat_drive 首尾要动真 QgsProject,跨线程访问 QObject 是真风险——而且这个函数历史上出过一次"无头能过、界面必挂"的文件锁翻车。所以它是全插件唯一强制主线程的领域工具,工具描述里写明"期间界面无响应属正常",指令要求模型提前告知用户。

产物自动上图是这个设计的收尾:领域工具把产物路径列在 payload["load_layers"],worker 发信号回主线程逐个加载(支持 GeoPackage path|layername 子层写法),对话区显示"✓ 已加载图层(工具产物)"。用户不用自己去菜单里翻文件。

四、权限门控三级

只读放行、写操作确认、代码预览确认。门控点在工具适配层,模型每次调用都先过闸。

只读工具自动放行(可整体关闭)——列图层、查属性、查工程状态,问不伤人。写操作弹窗确认——加载/移除图层、拉数据、跑模型,确认框展示工具说明与完整参数;勾选"本会话内同类操作不再询问"后按工具名记忆,一次串跑只确认一次。run_pyqgis 强制代码预览——能力最强也最危险,确认框必须完整展示将执行的代码。

一个容易忽略的语义细节:权限拒绝不抛异常。内核对异常的反应是附加"让我们重试"的提示——但权限拒绝不该重试。所以适配层把拒绝作为 JSON 错误串("操作被用户拒绝")回给模型,指令里配套一条:"被拒时解释风险并询问替代方案,不要反复重试"。第 3 篇实战里能看到这条纪律真的起作用。

五、run_pyqgis:能力兜底的边界

专用工具覆盖不到的需求,模型可以写 PyQGIS 代码。这不是漏洞而是设计——第 3 篇里模型诊断工程数据库(查 sqlite 表结构、翻 QSWAT+ 插件源码定位 soils_sol 的写入逻辑)用的全是它,专用工具不可能穷举这些需求。风险由三层兜住:代码预览确认在前、预置命名空间收窄了入口、输出截断(stdout 2000 字符)防止刷爆上下文。


写在最后

工具化做完,插件在模型眼里是一份 28 项的菜单,每项都有说明、有参数表、有权限等级、有执行通道。但菜单不等于会点菜——"准备济南的 SWAT 分析数据并进行流域分析"这句话要被拆成十几个工具调用的正确顺序,模型还得知道划界前要先自检、气象导入前要先初始化工程、土壤库要贯穿哪几步。这些业务知识放在哪里、怎么让模型在真实串跑里用对,是第 3 篇(实战)和第 4 篇(技能化)的内容。

(本篇是我个人开发与测试的记录整理;工具数量、参数行为均来自插件源码与实测。欢迎交流指正。)


系列目录智能篇 · 插件智能化 第 1 篇 · 给 QGIS 装一个会说话的助手:插件内嵌 Agent 的四层架构 第 2 篇 · 把插件能力做成 Agent 的手:28 个工具的契约、线程与权限(本篇) 第 3 篇 · 一句"准备济南的 SWAT 数据"之后:Agent 串跑与三根新保险丝 第 4 篇 · 从工具到技能:让 Agent 懂业务的指令工程

相关系列正式篇 · 插件迁移与工程化(1–7 篇,含潍坊 SWAT 串跑复盘) 数据准备篇 · 第 1 篇 自动进货 / 第 2 篇 CMADS 实测

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料