Validar la salida de un LLM con un grafo de conocimiento ejecutable y dos compuertas
RelationalAI como capa de verificación: afirmaciones estructuradas del LLM, validación de esquema, un grafo de política de reembolsos y una segunda compuerta que rechaza respuestas contrarias a las reglas de negocio.
Fluido no es lo mismo que correcto
Los modelos de lenguaje escriben respuestas fluidas, pero la fluidez no garantiza que sean correctas. Supongamos que un modelo dice: «Este cliente tiene derecho a un reembolso completo». Suena bien. Pero el modelo puede haberse inventado una política, haber leído mal una fecha, haberse saltado una excepción o haber supuesto datos que faltaban. En flujos de cara al cliente eso es inaceptable, así que generar lenguaje y comprobar hechos tienen que ser tareas separadas.
Hay un precedente real. En Moffatt v. Air Canada, 2024 BCCRT 149, el chatbot de una aerolínea dijo que una tarifa por duelo podía solicitarse después del viaje, cuando la política real de la aerolínea no admitía solicitudes retroactivas. El Civil Resolution Tribunal de Columbia Británica declaró a Air Canada responsable de tergiversación negligente y le ordenó pagar daños, intereses y tasas. La lección: en cuanto un sistema de cara al cliente cita una política, la empresa puede quedar obligada por ella.
El objetivo, entonces, es conservar la flexibilidad de un LLM y a la vez tener algo que verifique los hechos antes de que la respuesta llegue al usuario. El enfoque que se describe aquí usa RelationalAI como grafo de conocimiento ejecutable que valida las afirmaciones estructuradas que produce un LLM.
Un bucle de agente con dos compuertas
El patrón procede de una charla de Frank Coyle, de UC Berkeley, en la AI Engineer World's Fair, sobre cómo combinar LLM con validación y verificación. El núcleo es un bucle de agente con una compuerta a cada lado de la ejecución de herramientas. Funciona así:
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.
En forma de diagrama:
LLM proposes an action
|
Gate 1 validates the tool input
|
Tool runs
|
Gate 2 validates the tool output
|
LLM continues or finishes
La compuerta 1 comprueba la forma. Pregunta si el modelo produjo una petición bien formada, y eso es tarea de la validación de esquema: antes de ejecutar ninguna herramienta, confirmar que están los campos obligatorios y que los valores encajan con tipos de afirmación que el sistema reconoce.
La compuerta 2 comprueba el fondo, es decir, si el resultado concuerda con los hechos y las reglas del dominio. Justo en ese punto resulta útil un grafo de conocimiento ejecutable.
Qué aporta RelationalAI
Con RelationalAI se coloca un grafo de conocimiento ejecutable sobre tus datos. Guarda hechos y, además, permite escribir reglas que producen nuevos hechos a partir de ellos. Eso es lo que separa un grafo en el que se pueden consultar cosas de uno con el que se puede razonar.
En este patrón actúa como capa de verificación. El LLM interpreta lo que quiere el usuario y emite una afirmación estructurada. RelationalAI decide si los hechos y reglas del negocio la respaldan, y la aplicación la acepta, la rechaza o la marca como no respaldada:
LLM output
|
Pydantic validates the tool-call shape
|
RelationalAI derives the authoritative value
|
Claim is marked entailed, contradicted, or unsupported
Un ejemplo concreto muestra cómo encaja todo.
Paso 1: obtener afirmaciones estructuradas del modelo
El LLM no puede responder solo con prosa libre. También tiene que generar afirmaciones estructuradas que se puedan comprobar. Por ejemplo:
{
"claim_type": "refund_method",
"subject_id": "A-91",
"value": "ORIGINAL_PAYMENT",
"evidence": "Refund policy for GOLD uses ORIGINAL_PAYMENT."
}
Así el sistema tiene algo concreto que probar. La pregunta pasa de «¿suena bien este párrafo?» a «¿es cierta esta afirmación concreta para este pedido concreto?». Esa es la compuerta 1 en acción. Un tipo de afirmación desconocido o un campo obligatorio ausente detienen la llamada a la herramienta antes siquiera de consultar el grafo.
Paso 2: codificar la política de reembolsos en el grafo
Después, RelationalAI modela la lógica de negocio de referencia. La demo usa un pequeño dominio de reembolsos con tres conceptos: Customer, Order y RefundPolicy. Las relaciones y las propiedades derivadas describen cómo se conectan:
- 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
A partir de esos hechos y reglas, el grafo deriva los valores que hay que comprobar:
- customer tier
- refund eligibility
- refund amount
- restocking fee
- refund method
- return window
- whether shipping is refundable
- whether the order was defective
No hay que confiar en que el LLM invente o recuerde estos valores; debe consultarlos al grafo. Digamos que los hechos conocidos son:
Order A-91 belongs to Customer C-184
Customer C-184 has tier GOLD
GOLD customers have a 30-day return window
RelationalAI puede derivar entonces:
Order A-91 is refund eligible
Order A-91 refund amount is 129.99
Order A-91 refund method is ORIGINAL_PAYMENT
El grafo se convierte en una fuente de verdad ejecutable. Una versión abreviada del modelo se ve así:
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 = ...
Luego vienen los valores derivados que consultará la compuerta 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)
)
Ni el derecho al reembolso ni el método de reembolso salen del LLM. Los calcula un grafo de conocimiento construido sobre reglas de negocio, que los expertos del dominio y los desarrolladores pueden revisar, versionar y gobernar.
Paso 3: validar lo que dijo el modelo
Con el grafo listo, se pueden probar las afirmaciones. Supongamos que el modelo responde: «Reembolsa el pedido A-91 como crédito en tienda, ya que el cliente es Platinum». Parece verosímil, pero el grafo puede demostrar lo contrario:
- el cliente es
GOLDy noPLATINUM - el método de reembolso es
ORIGINAL_PAYMENTy noSTORE_CREDIT - el pedido no está marcado como defectuoso
- la política no hace reembolsable el envío
El sistema rechaza la respuesta. No lo decidió un segundo LLM, sino lógica de negocio ejecutable sobre hechos verificados. El código de validación es sencillo a propósito: para cada afirmación, buscar la propiedad esperada correspondiente en RelationalAI, consultarla y comparar el resultado con el valor que propuso el modelo.
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
En producción habría que normalizar los valores con cuidado, tratar de forma explícita las afirmaciones no admitidas y registrar la evidencia detrás de cada decisión. Pero el flujo central sigue siendo el mismo: el LLM propone y RelationalAI verifica.
Por qué repartir así el trabajo
Los LLM son buenos expresándose. Entienden la intención, redactan respuestas y explican resultados en lenguaje natural. No deberían tener la última palabra sobre políticas, precios, elegibilidad, cumplimiento normativo u otros hechos operativos. La secuencia más adecuada:
- Deja que el LLM interprete la petición.
- Haz que emita afirmaciones estructuradas.
- Valida el objeto generado con Pydantic.
- Deriva la respuesta de referencia en RelationalAI.
- Devuelve solo las afirmaciones que respalda el grafo de conocimiento.
El LLM se encarga del lenguaje y la interacción, y RelationalAI de la verificación.
El bucle en código
A grandes rasgos, el sistema se ve así:
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()))
El bucle en sí es rutinario. Lo que cuenta es quién se encarga de qué:
- el modelo sugiere una afirmación o una consulta
- la primera compuerta inspecciona la forma de la sugerencia
- RelationalAI determina qué hechos se cumplen
- la segunda compuerta descarta todo lo que se contradice o no está respaldado
- solo las afirmaciones que sobreviven llegan a la respuesta
Más allá de los reembolsos
El caso de los reembolsos es pequeño a propósito, pero la misma estructura sirve para cláusulas contractuales, normas regulatorias, lógica de descuentos y precios, límites de la cadena de suministro, quién puede optar a qué producto y a qué tiene derecho cada cliente. Cualquier flujo en el que un LLM hable en nombre de una empresa puede usar una capa de verificación, y cuanto más caro sea el error, más importa separar el lenguaje generado de la verdad ejecutable.
Referencias:
- https://www.youtube.com/watch?v=Sir59K8ZDPU (la charla de la conferencia)
- https://www.canlii.org/en/bc/bccrt/doc/2024/2024bccrt149/2024bccrt149.html (Moffatt v. Air Canada)
- https://docs.relational.ai/ (documentación de RelationalAI)