JSON як контракт: як зробити результат AI придатним до автоматизації
Вільний текст добре читає людина, але погано живе в автоматичному процесі. Якщо наступний крок має змінити файл, надіслати повідомлення або вирішити, чи пропускати публікацію, відповідь моделі повинна бути не просто переконливою, а машинно перевірюваною.
Практичний підхід — описати результат JSON Schema. Це не спосіб змусити модель бути правою. Це контракт форми: які поля обов’язкові, які значення дозволені та що робити, якщо контракт не виконано.
Що змінилося в основних інструментах
В OpenAI Structured Outputs схема передається як text.format для відповіді або як strict-схема виклику функції. OpenAI розділяє ці випадки: text.format — коли структурований результат потрібен застосунку, function calling — коли модель має викликати функцію. Це сильніше за JSON mode: правильний JSON ще не означає правильні поля. Відмову моделі також можна обробити окремо від успішного результату.
У Claude тепер є два близькі механізми в Structured outputs: output_config.format повертає JSON за схемою, а strict tool use перевіряє назви інструментів і їхні аргументи. Документація прямо попереджає про обмежену підмножину JSON Schema, тому складну схему спочатку треба прогнати через локальну перевірку. Для довших агентних циклів Claude Agent SDK дозволяє агенту користуватися інструментами, а наприкінці повертає structured_output; після невдалих повторних спроб це помилка, а не «майже придатний» текст.
У Codex схема результату не замінює інструкції. AGENTS.md задає сталі правила роботи та підвантажується в ланцюжок інструкцій, а skill пакує повторювану процедуру, ресурси й, за потреби, скрипти. Тому для Codex корисна пара: короткий контракт у skill або AGENTS.md плюс зовнішній валідатор JSON. Інструкція описує процес, схема — доказ завершення.
В OpenCode SDK структурований результат запиту задається json_schema. OpenCode повертає перевірений JSON і має retryCount; після вичерпання повторів результат містить StructuredOutputError. Це хороший приклад правила: помилку форми не можна маскувати порожнім текстом. Додатковий hook може перехоплювати події та інструменти, але має бути лише бар’єром, а не заміною перевірці схеми.
Мінімальний контракт
Починайте з вузького результату. Не просіть модель повертати весь діалог, пояснення і «все, що вона вважає важливим». Для рішення маршрутизатора достатньо статусу, причини та ідентифікатора артефакту:
{
"type": "object",
"additionalProperties": false,
"properties": {
"status": {
"type": "string",
"enum": ["pass", "changes_requested", "blocked"]
},
"reason": {"type": "string"},
"artifact_id": {"type": "string"},
"evidence": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["status", "reason", "artifact_id", "evidence"]
}
status обмежує переходи стану, evidence змушує повернути посилання на перевірки, а additionalProperties: false не дає тихо додати поле, яке маршрутизатор не вміє обробляти. Семантичні твердження все одно потрібно перевіряти окремо: схема гарантує наявність рядка, але не правдивість його змісту.
Безпечною є така послідовність:
- Сформувати запит і схему версії
v1. - Отримати структурований результат.
- Перевірити JSON Schema локально.
- Перевірити докази детермінованими командами або політиками.
- Виконувати дію лише для дозволеного статусу й відповідної версії схеми.
Якщо модель повернула відмову, тайм-аут або StructuredOutputError, стан має бути blocked, а не pass. Не запускайте необмежені повтори: два-три повтори з тією самою схемою — це діагностика проблеми, а не гарантія якості.
Чотири робочі схеми для OpenClaw
1. Vault як типізований конвеєр. Зберігайте окремо вхідний контракт, результат і перевірку. Наприклад, inbox містить мету та schema_version, outbox — JSON-відповідь агента, reviews — докази й рішення. Skill описує порядок переходів, а валідатор перевіряє JSON до того, як інший агент прочитає його. Це корисно для досліджень, щоденних статей і планів інфраструктури: контекст можна скоротити, не втративши стан.
2. Telegram як диспетчер, а не місце для довгого контексту. Команда /do створює артефакт у стані draft, а /check <id> передає лише його ідентифікатор окремому read-only агенту. Telegram отримує короткий підсумок зі status, а повні докази лежать у vault. Приклад маршрутизації:
routes:
/do:
agent: builder
output_schema: task-result-v1
permissions: [read_workspace, write_workspace, run_tests]
/check:
agent: reviewer
input: artifact_id
output_schema: review-result-v1
permissions: [read_workspace, read_vault]
allowed_transitions: [pass, changes_requested, blocked]
Не давайте рев’юеру право писати в робоче дерево або надсилати зовнішні повідомлення. Він може змінити лише стан перевірки, якщо це реалізовано окремим вузьким інструментом.
3. Skill для процесу, агент для меж. У skill тримайте сталі кроки: зібрати артефакт, застосувати схему, запустити перевірки, сформувати receipt. У конфігурації агента — дозволи, модель, мережевий доступ і можливість писати. Так одну процедуру можна запускати з різними рівнями доступу: дослідник лише читає, видавець може створити файл, але не може пушити зміни.
4. Нетиповий варіант — схема як шлюз між моделями. Перший агент класифікує запит у невеликий JSON: kind, risk, required_tools, budget. Диспетчер за цим результатом обирає спеціалізований агент і не передає йому весь первинний діалог. Це зменшує контекст і ризик випадкового доступу до зайвих даних, але додає ще одну точку відмови: помилкова класифікація відправить роботу не туди. Тому для невідомого kind, високого risk або відсутнього поля маршрут повинен завершуватися blocked і просити людське рішення.
Контракт не скасовує перевірку
Типізований результат вирішує проблему форми, не змісту. Рядок evidence може бути вигаданим, artifact_id — вказувати на не той файл, а status: pass — суперечити тесту. Додайте до кожного рішення:
- версію схеми й ідентифікатор моделі;
- список фактично виконаних перевірок;
- хеш або інший стабільний ідентифікатор артефакту;
- обмежений термін дії рішення;
- окремий стан для відмови, тайм-ауту та неповного результату.
Для OpenClaw практичний playbook такий: агент створює артефакт і receipt, read-only агент читає лише пакет, детермінований валідатор перевіряє формат і scope, а Telegram показує тільки фінальний стан. Якщо змінюється схема — підвищуйте її версію й не приймайте старий JSON мовчки.
Найкорисніша властивість structured output — не «AI нарешті завжди правий». Вона в тому, що систему можна зробити чесною щодо невдачі: або є результат потрібної форми та докази, або конвеєр зупиняється в явному стані, який можна повторити, дослідити й виправити.