AI-инструмент — это модульный скрипт, который владелец магазина регистрирует для AI-помощника. Агент видит перечень инструментов при подключении и запускает их по имени — так магазин получает собственные «кнопки»: завести товар так, как заведено у вас, закрыть заказ по вашим правилам.
Перечень — данные, а не код. Новый инструмент появляется у агента без
обновления программы: строки в реестре плюс модуль в units.
Реестр владелец ведёт в программе: Проектирование →
AI-инструменты.
| Таблица | Что хранит |
|---|---|
agent_tool |
инструмент: название, описание, модуль (unit); дерево с
папками |
agent_tool_command |
команды инструмента: имя — оно же имя функции, — описание, порядок |
agent_tool_param |
параметры команды: имя, описание, тип, обязательность, умолчание, порядок |
agent_tool_right |
гранты: строка выдаёт одну команду (command_id)
человеку (user_id) или группе (group_id) |
Реестр — единственный источник подписи: агент узнаёт из него и что инструмент делает (описания), и как его звать (команды с полями). Модуль себя не описывает — в нём остались только тела команд.
Права выдаются людям: агент входит в магазин под
логином того сотрудника, что сидит за клавиатурой — отдельного
пользователя ИИ не существует, — и грант считается по нему: строка его
собственная или строка его группы. Отсюда и то, что один и тот же
инструмент у разных сотрудников умеет разное. Право — это команда:
сколько команд, столько прав. Держатель права «Изменение настроек AI»
(PUT_AGENT_OPTION) владеет всеми командами автоматически.
Перечень открыт всем: агент видит все инструменты и все команды, а
выданные — отдельной строкой may:; пусто — он подсказывает
сотруднику, у кого просить доступ.
Один инструмент покрывает одну сущность целиком — «Пользователи»,
«Задачи», — и это один модуль. Команда называет одно её дело, и её имя в
реестре — это имя функции модуля: CmdList,
CmdTaskAdd. Приставка Cmd отличает команду от
функций-помощников, которые агенту не видны.
Право выдаётся на команду целиком, со всей её параметрической
широтой: CmdNoteAdd пишет и комментарий, и движение задачи
— одна дверь, как в программе. Хочется разделить «комментировать» и
«двигать» грантом — это две команды, а не два значения параметра.
Модуль объявляет пространство имён своим именем заглавными, и движок
зовёт функцию команды напрямую — ни точки входа, ни разводящего
switch в модуле нет:
namespace MELBIS_AGENT_USER;
/**
* Function CmdList
* The users of the store
**/
function CmdList($mUserId, $mParam)
{
// ...
}$mUserId — id сотрудника, под которым открыта
сессия, то есть человека за клавиатурой. Он всегда настоящий,
безымянной сессии не бывает, и проверять его на ноль незачем. Им
подписывается авторство: задач, записей, изменений.$mParam — поля команды готовым массивом, уже взвешенные
по реестру (см. «Рутина — дело движка»).Ответ — массив, он целиком уезжает агенту. Соглашение:
result — однозначный true или
false, message — человеческий текст, который
агент прочтёт сотруднику, остальные ключи — полезная нагрузка
(id, users, password…). Машинных
слов-кодов в ответе нет: агенту хватает булева результата и текста.
Отказы движка приходят агенту в том же контракте — один язык отказов,
кто бы ни отказал.
До модуля движок проверяет всё, что записано в реестре, и модулю достаются только правила предметной области:
agent_tool_param.
Поле, которого команда не объявляла, — отказ со списком принимаемых:
опечатка не пропадает молча. Незаданное обязательное — отказ. Поле со
значением null считается неназванным — так агент «снимает»
поле;value_def
подставляется в неназванное поле. У команд, меняющих существующее,
умолчаний не бывает вовсе: неназванное поле должно остаться неназванным,
иначе частичное изменение станет перезаписью.| Тип | Что принимает | Что получает модуль |
|---|---|---|
str |
любое одиночное значение | строка |
int |
целое число или его запись словом "12" |
int |
float |
число | float |
bool |
true/false,
yes/no, 1/0,
on/off |
bool |
date |
день как YYYY-MM-DD |
строка в форме базы |
time |
час как HH:MM:SS, секунды можно опустить |
строка в форме базы |
datetime |
день, и час после него; час можно опустить | строка в форме базы |
json |
список или объект; скаляр — отказ | массив |
jsonl |
поток строк: список объектов или файл с ними (см. ниже) | массив строк |
files |
вложения вызова, не поле (см. ниже) | строки таблицы файлов в $mParam['files'] |
Дни и часы приводятся к той форме, в которой их держит база, и «31 февраля» отбивается, а не сползает на третье марта. Проверять их в модуле не нужно и не следует: база строгая, и слово, которого она не прочтёт, губит не поле, а весь ответ.
Поток строк. Команда, которая грузит пачку
однородных строк — товары импорта, значения характеристик, цены прайса,
— объявляет параметр типа jsonl. Помощник кладёт туда либо
сами строки массивом, либо путь к jsonl-файлу на своей машине:
{"file": "..."}, строка на запись. Модуль получает
массив в обоих случаях — файл разворачивается на стороне
помощника, до вызова, и читать файлы модулю не нужно вовсе.
Разница не в удобстве, а в возможности: партия в пятьсот строк, набранная помощником в параметрах вызова, — это сотни тысяч знаков в его собственном сообщении, а файл, который написал его скрипт, не проходит через него совсем.
Список вместо одного значения. К любому типу, кроме
json, jsonl и files, дописывается
хвост /json — int/json, str/json,
datetime/json. Такое поле принимает и одно значение, и
список, а модулю всегда достаётся массив, так что
развилки «один или несколько» в коде не появляется:
$list = implode(',', $mParam['store_id']); // int/json: элементы уже взвешеныКаждый элемент взвешивается тем же типом, что и одиночное значение, —
поэтому int/json и есть то, что делает безопасной
подстановку списка в IN ( … ). Пустой список и список
внутри списка — отказ.
Множественность — свойство строки реестра, а не поля вообще: у одной
и той же price в читающей команде может стоять
float/json (диапазон, поиск), а в пишущей —
float, потому что записать в колонку список нельзя.
Файлы. Команда, принимающая вложения, объявляет один
параметр типа files. В подписи он показывается не полем, а
пометкой команды — файлы прикладываются к вызову, а не передаются в
параметрах. Движок раскладывает их до модуля, и команда читает готовые
строки из $mParam['files']; обязательный files
без вложений — отказ, вложения в команду без files — отказ.
Команда, принявшая файлы, называет их в ответе под ключом
files — так движок знает, что у файлов есть хозяин;
безхозные он убирает сам.
MELBIS SYSTEM.result=false.recursive. Это и есть
подтверждение — в контракте команды, а не в уговорах.Агент собирает вызов из трёх слоёв текста, и у каждого своя глубина:
descr инструмента — что он делает и когда его
звать;descr команды — смысл и оговорки поведения («пароль не
задаётся и возвращается один раз»);descr параметра — что это за значение и каким оно
должно быть; словарь допустимых значений называется здесь словами
(a value of STORE_KIND_KEY).Первые два едут в перечне при каждом подключении, параметры агент берёт по одному инструменту, когда собрался им работать.
Общая часть инструментов — модули-библиотеки
melbis_inc_agent_* (util, tree,
store, info, file). Юнит
подключает библиотеку манифестом
(includes: melbis_inc_agent_util.php=1) и объявляет
алиас:
use MELBIS_INC_AGENT_UTIL as UTIL;
// ...
$lock = UTIL\Lock([$table]);Публикуемые алиасы библиотека называет в своём манифесте, в поле
param_info — по ним движок сверяет use при
сохранении.
Проектирование → AI-инструменты → Экспорт (право
TOOL_EXPORT; у агента — tool_export) собирает
весь реестр и модули за ним в один архив: index.json с
деревом и md5-суммой каждого файла, tools/<unit>.json
на инструмент — команды с полями, — units/ с модулями,
манифестами и библиотеками, которые нашлись по манифестам. Гранты в
архив не входят: они про людей магазина, а не про инструменты.
Двери импорта нет, и это решение: после установки владелец дорабатывает инструменты под себя, и обновление — всегда сравнение, а не накат. Агент распаковывает контейнер, по суммам индекса находит разошедшееся и переносит точечно: реестр — прямыми запросами, модуль — сохранением файла.
Живые образцы в демонстрационном магазине платформы:
melbis_agent_key_value.php — компактная сущность:
словари реестра настроек, пять команд;melbis_agent_user.php — сущность на четыре команды:
генерация пароля, защита удаления историей, частичный
CmdUpdate;melbis_agent_task.php — зеркало дверей планировщика:
CmdTask* / CmdNote*, одна дверь CmdNoteAdd на
комментарий и движение, приватность задач одной формулой во всех
выборках.