TAOS
← White Papers
AI Engineering

LangGraph Is Great. But Who Governs the Agent?

May 1, 2026Taos Team
LangGraphGovernanceArchitecture

LangGraph Is Great. But Who Governs the Agent?

Category: AI Engineering | Reading time: 7 min


The Missing Layer

LangGraph is an excellent framework for building stateful, multi-step AI agents. Its graph-based execution model, checkpointing, and support for human-in-the-loop patterns have made it a popular choice for production AI applications. If you're building an AI agent today, LangGraph is a reasonable choice.

But there's a question LangGraph doesn't answer: who governs what the agent is allowed to do?

LangGraph gives you the execution model. It doesn't give you policy enforcement, approval routing, audit trails, or compensation. These aren't criticisms — they're architectural observations. LangGraph is an agent framework. Governance is a different layer.

This post compares a LangGraph payment agent with and without the Taos governance kernel, using a real working example.


The Ungoverned LangGraph Agent

Here's a minimal LangGraph payment agent. It works — it processes invoices, calls tools, and produces results:

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent

@tool
async def process_payment(invoice_id: str, amount: float, vendor: str) -> dict:
    """Process a vendor payment."""
    # Direct call to payment system
    result = await payment_system.submit(invoice_id, amount, vendor)
    return result

llm = ChatOpenAI(model="gpt-4o-mini")
agent = create_react_agent(llm, tools=[process_payment])

# Run it
result = await agent.ainvoke({"messages": [("user", f"Pay invoice {invoice_id}")]})

This agent will process any invoice you give it. $500? Processed. $500,000? Also processed. Vendor on the OFAC sanctions list? The agent will look at the vendor name, note that it looks unusual, perhaps add a comment in its response — and process it anyway, because nothing stopped it.

The agent makes no governance decisions. More accurately: the agent makes governance decisions implicitly, based on the LLM's training and whatever you put in the system prompt. These are not reliable controls.


What's Missing: The Governance Gap

Capability LangGraph (alone) Required for Production
Spending tier enforcement ❌ Prompt-based ✅ Policy-enforced
OFAC/sanctions check ❌ LLM reasoning ✅ Deterministic rule
Approval routing ❌ Manual workflow ✅ Role-based auto-routing
SOX audit trail ❌ Application logs ✅ Tamper-evident hash chain
Saga compensation ❌ Not provided ✅ LIFO rollback
Policy change w/o restart ❌ Code deployment ✅ Live policy reload

None of these are exotic requirements. They're the baseline for any AI agent handling financial transactions in a regulated environment.


The Governed LangGraph Agent

Adding the Taos governance kernel to the same LangGraph agent:

from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from agent.shared.taos_client import TaosKernelClient, PolicyDeniedError, ApprovalPendingError

@tool
async def run_payment(invoice_id: str, method: str = "ach") -> dict:
    """Submit invoice for governed payment processing via Taos kernel."""
    taos = TaosKernelClient(
        submitter="aclerk",
        submitter_role="ap_clerk",
        mock_approvals={"manager": "approved"},  # production: real approver
    )

    # Step 1: Fetch invoice and vendor data
    invoice = await db.fetch_invoice(invoice_id)
    vendor = await db.fetch_vendor(invoice.vendor_id)

    # Step 2: Policy evaluation — Rego, not Python
    try:
        decision = await taos.check_policy(
            amount=invoice.amount,
            vendor_status=vendor.status,
            is_ofac_cleared=vendor.is_ofac_cleared,
            invoice_id=invoice_id,
            vendor_name=vendor.name,
        )
    except PolicyDeniedError as e:
        return {"blocked": True, "reason": e.reason, "rule": e.rule_fired}

    # Step 3: Approval routing (if required)
    if decision.required_role:
        try:
            approval_id = await taos.request_approval(
                approver_role=decision.required_role,
                invoice_id=invoice_id,
                amount=invoice.amount,
                vendor_name=vendor.name,
            )
        except ApprovalPendingError as e:
            return {"approval_required": True, "approver_role": e.approver_role}

    # Step 4: Submit payment (with saga compensation registered)
    payment = await db.create_payment(invoice_id, invoice.amount, method)
    taos.register_compensation("submitPayment", lambda: db.void_payment(payment.id))

    # Step 5: OBO chain for SOX audit
    obo = taos.build_obo_chain()
    await db.record_obo_chain(payment.id, obo)

    return {"payment_id": payment.id, "status": "completed", "obo_chain": obo.model_dump()}

llm = ChatOpenAI(model="gpt-4o-mini")
agent = create_react_agent(llm, tools=[run_payment], prompt=SYSTEM_PROMPT)

Same LangGraph framework. Same OpenAI model. Completely different governance posture.


What Changed

Policy evaluation is deterministic. The check_policy() call runs the actual policy.rego file through the Regorus engine. The LLM has no involvement in the governance decision. A blocked vendor is denied deterministically, not probabilistically.

Approval routing is automatic. The policy engine determines the required approver role. The kernel routes the request. The LLM doesn't decide whether a $30,000 payment needs manager approval — the policy does.

The audit trail is complete. Every policy evaluation, approval decision, and workflow outcome is written to the audit log with the OBO chain. The LLM's natural language response is narrative — the audit log is the system of record.

Policy changes don't require code changes. Change the approval threshold in the Taos control plane, and the next policy evaluation picks it up. The LangGraph code doesn't change.


The Architecture Insight

The governed LangGraph pattern embodies an important architectural principle: separate the agent's cognitive capabilities from its governance boundaries.

The LLM is good at:

  • Understanding invoice context from natural language
  • Deciding which tool to call and when
  • Generating human-readable summaries of outcomes

The governance kernel is good at:

  • Deterministic policy evaluation
  • Role-based approval routing
  • Tamper-evident audit logging
  • Compensating transaction rollback

Don't ask the LLM to do the kernel's job, and don't ask the kernel to do the LLM's job. Each component does what it's designed for.


Seeing It in Production

The full working implementation — LangGraph + OpenAI + Taos governance kernel — is available on GitHub in the payment-governed-langgraph repository. It includes:

  • The complete governed payment agent
  • A real policy.rego file evaluated by regopy (Regorus engine)
  • Docker Compose setup with PostgreSQL, FastAPI, and React UI
  • Live policy reload from the Taos control plane
  • Six policy scenarios: OFAC deny, auto-approve, manager/VP/CFO routing, new vendor gate

Run it locally in five minutes. Change a policy in the UI. See the agent enforce the new rule without restarting.


The Bottom Line

LangGraph is a great choice for building AI agents. It's not a governance framework — and it's not trying to be. The Taos governance kernel fills that gap: deterministic policy enforcement, approval routing, audit trails, and compensation, wrapped around any LangGraph agent.

Build the agent with LangGraph. Govern it with Taos.


Tags: LangGraph, AI governance, policy-as-code, governed AI agent, OpenAI, payment agent, enterprise AI