Головна / Статті

Графи фінансових злочинів із багатьма агентами за допомогою LangChain, LangGraph та LangSmith

Граф фінансових злочинів з багатьма агентами за допомогою LangChain, LangGraph та LangSmith: маршрутизація керівника, підграфи, переривання з участю людини, оцінка, захисні механізми.

Видавець: REACTAPP.TOP10 хв читання2374 слів

Джерела: Building Multi-Agent Financial Crime Detection Systems with LangGraph, LangChain, and LangSmith

Проблема на місцях

Перевірка фінансових злочинів — це не одна-єдина задача. Для розслідування справи може знадобитися поглиблена перевірка даних клієнтів, аналіз санкцій, перевірка інформації з ЗМІ, виявлення закономірностей у транзакціях та створення опису подій для слідчих — кожна з цих задач вимагає різних інструментів, термінів виконання та способів усунення проблем. Єдиний механізм, який намагається виконати все сам, стає нечітким у функціонуванні, складним для тестування та ризикованим у разі збою одного з інструментів.

Чому багато агентів краще за один величезний механізм

Спеціалізовані агенти допомагають зосередитися на конкретних завданнях та інструментах. Керівник може розподіляти роботу між агентами. Проблеми залишаються локальними. Людський контроль дозволяє контролювати операції з високим ризиком. Завдяки можливості спостереження можна визначити витрати та помилки для кожної ролі, а не лише для всього механізму в цілому.

Три рівні: LangChain, LangGraph, LangSmith

LangChain надає моделі, інструменти та механізми обробки повідомлень. LangGraph забезпечує оркестрацію із збереженням стану — спільний стан справи, краї, можливість збереження даних та обриви виконання. LangSmith відповідає за трасування, набори даних та механізми оцінки. Агент на основі звичайного циклу while може викликати інструменти, але рідко забезпечує стабільне збереження пам’яті справи, паралельну перевірку, повторне використання підграфів чи першокласну підтримку HITL.

Спільний стан справи

Почніть із чіткого схематизування стану: ідентифікатор справи, повідомлення, оцінки, прапорці, рішення щодо маршрутизації та нотатки слідчого.

from typing import TypedDict, Annotated, Literal
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from operator import add

class CaseState(TypedDict):
    case_id: str
    customer_id: str
    transactions: list[dict]
    messages: Annotated[list, add_messages]
    kyc_flags: Annotated[list[str], add]
    sanctions_hits: Annotated[list[dict], add]
    risk_score: float
    narrative: str
    requires_human_review: bool

Один вузол агента з інструментами

Під’єднайте модель до інструментів конкретної галузі (пошук санкцій, перевірка списку під контролем) та дозвольте вузлу інструментів виконувати відповідні виклики.

from langchain_anthropic import ChatAnthropic
from langchain_core.tools import tool

@tool
def screen_ofac(name: str, dob: str | None = None) -> dict:
    """Screen an individual or entity name against the UK list."""
    # In production: call a real screening API (e.g. UK100, Refinitiv)
    return {"name": name, "match": False, "score": 0.02}

@tool
def screen_un_sanctions(name: str) -> dict:
    """Screen a name against the UN Consolidated Sanctions List."""
    return {"name": name, "match": False, "score": 0.0}
llm = ChatAnthropic(model="claude-sonnet-4-6", temperature=0)
sanctions_llm = llm.bind_tools([screen_ofac, screen_un_sanctions])

def sanctions_agent(state: CaseState) -> dict:
    response = sanctions_llm.invoke(state["messages"])
    return {"messages": [response]}

Підключення елементів графа

Приєднайте вузли агента та інструментів, використовуйте tools_condition (або еквівалент) для циклічного виконання дій, поки модель не припинить викликати інструменти, а потім переходьте до наступної стадії.

from langgraph.prebuilt import ToolNode, tools_condition

graph = StateGraph(CaseState)
graph.add_node("kyc_agent", kyc_agent)
graph.add_node("sanctions_agent", sanctions_agent)
graph.add_node("sanctions_tools", ToolNode([screen_ofac, screen_un_sanctions]))
graph.add_node("tx_monitoring_agent", tx_monitoring_agent)
graph.add_node("narrative_agent", narrative_agent)
graph.set_entry_point("kyc_agent")
graph.add_edge("kyc_agent", "sanctions_agent")
# Conditional edge: loop back to tools if the LLM requested a tool call
graph.add_conditional_edges(
    "sanctions_agent",
    tools_condition,
    {"tools": "sanctions_tools", END: "tx_monitoring_agent"},
)
graph.add_edge("sanctions_tools", "sanctions_agent")
graph.add_edge("tx_monitoring_agent", "narrative_agent")
graph.add_edge("narrative_agent", END)
app = graph.compile()

Перевірте вузли з фальшивим станом перед створенням повної графики:

def test_sanctions_agent_flags_high_score_match():
    fake_state = {
        "messages": [HumanMessage(content="Screen: Igor Petrov, DOB 1978-03-11")],
    }
    result = sanctions_agent(fake_state)
    assert "tool_calls" in result["messages"][-1].additional_kwargs

Маршрутизація керівника

Клас запиту керівника класифікує наступного спеціаліста — KYC, санкції, негативні повідомлення в ЗМІ — або завершується підсумком.

from langchain_core.messages import SystemMessage

SUPERVISOR_PROMPT = """You are a financial crime case supervisor.
Route to exactly one of: kyc_agent, sanctions_agent, tx_monitoring_agent,
adverse_media_agent, narrative_agent, or FINISH if the case is fully investigated."""

def supervisor(state: CaseState) -> dict:
    routing_llm = llm.with_structured_output(RouteDecision)
    decision = routing_llm.invoke(
        [SystemMessage(content=SUPERVISOR_PROMPT)] + state["messages"]
    )
    return {"next": decision.next_agent}

def route_next(state: CaseState) -> str:
    return state["next"] if state["next"] != "FINISH" else END
graph.add_node("supervisor", supervisor)
for agent_name in ["kyc_agent", "sanctions_agent", "tx_monitoring_agent", "adverse_media_agent"]:
    graph.add_edge(agent_name, "supervisor")
graph.add_conditional_edges("supervisor", route_next)

Паралельне розгортання

Незалежні перевірки можуть виконуватися після KYC без необхідності серіалізації всього:

graph.add_edge("kyc_agent", "sanctions_agent")
graph.add_edge("kyc_agent", "adverse_media_agent")
graph.add_edge("kyc_agent", "tx_monitoring_agent")

# Fan-in: all three must complete before scoring
graph.add_edge("sanctions_agent", "risk_scoring_agent")
graph.add_edge("adverse_media_agent", "risk_scoring_agent")
graph.add_edge("tx_monitoring_agent", "risk_scoring_agent")

Участь людини

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

from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import interrupt, Command

def compliance_review(state: CaseState) -> dict:
    if state["risk_score"] > 0.7:
        decision = interrupt({
            "narrative": state["narrative"],
            "risk_score": state["risk_score"],
            "action_needed": "approve_or_reject_sar",
        })
        return {"requires_human_review": False, "human_decision": decision}
    return {"requires_human_review": False}

checkpointer = MemorySaver()
app = graph.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "case-2026-00931"}}
result = app.invoke({"case_id": "case-2026-00931", ...}, config=config)

# Later, once a human reviews in your case management UI:
final = app.invoke(Command(resume={"approved": True, "reviewer": "j.smith"}), config=config)
for chunk in app.stream(
    {"case_id": "case-2026-00931", ...},
    config=config,
    stream_mode="updates",
):
    for node_name, node_output in chunk.items():
        print(f"[{node_name}] emitted: {node_output}")
        # push node_output to a websocket / case UI here

Підграфи для повторного використання

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

kyc_subgraph = StateGraph(CaseState)
kyc_subgraph.add_node("resolve_entity", resolve_entity_node)
kyc_subgraph.add_node("verify_documents", verify_documents_node)
kyc_subgraph.add_node("pep_check", pep_check_node)
kyc_subgraph.set_entry_point("resolve_entity")
kyc_subgraph.add_edge("resolve_entity", "verify_documents")
kyc_subgraph.add_edge("verify_documents", "pep_check")
kyc_subgraph.add_edge("pep_check", END)
compiled_kyc = kyc_subgraph.compile()
parent_graph = StateGraph(CaseState)
parent_graph.add_node("kyc_process", compiled_kyc)  # subgraph as a node

Оперативність завдяки LangSmith

Увімкніть відстеження та позначайте запуски ідентифікаторами справ та ролями агентів.

import os

os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = "ls__..."
os.environ["LANGSMITH_PROJECT"] = "financial-crime-agents"
result = app.invoke(
    {"case_id": "case-2026-00931", ...},
    config={
        "configurable": {"thread_id": "case-2026-00931"},
        "metadata": {"case_id": "case-2026-00931", "customer_tier": "high_risk"},
        "tags": ["sar_pipeline", "prod"],
    },
)

Ітерації, засновані на оцінці

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

from langsmith import Client
from langsmith.evaluation import evaluate

client = Client()
def correctness_evaluator(run, example) -> dict:
    predicted_risk = run.outputs.get("risk_score", 0)
    actual_risk = example.outputs.get("risk_score", 0)
    return {
        "key": "risk_score_accuracy",
        "score": 1.0 if abs(predicted_risk - actual_risk) < 0.15 else 0.0,
    }
results = evaluate(
    lambda inputs: app.invoke(inputs, config={"configurable": {"thread_id": "eval"}}),
    data="aml-labeled-cases-2026-h1",
    evaluators=[correctness_evaluator],
    experiment_prefix="sar-pipeline-v3",
)
from langsmith.evaluation import LangChainStringEvaluator

narrative_judge = LangChainStringEvaluator(
    "criteria",
    config={
        "criteria": {
            "cites_evidence": "Does the narrative cite specific transaction IDs and dates?",
            "regulatory_tone": "Is the language neutral and factual, avoiding speculation?",
        },
        "llm": ChatAnthropic(model="claude-sonnet-4-6", temperature=0),
    },
)
results = evaluate(
    lambda inputs: app.invoke(inputs, config=config),
    data="aml-labeled-cases-2026-h1",
    evaluators=[correctness_evaluator, narrative_judge],
    experiment_prefix="sar-narrative-v2",
)

Механізми контролю та обробки помилок

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

from langgraph.pregel import RetryPolicy

graph.add_node(
    "sanctions_tools",
    ToolNode([screen_ofac, screen_un_sanctions]),
    retry=RetryPolicy(max_attempts=3, backoff_factor=2.0),
)
result = app.invoke(initial_state, config={**config, "recursion_limit": 25})

Підводні камені у продакшн-схемах AML

Приховані спільні змінні глобальних змінних, автоматичне подання даних без нагляду, відсутність зв’язку між оцінкою та доказами, а також системи керування, які постійно задають однакові запитання тому самому агенту. Обмежуйте цикли, вимагайте посилань у стані системи та зберігайте дії з поданням даних позаду HITL.

Формат посилання

Практична топологія: керівник у центрі, спеціалізовані агенти з циклами інструментів, необов’язкові паралельні гілки, вузол об’єднання/опису, бранка переривання, а потім експорт — із використанням повторюваних підграфів там, де одиниці повторюються.

             ┌─────────────┐
             │  Supervisor │◄───────────────-─┐
             └──────┬──────┘                  │
     ┌───────────────┼───────────────┐        │
     ▼               ▼               ▼        │
┌─────────┐   ┌──────────────┐  ┌───────────┐ │
│   KYC   │   │ Sanctions    │  │ TX Monitor│ │
│Subgraph │   │ Agent + Tools│  │  Agent    │ │
└────┬────┘   └──────┬───────┘  └─────┬─────┘ │
     └───────────────┴────────────────┘       │
                       ▼                      │
              ┌─────────────────┐             │
              │ Risk Scoring    │─────────────┘
              └────────┬────────┘
                       ▼
              ┌─────────────────┐        ┌──────────────┐
              │ Narrative Agent │───────►│ Human Review │
              └─────────────────┘        │ (interrupt)  │
                                         └──────┬───────┘
                                                 ▼
                                          SAR Filed / Closed

Витрати та затримки

Розгалуження витрачає токени; кешування стабільних профілів KYC; використання менших моделей для маршрутизації та більших — для опису ситуацій; потокове оновлення інтерфейсу, щоб слідчі бачили прогрес перед остаточним записом.

Заключні зауваження

Системи боротьби з фінансовими злочинами з багатьма агентами ефективні, коли стан є чітким, спеціалісти піддаються тестуванню, оркестрація є видимою, а люди залишаються у процесі при виконанні незворотних дій. LangGraph забезпечує план керування; LangChain — інструменти; LangSmith — цикл зворотного зв’язку, який підтримує чесність графа у міру розвитку типологій.

Управління агентами регульованих розслідувань

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

Зміни у запитах та інструментах мають проходити через ту саму систему управління змінами, що й двигуни правил. Тестуйте нові запити-керівники на історичних справах, порівнюйте розподіли маршрутизації та вимагайте підтвердження перед їх запровадженням. Дані з наборів LangSmith допомагають, але відповідальні за управління все одно потребують письмового схвалення.

Людські фактори мають велике значення. Якщо переривання відбуваються занадто часто, слідчі їх ігнорують; якщо занадто рідко, ризик залишається неконтрольованим. Налаштовуйте пороги за допомогою перевірок з вибіркою. Стан процесу у реальному часі має підкреслювати невизначеність, а не лише достовірну інформацію, щоб перевіряючі знали, де шукати.

Стійкість до атак є частиною надійності: результати інструментів можуть бути спотвореними або сфабрикованими (наприклад, отруєний текст у негативних ЗМІ). Вузли верифікації повинні очищувати дані та наводити джерела. Ніколи не дозволяйте одному лише абстрагованому абзацу схвалювати дію без підтверджуючих механізмів.

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

Ці практики перетворюють архітектуру посилань з просто розумної діаграми на функціональну систему. Наведені вище зразки коду є лише основою; саме модель керування забезпечує довіру до агентів, які борються з фінансовими злочинами.

Створення спеціалізованих запитів без дублювання

Кожен спеціалізований агент має отримувати лише ту частину інформації про стан справи, яка йому потрібна. Завантаження всього обсягу розслідування в кожен запит марнує ресурси та призводить до витоку непотрібних персональних даних у інструменти, які їх не потребують. Необхідно визначити функції перегляду: sanctions_view(state), kyc_view(state) та протестувати їх за допомогою модулів одиниць тестування. Керівники бачать підсумки маршрутизації; автори — пакети доказів.

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

Лінійність даних та сховища ознак

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

Паралельність та послідовність

Гілки, що розходяться, мають об’єднуватися детерміновано. Визначте функції для обробки спискових полів та правила „останній, хто записав“ для скалярних значень. Протестуйте одночасні оновлення. Якщо як негативні медіа, так і санкції записують значення у поле risk_flags, використовуйте функції з примітками, щоб значення об’єднувалися, а не перезаписувалися.

Інтеграція з робочим процесом людини

Системи управління справами (на кшталт Jira, користувацькі CRM) повинні керувати перериваннями. Надсилайте навантаження переривань у вигляді завдань; після їх виконання викликайте API для продовження роботи з результатом завдання. Не створюйте окремий веб-сайт для схвалень, якщо слідчі вже працюють у існуючому консолі — інтегруйте це функціонал там.

Тестування на проникнення до графа

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

Керування витратами

Тег LangSmith (або еквівалентний) працює з параметрами case_type, agent та model. Бюджет визначається за типом справи. Попередження при виявленні аномалій. Для очевидних ситуацій затвердження/відхилення краще використовувати детерміністичні правила, а ШІ-моделі — для роботи з неоднозначними сценаріями. Гібридні системи кращі за чисто ШІ-орієнтовані підходи як за витратами, так і за можливістю аудиту.

Підбір персоналу та відповідальність

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

Завдяки таким практикам патерн багатоагентної системи LangGraph перетворюється на операційну систему для розслідувань, а не на демонстраційний інструмент, який працює лише у одному конкретному випадку.

Від пілотування до впровадження у бізнес

Пілотні проекти часто базуються на кількох синтетичних випадках. Для впровадження в бізнес необхідна локалізація типологій, підтримка мов у описах ситуацій та інтеграція з існуючими механізмами відстеження часу та SLA. Плануйте поетапне впровадження за сегментами: спочатку продукти з низьким рівнем ризику, а потім — продукти з вищим рівнем ризику. Тримайте контрольну групу випадків, які переглядаються вручну, щоб оцінити ефективність. Пояснюйте, що використання моделей не означає відсутності нагляду. Навчання слідчих має включати інструкції щодо читання графіків даних, як їх переважити та як повідомляти про проблемні дані інструменту. Технології без такої людської підтримки працюватимуть гірше, навіть якщо схема архітектури ідеальна.

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

Чек-лист перед запуском у реальних умовах

Схему системи перевірили відповідно до стандартів; інструменти оснащені механізмами автентифікації та таймаутами; керівник оцінює минулі випадки як успішні; шлях HITL протестовано повністю; панелі керування LangSmith (або аналогічних інструментів) працюють; встановлено обмеження на рекурсію; документовано механізм припинення роботи; налаштовано сповіщення про перевищення бюджету; узгоджено версіонування підграфів; протестовано засоби паралельного об’єднання даних; необхідні описові посилання; опубліковані інструкції для екстрених ситуацій. Виявлення фінансових злочинів за допомогою кількох агентів — це не стільки справа хитрих запитів, скільки використання цих простих інструментів. Позначте їх, потім обережно збільшуйте обсяг оброблюваних випадків, щотижня перевіряючи зразки з хибними результатами протягом першого кварталу.

Співпраця з слідчими як користувачами продукту

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

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

Публікуйте щомісячний звіт про якість, оцінку якого допомагають здійснювати аналітики. Спільна відповідальність забезпечує, щоб багатоагентна система була орієнтована на виконання місії — виявлення фінансових злочинів, — а не лише на показники демонстраційної версії. Якщо робити це послідовно, багатоагентний дизайн LangGraph здобуває довіру — єдиний спосіб, який має значення у боротьбі з фінансовими злочинами: завдяки роботі з реальними справами, реальними слідчими та реальними аудитами, а не лише через елегантний вигляд у схемі для демонстрації. Спочатку реалізуйте нудні механізми контролю; дозвольте розумному маршрутизуванню зайняти своє місце лише після того, як контрольні механізми будуть функціонувати належним чином. Слідчі одразу помітять різницю. Завжди будуйте систему з урахуванням такої ретельної перевірки. Тут менше недостатньо.