AI Architect Trainer Відкрити інтерактивний трек

ГоловнаАрхітектура корпоративної аналітики

Агентні міркування, консенсус і розгортання

Агент, що міркує над типізованою онтологією, а не над текстом; п'ять рівнів оркестрації інструментів; Raft, Paxos і CRDT для спільного стану; доставка в ізольовані та відрізані контури.

Востаннє переглянуто: 2026-09-04 · In English

У цьому напрямі

Четвертий шар платформи — це там, де дані нарешті ухвалюють рішення. Але агент, який отримує текстові фрагменти, вигадує ідентифікатори; агент, який отримує типізовані об'єкти онтології, — ні. Цей модуль розбирає три речі, що визначають, чи виживе агентна система в продакшні: нейросимволічний поділ обов'язків між ймовірнісною моделлю та детермінованим рушієм онтології, інженерія поверхні інструментів та її оркестрація з бюджетом, і механіка спільного стану — коли потрібен Raft із кворумом, коли достатньо CRDT без координації, і що саме перетинає повітряний зазор під час доставки у відрізане середовище.

Агент над онтологією, а не над текстом

E8.1

Типовий RAG-агент отримує фрагменти тексту і здогадується, про які сутності йдеться. Агент над онтологією отримує типізовані об'єкти зі стабільною ідентичністю, типізованими зв'язками та закритим переліком дій. Різниця не косметична — вона змінює три властивості системи одразу.

Нейросимволічний поділ обов'язків. Ймовірнісна половина (LLM) перетворює намір на кандидатний план. Детермінована половина (онтологія + рушій правил) тримає типи, кардинальності, інваріанти та дозволи. Правило, яке не має винятків: інваріанти ніколи не живуть у ймовірнісній половині. Модель, що на 97% дотримується правила «не переспрямовувати вантаж під митним арештом», порушує його раз на тридцять три виклики. І це не проблема якості моделі: 97% — уже добрий показник. Просто інваріант не є статистичною величиною, і 99,9% його теж не задовольняють.

Практична форма поверхні інструментів. search_objects(object_type, filter) повертає масив посилань на об'єкти, а не markdown. get_links(id, link_type) обходить граф. propose_action(action_type, object_id, params, idempotency_key) ініціює двофазний запис. Векторний пошук тут лише звужує кандидатів; вирішує предикат онтології.

Що змінюється в пошуку. Питання перестає бути «який чанк найсхожіший» і стає «які об'єкти задовольняють предикат». Векторний пошук лишається, але як груба відсічка кандидатів; далі працює обхід зв'язків: замість зшивати три абзаци з різних документів, агент робить два кроки get_links і отримує точну відповідь на багатокроковий запит. Побічний ефект приємний і вимірюваний: типізована відповідь на десять об'єктів — це кількасот токенів замість десяти чанків по 400.

Двофазний запис. Пропозиція → валідація → шлюз (політика або людина) → коміт із ключем ідемпотентності. Ключ обов'язковий: агент, який повторив крок після таймауту, не повинен переспрямувати вантаж двічі. Кожен коміт лишає в журналі актора, тип дії, id об'єкта та версію онтології — це і є аудиторський слід, який регулятор може перевірити, жодного разу не читаючи промптів.

# Ontology-grounded tool surface. The model never receives prose:
# every result is a typed object reference it can cite and act on.

TOOLS = [
    {
        'name': 'search_objects',
        'description': 'Find objects of ONE ontology type. Returns object refs, not text.',
        'input_schema': {
            'type': 'object',
            'properties': {
                'object_type': {'enum': ['Shipment', 'Wagon', 'Customer']},
                'filter': {'type': 'object'},
                'limit': {'type': 'integer', 'maximum': 50}
            },
            'required': ['object_type', 'filter']
        }
    },
    {
        'name': 'propose_action',
        'description': 'Propose a typed write. Symbolically validated before commit.',
        'input_schema': {
            'type': 'object',
            'properties': {
                'action_type': {'enum': ['reroute_shipment', 'flag_wagon']},
                'object_id': {'type': 'string'},
                'params': {'type': 'object'},
                'idempotency_key': {'type': 'string'}
            },
            'required': ['action_type', 'object_id', 'idempotency_key']
        }
    }
]


def commit(proposal, actor, ontology, policy, log):
    # The deterministic half owns types, invariants and permissions.
    obj = ontology.get(proposal['object_id'])
    if obj is None or obj.type not in ACTION_DOMAIN[proposal['action_type']]:
        return Rejected('TYPE_MISMATCH', retryable=False)

    if not policy.permits(actor, proposal['action_type'], obj):
        return Rejected('FORBIDDEN', retryable=False)   # never decided in a prompt

    for inv in ontology.invariants(proposal['action_type']):
        if not inv(obj, proposal['params']):
            return Rejected('PRECONDITION_FAILED:' + inv.name, retryable=True)

    # ordered, replicated, and idempotent by key (see E8.3)
    return log.append(proposal, key=proposal['idempotency_key'])

На практиці

Оператор вантажних залізничних перевезень підключив агента до сховища на 4,2 млн об'єктів (вантажі, вагони, митні статуси). Базовий текстовий RAG правильно прив'язував сутність у 61% запитів «які вантажі під ризиком»; після переходу на типізовані інструменти — 94%. Вигадані номери вагонів упали з 12% відповідей до нуля, бо жоден ідентифікатор більше не генерувався моделлю.

Антипатерн

Серіалізувати весь підграф у промпт як JSON-текст і покластися на модель у виконанні з'єднань. Це роздуває контекст, повертає вигадані ідентифікатори і — найгірше — переносить авторизацію в промпт, де її неможливо застосувати примусово.

Оркестрація інструментів: п'ять рівнів і бюджет

E8.2

Здатність агента користуватися інструментами вимірюється не бінарно. Корисно розкласти її на п'ять рівнів — і побачити, що продакшн-збої майже ніколи не на першому.

Головний важіль — не промпт, а поверхня інструментів. Опис інструмента — це його контракт; він важливіший за розмір моделі. Тримайте до ~20 інструментів на одного агента: далі точність вибору просідає, і лікується це маршрутизацією до вужчих під-агентів, а не більшою моделлю. Помилки мають бути дієвими: code, message, retryable. Помилка «щось пішло не так» гарантує, що рівня 5 не буде ніколи.

Опис — це контракт, а не документація. Іменуйте інструменти за типом об'єкта, яким вони оперують (shipment.search, wagon.flag), а не за дією взагалі. Два інструменти з описами, що перетинаються, гарантують плутанину, і жоден промпт її не розводить. Коли поверхня росте, розділяйте не всередині агента, а між агентами: маршрутизатор передає під-агентові явно сформульоване завдання й потрібні посилання на об'єкти, а не спільний блокнот міркувань — інакше контекст росте, а точність падає.

Бюджет — це архітектура, а не налаштування. Цикл ReAct (думка → дія → спостереження) без обмежень на кроки, час і вартість — це аварія зі спінером. Досягнення межі не має завершуватися вигаданою відповіддю: воно має ескалювати з накопиченим трейсом.

Маршрутизація за корисністю. Очікувана цінність виклику = P(корисно) × цінність − вартість (затримка + токени + гроші). Дешеві детерміновані інструменти (фільтр онтології, точковий lookup) йдуть першими; дорогі генеративні — останніми. Паралелити можна лише читання без побічних ефектів; записи серіалізуються через реплікований журнал (E8.3).

Вимірювання. Точність кінцевої відповіді приховує крихкість. Міряйте окремо: точність вибору інструмента, валідність аргументів, частку успішного відновлення після помилки. Агент із 92% кінцевої точності та 40% відновлення розсиплеться при першій деградації API. Причина проста: офлайн-набір складається зі здорових викликів, тож рівень 5 у ньому просто не трапляється — його треба перевіряти окремо, навмисно ламаючи інструменти.

# Bounded ReAct loop with utility-guided tool selection.
# An unbounded agent loop is an outage with a spinner on it.

BUDGET = {'steps': 8, 'seconds': 25.0, 'usd': 0.05}


def expected_utility(tool, trace):
    # value of the information, minus what the call actually costs us
    return tool.p_useful(trace) * tool.value - (
        tool.latency_s * LATENCY_PRICE + tool.usd
    )


def run(goal, tools, model, budget=BUDGET):
    trace = []
    spent = {'steps': 0, 'seconds': 0.0, 'usd': 0.0}

    while spent['steps'] < budget['steps']:
        # cheap deterministic tools outrank expensive generative ones;
        # the slice keeps the visible surface under the selection cliff
        allowed = sorted(tools, key=lambda t: -expected_utility(t, trace))[:9]

        step = model.plan(goal, trace, allowed)
        if step.kind == 'final':
            return step.answer, trace

        obs = call(step.tool, step.args)          # typed result, never raw prose
        if obs.error and obs.error.retryable:
            # actionable error -> level 5 recovery is possible
            trace.append(Observation(obs.error.code, obs.error.message))
        else:
            trace.append(obs)

        spent['steps'] += 1
        spent['usd'] += obs.usd
        spent['seconds'] += obs.latency_s
        if spent['usd'] > budget['usd'] or spent['seconds'] > budget['seconds']:
            return escalate(goal, trace), trace   # hand over the trace, do not spin

    return escalate(goal, trace), trace

На практиці

Агент реагування на інциденти мав 34 інструменти в одній пласкій поверхні. Після розділення на три маршрутизовані під-агенти по ≤9 інструментів точність вибору інструмента зросла з 71% до 96%, медіанна кількість кроків упала з 11 до 6, а вартість опрацювання одного інциденту — з $0.84 до $0.31. Модель не змінювали жодного разу.

Антипатерн

Виставити один узагальнений інструмент run_query(sql) замість типізованих дій. Модель пише синтаксично валідний, але семантично хибний SQL, авторизація на рівні окремої дії стає неможливою, а точність вибору інструмента неможливо виміряти — інструмент один.

Спільний стан: консенсус, CRDT і відрізані контури

E8.3

Дві різні задачі постійно плутають. Узгодження єдиного впорядкованого журналу (Raft, Paxos) дає лінеаризовність, потребує кворуму і жертвує доступністю під час розділення мережі. Збіжність без координації (CRDT) завжди доступна на запис і зливається детерміновано, але не вміє виражати інваріант «схвалення має бути рівно одне».

Raft у трьох рядках. Вибори лідера з термами, реплікація журналу, коміт за більшістю. Щоб пережити f відмов, потрібно 2f+1 вузлів: п'ять витримують дві. Лідер — це водночас стеля пропускної здатності й підлога затримки (один RTT до більшості). Кладіть у нього те, де важливий порядок: журнал дій агента, версію онтології, версію бандла політик.

Paxos чи Raft — та сама арифметика. Multi-Paxos і Raft дають однакові гарантії й однакову вимогу більшості; Raft виграє зрозумілістю реалізації та явним поняттям лідера, тому його простіше правильно експлуатувати. Що не варто класти в консенсус: високочастотну телеметрію, метрики та проміжні спостереження агента. Лідер миттєво стає вузьким місцем, а порядок цих подій нікому не потрібен — їм місце в потоковому конвеєрі, а не в реплікованому журналі.

CRDT там, де операції комутативні. OR-Set для тегів і міток (add-wins із tombstone), LWW-регістр для нотаток тріажу, лічильники. Критична деталь: LWW за настінним годинником при розбіжності 400 мс тихо втрачає редагування. Використовуйте гібридний логічний годинник — він зберігає причинність і не залежить від NTP. Жорсткіша синхронізація тут не рятує: вона звужує вікно втрат, не усуваючи саму можливість.

Відрізані та ізольовані контури. В анклав заходить підписаний бандл: ваги моделі, версія онтології, бандл політик, маніфест інструментів — усе з контент-хешем і перевіркою підпису при завантаженні. Назовні через односторонній канал виходить лише підписана дельта.

# fleet.yaml - one core Raft group plus disconnected enclaves with CRDT state

core:
  consensus: raft
  members: [core-1, core-2, core-3, core-4, core-5]   # 2f+1 -> tolerates f=2
  linearizable_state:
    - action_log             # order matters: who approved what, and first
    - ontology_version
    - policy_bundle_version

enclaves:
  - id: fwd-17
    connectivity: intermittent       # observed dark window: 6-72h
    consensus: raft                  # SEPARATE group - never spans the air gap
    members: [fwd-17a, fwd-17b, fwd-17c]
    authority_scope: local           # commits are 'local_commit', never global
    convergent_state:                # coordination-free, always writable
      annotations: or-set            # add-wins, tombstoned removes
      triage_notes: lww-register
      clock: hybrid-logical          # NOT wall clock: 400ms skew loses edits

bundle:                              # the only thing that crosses the diode, one way
  pins:
    ontology_version: 2026.31.0
    policy_bundle: sha256:9f3c1d...
    model: local-8b-q4:sha256:1a77e0...
  signature: minisign
  verify_on_load: true               # refuse to start on a hash mismatch

reconnect:
  annotations: merge                 # CRDT: deterministic, no human in the loop
  actions: replay_as_proposals       # re-validated against the CURRENT policy
  on_version_skew: reject            # never silently coerce a stale action

На практиці

Логістичне розгортання на 40 передових вузлах із вікнами автономності 6–72 год: Raft-група з 5 вузлів у ядрі та CRDT-шар анотацій на кожному вузлі. Після відновлення зв'язку 18 400 анотацій злилися за 40 секунд без жодного ручного розв'язання конфліктів, тоді як 260 дій запису переграли як пропозиції — і 11 із них відхилив рушій політик, переглянутий, поки вузли були відрізані.

Антипатерн

Розтягнути одну Raft-групу через повітряний зазор і покластися на LWW за настінним годинником між вузлами з розбіжністю 400 мс. Перше зупиняє записи всього флоту при кожному від'єднанні; друге тихо втрачає редагування, і виявляється це лише під час аудиту.

Джерела, з яких виведено напрям

  1. Agentic Reasoning for Large Language Mod
  2. A Survey on Large Language Model based A
  3. A Relational Neural Network Database Mod
  4. ReAct Synergizing Reasoning and Acting in Language
  5. ETOM A Five Level Benchmark for Evaluating Tool Orchestrat
  6. The Evolution of Tool Use in LLM Agents From Single Tool C
  7. Utility Guided Agent Orchestration for Efficient LLM Tool
  8. Reinforcement Learning for LLM based Multi Agent Systems t
  9. A Survey on Consensus Algorithms in Bloc
  10. A Deep Dive into Blockchain Consensus Pr
  11. A Security Reference Architecture for Bl
  12. A comparative study on consensus mechani

Пройти інтерактивно

У кожного напряму є питання, картки з інтервальним повторенням і облік прогресу. Для них потрібен акаунт — безкоштовний і на одну хвилину.

Відкрити інтерактивний трек Створити безкоштовний акаунт

Далі в цьому треку