Головна / Статті / Перевірка відповідей LLM виконуваним графом знань і двома шлюзами

Перевірка відповідей LLM виконуваним графом знань і двома шлюзами

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

1546 слів

Гладко — не означає правильно

Мовні моделі пишуть гладкі відповіді, але гладкість не гарантує правоти. Припустімо, модель каже: «Цей клієнт має право на повне повернення коштів». Звучить нормально. Але модель могла вигадати політику, неправильно прочитати дату, пропустити виняток або домислити відсутні факти. У сценаріях, де модель спілкується з клієнтами, це неприпустимо, тож генерування тексту й перевірка фактів мають бути різними задачами.

Реальний прецедент є. У справі Moffatt v. Air Canada, 2024 BCCRT 149, чат-бот авіакомпанії повідомив, що пільговий тариф у зв'язку з утратою близької людини можна запросити після поїздки, хоча справжня політика авіакомпанії не дозволяла заднім числом подавати такі запити. Трибунал із цивільних спорів Британської Колумбії визнав Air Canada відповідальною за недбале введення в оману й зобов'язав сплатити збитки, відсотки та збори. Висновок: щойно система, що працює з клієнтами, цитує політику, компанію можуть змусити її дотримуватися.

Отже, мета — зберегти гнучкість LLM і водночас доручити комусь перевірку фактів до того, як відповідь дійде до користувача. Описаний підхід використовує RelationalAI як виконуваний граф знань, що перевіряє структуровані твердження, згенеровані LLM.

Цикл агента з двома шлюзами

Патерн узято з доповіді Френка Койла з Каліфорнійського університету в Берклі на AI Engineer World's Fair про поєднання LLM із валідацією та верифікацією. В основі — цикл агента зі шлюзом з обох боків від виконання інструмента. Працює він так:

1. The user asks a question.
2. The LLM decides whether it needs to call a tool.
3. Before the tool runs, the system validates the tool input.
4. The tool runs against an authoritative system.
5. After the tool runs, the system validates the output.
6. The result is appended back into the conversation.
7. The loop repeats until the model produces a final answer.

У вигляді схеми:

LLM proposes an action
   |
Gate 1 validates the tool input
   |
Tool runs
   |
Gate 2 validates the tool output
   |
LLM continues or finishes

Шлюз 1 перевіряє форму. Він з'ясовує, чи сформувала модель коректний запит, і це задача для валідації схеми: перш ніж запускати будь-який інструмент, переконатися, що обов'язкові поля на місці, а значення відповідають типам тверджень, які система знає.

Шлюз 2 перевіряє суть, тобто чи узгоджується результат із фактами й правилами предметної галузі. Саме тут виконуваний граф знань і корисний.

Що дає RelationalAI

RelationalAI дає змогу покласти виконуваний граф знань поверх ваших даних. Він зберігає факти, а ви ще й пишете правила, що виводять із них нові факти. Саме це відрізняє граф, у якому можна щось подивитися, від графа, за допомогою якого можна міркувати.

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

LLM output
   |
Pydantic validates the tool-call shape
   |
RelationalAI derives the authoritative value
   |
Claim is marked entailed, contradicted, or unsupported

Як усе це складається докупи, покаже конкретний приклад.

Крок 1: отримати від моделі структуровані твердження

LLM не може відповідати лише вільною прозою. Вона також має видавати структуровані твердження, які можна перевірити. Наприклад:

{
  "claim_type": "refund_method",
  "subject_id": "A-91",
  "value": "ORIGINAL_PAYMENT",
  "evidence": "Refund policy for GOLD uses ORIGINAL_PAYMENT."
}

Так система отримує щось конкретне для перевірки. Питання змінюється з «чи звучить цей абзац правильно?» на «чи правдиве це конкретне твердження для цього конкретного замовлення?». Це і є робота шлюзу 1. Незнайомий тип твердження або пропущене обов'язкове поле зупиняють виклик інструмента ще до звернення до графа.

Крок 2: закодувати політику повернень у графі

Далі RelationalAI моделює авторитетну бізнес-логіку. У демо використано невелику предметну галузь повернень із трьома поняттями: Customer, Order і RefundPolicy. Зв'язки й похідні властивості описують, як вони співвідносяться:

- an order belongs to a customer
- a refund policy applies to a customer tier
- refund eligibility depends on final-sale status and return window
- refund amount depends on eligibility and restocking fee
- refund method comes from the applicable policy

Із цих фактів і правил граф виводить значення, які треба перевірити:

- customer tier
- refund eligibility
- refund amount
- restocking fee
- refund method
- return window
- whether shipping is refundable
- whether the order was defective

LLM не можна довіряти вигадувати чи пригадувати ці значення, вона має запитувати їх у графа. Припустімо, відомі такі факти:

Order A-91 belongs to Customer C-184
Customer C-184 has tier GOLD
GOLD customers have a 30-day return window

Тоді RelationalAI може вивести:

Order A-91 is refund eligible
Order A-91 refund amount is 129.99
Order A-91 refund method is ORIGINAL_PAYMENT

Граф стає джерелом виконуваної істини. Скорочена версія моделі виглядає так:

model = Model("refund_policy_kg")

Customer = model.Concept("Customer", identify_by={"customer_id": String})
Order = model.Concept("Order", identify_by={"order_id": String})
RefundPolicy = model.Concept("RefundPolicy", identify_by={"policy_id": String})

Customer.tier = ...

Order.customer = ...
Order.amount = ...
Order.final_sale = ...
Order.request_age_days = ...

RefundPolicy.tier = ...
RefundPolicy.return_window_days = ...
RefundPolicy.refund_method = ...

Потім ідуть похідні значення, які запитуватиме шлюз 2:

Order.expected_refund_method = model.Property(
    f"{Order} has {String:expected_refund_method}"
)
Order.expected_eligible_for_refund = model.Property(
    f"{Order} has {Boolean:expected_eligible_for_refund}"
)

model.where(
    Order.customer(Customer),
    Customer.tier == RefundPolicy.tier,
).define(
    Order.expected_refund_method(RefundPolicy.refund_method)
)

model.where(
    Order.customer(Customer),
    Customer.tier == RefundPolicy.tier,
    Order.final_sale == False,
    Order.request_age_days <= RefundPolicy.return_window_days,
).define(
    Order.expected_eligible_for_refund(True)
)

Ні право на повернення, ні спосіб повернення не беруться від LLM. Їх обчислює граф знань, побудований на бізнес-правилах, а ці правила експерти предметної галузі й розробники можуть рев'юїти, версіонувати й контролювати.

Крок 3: перевірити, що сказала модель

Коли граф готовий, твердження можна перевіряти. Припустімо, модель відповідає: «Поверніть замовлення A-91 бонусами магазину, адже клієнт Platinum». Звучить правдоподібно, але граф може показати протилежне:

  • клієнт — GOLD, а не PLATINUM
  • спосіб повернення — ORIGINAL_PAYMENT, а не STORE_CREDIT
  • замовлення не позначене як браковане
  • політика не робить доставку такою, що підлягає поверненню

Система відхиляє відповідь. Це рішення ухвалила не друга LLM, а виконувана бізнес-логіка поверх перевірених фактів. Код валідації навмисно простий: для кожного твердження знайти відповідну очікувану властивість у RelationalAI, запитати її й порівняти результат зі значенням, яке запропонувала модель.

EXPECTED_PROPERTY_BY_CLAIM = {
    "refund_method": "expected_refund_method",
    "eligible_for_refund": "expected_eligible_for_refund",
    "refund_amount": "expected_refund_amount",
    "customer_tier": "expected_customer_tier",
}

def check_claims(model, concepts, claims):
    Order = concepts["Order"]
    results = []

    for claim in claims:
        expected_property = getattr(
            Order,
            EXPECTED_PROPERTY_BY_CLAIM[claim.claim_type],
        )

        df = model.where(
            Order.order_id == claim.subject_id
        ).select(
            Order.order_id.alias("subject_id"),
            expected_property.alias("expected"),
        ).to_df()

        if df.empty:
            status = "unsupported"
            expected = None
        else:
            expected = str(df.iloc[0]["expected"])
            status = "entailed" if claim.value == expected else "contradicted"

        results.append((claim, status, expected))

     return results

У продакшні ви б ретельно нормалізували значення, явно обробляли непідтримувані твердження й логували докази за кожним рішенням. Але основний потік той самий: LLM пропонує, RelationalAI перевіряє.

Навіщо так ділити роботу

LLM добре вміють висловлюватися. Вони розуміють намір, пишуть чернетки відповідей і пояснюють результати природною мовою. Але останнє слово щодо політики, цін, права на послуги, комплаєнсу та інших операційних фактів не має лишатися за ними. Краща послідовність:

  1. Нехай LLM тлумачить запит.
  2. Змусьте її видавати структуровані твердження.
  3. Перевірте згенерований об'єкт через Pydantic.
  4. Виведіть авторитетну відповідь у RelationalAI.
  5. Повертайте лише твердження, які підтверджує граф знань.

LLM відповідає за мову та взаємодію, а RelationalAI — за перевірку.

Цикл у коді

Загалом система виглядає так:

context = [user_question]

while True:
    response = llm.generate(context)

    if response.stop_reason != "tool_use":
        return response.text

    tool_call = response.tool_call

    # Gate 1: validate the model's requested action.
    claims = validate_tool_input(tool_call)

    # Tool execution: query authoritative facts and rules.
    graph = relationalai_model()
    checked_claims = graph.validate_claims(claims)

    # Gate 2: only grounded claims move forward.
    if checked_claims.has_contradictions():
        context.append(rejection_message(checked_claims))
        continue

    context.append(tool_result(checked_claims.entailed()))

Сам цикл рутинний. Важливо, хто за що відповідає:

  • модель пропонує твердження або запит
  • перший шлюз перевіряє форму пропозиції
  • RelationalAI обчислює, які факти правдиві
  • другий шлюз відкидає все, що суперечить фактам або не підтверджене
  • до відповіді потрапляють лише твердження, що вціліли

Не лише повернення

Приклад із поверненнями навмисно маленький, але та сама структура працює для умов договорів, регуляторних правил, логіки знижок і цін, обмежень ланцюга постачання, того, хто має право на який продукт, і того, що належить кожному клієнтові. Шар верифікації знадобиться в будь-якому процесі, де LLM говорить від імені бізнесу, і що дорожча помилка, то важливіше тримати згенерований текст окремо від виконуваної істини.

Джерела:

  • https://www.youtube.com/watch?v=Sir59K8ZDPU (доповідь із конференції)
  • https://www.canlii.org/en/bc/bccrt/doc/2024/2024bccrt149/2024bccrt149.html (Moffatt v. Air Canada)
  • https://docs.relational.ai/ (документація RelationalAI)