Gráficos de delitos financieros multiagente con LangChain, LangGraph y LangSmith
Un grafo de delitos financieros con múltiples agentes utilizando LangChain, LangGraph y LangSmith: enrutamiento por supervisor, subgrafos, interrupciones por intervención humana, evaluaciones y medidas de control.
Fuentes: Building Multi-Agent Financial Crime Detection Systems with LangGraph, LangChain, and LangSmith
El problema en el terreno
La revisión de delitos financieros no es una solicitud única. Un caso puede requerir verificación de identidad, análisis de sanciones, revisión de medios negativos, detección de patrones en transacciones y una narrativa para los investigadores; cada uno con herramientas, plazos de respuesta y modos de fallo diferentes. Una cadena única que intenta hacerlo todo se vuelve opaca, difícil de probar y arriesgada cuando una herramienta falla.
Por qué los múltiples agentes superan a una sola mega-cadena
Los agentes especializados mantienen las solicitudes y herramientas enfocadas. Un supervisor puede redirigir o distribuir el trabajo. Los fallos se limitan a un área específica. La revisión humana puede controlar las transiciones de alto riesgo. La capacidad de observación permite atribuir costos y errores a cada rol en lugar de tener un único registro general.
Tres capas: LangChain, LangGraph, LangSmith
LangChain proporciona modelos, herramientas y mecanismos para gestionar mensajes. LangGraph se encarga de la orquestación con estado: estado compartido del caso, enlaces, persistencia e interrupciones. LangSmith abarca el seguimiento de operaciones, conjuntos de datos y evaluadores. Un agente basado en bucles while simples puede llamar a herramientas, pero rara vez ofrece memoria duradera para el caso, verificaciones en paralelo, reutilización de subgrafos o un sistema HITL de primera clase.
Estado compartido del caso
Comience con un esquema de estado explícito: ID del caso, mensajes, puntuaciones, indicadores, decisiones de enrutamiento y notas del investigador.
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
Un nodo de agente con herramientas
Vincule un modelo a herramientas específicas del dominio (búsqueda de sanciones, consulta en listas de vigilancia) y permita que un nodo de herramientas ejecute las llamadas correspondientes.
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]}
Conexión del grafo
Conecte los nodos de agente y herramientas, utilice tools_condition (o equivalente) para crear bucles hasta que el modelo deje de llamar a las herramientas, y luego continúe con la siguiente etapa.
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()
Pruebe los nodos con estado falso antes de armar el grafo completo:
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
Enrutamiento del supervisor
Una clase de comando del supervisor clasifica al siguiente especialista —verificación de identidad, sanciones, medios negativos— o finaliza con un resumen.
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)
Difusión paralela
Se pueden realizar verificaciones independientes después de la verificación de identidad sin serializar todo:
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")
Intervención humana
Haga una marca de control, interrumpa cuando el riesgo supere los parámetros establecidos, envíe el estado parcial a la interfaz de usuario del caso y luego continúe con las indicaciones del investigador.
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
Subgrafos para unidades reutilizables
Empaque la resolución de la verificación de identidad como un grafo independiente y úselo como nodo para que otros tipos de casos reutilicen la misma unidad.
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
Observabilidad con LangSmith
Habilite el seguimiento y etiquete las ejecuciones con IDs de caso y roles de los agentes.
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"],
},
)
Iteración basada en la evaluación
El conjunto de datos evalúa las regresiones en la captura cuando cambian los prompts o las herramientas. El LLM como juez puede calificar la claridad narrativa de los resúmenes similares a SAR; siempre se utiliza una verificación humana cuando las consecuencias son graves.
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",
)
Límites y manejo de fallos
Volver a intentar con los nodos de herramientas inestables, limitar la recursión y detenerse ante interrupciones por sanciones en lugar de inventar un resultado claro.
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})
Riesgos en los gráficos AML en producción
Variables globales mutables compartidas ocultas, archivo automático sin supervisión, falta de trazabilidad desde la puntuación hasta las pruebas, y supervisores que siguen preguntando al mismo agente una y otra vez. Limitar los bucles, requerir citas en el estado y mantener las acciones de archivo detrás del HITL.
Forma de referencia
Una topología práctica: un supervisor en el centro, agentes especializados con bucles de herramientas, ramificaciones paralelas opcionales, nodo de fusión/narrativa, puerta de interrupción y, finalmente, exportación; se incluyen subgrafos reutilizables donde las unidades se repiten.
┌─────────────┐
│ Supervisor │◄───────────────-─┐
└──────┬──────┘ │
┌───────────────┼───────────────┐ │
▼ ▼ ▼ │
┌─────────┐ ┌──────────────┐ ┌───────────┐ │
│ KYC │ │ Sanctions │ │ TX Monitor│ │
│Subgraph │ │ Agent + Tools│ │ Agent │ │
└────┬────┘ └──────┬───────┘ └─────┬─────┘ │
└───────────────┴────────────────┘ │
▼ │
┌─────────────────┐ │
│ Risk Scoring │─────────────┘
└────────┬────────┘
▼
┌─────────────────┐ ┌──────────────┐
│ Narrative Agent │───────►│ Human Review │
└─────────────────┘ │ (interrupt) │
└──────┬───────┘
▼
SAR Filed / Closed
Costo y latencia
La expansión de conexiones consume tokens; se almacenan en caché perfiles KYC estables; se utilizan modelos más pequeños para el enrutamiento y otros más grandes para las narrativas; se transmiten actualizaciones de la interfaz de usuario para que los investigadores puedan ver el progreso antes de la redacción final.
Notas finales
Los sistemas de delitos financieros con múltiples agentes tienen éxito cuando el estado es explícito, los especialistas son verificables, la orquestación es visible y los humanos permanecen involucrados en las acciones irreversibles. LangGraph proporciona el plano de control; LangChain ofrece las herramientas; LangSmith constituye el bucle de retroalimentación que mantiene el grafo fiable a medida que evolucionan las tipologías.
Gobernanza para agentes de investigación regulados
Los equipos de AML y fraude ya operan bajo los requisitos relacionados con el riesgo de modelos y las auditorías. Un grafo de agentes debe generar rastros de evidencia que los investigadores y reguladores puedan seguir: qué herramientas se ejecutaron, qué listas coincidieron, qué umbrales se activaron, quién aprobó una excepción y qué versión del modelo redactó el informe. Almacene esos campos en el estado del caso y exportelos junto con el archivo del caso, no solo en una interfaz de seguimiento propietaria.
Los cambios en prompts y herramientas deben seguir el mismo proceso de gestión de cambios que los motores de reglas. Ejecute pruebas con nuevos prompts de supervisión en casos históricos, compare las distribuciones de enrutamiento y exija la aprobación antes de promoverlos. Los conjuntos de datos de LangSmith son útiles, pero los responsables de la gobernanza aún necesitan una confirmación por escrito.
Los factores humanos son importantes. Si las interrupciones ocurren con demasiada frecuencia, los investigadores las ignoran; si ocurren con demasiada poca frecuencia, el riesgo escapa. Ajuste los umbrales mediante revisiones por muestreo. El estado intermedio transmitido en tiempo real debe resaltar la incertidumbre, no solo descripciones seguras, para que los revisores sepan dónde buscar.
La robustez ante ataques forma parte de la fiabilidad: los resultados de las herramientas pueden ser erráticos o engañosos (texto en la web manipulado en medios hostiles). Los nodos de validación deben purificar la información y citar sus fuentes. Nunca permita que un solo párrafo extraído autorice una acción de registro sin controles de verificación.
Al medir el éxito, equilibre la tasa de automatización con la calidad: porcentaje de casos cerrados automáticamente, tiempo promedio para su triaje, tasa de autorizaciones erróneas en auditorías por muestreo y costo en dólares por caso. Los gráficos que ahorran tiempo a los analistas pero aumentan las autorizaciones erróneas no constituyen un éxito. Mantenga un interruptor de emergencia que dirija todo a los humanos si los proveedores de sanciones degradan su funcionamiento.
Estas prácticas convierten la arquitectura de referencia, que inicialmente es un diagrama ingenioso, en un sistema operativo funcional. Los ejemplos de código anteriores sirven como estructura básica; el modelo operativo es lo que mantiene la confianza de los agentes encargados de combatir el crimen financiero.
Creación de prompts especializados sin duplicaciones
Cada agente especializado debe recibir únicamente la información relacionada con el estado del caso que necesita. Al incluir toda la investigación en cada prompt se desperdician recursos y se filtran datos personales irrelevantes en herramientas que no los requieren. Defina funciones de visualización: sanctions_view(state), kyc_view(state), y pruébelas con pruebas unitarias. Los supervisores ven resúmenes de enrutamiento; los responsables de redactar informes, conjuntos de pruebas.
Los clientes de herramientas compartidas deben encontrarse en una biblioteca que incluya mecanismos de reintentos y métricas. Los agentes no deberían implementar los tiempos de espera de HTTP de manera diferente. Centralice las credenciales de los proveedores de listas y los dispositivos de protección contra fallos para que cualquier interrupción en el sistema de sanciones se manifieste de forma consistente en todo el sistema.
Línea de datos y almacenes de características
Las características transaccionales utilizadas por los agentes de patrón deben provenir de pipelines regulados, y no de consultas SQL ad hoc dentro de una herramienta. Versione las definiciones de características. Cuando un analista dispute una puntuación, es necesario reconstruir las entradas. Los gráficos que no puedan explicar una puntuación no superarán la revisión de riesgo del modelo.
Paralelismo y consistencia
Las ramas de expansión deben fusionarse de manera determinista. Defina reductores para campos de lista y reglas del último escritor para valores escalares. Pruebe actualizaciones concurrentes. Si los medios adversos y las sanciones escriben ambos en risk_flags, utilice reductores anotados para que las banderas se unan en lugar de sobrescribirse.
Integración con flujos de trabajo humanos
Los sistemas de gestión de casos (como Jira, CRMs personalizados) deben manejar las interrupciones. Envíe los datos de las interrupciones como tareas; al completarse, llame a las APIs de reanudación con el resultado de la tarea. No cree un sitio web de aprobación único si los investigadores ya trabajan en una consola existente: intégrelo allí.
Pruebas de ataque al grafo
Simule envenenamiento de herramientas, inyección de comandos en las notas de los clientes y resolución incorrecta de entidades. Asegúrese de que el grafo se niegue a archivar los datos cuando la corroboración sea débil. Registre estas simulaciones como casos de evaluación. Los agentes encargados de los delitos financieros son de doble uso; los atacantes intentarán forzar la aprobación.
Gobernanza de costos
La etiqueta LangSmith (o equivalente) funciona con case_type, agent y model. Presupuesto por tipo de caso. Alertas para valores atípicos. Preferir reglas deterministas para casos claros de aprobación/rechazo y reservar los LLMs para tareas narrativas ambiguas. Los sistemas híbridos superan a los sistemas basados únicamente en LLMs tanto en costos como en capacidad de auditoría.
Dotación de personal y responsabilidades
Designe a un responsable de orquestación, a uno de herramientas/datos y a uno de cumplimiento. La ambigüedad en este aspecto genera diagramas complejos que nadie puede modificar sin riesgo. Programe revisiones conjuntas al agregar un nuevo agente especialista: cada nodo nuevo representa un nuevo dominio de fallos.
Con esas prácticas, el patrón multiagente de LangGraph se convierte en un sistema operativo para investigaciones, en lugar de una demostración que solo funciona con un caso específico sin complicaciones.
De piloto a adopción en el negocio
Los pilotos suelen funcionar con un número limitado de casos sintéticos. La adopción en los diferentes sectores empresariales requiere la localización de las tipologías, el soporte lingüístico para las narrativas y la integración con los sistemas de seguimiento de casos y acuerdos de nivel de servicio existentes. Planifique una implementación por fases según los segmentos: primero los productos de bajo riesgo, y más tarde aquellos de mayor riesgo. Mantenga un grupo de control con casos revisados manualmente para medir los beneficios obtenidos. Comunique que el uso de modelos asistidos no implica trabajo sin supervisión. La formación para los investigadores debe incluir cómo leer las trazas de gráficos, cómo anular decisiones automatizadas y cómo reportar datos defectuosos provenientes de las herramientas. La tecnología, sin ese componente humano, rendirá peor incluso cuando el diagrama de arquitectura sea impecable.
Espere que los proveedores y los equipos internos de datos modifiquen las API en segundo plano. Los puntos de versión fijos, los gráficos de prueba y las banderas de funcionalidad activadas por solicitud del supervisor son obligatorios. El sistema multiagente para la lucha contra los delitos financieros es un servicio en constante evolución, y no una simple conversión de un cuaderno de notas.
Lista de verificación antes del tráfico de producción
El esquema del estado fue revisado por el departamento de cumplimiento; las herramientas cuentan con autenticación y tiempos de espera establecidos; el supervisor evalúa los casos anteriores como positivos; la ruta HITL se probó de extremo a extremo; los paneles de control de LangSmith (u otros similares) están activos; se han definido los límites de recursión; existe un mecanismo de apagado documentado; se han configurado alarmas para los presupuestos de costos; se acordó el versionado de subgrafos; se probaron los reducidores de fusión paralela; se requieren citas narrativas; se publicaron las guías para situaciones de emergencia. La detección de delitos financieros con múltiples agentes se basa menos en prompts ingeniosos y más en estos componentes poco llamativos. Marque cada ítem, luego aumente gradualmente el volumen de casos, vigilando semanalmente las muestras erróneamente consideradas como positivas durante el primer trimestre.
Colaboración con investigadores como usuarios del producto
Los investigadores no son un elemento secundario en la interfaz de usuario. Únase a ellos durante las pruebas piloto. Observe dónde desconfían de los resúmenes, dónde necesitan datos brutos y dónde quieren la posibilidad de elevar el nivel con un solo clic. Codifique esas necesidades como campos de estado y cargas útiles interrumpidas. Un gráfico que se optimice únicamente para la tasa de automatización será eludido, y esos intentos de elusión eliminarán los beneficios de auditoría que usted afirmaba tener.
Diseñe junto a ellos paneles de control que muestren por qué el supervisor asignó sanciones antes del proceso KYC en un martes determinado. La transparencia fomenta la adopción, y la adopción genera los comentarios que mejoran las instrucciones y los umbrales. Sin ese ciclo, incluso una arquitectura de referencia perfecta se estanca después de la semana de lanzamiento.
Publicar un informe mensual de calidad que los analistas ayuden a evaluar. La propiedad compartida mantiene al sistema multiagente alineado con la misión: detectar delitos financieros, y no solo con métricas de demostración. Al hacerlo de manera constante, el diseño multiagente de LangGraph gana la confianza de la única forma que importa en el trabajo contra los delitos financieros: sobreviviendo al contacto con casos reales, investigadores reales y auditorías reales, y no solo por lucir elegante en un diagrama de referencia. Envíe primero los controles aburridos; permita que la ruta inteligente se establezca únicamente después de que los controles funcionen bien. Los investigadores notarán la diferencia de inmediato. Construya siempre pensando en esa revisión minuciosa. Nada menos es suficiente aquí.
Lecturas relacionadas
- Multi-Agent KAG en tablas dinámicas de Snowflake con LangGraph — Combina generación mejorada con conocimiento, tablas dinámicas y enrutamiento multi-agente mediante LangGraph para flujos de trabajo propios de almacenes.
- Catalogo LangGraph y agentes de facturas con visibilidad LangSmith — Enrutamiento multi-agente al estilo supervisor, interrupciones humanas, memoria a largo plazo y bucles de evaluación que mantienen la complejidad bajo control.
- Triaje de quejas de seguros multi-agente en Microsoft Foundry — Coordinador además de especialistas en cobertura, fraude y liquidación, con herramientas, puntos de control, App Insights y Container Apps.