Skip to content

Repository files navigation

BERT Cross-Encoder Entailment Agent

TestsLicense: TriModel: DeBERTa-v3Backend: TensorRTRustAudit: BLAKE3+EREWORMLean 4

Authors: Ahmad Ali Parr, Jessica L. Williams (SNAPKITTYWEST)
Stack: DeBERTa-v3 · ONNX · TensorRT FP16 · Rust/Tokio · BLAKE3 · WORM ledger · ERE P1-P5

A production-grade entailment verification agent. Pass a retrieved source chunk and an LLM-generated claim; get back a mathematically bounded entailment score, a verdict, and a BLAKE3 cryptographic attestation sealed into an append-only WORM audit chain — then passed through the ERE five-gate protocol before it leaves the system.


What This Is

LLMs hallucinate. RAG systems retrieve chunks and generate claims against them. Without a verification layer, a model can produce a plausible-sounding claim that contradicts its own source — and no downstream system will catch it.

This agent is the verification layer. It does one thing:

Given a retrieved source and a generated claim, determine with cryptographic certainty whether the claim is entailed by the source.

It is not a chatbot. It is not a general-purpose NLI system. It is a production daemon that runs at the end of every RAG pipeline and refuses to propagate a claim until it can prove the claim is entailed.


How This Compares to Google BERT

PropertyGoogle BERT (2018)This Agent
ArchitectureBi-directional encoderCross-encoder (premise ++ hypothesis)
NLI taskFine-tuned on MNLI onlyANLI + TrueTeacher + MNLI (3-source)
Hallucination detectionNot designed for itPrimary objective
Negation detectionWeak (symmetric embeddings)Strong (joint self-attention)
Date/number flip detectionFailsCatches (e.g. 1962 → 1926)
RuntimePython / TF / PyTorchRust daemon, TensorRT FP16, GPU
Latency~100-300 ms (Python)<5 ms batched (TRT)
ThroughputSingle requestDual-trigger continuous batching
Audit trailNoneBLAKE3 + WORM chain per inference
Security gatesNoneERE P1-P5 (5-gate sovereign protocol)
Formal invariantsNoneLean 4, zero sorry
LicenseApache 2.0Tri-license (AGPL / BSL 1.1 / MIT)

Key difference: BERT embeds premise and hypothesis separately and compares them with cosine similarity. A cross-encoder concatenates them and runs joint self-attention. That joint attention is what lets this agent catch subtle hallucinations — the model can directly compare "born in 1962" against "born in 1926" at the token level. BERT cannot do this. It sees two vectors, not two sentences in dialogue.


Why Cross-Encoder, Not Bi-Encoder

A Bi-Encoder embeds premise and hypothesis separately. At inference, you compare embeddings with cosine similarity. This works for semantic similarity, but it misses:

  • Flipped dates: "born in 1962" vs "born in 1926" — both embed nearly identically
  • Switched subjects: "X defeated Y" vs "Y defeated X" — same semantic field
  • Negation: "the vote passed" vs "the vote did not pass"

A Cross-Encoder concatenates both and runs them through a single forward pass:

[CLS] retrieved_chunk [SEP] generated_claim [SEP]

Self-attention directly compares entities across the premise-hypothesis boundary at every layer. The model learns to detect contradiction, not just similarity. This is the architecture that makes hallucination detection tractable.


Architecture

 Training Pipeline (Python)
│
DeBERTa-v3-base + 3-label head
Weighted CrossEntropyLoss
(Contradiction=2.0, Neutral=1.5, Entailment=1.0)
ANLI + TrueTeacher + MNLI
│
▼
ONNX export (dynamic axes)
│
ORT graph optimization + FP16
│
▼
TensorRT engine (.plan cache)
│
Rust Inference Daemon
┌────────────┴───────────────┐
│ Dual-trigger batching │
│ MAX_BATCH or 5 ms timer │
│ Dynamic padding/ndarray │
│ TRT forward pass (GPU) │
│ Softmax → score │
│ BLAKE3 attestation seal │
│ WORM ledger append │
└────────────────────────────┘
│
HTTP POST /verify
{ score, verdict, hash }
│
┌───────▼────────┐
│ ERE P1-P5 │ ← agent/ere_gate.py
│ Five gates │
│ P5 seal added │
└───────┬────────┘
│
Gated response
{ score, verdict, hash,
ere_seal, ere_gates }
OR { ere_halt: true }

Milestones

#MilestoneStatus
M1DeBERTa-v3 cross-encoder + weighted 3-label loss✅ Done
M2ANLI + TrueTeacher + MNLI joint training dataset✅ Done
M3ONNX export + ORT FP16 graph optimization✅ Done
M4TensorRT engine with .plan caching✅ Done
M5Rust inference daemon (Tokio, Axum, dual-trigger batching)✅ Done
M6BLAKE3 attestation seal per inference✅ Done
M7WORM append-only audit chain (tamper-evident)✅ Done
M8FPR=0.0 PR-curve threshold calibration✅ Done
M911/11 tests passing (dataset, calibrate, ledger)✅ Done
M10Lean 4 formal invariants (zero sorry)✅ Done
M11ERE P1-P5 gate integration (agent/ere_gate.py)✅ Done
M12Tri-license (AGPL / BSL 1.1 / MIT)✅ Done
M13Sovereign Engine v2 gap integration (Gap 4 candidate)🔜 Planned
M14Rust daemon ERE gate enforcement (inline, pre-response)🔜 Planned
M15Benchmark vs NLI baselines (BERT, RoBERTa, DeBERTa-v2)🔜 Planned

ERE Gate Protocol

Every verdict produced by this agent passes through the ERE (Expected Reasoning Error) five-gate protocol before leaving the system:

GateCheckFailure means
P1No secrets in payloadCredential leaked in model output
P2No eval / code injectionAdversarial input tried to inject code
P3Loop safetyOutput contains infinite loop without exit
P4No telemetry beaconsAnalytics SDK call in model output
P5SHA-256 audit sealCommitment over agent_id:intent:verdict

A verdict that fails any gate is suppressed. The caller receives { ere_halt: true }. The WORM ledger records the halt. The chain is not broken.

fromagent.ere_gateimportgate_verdictraw= {"score": 0.98, "verdict": "Entailment", "hash": "a3f8..."}
gated=gate_verdict(
premise="The Battle of Hastings took place in 1066.",
hypothesis="Hastings occurred in 1066.",
raw_verdict=raw,
)
ifnotgated.allowed:
raiseRuntimeError(f"ERE halt: {gated.violations}")
print(gated.to_dict())
# { score, verdict, hash, ere_seal, ere_gates: {P1:T, P2:T, P3:T, P4:T, P5:T} }

Full Pipeline

1. Install dependencies

pip install -r requirements.txt

2. Download datasets

data/
anli/R1/{train,dev,test}.jsonl
anli/R2/{train,dev,test}.jsonl
anli/R3/{train,dev,test}.jsonl
trueteacher/{train,dev}.jsonl # Google, 1.4M records
mnli/{train,dev}.jsonl

3. Fine-tune DeBERTa-v3

python -m bert.train \
--data_dir data/ \
--output_dir checkpoints/ \
--backbone microsoft/deberta-v3-base \
--epochs 5 \
--batch_size 32 \
--lr 2e-5

4. Export to ONNX + optimize FP16

python -m bert.export \
--checkpoint checkpoints/best_model.pt \
--output_dir onnx/ \
--device cuda

5. Calibrate rejection threshold

python -m bert.calibrate \
--checkpoint checkpoints/best_model.pt \
--data_dir data/ \
--output config/threshold.json

6. Build and run the Rust daemon

cd daemon
cargo build --release
RUST_LOG=info ./target/release/bert-daemon --config ../config/daemon.json

First startup: ~5 min for TensorRT engine compilation. Subsequent starts: instant from .plan cache.

7. Verify a claim

curl -X POST http://localhost:8080/verify \
-H "Content-Type: application/json" \
-d '{ "premise": "The Battle of Hastings took place in 1066.", "hypothesis": "Hastings occurred in 1066.", "chunk_id": "chunk-001" }'

Response:

{
"score": 0.9812,
"verdict": "Entailment",
"hash": "a3f8d2c1...",
"ere_seal": "7f3c8a19...",
"ere_gates": { "P1": true, "P2": true, "P3": true, "P4": true, "P5": true }
}

The hash is the BLAKE3 attestation over the inference. The ere_seal is the P5 SHA-256 commitment over agent_id:intent:verdict. Both are recorded in the WORM ledger.


File Structure

bert-agent/
├── agent/
│ ├── __init__.py # Exports BERTEREGate, GatedVerdict, gate_verdict
│ └── ere_gate.py # ERE P1-P5 gate adapter for BERT verdicts
├── bert/
│ ├── dataset.py # ANLI + TrueTeacher + MNLI cross-encoder dataset
│ ├── model.py # DeBERTa-v3 cross-encoder + weighted loss
│ ├── train.py # Fine-tuning loop (AdamW + cosine LR)
│ ├── export.py # ONNX export + ORT FP16 graph optimization
│ ├── trt_session.py # TensorRT ORT session with optimization profiles
│ └── calibrate.py # PR curve threshold calibration
├── daemon/
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs # Startup, channel wiring
│ ├── types.rs # VerifyRequest, Attestation, Config
│ ├── session.rs # TRT ORT session init
│ ├── inference.rs # Dual-trigger continuous batching loop
│ ├── ledger.rs # WORM append-only audit chain
│ └── server.rs # Axum HTTP /verify handler
├── config/
│ └── daemon.json
├── tests/
│ ├── test_dataset.py
│ ├── test_calibrate.py
│ └── test_ledger.py
├── Invariants.lean # Lean 4 formal invariants, zero sorry
├── LICENSE # Tri-license: AGPL-3.0 | BSL 1.1 | MIT
└── requirements.txt

Design Decisions

DecisionWhy
DeBERTa-v3 over BERT/RoBERTaDisentangled attention handles positional reasoning — critical for detecting reordered events
Cross-Encoder over Bi-EncoderCannot cache embeddings, but self-attention compares entities across premise-hypothesis directly
Weighted loss (2.0/1.5/1.0)False-positive Entailment is the worst failure mode — weight Contradiction higher
ANLI + TrueTeacherStandard NLI is too easy; TrueTeacher mirrors actual LLM hallucination patterns
FPR=0.0 threshold calibrationIn a verification engine, precision > recall — never cite a hallucinated claim
Dual-trigger batching (batch size OR 5ms)Bounded latency guarantee without sacrificing GPU throughput
Dynamic padding per batchPad to longest sequence in the batch, not global max — avoids wasted compute
BLAKE3 + bincode attestationMemory-bandwidth hashing speed; deterministic binary serialization (no JSON ordering ambiguity)
WORM ledger as chainEvery record links to previous hash — tamper detection is immediate
ERE P1-P5 gate layerEvery verdict inspected for secrets, injection, loops, telemetry before propagation
Lean 4 invariantsFormal proof that well-formed agents satisfy trust and entropy bounds — not just assertions

Theoretical Foundation

This agent is a component of the Sovereign Stack. Its cryptographic and formal foundations are documented in the following published papers:

DOIContribution
10.5281/zenodo.21443609Jordan Spectral Transformer — phi-weighted routing
10.5281/zenodo.21132094Sovereign Compute Architecture
10.5281/zenodo.20678420Attention Exhaustion Attacks — 0% detection rate
10.5281/zenodo.21268911GKN I4 Quartic Invariant and E7 Symmetry

Unified paper: The Sovereign Stack


License

Tri-license — choose any one:

  • AGPL-3.0 for open source / community use
  • BSL 1.1 → MIT for commercial / production use (< 5 servers free; converts to MIT 2029-01-01)
  • MIT after 2029-01-01

See LICENSE for the full text and list of six protected inventions.

Copyright (C) 2026 Ahmad Ali Parr, Jessica L. Williams / SNAPKITTYWEST
Bel Esprit D'Accord Irrevocable Trust


Built to catch what BERT cannot see.
Every claim sealed. Every halt recorded. Nothing propagates without proof.