Smoke Checklist¶
Ручная проверка в живом QGIS — то, что не покрыть тестами: настоящие вызовы
PyQGIS к слоям и отрисовка Qt. Всё остальное закрыто набором tests/.
Техническая проверка после правок¶
python3 -m unittest discover -s tests -t .
Набор проходит без QGIS. Если он красный — в живой QGIS идти рано.
Read-тулы без агента¶
Открыть проект со слоями, затем Плагины → Консоль Python:
from ai_agent.qgis_tools.registry import execute_tool
execute_tool("get_project_info", {})
execute_tool("list_layers", {})
execute_tool("describe_layer", {"layer_name": "ИМЯ_СЛОЯ"})
execute_tool("get_field_values", {"layer_name": "ИМЯ_СЛОЯ", "field_name": "ПОЛЕ"})
execute_tool("sample_features", {"layer_name": "ИМЯ_СЛОЯ", "limit": 3})
execute_tool("query_layer", {"layer_name": "Дороги", "aggregate": "count"})
execute_tool("query_layer", {"layer_name": "Дороги", "aggregate": "count", "filter": "highway = 'motorway'"})
execute_tool("query_layer", {"layer_name": "Города", "order_by": "population DESC", "limit": 5, "fields": ["name", "population"]})
execute_tool("query_layer", {"layer_name": "Реки", "order_by": "$length DESC", "limit": 1})
execute_tool("query_layer", {"layer_name": "Озера и пруды", "aggregate": "sum", "expression": "$area"})
execute_tool("query_layer", {"layer_name": "Дороги", "aggregate": "mean", "expression": "$length", "group_by": "highway"})
execute_tool("describe_style", {"layer_name": "ИМЯ_СЛОЯ"})
execute_tool("get_qgis_info", {})
execute_tool("get_canvas_extent", {})
execute_tool("search_processing", {"query": "buffer"})
execute_tool("describe_processing", {"algorithm_id": "native:buffer"})
Ожидания:
get_project_infoотдаёт дерево слоёв с группами и видимостью, единицы, темыdescribe_layerдля слоя вEPSG:4326отдаётcrs_is_geographic: True,suggested_metric_crs, а такжеprovider,is_validиstyle_summaryget_field_valuesдля числового поля отдаётmin/max, для текстового — список уникальных значений с пометкой об обрезкеsample_featuresотдаёт реальные записи, длинные значения обрезаныdescribe_styleпоказывает тип рендерера и классы с цветамиdescribe_processingотдаёт enum парами{"value": 0, "label": "Round"}- несуществующее имя слоя или поля даёт ошибку со списком доступных
query_layerбезaggregateотдаёт объекты, сaggregate— одно числоgroup_byдаёт список групп со значением и числом объектов в каждой$lengthи$areaсчитаются в единицах CRS слоя: на слое в градусах число получится бессмысленным, агент обязан это сказать- ошибка в выражении даёт текст парсера, а не падение
Ветки классов в describe_style¶
Категории, градации и правила не проверить на проекте с одиночными символами. Снипет подставляет категоризацию, проверяет и возвращает рендерер обратно — в проекте ничего не остаётся:
from qgis.core import QgsProject, QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsSymbol
from ai_agent.qgis_tools.registry import execute_tool
layer = QgsProject.instance().mapLayersByName("ИМЯ_СЛОЯ")[0]
saved = layer.renderer().clone()
field = layer.fields().names()[1]
values = list(layer.uniqueValues(layer.fields().indexOf(field)))[:4]
categories = [
QgsRendererCategory(v, QgsSymbol.defaultSymbol(layer.geometryType()), str(v))
for v in values
]
layer.setRenderer(QgsCategorizedSymbolRenderer(field, categories))
print(execute_tool("describe_style", {"layer_name": "ИМЯ_СЛОЯ"}))
print(execute_tool("describe_layer", {"layer_name": "ИМЯ_СЛОЯ"})["style_summary"])
layer.setRenderer(saved)
Ожидания: class_attribute, список classes со значением, подписью и символом
на каждый класс, style_summary вида «категории по полю «…», классов: 4».
Секреты в источнике¶
Если есть слой PostGIS — проверить, что пароль не утекает:
execute_tool("describe_layer", {"layer_name": "ИМЯ_СЛОЯ_POSTGIS"})["source"]
В строке должно быть password=‹скрыто›, а не сам пароль.
Агентный цикл¶
- Чтение без подтверждения. «что у меня в проекте?» → агент вызывает
list_layers, отвечает по факту, кнопки подтверждения не появляются. - Данные из проекта. «какие поля в слое X?» →
describe_layer, в ответе реальные поля. - Формулировка до подтверждения. Агент пишет «предлагаю», а не «я создал».
- Отмена. Нажать «Отмена» → в проекте ничего не изменилось.
- Ошибка тула не рвёт прогон. Запрос с несуществующим слоем → агент видит ошибку и исправляется сам.
- Лимит ходов. Заведомо неподъёмная задача → остановка на
MAX_ITERATIONSс внятным сообщением, QGIS не виснет.
Скиллы¶
- Вопрос про слои не требует
load_skill—inspectпредзагружен. - Запрос про обработку → в логе видно
Загружен скилл: processing. - Вопрос про цвета и оформление →
Загружен скилл: style. - Скилл загружается один раз за прогон.
Сбор контекста¶
- «расскажи про мой проект» →
get_project_info, в ответе группы слоёв, что включено, единицы измерения - «какие значения в поле X» →
get_field_values, реальные значения - «почему города красные» →
load_skill(style)→describe_style, ответ называет поле классификации и цвет, а не просто «красные» - битый слой (переименовать исходный файл) →
describe_layerотдаётis_valid: false, агент предупреждает, а не строит планы поверх
Обработка и проверка CRS¶
Главный сценарий, ради которого сделана валидация до очереди:
- «построй буфер 500 м вокруг городов» на слое в
EPSG:4326 - первый
run_processingотклоняется — шаг помечен ✕ в чате - агент не останавливается: читает ошибку и строит план из двух шагов —
native:reprojectlayer→native:bufferна его результате - после подтверждения в проекте появляются оба слоя, буфер геометрически верный
Дополнительно:
- «найди алгоритм буфера» →
search_processingвозвращаетnative:buffer - enum передан подписью вместо индекса → тул сам приводит к индексу
Транспорт¶
- Эндпоинт с function calling — работает нативный путь.
- Эндпоинт без него — первый запрос падает на
tools, адаптер уходит в JSON-протокол, флагsupports_toolsзаписывается, следующие запросы сразу идут по JSON-пути. - Смена URL в настройках не ломает выбор: флаг хранится по хешу URL.
from ai_agent.core.settings import get_api_url, get_supports_tools
get_supports_tools(get_api_url())
Потоки и выгрузка¶
- UI не подвисает во время многошагового прогона.
- Во время применения батча кнопка «Отправить» заблокирована, в чате видно прогресс по шагам.
- Выгрузка плагина при активном запросе не роняет QGIS.
Диалоги¶
Кнопка «Диалоги» — в шапке панели, слева от «Очистить».
- Диалог переживает перезапуск. Спросить «какие у меня слои?», дождаться ответа, закрыть QGIS, открыть заново, открыть плагин → «Диалоги» → в списке есть строка с текстом вопроса. Выбрать её: переписка вернулась целиком.
- Модель помнит контекст восстановленного диалога. После пункта 1 спросить «а сколько их?» — ответ должен опираться на прошлый вопрос, а не переспрашивать.
- Новый диалог не тянет старое. «Диалоги» → «Новый диалог»: лента пуста. Задать вопрос, вернуться к прошлому диалогу — оба на месте и не перемешаны.
- Заголовок — первая реплика. Длинный вопрос обрезается многоточием, не ломает ширину меню.
- Привязка к проекту. Открыть другой проект QGIS → «Диалоги»: диалогов из прошлого проекта в списке нет. Вернуть прежний проект — список вернулся.
- Пустое не копится. Нажать «Новый диалог» пять раз подряд, ничего не спрашивая → в списке не появилось пяти пустых строк.
- Переключение во время работы запрещено. Дать долгую задачу и, пока агент работает, нажать «Новый диалог» → служебное сообщение «Дождитесь окончания текущей задачи», лента не очистилась.
- Переключение с неприменённым планом запрещено. Дождаться карточки плана и, не нажимая «Применить», выбрать другой диалог → сообщение про запланированные изменения, карточка на месте, кнопка «Применить» всё ещё работает.
- «Очистить диалог» не удаляет сохранённое. Очистить ленту, открыть «Диалоги» → диалог по-прежнему в списке и открывается с сообщениями.
Остановка прогона¶
- Кнопка меняется. Задать любой вопрос: в момент работы кнопка отправки становится красным квадратом, подсказка — «Работаю… нажмите ■, чтобы остановить».
- Остановка срабатывает сразу. Дать долгую задачу и нажать ■ — панель разблокируется мгновенно, не дожидаясь ответа модели. Появляется сообщение «Прогон остановлен».
- Поздний ответ не всплывает. После остановки подождать минуту: ответ модели на прерванный запрос не должен появиться в ленте задним числом.
- После остановки можно работать дальше. Задать новый вопрос — он проходит обычным порядком.
- Остановка отменяет план. Довести до карточки плана, нажать ■ (если прогон ещё идёт) или проверить, что после остановки «Применить» ничего не применяет.
- Enter во время работы поправляет, а не ставит в очередь. Начать долгую задачу, ввести «вообще-то сделай синим, не красным», нажать Enter → реплика появляется в ленте с пометкой, что передана агенту, и агент учитывает её на следующем шаге, не начиная задачу заново.
Изменение оформления¶
Требует живого проекта со слоями. Все пять тулов — пишущие, значит каждый раз должна появляться карточка плана с кнопкой «Применить».
- Один цвет. «Сделай реки синими» → карточка плана, после «Применить» слой перекрашен и легенда обновилась без перезапуска QGIS.
- Отмена ничего не меняет. Повторить пункт 1 и нажать «Отмена» — цвет слоя прежний.
- Категории. «Раскрась дороги по типу» → категорий столько же, сколько уникальных значений поля; в легенде подписи значений.
- Палитра по умолчанию. Тот же запрос без указания палитры не должен падать с ошибкой про палитры.
- Несуществующая палитра. «Раскрась по типу палитрой ЧегоТоТам» — агент получает список доступных и повторяет вызов сам, не спрашивая пользователя.
- Градации. «Раскрась по населению, 7 классов, jenks» → семь классов, границы не одинаковые.
- Текстовое поле в градациях. «Градации по названию» — агент должен переключиться на категории, а не сдаться.
- Подписи. «Подпиши города названиями» → подписи появились. «Убери подписи» → исчезли, оформление символов при этом не изменилось.
- Прозрачность. «Сделай подложку на 50% прозрачной» → слой полупрозрачный, рендерер не сброшен.
- Растр. Прозрачность работает и на растровом слое.
- Цвет словами. «Сделай леса тёмно-зелёными» — агент подбирает hex сам, ошибки про нераспознанный цвет быть не должно.
- Чтение перед записью. «Почему города красные? Сделай их синими» — в ленте сначала describe_style, потом set_symbol.
Подписи: обводка текста¶
- Обводка включается. «Сделай у подписей городов белую обводку, чтобы читались» → в плане один шаг, в нём видно «обводка текста white». После применения подписи с ореолом, размер и цвет текста не сброшены.
- Обводка снимается. «Убери обводку у подписей» → ореол исчез, подписи остались.
- Шаги в плане различимы. Запрос, где меняется и цвет, и обводка, не должен давать два одинаковых по тексту шага.
- Дубли схлопываются. Если агент поставил один и тот же вызов дважды, в карточке плана он должен быть один раз.
- Агент не обещает словами. Запрос про оформление должен сразу давать карточку плана, а не фразу «предлагаю изменить…» без единого шага.
Подписи: свойства одним вызовом¶
- Шрифт. «Сделай подписи городов шрифтом Arial, жирным» → в плане один шаг, в нём видно font и bold. После применения шрифт сменился.
- Сдвиг. «Сдвинь подписи городов на 3 мм вверх» → подписи сместились; вверх это offset_y отрицательный, проверить направление глазами.
- Размещение. «Поставь подписи вокруг значков, а не поверх» → placement сменился на around.
- Каталог свойств. «Какие настройки подписей есть?» → агент зовёт describe_style_options и перечисляет реальные свойства, а не выдуманные.
- Незнакомое свойство. Попросить что-то на грани, например «сделай подписи вразрядку» — агент либо находит свойство, либо честно говорит, что такого нет, а не обещает прозой.
- Всё одним шагом. «Подпиши названиями, жирным, 12 пунктов, с белой обводкой» → в карточке ровно один шаг, а не четыре.
Символ: свойства одним вызовом¶
- Пунктир. «Сделай дороги серыми пунктирными» → в плане один шаг со stroke_style=dash, после применения линии пунктирные.
- Форма значка. «Города квадратными значками» → значки квадратные.
- Только контур. «Полигоны без заливки, только контур» → fill_style=none, контур виден.
- Неприменимое свойство. «Сделай дороги квадратными» → агент не должен молча отчитаться об успехе: в результате будет skipped с пояснением, и агент сообщит пользователю, что форма к линиям неприменима.
- Каталог символа. «Какие настройки символа есть?» → describe_style_options с kind=symbol, перечислены реальные свойства.
Проект и слои¶
- Загрузка слоя. «Загрузи /путь/к/файлу.geojson» → карточка плана, после применения слой в дереве и на карте.
- Несуществующий файл. «Загрузи /нет/такого.shp» → внятная ошибка про путь, ничего не поставлено в очередь.
- Повтор имени. Загрузить тот же файл второй раз → агент получает отказ и сам предлагает другое имя, а не пытается снова.
- Группа. «Добавь слой в группу Фон» → группа создалась, слой внутри.
- Видимость. «Спрячь слой дорог» → галочка снята, карта перерисована.
- Переименование. «Переименуй слой в «Дороги города»» → имя сменилось и в дереве, и в легенде.
- Порядок. «Подними реки наверх» → слой стал первым в своей группе и рисуется поверх остальных.
- Возврат в корень. Переместить слой в группу, затем «вынеси из группы» → слой в корне дерева.
- Зум. «Покажи слой городов» → карта подогналась под охват, подтверждения не спрашивалось.
- CRS проекта. «Переведи проект в EPSG:3857» → сменилась проекция карты, CRS самих слоёв прежняя.
- Сохранение. «Сохрани проект» на уже сохранённом проекте → записался туда же, заголовок окна без звёздочки.
- Новый проект. «Сохрани проект» на несохранённом → агент не выдумывает путь, а просит его.
- Удаление слоя. «Убери слой X» → слой исчез из проекта, файл на диске остался.
- Сквозной сценарий. «Загрузи файл, раскрась по типу, подпиши названиями и сохрани проект» → один прогон, все шаги в одной карточке плана.
Данные из OpenStreetMap¶
Требует интернета. Overpass — публичный сервис, отказ «занят» это не баг.
- Кафе по имени места. «Скачай кафе в Твери» → карточка плана, после применения слой точек с кафе, объектов больше нуля.
- Текущий вид. Приблизиться к небольшому району, «загрузи здания в текущем виде» → агент передаёт bbox=canvas, а не выдумывает координаты.
- Геометрия. «Скачай дороги» → слой линий; агент не должен добавлять заодно слой точек, если его не просили.
- Слишком широкий охват. Отдалиться до континента и повторить пункт 44 → отказ до отправки запроса, с объяснением про пять градусов.
- Русское значение тега. «Скачай amenity=кафе» → пустой результат, агент должен объяснить про английские теги, а не повторять запрос.
- Несуществующее место. «Скачай кафе в Нетакогогорода» → пусто, внятное сообщение.
- Занятый Overpass. Если сервис вернул отказ — агент сообщает и предлагает повторить, а не долбит запрос заново.
- Сквозной сценарий. «Скачай парки в Твери, раскрась зелёным, подпиши названиями и сохрани проект» → один прогон, все шаги в одной карточке.
- Пустые подслои не приезжают. «Скачай кафе в Твери» с geometry=all → в проект добавлен только слой точек; пустые линии и полигоны отброшены.
- Несколько тегов разом. «Скачай кафе, бары и рестораны в Твери одним слоем» → один вызов с selectors и регуляркой, один слой точек.
- Исключение. «Загрузи дороги кроме грунтовых» → selectors с
!~, в результате нет highway=track. - Разные ключи вместе. «Магазины и кафе» → несколько селекторов в одном вызове, а не два отдельных вызова.
- Селектор без условий. Попросить «скачай вообще всё отсюда» → отказ с объяснением, что нужен хотя бы один тег.
Штатные инструменты QGIS¶
Проверяют, что агент решает типовые задачи без блужданий по поиску.
- Буфер находится с первого раза. «Построй буфер 500 м вокруг школ» → в
ленте
native:buffer, а неnative:taperedbuffer. - Площадь — не алгоритм. «Посчитай площадь каждого полигона» → агент зовёт
native:fieldcalculatorс$area, а неnative:serviceareafrompoint. - Длина. «Добавь поле с длиной линий в километрах» →
$length / 1000. - Площадь на географической CRS. То же на слое в EPSG:4326 → агент сначала перепроецирует, а не выдаёт квадратные градусы.
- NDVI. «Посчитай NDVI по этому снимку» →
native:rastercalcс выражением по каналам, extent и cell size взяты изdescribe_layerрастра. - Обрезка растра. «Обрежь растр по границе района» →
gdal:cliprasterbymasklayer. - Зональная статистика. «Средняя высота по каждому району» →
native:zonalstatisticsfb. - Пространственное соединение. «Добавь к точкам название района, в котором
они лежат» →
native:joinattributesbylocation. - Растворение по полю. «Объедини районы в области по полю region» →
native:dissolveс полем. - Цепочка. «Обрежь дороги по границе города, посчитай длину и сохрани» → все шаги в одной карточке плана.
- Запрос не на английском в поиске. Агент не должен искать «растровый калькулятор» — поиск по русскому даёт ноль, он обязан переводить сам.
Локальная модель¶
- Подключение без ключа. Запустить Ollama, в настройках указать
http://localhost:11434/v1, модель — любую установленную, ключ оставить пустым → «Проверить подключение» отвечает. - Удалённый адрес без ключа. Стереть ключ, вернуть адрес OpenAI → внятное сообщение про ключ, а не про сеть.
- Прогон на локальной модели. «Какие у меня слои?» отрабатывает; если модель мелкая и путается в вызовах — это её предел, а не поломка плагина.
- OpenRouter. Адрес
https://openrouter.ai/api/v1, ключ OpenRouter, модель видаanthropic/claude-sonnet-4→ «Проверить подключение» отвечает, прогон с вызовом тулов проходит. - Anthropic напрямую. Адрес
https://api.anthropic.com/v1, ключ Anthropic, форматauto→ плагин сам уходит на/messages, вызовы тулов работают. - Диалект вручную. Поставить формат
openaiна адресе Anthropic → запрос уходит на/chat/completionsи сервис отвечает ошибкой; это проверка, что ручной выбор действительно перебивает определение.
Окно настроек¶
- URL помещается. Открыть настройки: длинный адрес шлюза виден целиком, окно не приходится растягивать.
- Пресет подставляет адрес. Выбрать «Anthropic» → адрес и формат API заполнились сами, поле модели показывает подсказку.
- Пресет определяется обратно. Вписать вручную адрес OpenRouter → в списке провайдеров сам выбрался OpenRouter.
- Локальный провайдер. Выбрать «Ollama» → подсказка у ключа меняется на «Не требуется».
- Проверка не открывает окон. «Проверить подключение» → результат строкой внизу диалога: зелёной при успехе, красной при ошибке. Нажать несколько раз подряд — окна поверх окна не появляются.
- Сохранение. «Сохранить» → строка «Настройки сохранены», диалог остаётся открытым.
- Тёмная и светлая тема. Переключить тему QGIS и открыть настройки — карточки и подсказки читаются в обеих.
- У полей видна рамка. В настройках у «Базовый URL», «Модель», «API-ключ» и у выпадающих списков есть контур; при клике в поле контур становится акцентным.
- Глубина видна. В настройках карточки светлее фона окна, а поля ввода темнее карточек — три различимых уровня, а не одно тёмное пятно.
- Иконки шапки. Три значка — часы, корзина, шестерёнка — одного цвета и веса, не разноцветные. На retina не мылят и не обрезаются. У шестерёнки различимы зубцы, а не сплошной кружок.
- Иконки следуют теме. Переключить светлую и тёмную тему QGIS и открыть панель заново: значки читаются в обеих.
Язык интерфейса и ответов¶
- Русский QGIS. Настройки QGIS → «Общие» → язык интерфейса «Русский», перезапустить QGIS, открыть панель агента: заголовок кнопки отправки, подсказка в поле ввода, «Настройки», «Диалоги», «Очистить диалог» — по-русски. Это проверяет, что переводчик встаёт до импорта модулей: именно эти строки вычисляются на импорте.
- Окно настроек по-русски. Открыть настройки: «Подключение», «Провайдер», «Базовый адрес», «Ключ API», «Проверить подключение», «Сохранить» — переведены, ничего не осталось английским.
- Карточка плана по-русски. Попросить перекрасить слой → в карточке «Изменит проект — N шагов» с правильной формой: 1 шаг, 2 шага, 5 шагов. Кнопки — «Применить» и «Отменить», после применения — «Применено».
- Лента шагов по-русски. Во время прогона строки вида «Смотрю слои проекта.», «Оформляю «Дороги»: color=blue.» — не английские.
- Английский QGIS. Переключить язык QGIS на English, перезапустить: весь интерфейс плагина по-английски, без вкраплений русского.
- Язык ответа модели следует за пользователем. В английском QGIS написать агенту по-русски → он отвечает по-русски. В русском QGIS написать по-английски → отвечает по-английски. Интерфейс при этом не меняется.
- Незнакомый язык QGIS. Поставить, например, немецкий: интерфейс плагина английский (перевода нет), плагин не падает, агент отвечает по-английски, пока пользователь не напишет иначе.
Зрение и самопроверка¶
- render_map возвращает картинку. В консоли Python:
execute_tool("render_map", {})→ словарь сwidth,height,extentи непустымimage_base64; после декодирования — валидный PNG текущего вида. - Агент смотрит на карту. Спросить «как выглядит карта?» на модели со зрением → в ленте render_map, а в ответе — настоящие цвета с экрана, не догадки.
- Слепой эндпоинт деградирует мягко. Тот же вопрос на модели без зрения → первый запрос повторяется без картинки, прогон завершается текстовой пометкой, а не ошибкой; следующие прогоны сразу идут без изображений.
- Проверка идёт после «Применить». «Сделай реки синими» → Применить → в ленте «Проверяю применённые изменения…», затем describe_style или render_map, затем короткий вердикт, что реки теперь синие.
- Проверка чинит падение. Уронить один шаг (например, переименовать слой между постановкой и применением) → проверочный прогон видит падение и ставит исправленный вызов; появляется новая карточка плана.
- Переключатель работает. Снять галочку «Проверять результат после применения изменений» в настройках → после «Применить» проверочный прогон не стартует.
- Проверка не зацикливается. Применить план, поставленный САМИМ проверочным прогоном → изменения легли, новая проверка сама не начинается.
Выделение, подложки, базы, правка данных¶
- Агент видит выделение. Выделить несколько объектов руками, спросить «что я выделил?» → get_selection называет слой, количество и настоящие атрибуты.
- Счёт по выделенному. «Суммарная площадь выделенных полигонов» → query_layer с selected_only=true; число сходится с ручной проверкой.
- Пустое выделение называется прямо. Снять выделение и повторить → агент говорит, что ничего не выделено, а не считает по всему слою.
- Подложка ложится вниз. «Добавь подложку OpenStreetMap» → после «Применить» тайловый слой под всеми слоями, карта показывает тайлы.
- Свой URL без {z} отклоняется с внятным сообщением до постановки в план.
- Подключения к базе только читаются. С сохранённым подключением PostGIS «загрузи дороги из базы» проходит путь list_db_connections → list_db_tables → add_db_layer и никогда не спрашивает пароль в чате.
- Правка спрашивает дважды. «Поставь type=park выделенным объектам» → карточка плана, затем «Применить» → дополнительный предупреждающий диалог ровно с необратимыми шагами. Отказ оставляет данные нетронутыми.
- Правка действительно ложится. Согласие в диалоге меняет значения; проверочный прогон перечитывает их и подтверждает количество.
- delete_features не удаляет всё молча. «Удали все объекты» работает только с фильтром-словом all; пустой фильтр отклоняется с объяснением.
Печатные макеты¶
- Лист одним прогоном. «Собери альбомный А4 с картой, заголовком, легендой и масштабной линейкой» → одна карточка плана; после «Применить» лист в менеджере макетов, всё внутри страницы.
- Агент смотрит на лист. Проверочный прогон зовёт render_layout; если легенда накрыла карту — появляется план исправления с configure_layout_item.
- Легенда раньше карты отклоняется. Попросить легенду в пустом макете → внятная ошибка «сначала добавьте карту», ещё при постановке.
- Элементы за страницей отклоняются при постановке, с размером страницы в сообщении.
- Экспорт. «Экспортируй макет в /tmp/map.pdf» → файл существует и открывается; путь в несуществующую папку отклоняется до очереди.
- Элементы адресуемы. describe_layout показывает map-1/title; «опусти заголовок чуть ниже» меняет ровно этот элемент.
Полное покрытие: python, растры, поля, сервисы, откат¶
- run_python сначала показывает код. «Поставь режим наложения, которого нет в тулах» → карточка плана, затем «Применить» → предупреждающий диалог содержит сам сниппет, читаемый. Отказ ничего не выполняет.
- Сломанный сниппет отклоняется при постановке с синтаксической ошибкой и номером строки, ещё до вопроса пользователю.
- Вечный цикл не вешает QGIS. Поставить
while True: pass→ бюджет строк останавливает его, агент получает объяснение. - Агент предпочитает штатные тулы. «Сделай реки синими» НЕ должно идти через run_python — это покрыто тулами стиля.
- Псевдоцвет растра. «Раскрась DEM палитрой Viridis» → палитра покрывает настоящие min/max канала, в легенде видны классы.
- Отмывка. «Сделай отмывку по DEM» → появляется теневой рельеф, азимут по умолчанию 315.
- Скрытие no-data. Растр с заполнителем -9999 → «скрой значения -9999» делает их прозрачными, цвета становятся осмысленными.
- Виртуальное поле. «Добавь виртуальное поле с площадью в гектарах» → колонка появилась в таблице атрибутов, файл на диске не тронут.
- Реальное поле, переименование, удаление. Добавить текстовое поле, переименовать, удалить → удаление спрашивает подтверждение необратимого шага; источник только для чтения сообщает об откате, а не падает молча.
- WMS и WFS. Добавить публичный WMS-слой и WFS-слой → тайлы рисуются, объекты WFS запрашиваются через query_layer.
- Откат. Применить изменение стиля, затем «откати» → проект возвращается к прежнему состоянию; агент говорит, что правки данных это не покрывает.
- Закладки и темы. «Запомни этот вид как центр», «сохрани этот вид как печать» → оба появляются в list_views и в панелях QGIS.
Автономность: этапные прогоны, план, бюджет¶
- Целая задача за один запрос. «Скачай кафе <города> из OSM, раскрась, подпиши, собери лист А4 и экспортируй в PDF» → агент составляет план, ставит в очередь скачивание, просит применить, а затем продолжает тот же прогон: читает новый слой, оформляет, применяет снова, собирает макет, смотрит на него, экспортирует. Один запрос, несколько нажатий «Применить», без повторных объяснений.
- План виден. Во время такого прогона в ленте идут строки вида «План 2/5: …», продвигающиеся по мере выполнения шагов.
- Отказ на этапе завершает чисто. Нажать «Отменить» на этапной карточке → прогон заканчивается сообщением, что изменения отклонены; наполовину применённого не остаётся.
- apply_now не злоупотребляется. Односложный запрос («сделай реки синими») по-прежнему должен давать одну карточку в конце, а не паузу на этапе.
- Счётчик токенов работает. В шапке растёт число токенов во время прогона и обнуляется при новом запросе.
- Бюджет останавливает прогон. Поставить в настройках маленький бюджет (скажем, 5000), запустить длинную задачу → прогон вежливо останавливается с объяснением, а не сжигает ключ.
- Длинный прогон не рвёт контекст. Прогон на 20+ ходов продолжает работать; старые результаты тулов приходят свёрнутыми, а не валят запрос ошибкой о длине контекста.
- Проверка итеративна. Сделать так, чтобы изменение стиля легло неверно → проверочный прогон ставит исправление, и если оно тоже неверно, идёт второй круг; после трёх кругов останавливается, а не крутится вечно.
Онбординг и ответ картой¶
- Пустая панель приглашает. Открыть плагин на свежем профиле без ключа → в ленте карточка с объяснением про ключ и кнопкой в настройки. Никакой загадочной ошибки при первой отправке.
- После сохранения ключа карточка меняется на три кликабельных примера запросов; нажатие отправляет запрос как набранный вручную.
- Выделение как ответ. «Покажи мне автомагистрали» → объекты выделены, карта подлетела к ним, они мигнули; в ответе назван счёт.
- Пустое выделение честно. «Покажи автомагистрали» на слое, где их нет → агент говорит, что ничего не совпало, а не рапортует об успехе.
- Экспорт слоя. «Сохрани слой дорог в /tmp/roads.gpkg» → файл существует и открывается в QGIS; неверное расширение отклоняется до постановки в план.
- Экспорт выделенного. Выделить несколько объектов, «экспортируй выделенное в GeoJSON» → в файле только эти объекты.
Поправка на ходу и память проекта¶
- Поправка доходит во время прогона. Запустить «покрась дороги красным» и во время работы написать «вообще-то синим» → реплика появляется с пометкой о передаче, агент переключается на синий, не начиная заново.
- Та же фраза в покое — обычный запрос, а не поправка: начинается новый прогон.
- Запоминание. «Запомни, что POP2020 — это перепись 2020 года» → в
карточке плана видно; после «Применить»
list_notesэто возвращает. - Память переживает перезапуск и привязана к проекту. Перезапустить QGIS, спросить «что ты помнишь?» → заметка на месте. Открыть другой проект → её нет.
- Заметки доходят до модели. С этой заметкой спросить «что в POP2020?» → ответ опирается на запомненное, не переспрашивая вас.
- Забывание. «Забудь заметку про POP2020» → её нет в list_notes; попытка забыть несохранённое отклоняется с подсказкой.
Стриминг¶
- Ответ растёт. Спросить что-то с длинным ответом — «расскажи, что в этом проекте и что бы ты исправил» → текст появляется по словам, а не целиком после паузы.
- Markdown в итоге корректный. Попросить ответ со списком и жирным → по ходу разметка может быть недособранной, но готовое сообщение отрисовано как markdown, без торчащих звёздочек.
- Вызов тула снимает черновик. Спросить так, чтобы агент сначала полез читать проект → сказанное до тула исчезает, когда появляется строка тула; ничего не показывается дважды.
- Сохранённая переписка совпадает с экраном. После потокового ответа переключиться на другой диалог и обратно → реплика на месте, в одном экземпляре, ровно та, которую читали.
- Эндпоинт без SSE работает. Указать сервер, который отказывает в стриминге → ответ приходит целиком, без ошибки, а следующий запрос сразу идёт обычным путём.
- Остановка во время потока. Нажать ■ пока текст растёт → прогон останавливается, черновик перестаёт расти, QGIS не подвисает.
Думающие модели¶
- Локальная думающая модель не выносит монолог наружу. Указать плагин на Ollama с дистиллятом DeepSeek-R1 или QwQ, спросить что угодно → ответ остаётся ответом, а рассуждение лежит в своём блоке, не в тексте реплики.
- Блок сворачивается сам. Пока модель рассуждает, блок раскрыт и растёт; как только пошёл ответ — сворачивается в строку с затраченным временем, а по клику раскрывается снова.
- DeepSeek подаёт признаки жизни. На эндпоинте DeepSeek с рассуждающей моделью блок наполняется во время паузы, а не панель стоит неподвижно.
- Рассуждение не уходит обратно. После ответа с рассуждением задать следующий вопрос → счётчик токенов на следующем шаге не тянет прошлый монолог, и модель на него не ссылается.
- Многошаговая задача с думающей моделью доходит до конца. Попросить то, что требует тулов → у каждого шага может быть свой блок, вызовы тулов по-прежнему идут по порядку.
- Расширенное рассуждение Anthropic выключено по умолчанию. С бюджетом 0 Claude отвечает ровно как раньше.
- Расширенное рассуждение Anthropic включено. Поставить бюджет 4096, попросить то, что требует тулов → появляется блок рассуждения, тулы отрабатывают, прогон заканчивается без ошибки API про блоки размышления.
- Модель без размышления не ломается от настройки. С заданным бюджетом указать модель без extended thinking → ответ всё равно приходит, отказ запоминается, дальнейшие запросы идут сразу.
Стриминг на Anthropic¶
- Claude тоже стримит. На эндпоинте Anthropic попросить длинный ответ → текст растёт по словам, ровно как на openai-совместимом.
- Рассуждение течёт вместе с ним. Поставить бюджет 4096 и спросить что-то сложное → блок рассуждения наполняется во время паузы, а не появляется целиком в конце, и показывает затраченное время.
- Тулы работают через поток. Попросить то, что требует тулов → аргументы приходят по кускам, но вызов уходит с правильными значениями, а в карточке плана перечислено то, что нужно.
- Отказ в размышлении не путается с отказом в стриминге. С заданным бюджетом указать модель без extended thinking → ответ приходит потоком; выключается только размышление, не стриминг.
Вопросы пользователю¶
- Настоящая неоднозначность становится вопросом, а не догадкой. При двух похоже названных слоях попросить «раскрась дороги» → агент спрашивает, какой из них, панель пишет, что ждёт, и следующее сообщение продолжает тот же прогон.
- Ответ продолжает, а не перезапускает. После ответа агент использует его сразу — без чтения проекта заново, план задачи переживает паузу.
- Никаких вопросов-разрешений. Обычные запросы по-прежнему кончаются карточкой плана, а не «можно продолжать?».
Интернет¶
- Место превращается в bbox через одобренный сервис. В настройках выберите Photon или укажите разрешённый тестовый Nominatim-сервис, затем попросите «Скачай кафе в Дивноморском» → в плане виден хост геокодера; после отдельного подтверждения агент передаёт полученный bbox в download_osm.
- Вопрос не о проекте уходит в веб. «Какой EPSG-код у UTM-зоны Казани?» → в плане названы DuckDuckGo/Wikipedia; после подтверждения search_web отрабатывает, ответ называет ссылку-источник.
- Вставленная ссылка читается. Вставить URL документации и спросить, о чём она → в плане виден публичный HTTPS-хост; после подтверждения fetch_url возвращает читаемый текст, ответ цитирует страницу, а не галлюцинацию.
- Закрытая сеть деградирует громко. В сети, где поисковик недоступен, search_web падает на Википедию, и ответ это говорит — без тихой имитации поиска по всему вебу.
- Публичный геокодер OSMF остаётся заблокирован. Попытка сохранить
https://nominatim.openstreetmap.orgкак свой Nominatim отклоняется до сетевого запроса со ссылкой на правила использования OSMF.
Новые возможности и журнал аудита¶
- Аннотации проходят полный цикл. Попросить текстовую заметку и маркер →
оба ждут в плане, появляются после Применить, видны в
list_annotationsи удаляются по id. - 3D-вид открывается в заявленных границах. Попросить именованный 3D-вид → план говорит, что инструмент только открывает окно; после Применить вид появляется, а сборка QGIS без нужного API возвращает явную подсказку.
- Журнал прогона видим и точен. После применения плана чат сообщает путь
к Markdown-файлу в каталоге
ai_agent_runsактивного профиля QGIS. Где поддерживается, проверить права каталога/файла0700/0600, затем открыть файл и проверить сокращённые тексты запроса и агента, имена инструментов, ошибки неудачных вызовов, число применённых шагов и итог; отдельной выгрузки успешных результатов быть не должно. - Gemini использует общий диалект. Выбрать пресет Google Gemini, указать действующие ключ и модель, нажать Проверить подключение → запрос идёт на документированный OpenAI-совместимый адрес и возвращает ответ проверки.
Скиллы и слэш-команды¶
- Попап по
/показывает скиллы и вставляет выбранный. Набрать/в композере → над полем список всех встроенных скиллов с однострочниками;/oсужает до совпадений по префиксу; ↓ и Tab вставляют/osmс курсором после пробела; Esc закрывает, не трогая текст. - Скилл из слэш-команды загружен до первого хода. Отправить
/osm кафе в Казани→ в ленте нет шага «Загружаю знания: osm», первое действие ужеdownload_osm, а пузырь пользователя сохраняет исходный текст/osm …. - Локальный скилл проходит весь путь. Настройки → Скиллы → Создать
пример → папка открывается по кнопке, пример в списке; изменить
description → он появляется в
/с пометкой локальный, и агент может сделатьload_skill; добавить неизвестный инструмент → страница показывает проблему, а скилл загружается только с известными. - Неизвестная команда отклоняется, а не отправляется.
/nope сделай→ одно системное сообщение со списком доступных команд; до модели ничего не доходит.