Skip to content

M-HuangX/audit-fence

Repository files navigation

audit-fence

Trace every claim to its source. Identify every hallucination. Before the report reaches your client.

Every AI agent system hallucinates — regardless of model, framework, or prompt engineering. audit-fence provides fully automated, post-hoc claim-to-source verification for any multi-agent pipeline — from the final report, through every intermediate step, back to the raw data.

Python Model Agnostic MIT License


The Problem

More and more enterprises and organizations are integrating AI orchestration pipelines into their workflows to produce reports — some client-facing, others used for internal analysis and decision-making. But one question remains inescapable:

"Can you prove each claim in this report is real — and not a hallucination?"

Regardless of the model provider, framework, or prompt engineering, AI-generated reports can contain hallucinations — especially when orchestration pipelines must synthesize large volumes of information and context windows are heavily packed.

When these reports reach clients or inform internal decisions, undetected hallucinations can lead to devastating consequences.

One proposed remedy is to require the AI to attach source citations alongside each claim as it writes the report. But this amounts to little more than a placebo. Research on transformer internals shows that LLMs select citations through shallow pattern matching — entity co-occurrence, surface similarity — not by verifying that the cited passage actually supports the claim.

And this is exactly the problem audit-fence tackles.


The Solution

audit-fence — automated claim-to-source verification for AI agent pipelines

audit-fence is a post-hoc audit system for AI agent pipelines. It can be integrated into your existing orchestration with minimal friction — 4 lines of code. While your pipeline runs normally, audit-fence silently captures every node's input, output, and tool calls as local snapshots, and resolves the runtime topology along the way.

After execution completes, you can launch an audit at any time: audit-fence verifies every factual claim in the final report against the captured trace data, and builds a complete evidence chain back to the raw sources.

Every claim in the final report links to an evidence chain that passes through each intermediate node in your pipeline — from synthesis, through specialist sub-reports, all the way to the raw data source. When a hallucinated claim is found, you see exactly which node first introduced the fabrication. When a claim checks out, you have a verifiable citation trail you can trust.

audit-fence has been systematically evaluated on real-world financial documents with deterministic ground truth — achieving 99.6% hallucination catch rate and 98.5% evidence accuracy across 12 S&P 500 companies.


Tracing Claims Across Your Entire Pipeline

Real production systems are not single-agent. A financial analysis pipeline might have four specialist agents — each querying different data sources — feeding into a synthesis agent that writes the final report. Claims propagate across agent boundaries, and so must the evidence trail.

audit-fence decomposes any multi-agent pipeline into audit units. Each unit verifies one node's output against its upstream sources. Units compose automatically based on your pipeline's topology — and evidence chains link across unit boundaries, so any claim in the final report traces all the way back to the raw data.

In Practice

Cascade audit decomposes a multi-agent pipeline into audit units — each unit verifies one agent's output against its upstream sources

The diagram above shows Firn, a production financial analysis system. Four specialist agents each query their own data sources (SEC filings, price history, analyst estimates, macroeconomic indicators), then a core agent synthesizes all four sub-reports into the final output.

How cascade audit maps onto this pipeline:

1. Capture. snap.config() records every node's input/output and tool calls as grep-searchable trace files during normal execution. No code changes to your agents.

2. Decompose. audit_cascade() reads the captured topology and creates one audit unit per pipeline edge. For fan-in — where four specialists feed into one core agent — it creates a single merged unit: one audit with access to all four upstream outputs at once, not four separate audits of the same report.

3. Audit. Each unit reads its document claim by claim, searches the upstream trace files for evidence, and records findings. Fabricated evidence is programmatically rejected.

4. Link. After all units complete, trace_claim() walks any claim in the final report back through the cascade — from report to specialist sub-report to raw data source — in a single call. Linking is deterministic substring matching; no LLM needed.

Any Pipeline Architecture

Supported topologies — linear, fan-out, fan-in, hub-and-spoke, nested subgraph

audit-fence works with any pipeline topology — linear chains, parallel fan-out, fan-in synthesis, hub-and-spoke orchestration, nested subgraphs. Topology is resolved automatically from your pipeline's runtime execution; evidence tracing works across all of them.

How Each Claim Is Verified

Each audit unit follows the same enforcement pattern — an automated process reads the document under review, then verifies each claim against the unit's data sources:

Runtime enforcement — how audit-fence verifies evidence inside each audit unit

Without enforcement:
  "I found X in the data"  →  Record  →  accepted (unverified)

With audit-fence (happy path):
  search(query)              →  Result saved to tracked history
  submit(                    →  Validation Gate
    claim,                        search history exists?
    claim_in_document,            evidence long enough?
    evidence,                     evidence in search history?
    finding, ...                  claim in document?
  )                          →  Accepted

With audit-fence (hallucination caught):
  submit(                    →  Validation Gate
    claim,                        no search history!
    claim_in_document,            text not in document!
    evidence="revenue was...",    fabricated — not from any search!
  )                          →  REJECTED (must retry)

Search — the audit process searches the unit's data sources (upstream trace files, API outputs, raw documents) claim by claim using ripgrep. Results are automatically tracked for enforcement.

Evidence submission — before each submission executes, the fence validates:

Check What it validates On failure
Search history Recent search history is not empty — a search must precede every submission Rejected: "No search calls recorded"
Evidence length Evidence meets minimum length (min_evidence_length, default 20) Rejected: "Evidence too short"
Evidence match Submitted evidence is a verbatim substring of a recent search result — this is the core check that ties each submission to a specific search output Rejected: "Evidence does not match any recent search result"
Claim in document The verbatim text being audited must exist in the document provided via set_document() Rejected: "Claim text not found in the source document"

If any check fails, the submission is blocked and must be retried. Every rejection is logged for audit review.

Why this works

Requiring a search before each evidence submission exploits a known property of transformer attention. When an LLM's context window is packed with report text, source data, and reasoning traces, information in the middle is most prone to hallucination — the "lost in the middle" effect. By requiring a search() call before every submit(), audit-fence forces the relevant evidence to the tail of the context window — where attention is strongest and hallucination is least likely.

The enforcement doesn't just catch fabrication after the fact; it structurally reduces the conditions under which fabrication occurs.


Quick Start

Install

pip install audit-fence langgraph langchain-openai

Your existing pipeline

Suppose you have a LangGraph application — two agents that research a topic and write a report:

from langgraph.graph import StateGraph, MessagesState
from langchain_openai import ChatOpenAI

def research(state: MessagesState):
    # ... query data sources, produce findings ...
    return {"messages": [AIMessage(content=findings)]}

def write_report(state: MessagesState):
    # ... synthesize findings into final report ...
    return {"messages": [AIMessage(content=report)]}

graph = StateGraph(MessagesState)
graph.add_node("research", research)
graph.add_node("write", write_report)
graph.add_edge("research", "write")
app = graph.compile()

result = await app.ainvoke({"messages": [HumanMessage(content="Analyze AAPL")]})

# Save the final report (however you normally persist output)
open("report.md", "w").write(result["messages"][-1].content)

Make it auditable: add 4 lines

from audit_fence import Snapshot                     # ← add import

snap = Snapshot("trace/")                            # 1. create snapshot
result = await app.ainvoke(
    {"messages": [HumanMessage(content="Analyze AAPL")]},
    config=snap.config(),                            # 2. pass config
)
snap.finalize()                                      # 3. write manifest

open("report.md", "w").write(result["messages"][-1].content)

# trace/ now contains every node's I/O and tool calls as searchable text files

Run the audit

This can run in a separate script, a different session, or days later — it only reads from disk.

from audit_fence import FenceGroup, Snapshot
from langchain_openai import ChatOpenAI

snap = Snapshot("trace/")                            # point to existing traces

cascade = await FenceGroup.audit_cascade(
    manifest=snap.load_manifest(),
    llm=ChatOpenAI(model="gpt-4o", temperature=0.1),
    trace_dir=snap.trace_dir,
    final_document=open("report.md").read(),
)

# Walk any claim back to where it originated
for claim in cascade.group.all_claims:
    chain = cascade.trace_claim(claim)
    print(f"{claim.claim[:60]}{len(chain)} links to source")

Model-agnostic

Works with any LangChain-compatible model:

from langchain_anthropic import ChatAnthropic        # Claude
from langchain_openai import ChatOpenAI              # GPT / DeepSeek / Ollama
pip install langchain-anthropic    # for Claude
pip install langchain-openai       # for GPT
pip install langchain-community    # for DeepSeek, Ollama, etc.

See examples/ for complete runnable scripts including a financial report audit and multi-agent cascade.


Documentation

Guide Description
Capture Hierarchy Five capture levels — from snap.config to save_artifact
Common Patterns Five real-world integration patterns (module-level compile, nested subgraphs, Command routing, ephemeral sub-agents, remote API)
Workflow Projects Integrating StateGraph projects — zero-touch vs instrument_graph trade-offs
Snapshot Production trace capture, callback merging, round tracking
Integration Setup methods, tool wrapping, search configuration
Structured Claims ClaimRecord workflow, enrich hooks
Multi-Agent FenceGroup, cross-agent linking, dynamic topology
Soft Enforcement Conditional enforcement, skip patterns
Persistence JSON export, state serialization
Examples End-to-end usage examples

Proven Effective

We evaluated audit-fence on real annual reports (SEC 10-K filings) from 12 S&P 500 companies spanning technology, healthcare, financial services, energy, and consumer goods. Each document is 45K–250K tokens — the equivalent of a 200–500 page filing.

The task: an AI agent reads an annual report that contains a mix of real and hallucinated financial claims, and must identify which claims are genuine by finding the exact verbatim text in the source document that proves each one. Ground truth is determined by XBRL financial data — no LLM judges, no human annotation, no evaluation circularity.

We ran each company 3 times independently to measure not just average accuracy, but consistency. 108 runs total.

Results

We tested three configurations to show what audit-fence contributes:

Configuration Evidence Accuracy Run-to-Run Consistency
audit-fence (full system) 98.5% ± 3.8%
Search tools, no enforcement 95.2% ± 16.0%
No search tools 56.7% ± 40.4%

Evidence Accuracy — the fraction of submitted citations that are genuine verbatim text from the source document, not paraphrased or reconstructed from memory. 98.5% means that when audit-fence produces a citation, it is character-for-character real text from the original filing.

Run-to-Run Consistency — standard deviation across 3 independent runs on the same documents. audit-fence's ±3.8% means results are stable and predictable. The "search tools only" configuration looks almost as strong on average (95.2%), but its ±16.0% spread reveals a reliability problem: in one run on JPMorgan's filing, it produced 44% accuracy with 5 fabricated citations; in another run on the same document, it reached 100%. With audit-fence, this kind of collapse does not occur.

All three configurations achieve 99.6% hallucination catch rate — intentionally falsified claims are flagged as unverifiable at the same rate regardless of enforcement. The ablations degrade Evidence Accuracy, not detection capability: the underlying model knows something is wrong; what weakens without enforcement is the quality of the evidence trail it produces for the claims it does accept.

The no-tools baseline shows the scale of the underlying problem: an AI agent given a 250-page document but no search tooling will produce fabricated citations 40% of the time. The source material is present — the model simply cannot reliably retrieve precise verbatim text from a context window of that size.


These results reflect our current test suite on the most demanding evaluation setting: full annual reports, natural-language output. We are actively expanding the evaluation dataset for more comprehensive coverage.


Designed For

Financial services — Agent systems generating investment analysis, risk reports, compliance reviews. Every number traceable to SEC filings, market data feeds, or internal databases.

Legal — Automated contract review, regulatory compliance checking. Every statute citation verified against the actual legal text.

Life sciences — Clinical trial summaries, drug interaction reports. Every data point linked to the original study or FDA filing.

Any domain where an AI-generated report must withstand regulatory scrutiny.


How It Compares

audit-fence operates in the same paradigm as academic fact verification systems — decompose claims, retrieve evidence, verify against source. The difference is in enforcement mechanism and ground truth.

FActScore RAGAS FEVER audit-fence
What it does Evaluates factual precision Evaluates RAG faithfulness Classifies claim veracity Detects hallucinations + annotates sources
Verification LLM judge NLI model Trained classifier Mechanical enforcement
Source annotation No No No Yes — claim to source data
Dependencies Retriever + LLM LLM API Training data Zero (core) / LangGraph + any LLM (audit agent)
Designed for Research evaluation RAG pipeline evaluation Research benchmark Production compliance

These approaches are complementary. FActScore and RAGAS evaluate output quality after generation. audit-fence enforces source traceability during generation — different stages, different guarantees.

Scope and Limitations

Honesty about what a tool does and doesn't do matters — especially in compliance contexts.

Status Detail
Prevents fabrication Solved The auditor cannot record evidence it never searched for. Submission without a matching search result is programmatically rejected.
Improves attribution accuracy Improved Forcing a targeted search per claim is structurally better than matching against an entire static document — the search result is specific to the claim being verified.
Guarantees correct attribution Not yet solved The agent could still pick the wrong match from valid search results — a passage that is real but corresponds to a different claim. audit-fence reduces it; it does not eliminate it.
Proves causality Open research Tracing a number to its source proves where it came from, not why it was used or whether the reasoning is sound.

audit-fence provides a verifiable enforcement layer — a necessary foundation that other verification methods (semantic matching, causal reasoning) can build on top of.

Origin

audit-fence is extracted from Firn, a multi-agent financial analysis system with a full 3-phase audit pipeline, 1000+ tests, and deterministic verdict assignment. In Firn, the enforcement mechanism is integrated with a financial-domain workflow — specialist agents, trace directories, verdict merging. audit-fence isolates the core enforcement pattern as a standalone, domain-agnostic library.

The Snapshot capture system was field-tested across six real LangGraph projects: Firn, GPT-Researcher, company-research-agent, DeerFlow, Open Deep Research, and LangAlpha — covering tool-calling agents, pure workflow orchestrators, nested subgraphs, Command-based routing, and remote LangGraph API deployments.

License

MIT — use it anywhere, no restrictions.

About

Trace every claim to its source. Identify every hallucination. Before the report reaches your client.

Topics

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages