Ідея за 30 секунд
Tool Execution Layer — це шар контролю між рішенням агента і реальною дією.
Агент не запускає інструменти напряму. Він лише пропонує tool_call. Потім Tool Execution Layer перевіряє цей виклик, застосовує правила доступу, виконує інструмент і повертає результат у єдиному форматі.
Коли потрібен: коли агент працює з API, базами даних, файлами або кодом, де важливі безпека, стабільність і контроль побічних ефектів.
LLM не має прямого доступу до side effects (змін стану). Вона лише пропонує tool_call, а система вирішує, чи ця дія може бути виконана.
Проблема
Коли агент викликає інструменти напряму, швидко з'являються типові збої:
- модель генерує некоректні аргументи;
- викликається не той інструмент;
- інструмент зависає або повертає непередбачуваний формат;
- одна й та сама дія запускається повторно і ламає стан системи;
- інструмент виконує побічний ефект (зміну стану), яку не можна безпечно повторити;
- модель намагається виконати дію, яку система мала лише запропонувати для погодження.
У результаті агент формально "працює", але система стає крихкою і небезпечною.
Рішення
Додати Tool Execution Layer як окремий контрольований шлюз для всіх tool_call.
Він централізує перевірки, політики та обробку помилок перед тим, як дати агенту доступ до зовнішньої дії.
Аналогія: як контроль безпеки в аеропорту.
Пасажир не заходить одразу в літак. Спочатку є перевірка документів, багажу і правил доступу.
Tool Execution Layer так само не дає агенту виконати довільну дію без перевірки.
Як працює Tool Execution Layer
Tool Execution Layer отримує запит від Runtime, проходить послідовність перевірок і лише тоді виконує інструмент у контрольованому режимі.
Опис повного флоу: Validate → Authorize → Execute → Normalize → Return
Validate
Шар перевіряє, чи існує інструмент, чи він дозволений allowlist, і чи аргументи відповідають схемі.
Authorize
Застосовуються політики доступу: роль, середовище, рівень прав і ліміти на виклики.
Execute
Інструмент запускається з timeout та ізоляцією там, де це потрібно. retry вмикається лише для idempotent, read-only або спеціально захищених операцій.
Normalize
Результат приводиться до стабільного формату: ok, data, error_code, message, retryable.
Return
Runtime отримує структуровану відповідь і вирішує, робити наступний крок чи завершувати цикл.
Цей підхід дає передбачувану поведінку навіть тоді, коли окремі інструменти працюють нестабільно.
У коді це виглядає так
class ToolExecutionLayer:
def __init__(self, registry, policy, max_retries=1, timeout_s=8):
self.registry = registry
self.policy = policy
self.max_retries = max_retries
self.timeout_s = timeout_s
def execute(self, call, run_context):
tool_name = call["tool"]
args = call.get("args", {})
tool = self.registry.get(tool_name)
if tool is None:
return {"ok": False, "data": None, "error_code": "tool_not_found", "message": tool_name, "retryable": False}
if not self.policy.allowed(tool_name, run_context):
return {"ok": False, "data": None, "error_code": "tool_not_allowed", "message": tool_name, "retryable": False}
if not tool.validate_args(args):
return {"ok": False, "data": None, "error_code": "invalid_arguments", "message": "schema_mismatch", "retryable": False}
try:
# Retry only for idempotent/read-only/protected operations.
retries = self.max_retries if tool.retry_safe else 0
raw = tool.run(args, timeout_s=self.timeout_s, retries=retries)
return {
"ok": True,
"data": tool.normalize(raw),
"error_code": None,
"message": None,
"retryable": False,
}
except TimeoutError:
return {"ok": False, "data": None, "error_code": "tool_timeout", "message": tool_name, "retryable": True}
except Exception:
return {"ok": False, "data": None, "error_code": "tool_failed", "message": tool_name, "retryable": False}
Як це виглядає під час виконання
Запит: "Онови статус замовлення #4821 і підготуй відповідь клієнту"
Step 1
Agent Runtime: викликає LLM.decide(...)
LLM: повертає -> tool_call(update_order_status, {"order_id": 4821, "status": "shipped"})
Runtime: передає tool_call у Tool Execution Layer
Step 2
Tool Execution Layer: Validate -> інструмент існує, аргументи валідні
Tool Execution Layer: Authorize -> роль support_agent має доступ
Tool Execution Layer: Execute -> викликає API оновлення статусу
Tool Execution Layer: Normalize -> {"ok": true, "data": {"updated": true}, "error_code": null, "message": null, "retryable": false}
Runtime: додає результат у стан і переходить до наступного кроку
Runtime більше не працює з "сирими" викликами. Усі інструменти проходять через єдиний контрольований шар.
Коли підходить — і коли ні
Tool Execution Layer потрібен там, де важливі контроль доступу, стабільність і передбачуваний формат відповіді. Для прототипу з одним безпечним інструментом може бути зайвим.
Підходить
| Ситуація | Чому Tool Execution Layer підходить | |
|---|---|---|
| ✅ | Агент викликає кілька зовнішніх API з різними правилами доступу | Єдиний шар політик і валідації прибирає хаос у перевірках. |
| ✅ | Є інструменти, що змінюють стан системи (state-changing tools) | Потрібен контроль side effects (змін стану): права, підтвердження, ідемпотентність і аудит. |
| ✅ | Помилки інструментів не мають ламати весь цикл агента | Шар повертає контрольовані коди помилок і дозволяє Runtime продовжити або зупинити виконання. |
Не підходить
| Ситуація | Чому Tool Execution Layer не підходить | |
|---|---|---|
| ❌ | One-shot чатбот з одним безпечним інструментом лише для читання (read-only) | Повний execution layer зазвичай дає більше складності, ніж практичної вигоди. |
| ❌ | Немає вимог до політик, аудитів і обробки відмов | Додатковий шар ускладнить систему без помітної практичної користі. |
У таких випадках достатньо простого виклику:
result = tool.run(args)
Типові проблеми та відмови
| Проблема | Що відбувається | Як запобігти |
|---|---|---|
| Некоректні аргументи | Інструмент падає або повертає сміттєвий результат | Схемна валідація перед виконанням |
| Таймаут інструменту | Крок агента зависає і блокує execution loop | timeout, контрольований retry (лише для idempotent-операцій) і fallback-логіка |
| Небезпечна дія | Агент виконує операцію без прав доступу | Allowlist, role-based policy та deny by default |
| Неповторюваний side effect | Повторний виклик змінює стан системи вдруге (подвійне списання, дубльований апдейт) | Ідемпотентні ключі, дедуплікація, підтвердження перед mutation-діями |
| Нестабільний формат відповіді | Runtime не може коректно обробити результат | Нормалізація відповіді до єдиного контракту |
Стабільний Tool Execution Layer зменшує ризик тихих відмов і робить поведінку агента передбачуваною у production-середовищі.
Як поєднується з іншими патернами
Tool Execution Layer не приймає рішення замість агента. Він відповідає за те, як саме виконується дія після рішення моделі.
- Agent Runtime — Runtime керує циклом, а Tool Execution Layer безпечно виконує
tool_call. - Guarded-Policy Agent — policy-перевірки зазвичай реалізуються саме в Tool Execution Layer.
- Code-Execution Agent — запуск коду із sandbox та timeout проходить через цей шар.
- RAG Agent — запити до retrieval-інструментів також ідуть через єдиний шлюз.
Інакше кажучи:
- Agent Patterns визначають що агент вирішив зробити
- Tool Execution Layer визначає як ця дія безпечно виконається
Чим це відрізняється від Agent Runtime
| Agent Runtime | Tool Execution Layer | |
|---|---|---|
| Що контролює | Увесь цикл агента | Один конкретний tool_call |
| Що вирішує | Який крок робити далі | Чи можна безпечно виконати дію |
| Коли працює | На кожному кроці діалогу | Лише коли треба викликати інструмент |
| Що повертає | Наступний стан або фінальну відповідь | Нормалізований результат інструменту або контрольовану помилку |
Agent Runtime — це "диригент" усього процесу.
Tool Execution Layer — це "контрольований шлюз" для дій через інструменти.
Коротко
Tool Execution Layer:
- приймає
tool_callвід Runtime - перевіряє схему, права і ліміти
- виконує інструмент з timeout;
retryлише для безпечних операцій - повертає нормалізований результат або контрольовану помилку
FAQ
Q: Це те саме, що Agent Runtime?
A: Ні. Runtime керує всім циклом агента, а Tool Execution Layer виконує лише інструментальні дії під контролем правил.
Q: Чи може LLM напряму викликати API без цього шару?
A: Технічно може, але це ризиковано. Без Tool Execution Layer складно гарантувати валідацію, доступи, таймаути та стабільний формат відповіді.
Q: Чому не робити перевірки в кожному інструменті окремо?
A: Можна, але це швидко дублює логіку. Централізований шар дає єдині політики, простіший аудит і передбачувану поведінку.
Що далі
Tool Execution Layer відповідає за безпечну дію. Далі варто побачити, хто вирішує, коли і чому цю дію запускати:
- Policy Boundaries — які правила перевіряти перед виконанням дій.
- Agent Runtime — як runtime керує циклом і передає
tool_callу gateway. - Containerizing Agents — як ізолювати виконання ризикових інструментів.
- Production Stack — як зробити виконання інструментів керованим у production.