🤝 Integration Guide

Arbiter + LangChain

LangChain agents execute multi-step reasoning chains, invoke tools, and call functions at every step. When a tool fails mid-chain, a ReAct loop produces hallucinated output, or a RAG pipeline returns stale embeddings — you need a resolution path that does not require human intervention. Arbiter is that path: deterministic dispute resolution for LangChain pipelines, wired in with three API calls.

Why Arbiter + LangChain

LangChain handles chain composition, tool calling, and agentic loops. Arbiter handles what happens when execution breaks down. Together they close the loop on autonomous commerce — agents that invoke tools, run chains, and query vector stores know their failures are covered by deterministic resolution.

🔍
Fault Detection for LangChain Agents

Submit your chain's tool call sequence and Arbiter traces backward from failure to assign fault scores across the chain.

Sub-second Resolution

The fault engine resolves most disputes in under a second. No queue — resolution arrives with submission.

📋
Full Audit Trail

Every decision includes step-by-step reasoning, fault scores with confidence %, and an immutable record.

⚖️
Deterministic

Same chain + same SLA policies = same outcome. No opinion, no bias. Reproducible for compliance.

🔗
Multi-hop Chain Support

LangChain chains span multiple hops: retrieval → tool → output parsing. Arbiter handles chains of any depth.

🛡️
SLA-backed

Register each agent and tool with its SLA policy. Arbiter scores against declared expectations, not assumptions.

Quick Start

Three steps to connect a LangChain chain to Arbiter dispute resolution.

1
Get your API key

Create an account at arbiter-2.polsia.app/docs and generate an API key. Production keys use the arb_live_ prefix. Test keys use arb_test_ for safe integration testing.

bash
# Set as environment variable
export ARBITER_API_KEY=arb_live_your_key_here
2
Register your LangChain agents

Register each agent in your LangChain pipeline once at startup. Arbiter deduplicates by external_agent_id — safe to call on every boot. Include the tools field listing every tool the agent is authorized to call.

curl
curl -X POST https://arbiter-2.polsia.app/api/agents   -H "Authorization: Bearer $ARBITER_API_KEY"   -H "Content-Type: application/json"   -d '{"external_agent_id":"langchain-react-agent-001","name":"ReAct Research Agent","platform":"langchain","sla_policy":{"refund_window_hours":24,"max_retry_attempts":3},"tools":["search","retrieve","calculate"]}'
3
Submit a dispute when a chain fails

When a LangChain chain fails — a tool returns bad output, a chain produces hallucinated content, a retrieval step times out — submit the full chain sequence. Include every tool call, intermediate step, and failure context.

curl
curl -X POST https://arbiter-2.polsia.app/api/disputes   -H "Authorization: Bearer $ARBITER_API_KEY"   -H "Content-Type: application/json"   -d '{"description":"ReAct agent hallucinated stock price after retrieval tool returned empty result","chain_data":[{"agent_id":"langchain-react-agent-001","action":"tool_call","tool":"retrieve","timestamp":"2026-04-28T10:00:00Z","outcome":"failed","error":"no_results_found"},{"agent_id":"langchain-react-agent-001","action":"tool_call","tool":"calculate","timestamp":"2026-04-28T10:00:05Z","outcome":"failed","error":"invalid_input_format","amount":3.00}]}'

# Then poll for resolution (arrives in <1s typically):
curl https://arbiter-2.polsia.app/api/disputes/1/resolution   -H "Authorization: Bearer $ARBITER_API_KEY"

Python Example

Full integration using the requests library. Wire this into your LangChain agent callbacks or LCEL .with_fallbacks() chains.

No Python SDK required — Arbiter's REST API works with any HTTP client. pip install requests is all you need.

python
import os, time, requests
from typing import Optional

ARBITER_BASE = "https://arbiter-2.polsia.app"
HEADERS = {
    "Authorization": "Bearer " + os.environ["ARBITER_API_KEY"],
    "Content-Type": "application/json",
}

def register_langchain_agent(agent_id: str, name: str, tools: list, sla: dict) -> Optional[int]:
    """Register a LangChain agent. 409 = already registered, safe to ignore."""
    r = requests.post(ARBITER_BASE + "/api/agents", headers=HEADERS, json={
        "external_agent_id": agent_id, "name": name,
        "platform": "langchain", "tools": tools,
        "sla_policy": sla,
    })
    if r.status_code not in (200, 201, 409):
        r.raise_for_status()
    return r.json().get("id")

def submit_dispute(description: str, chain: list) -> dict:
    r = requests.post(ARBITER_BASE + "/api/disputes", headers=HEADERS,
        json={"description": description, "chain_data": chain})
    r.raise_for_status()
    return r.json()

def await_resolution(dispute_id: int, timeout: int = 10) -> Optional[dict]:
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(
            ARBITER_BASE + "/api/disputes/" + str(dispute_id) + "/resolution",
            headers=HEADERS)
        if r.status_code == 200:
            return r.json()
        if r.status_code != 404:
            r.raise_for_status()
        time.sleep(0.5)
    return None


# ── Wire into LangChain agent callbacks / LCEL with_fallbacks ──────

# 1. Register at startup (idempotent)
register_langchain_agent(
    "langchain-react-agent-001", "ReAct Research Agent",
    tools=["search", "retrieve", "calculate"],
    sla={"refund_window_hours": 24, "max_retry_attempts": 3})

# 2. On chain/tool failure, submit the full chain sequence
# Example: ReAct agent called retrieve -> got empty result -> hallucinated output
dispute = submit_dispute(
    description="ReAct agent hallucinated stock price after retrieval returned no results",
    chain=[
        {"agent_id": "langchain-react-agent-001", "action": "tool_call",
         "tool": "retrieve", "timestamp": "2026-04-28T10:00:00Z",
         "outcome": "failed", "error": "no_results_found"},
        {"agent_id": "langchain-react-agent-001", "action": "tool_call",
         "tool": "calculate", "timestamp": "2026-04-28T10:00:05Z",
         "outcome": "failed", "error": "invalid_input_format", "amount": 3.00},
    ])

# 3. Await resolution (typically <1s)
resolution = await_resolution(dispute["dispute_id"])
if resolution:
    r0 = resolution["resolutions"][0]
    print("Action:", r0["action"])       # e.g. "partial_credit"
    print("Reasoning:", r0["reasoning"])
else:
    print("Timed out — dispute queued for manual review")

TypeScript Example

Full integration using the Arbiter TypeScript SDK with LangChain.js. Typed request/response objects, no manual HTTP wiring required.

SDK is in open beta. Install: npm install arbiter-client

bash
npm install arbiter-client
typescript
import { ArbiterClient } from 'arbiter-client';

const arbiter = new ArbiterClient({
  apiKey: process.env.ARBITER_API_KEY!,
  baseUrl: 'https://arbiter-2.polsia.app',
});

// Register agents once at startup (idempotent)
async function ensureAgentsRegistered() {
  const agents = [
    { external_agent_id: 'langchain-react-agent-001', name: 'ReAct Research Agent',
      platform: 'langchain', tools: ['search', 'retrieve', 'calculate'],
      sla_policy: { refund_window_hours: 24, max_retry_attempts: 3 } },
    { external_agent_id: 'langchain-rag-pipeline-002', name: 'RAG Pipeline Agent',
      platform: 'langchain', tools: ['vector_search', 'llm_generate'],
      sla_policy: { quality_threshold: 0.9, max_latency_ms: 5000 } },
  ];
  for (const agent of agents) {
    try { await arbiter.registerAgent(agent); }
    catch (err: any) { if (err?.status !== 409) throw err; }
  }
}

// Submit dispute from a LangChain.js Chain callback or event hook
async function handleChainFailure(description: string, chain: any[]) {
  const dispute = await arbiter.submitDispute(chain, { description });

  let resolution = null;
  for (let i = 0; i < 20; i++) {
    try {
      resolution = await arbiter.getResolution(dispute.dispute_id);
      break;
    } catch (err: any) {
      if (err?.status !== 404) throw err;
      await new Promise(r => setTimeout(r, 500));
    }
  }
  if (!resolution) {
    console.warn('Resolution timed out — dispute queued for manual review');
    return null;
  }

  const { action, reasoning, fault_agent_id } = resolution.resolutions[0];
  console.log('Resolution:', action, '| Fault:', fault_agent_id);
  console.log('Reasoning:', reasoning);
  return resolution;
}

// Handle TimeoutError from a LangChain.js Chain.run() with fallback
async function runChainWithArbiter(chain: any, input: any) {
  try {
    return await chain.invoke(input);
  } catch (err: any) {
    if (err.name === 'TimeoutError') {
      console.log('Chain timed out — submitting to Arbiter');
      await handleChainFailure('Chain timed out mid-execution', [
        { agent_id: 'langchain-react-agent-001', action: 'chain_invoked',
          timestamp: '2026-04-28T10:00:00Z', outcome: 'failed',
          error: 'TimeoutError' },
      ]);
    }
    throw err;
  }
}

// Run
await ensureAgentsRegistered();

Fault Types Reference

Arbiter classifies every dispute into one of five fault categories. Understanding them helps you write better SLA policies and interpret resolution outcomes. Full definitions at /fault-taxonomy.

Fault TypeSeverityCommon in LangChainResolution
Unauthorized Action
Tool call outside defined scope
CRITICAL Tool call to unauthorized function; calling a tool not in the agent's declared tool list; RAG retrieval outside permitted corpus Full refund + agent flagged
Incorrect Execution
Wrong output within scope
HIGH Wrong tool output interpretation; chain produced hallucinated content; LCEL chain step yielded invalid format; RAG returned irrelevant docs Proportional credit
Partial Delivery
Some but not all work completed
HIGH ReAct loop terminated early; token limit hit mid-chain; LCEL chain threw mid-sequence; output truncated by max_tokens Proportional credit + grace period
Misrepresentation
SLA claims didn't match reality
MEDIUM Agent claimed tool capability unavailable at runtime; RAG retrieval confidence mismatch vs. declared accuracy; latency SLA exceeded Restitution + SLA update
Third-Party Failure
External or upstream failure
LOW (no-fault) External vector store timeout; upstream API outage affecting tool calls; network partition between chain steps Full refund, upstream liable

You don't pre-classify the fault type — Arbiter's engine determines it from the chain. See /fault-taxonomy for detection mechanisms, scoring rubrics, and resolution paths per category.

Next Steps

Grab your API key from the API docs, register your agents, and start submitting disputes. The full REST reference covers every endpoint, field, and error code.

Want to see how a specific LangChain failure maps to fault taxonomy? Submit a test dispute on the dashboard and inspect the resolution reasoning — it shows exactly how Arbiter scored the chain.