跳至內容
AI Agent
QGIS
教學

QGIS 自動化教學:同一任務 4 種方法,2 座城市實測計時

發布於

重複性的 QGIS 工作流程有四種自動化方式:用批次處理(Batch Processing)把同一個工具套用到大量檔案,用圖形建模器(Graphical Modeler)串起一條會重複使用的工具鏈,用 PyQGIS 腳本寫迴圈並精準控制每一步,或在 QGIS 裡使用 AI 代理,只要一則白話訊息就能拿到結果。

我讀過的教學都只單獨教其中一種,而且用的是玩具範例,沒有一篇測試過把工作流程換到新城市再跑一次會發生什麼事。2026 年 11 月 7 日,我拿一個多步驟任務(用德國 Bielefeld 的 180,602 棟 OpenStreetMap 建物計算各行政區的建成區面積),在 QGIS 3.44.15 中用四種方法各做一次,再把四種方法全部換到 Münster(135,577 棟建物、6 個行政區)重跑。四種方法在兩座城市都通過檢查,不過圖形建模器有一次執行先顯示「OK」,實際卻寫出了 1,058 個多邊形,而不是 10 個。

8.1秒

PyQGIS 腳本跑 Bielefeld(Münster 為 7.4 秒)

62.7秒

QGIS 內的圖形建模器(無介面執行 44.5 秒)

60秒

AI Agent 用 1 句話重做 Münster

1,058筆

模型靜默出錯時寫出的列數,應為 10

什麼是 QGIS 自動化?

QGIS 自動化是指不必逐一點開對話框,就能把一個處理工具或一整串工具套用到多個圖層上。每種方法的底層都是 QGIS Processing 框架,也就是驅動 Processing Toolbox(處理工具箱)的同一套引擎。不論你是從批次表格、圖形建模器的流程圖、Python 腳本,還是 qgis_process 命令列工具呼叫,工具本身都完全一樣。所以選擇自動化方法,其實是在選擇你想怎麼把這些工具串起來,以及下個月想在硬碟上留下什麼檔案。

測試任務與資料

我挑了一個在都市計畫與顧問工作中很常見的任務:對每個行政區,把建物裁切到行政區邊界內,計算建物數量,加總面積(平方公尺),將裁切後的建物做 25 公尺緩衝區並融合成單一建成區多邊形,最後輸出一個乾淨的 GeoPackage,每個行政區一列。

如果建物跨越行政區界線,就會被裁切,並在它碰到的每個行政區各算一次。兩座城市都使用 BBBike PBF 擷取檔中的 OpenStreetMap 資料(ODbL,OpenStreetMap 貢獻者),所有測量都重投影到 EPSG:25832(ETRS89 / UTM zone 32N)。

  • 城市 1 Bielefeld 共 10 個行政區(admin_level=9)、180,602 個建物多邊形,裁切後產生 115,002 個建物片段。原始 OSM 中有兩棟建物的幾何無效,先用 Fix geometries(修正幾何)修復一次,讓四種方法都從同一組乾淨檔案開始。
  • 城市 2 Münster 為重跑用城市,共 6 個行政區、135,577 個建物多邊形,裁切後產生 116,382 個片段。

在跑任何一種方法之前,我先用純 PyQGIS 幾何呼叫寫了一份獨立的參考答案(QgsSpatialIndex、geometry.intersection()、unaryUnion() 和 buffer(25, 5),完全不呼叫 Processing 演算法),並存成一支檢查腳本。一種方法要算通過,必須輸出一個 GeoPackage,內含 EPSG:25832 的 built_up 多邊形圖層,各行政區建物數量完全正確,建物面積與參考值差距在 0.5% 以內,建成區公頃數差距在 1% 以內,而且事後不做任何手動修改。

方法 1:批次處理

Processing Toolbox 裡每個工具的對話框左下角都有 Run as Batch Process (以批次處理執行)按鈕。按下去,對話框會變成一張試算表,每一列就是該工具的一次執行。

在這個任務中,批次處理能乾淨地完成各行政區的 Clip 和各行政區的 Buffer,因為這兩步都是對 10 個行政區重複同一個演算法。但它沒辦法一次做完整個流程,因為批次處理一次只能跑一個工具,而且會留下 10 個獨立的輸出圖層,你還得自己合併、再接回同一張表。

重投影並拆分輸入資料

對建物執行 Reproject layer (Vector general),轉成 EPSG:25832。接著對行政區圖層執行 Split vector layer (Vector general),依 name 欄位拆分,會在資料夾中為每個行政區各寫出一個 GeoPackage。

對所有行政區批次執行 Clip

開啟 Clip (Vector overlay),點 Run as Batch Process ,每個行政區檔案新增一列。把重投影後的建物設為 Input layer,用 Autofill 自動填入行政區疊加圖層與輸出表名稱(clip_<district>),並取消勾選 Load layers on completion 。Bielefeld 的 10 列全部在 13.7 秒內完成(每個行政區 1.0 到 4.2 秒)。

開啟 Dissolve 並批次執行 Buffer

以批次模式開啟 Buffer (Vector geometry):每個裁切圖層一列,Distance 設 25,Segments 設 5,並勾選 Dissolve result 。Bielefeld 的 10 個緩衝區花了 27.7 秒。

合併、彙總,再把表格接回來

執行兩次 Merge vector layers (一次合併 10 個裁切圖層,一次合併 10 個緩衝區圖層)。對合併後的裁切結果執行 Aggregate (Vector geometry),依 layer 欄位分組,得到 building_count(count($id))與 building_area_m2(sum(area($geometry)))。對合併後的緩衝區執行 Refactor fields (Vector table),用 $area / 10000 這個欄位計算機運算式算出 built_up_ha,最後用 Join attributes by field value (Vector general)以 district 連接,產生單一輸出圖層。

QGIS 中 Clip 演算法的批次處理對話框,已為 Bielefeld 的 10 個行政區設定 10 列,顯示 Input layer、Overlay layer 與 Clipped 輸出路徑。
批次處理對話框中的步驟 2:10 列 Clip,Bielefeld 每個行政區一列。執行耗時 13.7 秒。

9 次執行(8 種不同演算法)下來,Bielefeld 的工具總執行時間為 62.0 秒,每個行政區的數量都與參考值相符。換到 Münster,6 個行政區的工具時間降到 39.8 秒,但我必須重建 6 列的批次表格,再手動重跑全部 9 個步驟。如果你的工作流程是一串不同的工具,而不是同一個工具套用到 50 個檔案,批次處理就不是合適的形式。

方法 2:圖形建模器

圖形建模器(Processing > Graphical Modeler)讓你把一串 Processing 工具接成一張流程圖,存成 .model3 檔。建好之後,模型會像原生工具一樣出現在 Processing Toolbox 裡。

你可能以為要在建模器裡對行政區跑迴圈,其實不用。先對建物和行政區執行 Intersection ,每個建物片段就會繼承所屬行政區的 name 屬性,接著 Aggregate 和 Dissolve 依 name 分組,一次就能產生每個行政區一列。(如果不需要嚴格在行政區界線上切開建物,也可以改用空間連接。)

新增三個模型輸入

在新模型中新增兩個 Vector Layer 輸入(Polygons),分別命名為 Buildings 與 Districts,再新增一個 Number 輸入,命名為 Buffer distance (m),預設值 25。

重投影兩個輸入並做交集

新增兩個目標為 EPSG:25832 的 Reproject layer 節點。把兩者都接到 Intersection 節點(Buildings 為 Input,Districts 為 Overlay)。在 Intersection 的 Input fields to keep 中,建物欄位只保留 osm_id;在 Overlay fields to keep 中保留 name。

分支到 Aggregate 計數,以及 Dissolve + Buffer 處理幾何

從 Intersection 拉一條分支到 Aggregate ,依 name 分組,計算 count($id) 與 sum(area($geometry))。再從 Intersection 拉第二條分支到 Dissolve (欄位 name),後接 Buffer (連到 Buffer distance (m) 輸入,5 個 segments)。

合併分支並整理輸出表格

新增 Join attributes by field value ,以 name 把 Aggregate 表接到緩衝區多邊形上,再用 Refactor fields 把 name 改名為 district,並以 $area / 10000 計算 built_up_ha。將輸出標記為 built_up,模型存成 built_up_by_district.model3。

QGIS 圖形建模器畫布上的 built_up_by_district 模型:三個輸入接到八個演算法方塊(Reproject 兩次、Intersection、Aggregate、Dissolve、Buffer、Join、Refactor fields),最後輸出 built_up。
圖形建模器中完整的八個演算法模型。依行政區名稱欄位彙總與融合,就不需要迴圈。

在 Bielefeld 上從模型對話框執行花了 62.7 秒,所有檢查都通過。更棒的是,同一個 .model3 檔透過 qgis_process 在 macOS 終端機中執行、不開任何 QGIS 視窗,只要 44.5 秒。

真正的回報出現在 Münster 重跑時。我打開同一個模型對話框,在兩個下拉選單中選 muenster_buildings 和 muenster_districts,按下 Run 。67.2 秒跑完,模型一個字都沒改。

QGIS 中 built_up_by_district 的 Run Model 對話框,Bielefeld 執行完成後,記錄顯示「Execution completed in 62.68 seconds」。
模型存好後,在 Bielefeld 執行(或換到 Münster 重跑)只需一個有兩個圖層下拉選單的對話框。

方法 3:在 Python 主控台執行 PyQGIS 腳本

如果你熟悉 Python,在 Plugins > Python Console > Show Editor 裡寫腳本,就能有真正的 for 迴圈,輸入參數放在檔案最上方當變數,也不需要合併步驟。

以下是我在 QGIS 3.44.15 中執行的 38 行腳本(built_up_by_district.py),檔案路徑已縮短:

# Built-up area by district. Run in the QGIS Python console (Plugins > Python Console > Show Editor > Run).
# Change the first five lines for a new city.
BUILDINGS = "data/bielefeld_buildings.gpkg"
DISTRICTS = "data/bielefeld_districts.gpkg"
NAME_FIELD = "name"
BUFFER_M = 25
OUT = "out/script/built_up_script.gpkg"

import processing
from qgis.core import (QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFeature, QgsField, QgsFields, QgsGeometry)
from qgis.PyQt.QtCore import QVariant

crs = QgsCoordinateReferenceSystem("EPSG:25832")   # metric, Germany
def run(alg, **p):
    return processing.run(alg, p)["OUTPUT"]

buildings = run("native:reprojectlayer", INPUT=BUILDINGS, TARGET_CRS=crs, OUTPUT="memory:")
districts = run("native:reprojectlayer", INPUT=DISTRICTS, TARGET_CRS=crs, OUTPUT="memory:")

result = QgsVectorLayer("MultiPolygon?crs=EPSG:25832", "built_up", "memory")
result.dataProvider().addAttributes([QgsField("district", QVariant.String), QgsField("building_count", QVariant.Int),
                                     QgsField("building_area_m2", QVariant.Double), QgsField("built_up_ha", QVariant.Double)])
result.updateFields()

for d in districts.getFeatures():
    one = run("native:extractbyexpression", INPUT=districts, EXPRESSION=f"$id = {d.id()}", OUTPUT="memory:")
    clipped = run("native:clip", INPUT=buildings, OVERLAY=one, OUTPUT="memory:")
    area = sum(f.geometry().area() for f in clipped.getFeatures())
    built_up = run("native:buffer", INPUT=clipped, DISTANCE=BUFFER_M, SEGMENTS=5, DISSOLVE=True, OUTPUT="memory:")
    geom = next(built_up.getFeatures()).geometry()
    f = QgsFeature(result.fields())
    f.setGeometry(geom)
    f.setAttributes([d[NAME_FIELD], clipped.featureCount(), area, geom.area() / 10000])
    result.dataProvider().addFeature(f)
    print(d[NAME_FIELD], clipped.featureCount(), round(area), round(geom.area() / 10000, 1))

processing.run("native:savefeatures", {"INPUT": result, "OUTPUT": OUT, "LAYER_NAME": "built_up"})
print("saved", OUT)

這支腳本把所有中間圖層都留在記憶體中,並對行政區跑迴圈,是目前最快的方法(我們沒有分析原因)。它在 8.1 秒內跑完 Bielefeld,每個行政區都與獨立參考值相差 0.00%。

QGIS Python 主控台,程式碼編輯器開著 38 行的 built_up_by_district.py 腳本。
在 QGIS Python 主控台編輯器中執行 38 行腳本:Bielefeld 8.1 秒,Münster 7.4 秒。

要換到 Münster 重跑,我改了最上面三行(BUILDINGS、DISTRICTS 和 OUT),再按綠色的 Run Script 播放按鈕,7.4 秒就跑完。想深入了解 processing.run 的運作方式,請看我們的 PyQGIS 指南。

四種方法在兩座城市的比較

以下是我們在 2026 年 11 月 7 日對四種方法的實測結果:

批次處理圖形建模器PyQGIS 腳本AI Agent(Medium、Balanced)
設定 / 結構9 次執行、8 種演算法(2 張 10 列的批次表)3 個輸入 + 8 個演算法節點 + 1 個輸出38 行 Python、5 種演算法1 則白話訊息(代理呼叫 27 次工具)
Bielefeld 執行時間 (10 個行政區)工具時間 62.0 秒(逐一啟動)對話框 62.7 秒(qgis_process 為 44.5 秒)8.1 秒(修正 1 次失敗的存檔呼叫後)從送出到結果表 110 秒
Münster 重跑 (6 個行政區)工具時間 39.8 秒(重建批次列並重跑 9 步)67.2 秒(選 2 個新圖層,按 Run)7.4 秒(改 3 行檔案路徑,按 Run)60 秒(1 則 46 字的追加訊息、15 次工具呼叫)
與參考值的最大差距 (built_up_ha)+0.08%+0.08%0.00%+0.21%
事後留下什麼約 20 個中間圖層一個 .model3 檔(可在介面或無介面執行)一個 .py 腳本檔對話紀錄和你的提示文字

每種方法的建物數量與建物面積(building_area_m2)都與參考值相差 0.00%。批次處理和圖形建模器在 built_up_ha 上的 +0.08% 差距,來自 Refactor fields 中的 $area 是以專案橢球體計算,而腳本和參考值用的是 EPSG:25832 下的平面 geometry().area()。

過程中出了哪些問題(包括一次靜默的錯誤結果)

教學很少展示失敗的執行,所以我把當天所有錯誤都記錄下來。最可怕的失敗不是當機,也不是紅色錯誤訊息,而是一次圖形建模器執行回報成功,給出的卻是錯誤結果。

我第一次以無介面方式執行模型時,還沒限制 Intersection 節點的欄位,記錄印出:

Model processed OK. Executed 8 algorithm(s) total in 84.548 s.

沒有錯誤,也沒有警告。我檢查輸出的 GeoPackage,built_up 裡有 1,058 個多邊形 ,而不是 10 個。

原因是:OpenStreetMap 建物本身有 name 欄位(商店、學校或教堂的名稱),行政區圖層也有 name 欄位。Intersection 合併兩個圖層的所有欄位時,建物的 name 維持 name,行政區的 name 則被靜默改名為 name_2。下游的 Aggregate 和 Dissolve 依 name 分組,結果是依建物名稱分組,而不是依行政區!把 Intersection 的 Input fields to keep 限制為 osm_id 後,就避開了這個衝突,輸出也回到 10 個行政區。

另外還有三件事出了問題,在你自動化自己的資料前值得先知道:

  • 無效的 OSM 幾何預設會讓 Processing 停止 Bielefeld 的 180,602 棟建物中有兩棟是自相交的環。在 QGIS 預設設定下,Clip 會立刻停止並顯示 Feature (18818404) from 'b' has invalid geometry。只要輸入來自原始 OpenStreetMap,第一步就先執行 Fix geometries 。
  • PyQGIS 的 savefeatures 不接受 GDAL 連線字串 第一次執行腳本時(10.0 秒),把 ogr:dbname='...' table="built_up" 傳給 native:savefeatures 會出現 OGR driver for '' not found。請在 OUTPUT 傳入單純的 .gpkg 路徑,另外把 LAYER_NAME: "built_up" 設為獨立參數。
  • 載入大量中間圖層讓我們的工作階段當機 勾選 Load layers on completion 時,Processing 輸出載入圖層樹的過程中,QGIS 當機(SIGSEGV)了三次。對批次中的中間列取消勾選後,就不再當機。

方法 4:在 QGIS 裡請 AI 代理處理

AI Agent 是我們開發的,所以這一節談的是我們自己的外掛。它會在 QGIS 裡停駐一個聊天面板,檢查專案中現有的圖層和欄位,自行呼叫 QGIS Processing 工具和 PyQGIS,並在回答前檢查輸出。

如果只是一次性的工作,或只有兩座城市的專案,建一個 8 節點的圖形模型或除錯一支 38 行的腳本,常常比任務本身還費工。我打開一個含有 Bielefeld buildings 和 districts 圖層的專案,把面板設為 Medium 推理強度和 Balanced 權限,送出一則訊息:

The project has two layers: "buildings" (OSM buildings of Bielefeld, Germany) and "districts" (its 10 city districts, the district name is in the field "name"). For each district: clip the buildings to the district, count the buildings, sum their footprint area in square meters, and build a 25 m buffer around the clipped buildings, dissolved into one built-up polygon, with its area in hectares. Measure in a metric CRS (EPSG:25832). Write one GeoPackage at [output folder]/built_up_agent.gpkg with a single polygon layer named built_up, one feature per district, fields district, building_count, building_area_m2, built_up_ha, in EPSG:25832. Then show me the result table.

(兩則提示中的輸出路徑都已縮短。透明說明:第一次嘗試時,我按下送出 9 秒後 QGIS 就因 Qt slot segfault 當機,還沒回傳任何答案。我重新開啟專案,把完全相同的提示再送一次,之後就沒有再重送。)

在 110 秒內,代理呼叫了 27 次工具(12 run_processing、7 get_algorithm_help、4 execute_code、2 get_layer_info、1 export_layer、1 get_features),自行從一次內部 Processing 錯誤中恢復,沒有跳出權限卡片,寫出 GeoPackage,並在聊天中列出 10 個行政區的表格。它還在沒有被要求的情況下,在回答中提醒:「25 公尺緩衝區可能跨越行政區邊界並互相重疊。」

停駐在 QGIS 中的 AI Agent 面板,顯示完成的 Bielefeld 分析:已儲存的 GeoPackage 標籤、25 公尺緩衝區跨行政區重疊的提醒,以及列出 Bielefeld 全部 10 個行政區建物數量與面積的 markdown 表格。
一則提示、110 秒:Bielefeld 的 GeoPackage 已存到硬碟,聊天面板中出現 10 個行政區的摘要表。

接著我把 muenster_buildings 和 muenster_districts 拖進專案,在同一個對話中輸入一則 46 字的追加訊息:

Now do the same for Münster. I added two layers: "muenster_buildings" and "muenster_districts" (6 districts, the name is in the field "name"). Same fields and same 25 m buffer, in a new GeoPackage at [output folder]/built_up_agent_muenster.gpkg with the layer named built_up. Then show me the result table.

由於第一次測試就在同一個對話中,代理只用 60 秒 、15 次工具呼叫(11 run_processing、1 export_layer、1 get_features、1 zoom_to_layer、1 execute_code)就完成 Münster,零錯誤。

送出 46 字的 Münster 追加訊息後,QGIS 中的 AI Agent 面板顯示已完成「15 steps」,以及 6 個行政區的結果表,畫布上是 Münster 的地圖。
Münster 重做只需一則 46 字的追加訊息和 60 秒(15 次工具呼叫)。

兩座城市的每個建物數量和建物面積都與參考值相差 0.00%。

限制在哪裡?第一,代理的 built_up_ha 數值比平面參考值高出 0.07% 到 0.21%(例如 Brackwede 得出 1,390.51 ha,參考值為 1,388.31 ha;我們沒有測量是哪個內部步驟造成這個小差距)。第二,匯出的 GeoPackage 多了一個 _export_fid 欄位。第三,也是對自動化最重要的一點:代理每則訊息都會重新規劃步驟(Bielefeld 27 次工具呼叫,Münster 15 次),而且是在開著的 QGIS 工作階段中運作,所以不會留下可以用 cron 無人值守排程的 .model3 或 .py 檔。

Münster 六個行政區的 EPSG:25832 地圖,融合後的 25 公尺建成區多邊形以橘色繪製在行政區邊界上。
Münster 測試儲存的 `built_up` 圖層,以 EPSG:25832 繪製在六個行政區邊界上。

該選哪一種 QGIS 自動化方法?

與其認定某個工具是贏家,不如依你重複這項工作的頻率來選方法:

  • 要把同一個工具套用到 10 到 100 個檔案 用 批次處理 。它內建在每個 Processing 對話框中,免費,也不用寫程式。一旦工作流程要串三、四個不同工具,就別再用它。
  • 你或團隊每個月都要跑一條多步驟工具鏈,或要在伺服器上排程 用 圖形建模器 建。你會得到單一 .model3 檔,可以分享給不寫 Python 的同事,也能透過 qgis_process 從 shell 腳本或排程工作以無介面方式執行。
  • 需要自訂迴圈、精準的平面計算控制或最快的執行速度 寫一支 PyQGIS 腳本 。我們的 38 行腳本在兩座城市都比建模器快 8 到 9 倍。
  • 今天要把一個複雜任務跑一兩次,或套用到幾個專案變體 使用 QGIS 內的 AI 代理,例如 AI Agent(或參考 QGIS AI 專區的整體介紹)。你不必到處找確切的工具名稱,一句話就能換到第二座城市重做。Free 方案每月提供 5 個 Low 推理強度的任務;這些測試使用 Medium,屬於 Pro 方案(每月 49 EUR 未稅,300 個任務)。

我們如何測量 所有測試都在 2026 年 11 月 7 日,於一台 Apple Silicon Mac(macOS 27.0.1,arm64)上的獨立 QGIS 3.44.15-Solothurn 工作階段(Python 3.12.11)中進行,搭配 AI Agent 1.9.4(Medium 推理強度、Balanced 模式)。當天電腦負載有變動,所以請把時間當作數量級比較,而不是 CPU 效能基準。我們測量的是機器的實際執行時間與步驟數,不是 GIS 分析師從零開始拼出模型或寫出腳本所花的人工時間。所有輸入、.model3 檔、.py 腳本、參考檢查程式與原始 JSON 記錄都保存在我們的實驗檔案庫中。

常見問題

如何在 QGIS 中自動化重複性的工作流程?

依工作重複的頻率,你有四個主要選擇。單一工具套用到大量檔案,就在工具對話框中點 Run as Batch Process 。會定期重跑的多步驟工具鏈,就在 Processing > Graphical Modeler 中把工具接起來,存成 .model3 檔。需要迴圈和最快效能,就在 QGIS Python 主控台中用 processing.run() 寫 Python 腳本。只做一次或少數幾次、不想接節點也不想寫程式的分析,就在 AI Agent 這類代理外掛中用白話描述工作流程。

QGIS 圖形建模器和 Python(PyQGIS)該選哪個?

如果工作流程是一條直線串接的 Processing 演算法,而且你想要一個團隊中不寫程式的人也能打開的視覺化 .model3 檔,或想用 qgis_process 從命令列執行,就用圖形建模器。如果你需要對圖徵跑迴圈、把中間圖層留在記憶體中(在我們的 Bielefeld 測試中,腳本 8.1 秒,模型 62.7 秒)、在程式中處理錯誤,或明確控制輸出結構,就用 PyQGIS。

可以把 QGIS 圖形模型匯出成 Python 腳本嗎?

可以。圖形建模器能把模型匯出成 Python Processing 腳本( Export as Script Algorithm ),之後你可以再編輯,加入迴圈、變數或自訂邏輯。這次比較中我們沒有測試匯出功能。

QGIS 能不開啟程式就排程執行自動化工作流程嗎?

可以。QGIS 內建一個名為 qgis_process 的命令列工具。你可以從 bash 腳本、Windows 工作排程器或 cron 工作,把任何原生演算法或已存的 .model3 檔傳給它(例如 qgis_process run model3 --BUILDINGS=... --DISTRICTS=... --built_up=...),完全不必啟動 QGIS 圖形介面。在我們的 Bielefeld 測試中,模型透過 qgis_process 以無介面方式執行,耗時 44.5 秒。

免費試用 AI Agent

在 QGIS 裡開口就能完成

AI Agent 會在你自己的 QGIS 專案中,執行你描述的任務。免費使用,不需信用卡。

免費試用 AI Agent
由以下作者撰寫Yvann Barbot
·8 min read