🤖 AI-агенты для бизнеса

5. Инструменты — состояние, базы и визуализация

🔵 Хранение состояния (scoped store, SQL-база DuckDB) и генерация визуальных блоков (графики/таблицы). Сводную таблицу всех движков см. в «Справочник инструментов».

5.11 state_tool

Хранилище состояния со скоупом. kind: state_tool открывает агенту scoped state store ядра. Каждый YAML привязывает одну операцию (op) к одному скоупу + ключу — агенту даётся узкая, целенаправленная способность (например «только читать user/name»).

Конкретный id скоупа (session/user/template) резолвится в рантайме из контекста вызывающего инструмента — LLM никогда не видит чужой id.

Поле Обязат. Описание
kind да state_tool
name да имя для LLM
description да описание для LLM
op да одна операция (см. таблицу ниже)
scope да user | session | agent
key да ключ хранения
key_param нет входной аргумент, перекрывающий key
default нет значение get при промахе
ttl_secs нет TTL для записей
limit / offset нет пагинация чтения коллекций
filter нет JSON-фильтр по коллекциям
parameters нет переопределить авто-схему

Скоупы

Скоуп Хранится под Резолвится из
user user:<user_id> X-User-Id сессии
session session:<session_id> текущая сессия
agent agent:<template> имя шаблона агента

Виды значений

Вид Запись Чтение
скаляр set get
список push list, range
множество sadd, srem smembers, scard

delete удаляет любой ключ; keys перечисляет ключи скоупа.

op — справочник

op Описание Авто-параметры Возвращает
get прочитать скаляр (или default/null) значение
set upsert скаляра value {"ok":true}
delete удалить ключ {"deleted":true|false}
keys список ключей скоупа limit, offset [{key,kind,size}]
push добавить в список value {"seq":N}
list прочитать список limit, offset ["a", …]
range срез списка [from..=to] from, to ["a", …]
sadd добавить в множество value {"added":true|false}
smembers члены множества limit, offset ["x", …]
srem удалить из множества value {"removed":true|false}
scard размер множества {"count":N}

Чтение коллекций ограничено (по умолчанию 1000 элементов).

filter

filter:
  path: meta.priority
  op: gte               # eq | ne | contains | prefix | gt | gte | lt | lte | exists
  value: 3

Строковые операции регистронезависимы; gt/gte/lt/lte сравнивают численно.


5.17 duckdb_tool

Своя DuckDB-база для агента. Универсальный SQL-доступ к DuckDB: агент получает собственную базу (или доступ к общей), а забота о соединениях и схеме остаётся в движке. Подходит, когда key/value state_tool мало — нужны таблицы, JOIN, агрегации, индексы.

kind: duckdb_tool
name: memory
description: SQL-база фактов пользователя.
path: data/dbs/{user}.db     # файл, ":memory:" или шаблон пути
operation: query             # необязательно: query | execute | schema
init:                        # необязательно: выполняются ОДИН раз (идемпотентно)
  - |
    CREATE TABLE IF NOT EXISTS facts (
      id BIGINT PRIMARY KEY,
      topic TEXT NOT NULL,
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
readonly: false              # запретить execute
limit: 100                   # страница по умолчанию
max_rows: 1000               # жёсткий кап строк
Поле Обязат. Описание
kind да duckdb_tool
name да имя для LLM
description нет описание для LLM
path да файл базы или :memory:. Поддерживает {user}, {session}, {template}/{agent}
operation нет привязать к одной операции; без него операция выбирается аргументом operation (по умолч. query)
init нет строка или список SQL; выполняется один раз при первом открытии базы
readonly нет true запрещает execute
limit / max_rows нет страница по умолчанию / кап строк
parameters нет переопределить авто-схему

Операции

operation Назначение Параметры
query выполнить SQL и вернуть columns + rows sql, limit
execute DDL/DML (CREATE, INSERT, UPDATE, DELETE, …) sql
schema таблицы/вью и их колонки table (необязательно)

query материализует до limit строк и выставляет has_more, когда их больше — агент повторяет запрос со своим LIMIT/OFFSET. Результат query дополнительно кладётся в data (для композиции через visualize_tool source) и в visual (таблица для UI); content — JSON для LLM. Временны́е типы (TIMESTAMP, DATE, TIME) возвращаются строками ISO 8601.

Свои базы через user / session / agent

Плейсхолдеры в path резолвятся из контекста вызова:

path: data/dbs/{user}.db       # одна база на пользователя
path: data/dbs/{template}.db   # одна база на шаблон агента
path: data/dbs/{session}.db    # одна база на сессию

Нерезолвимый плейсхолдер (например {user} без user id) — явная ошибка, а не молчаливое падение в общий файл. Подстановка санитизируется (нельзя выйти из каталога).

Общая база для нескольких инструментов и инстансов

DuckDB допускает одного писателя на файл, поэтому движок держит процесс-глобальный пул соединений по каноническому пути: несколько определений duckdb_tool (и параллельные сессии агентов), указывающих на один файл, делят одно мьютекс-защищённое соединение. init при этом выполняется ровно один раз. Пример — memory + memory_schema на общей {user}.db в config/agents/db-demo/.


5.22 sql_tool

SQL-доступ к внешней PostgreSQL или MySQL — сетевой собрат duckdb_tool с тем же интерфейсом query/execute/schema, но для подключения к существующей учётной / CRM / ERP базе.

kind: sql_tool
name: crm_db
description: Чтение из базы CRM.
dialect: postgres            # postgres | mysql
url_env: CRM_DATABASE_URL    # URL подключения из env (postgres://… / mysql://…)
operation: query             # необязательно: query | execute | schema
readonly: false              # запретить execute
limit: 100                   # страница по умолчанию
max_rows: 1000               # жёсткий кап строк
init:                        # необязательно: выполняется один раз при создании пула
  - SET NAMES utf8mb4;
Поле Обязат. Описание
kind да sql_tool
name да имя для LLM
description нет описание для LLM
dialect да postgres | mysql
url_env да¹ имя env с URL подключения (секреты — не в YAML)
url нет буквальный URL (только для dev; предпочти url_env)
operation нет привязать к одной операции; без него операция выбирается аргументом operation (по умолч. query)
readonly нет true запрещает execute
limit / max_rows нет страница по умолчанию / кап строк
parameters нет переопределить авто-схему

¹ либо url_env, либо url — одно из двух обязательно.

Операции

operation Назначение Параметры
query выполнить SQL и вернуть columns + rows sql, limit
execute DDL/DML (CREATE, INSERT, UPDATE, DELETE, …) sql
schema таблицы/вью и их колонки table (необязательно)

query материализует до limit строк и выставляет has_more; результат кладётся в data (композиция через visualize_tool source) и visual (таблица). Соединения делятся через процесс-глобальный пул по URL: несколько определений sql_tool на одну базу используют один пул, init выполняется один раз. Временны́е типы, uuid и пр. возвращаются строками.


5.12 chart_tool и table_tool

Статичные визуальные данные. Движки для предвычисленных/статичных данных: компактный content (сводка для LLM) + visual (полный блок для UI).

kind: table_tool
name: price_list
description: Показать прайс.
parameters: { type: object, properties: {} }
data_file: data/prices.json
title: "Цены"
summary: "{{ count }} позиций"
columns:
  - { key: model, title: "Модель" }
  - { key: price, title: "Цена", align: right }
options: { sortable: true, searchable: true }
kind: chart_tool
name: sales_chart
description: Продажи по кварталам.
parameters: { type: object, properties: {} }
data_file: data/sales.json       # { type, title, labels, series }
summary: "{{ count }} точек"

Общие поля: kind, name, description, parameters, data_file (путь относительно YAML) или inline data, summary (MiniJinja, контекст count), ui. table_tool дополнительно: title, columns, options (sortable / searchable / paged). chart_tool берёт data как spec (type = bar | line | area | pie | scatter).

Оба движка принимают динамический аргумент data в вызове — он перекрывает статичный data/data_file.


5.13 visualize_tool

Графики и таблицы из произвольных данных. Универсальный собрат chart_tool/table_tool: превращает данные, переданные аргументами, в график или таблицу, с пайплайном трансформаций. LLM отдаёт строки (или spec), движок детерминированно агрегирует.

kind: visualize_tool
name: make_chart
description: Построить график/таблицу из переданных строк.
Аргумент Описание
data массив объектов-строк, или полный spec таблицы/графика
source сослаться на результат прошлого вызова инструмента: { tool, index, field, path, pages }
group_by поле группировки
aggregate { count, sum, avg, min, max } — результаты с префиксом (sum_cost, …)
filter { field: { op: value } }
sort { by, dir: asc|desc }
limit максимум строк
as table | bar | line | area | pie | scatter
title, x, series, columns, options оформление

Композиция инструментов (source)

Вместо копирования данных можно сослаться на результат прошлого вызова в той же сессии:

{ "source": { "tool": "trace_sessions" }, "group_by": "agent",
  "aggregate": { "sum": ["errors"] }, "as": "bar" }

trace_tool's sessions возвращает структурированные строки в data — готовый источник. Явный data выигрывает у source.