Open-source claim verification engine for agent-generated assertions in high-stakes domains
Project description
⛏️ Graphite
Claim verification engine for AI agent outputs.
LLMs judge. Graphs remember.
Graphite extracts claims from agent-generated text, retrieves evidence, verifies support and contradiction, flags unsupported reasoning leaps, and stores every verdict with a full provenance trail — building a verification memory that gets stronger with every review.
⚠️ v0.4.x — Experimental. Usable and tested, but API may change before 1.0. Pin your version.
How it works
Graphite turns raw agent output into a structured verification report.
from graphite.pipeline import verify_agent_output
report = verify_agent_output(
text=agent_memo_markdown,
corpus=sec_filings_corpus,
model="gemini-2.5-flash" # any OpenAI-compatible model works
)
print(f"Supported: {report.supported_count} | Conflicted: {report.conflicted_count}")
print(f"Requires Human Review: {len(report.risky_claim_ids)} claims")
Need domain-specific prompts? Pass a PromptSet:
from graphite.pipeline.prompts import PromptSet
medical_prompts = PromptSet(
extractor="You are a medical claim extractor. Extract clinical assertions...",
verifier="You are a clinical evidence checker. Evaluate against guidelines...",
)
report = verify_agent_output(text, corpus, prompts=medical_prompts)
This single API wraps a 5-step pipeline:
- Extract: Parses the document into atomic claims using LLMs.
- Retrieve: Finds candidate evidence spans across the corpus for each claim.
- Verify: Judges claims against the retrieved spans (Supported, Conflicted, Insufficient).
- Analyze: Flags argument-level reasoning leaps (
CONCLUSION_JUMP). - Report: Aggregates the findings into a
VerificationReportwith structured rationale, review flags, and full provenance.
Handling Logic Leaps & Human Review
Downstream UI and review workflows can be built directly on top of the structured output.
from graphite.pipeline.verdict import ArgumentVerdictEnum
# Check for logic leaps (Argument-level verification)
for argument in report.argument_verdicts:
if argument.verdict == ArgumentVerdictEnum.CONCLUSION_JUMP:
print(f"⚠️ LOGIC LEAP: {argument.text}")
# Route high-risk factual claims to a Human-in-the-loop review queue
for claim_id in report.risky_claim_ids:
verdict = report.get_verdict(claim_id)
if verdict.needs_human_review:
print(f"🚨 REVIEW NEEDED: {verdict.claim_text}")
print(f" Reason: {verdict.rationale.missing_evidence_reason or verdict.rationale.contradiction_type}")
Quickstart
pip install "graphite-engine[llm]"
export GEMINI_API_KEY="your-api-key-here"
python examples/quickstart_verification/run.py
Or from source:
git clone https://github.com/minjun1/graphite-core.git
cd graphite-core
pip install -e ".[llm]"
export GEMINI_API_KEY="your-api-key-here"
python examples/quickstart_verification/run.py
Supported Models
Graphite works with any major LLM provider:
from graphite.pipeline import verify_agent_output
# Gemini (default)
report = verify_agent_output(text, corpus)
# Claude
report = verify_agent_output(text, corpus, model="claude-sonnet-4-6")
# OpenAI
report = verify_agent_output(text, corpus, model="gpt-4o")
# Local models (Ollama, vLLM)
report = verify_agent_output(text, corpus, model="llama3")
Set the appropriate API key for your provider:
GEMINI_API_KEY— Google Gemini (default)ANTHROPIC_API_KEY— Anthropic ClaudeOPENAI_API_KEY+OPENAI_BASE_URL— OpenAI or any compatible endpoint
Why a Verification Memory?
Most verification tools run once and forget. Graphite anchors every judgment into a persistent claim store — turning disposable LLM outputs into a living verification memory.
Claims are first-class objects. The same assertion can be identified, revisited, and re-evaluated across documents and time — not lost in prompt logs.
Evidence accumulates, not overwrites. When a second source confirms (or contradicts) a claim, Graphite appends the new evidence to the existing claim instead of starting from scratch.
Review history becomes lineage. AI verdict → analyst override → re-evaluation with new data — every step is recorded as part of the claim's provenance, not a flat log entry.
Cross-document deduplication. When the same claim appears in TSMC's 10-K and Nvidia's 10-K, Graphite recognizes it as one canonical claim backed by two independent sources.
Reasoning structure, not just fact-checking. Claims don't exist in isolation. Graphite represents claim-to-conclusion relationships, enabling checks like CONCLUSION_JUMP when the logical link between premises and conclusion is unsupported.
Stateful Verification Memory
Unlike stateless evaluators that produce a score and discard context, Graphite's ClaimStore builds a persistent fact base that strengthens over time.
Run 1: Extract "TSMC supplies CoWoS to Nvidia" from TSMC 10-K
→ 1 evidence source recorded
Run 2: Same claim found in Nvidia 10-K
→ evidence accumulates → 2 independent sources
Run 3: Exact duplicate from same source
→ deduplicated, no change
Run 4: Related claim "Nvidia depends on TSMC" extracted
→ cross-claim linkage via shared entities
What this looks like as a graph:
Claim: "TSMC supplies CoWoS to Nvidia"
├── supported_by → TSMC 10-K (cited span)
├── supported_by → Nvidia 10-K (cited span)
├── reviewed_as → SUPPORTED (model verdict)
└── contributes_to → "Nvidia depends on TSMC"
Each claim is a deduplicated node. Evidence merges across extraction runs. Analyst overrides persist. The result is a verification memory where repeated reviews compound — not repeat.
Most verification tools forget. Graphite remembers — and gets stronger with every review.
(See examples/evidence_accumulation/ for a runnable demo — no API keys required.)
Graphite vs. Existing Tools
Evaluators grade your prompts. Graphite audits your agent's claims — and remembers every verdict.
These tools solve adjacent but different problems:
| Dimension | Ragas / TruLens / DeepEval | Graphite |
|---|---|---|
| Purpose | Prompt/model evaluation (CI/CD) | Production output verification (runtime) |
| State | Stateless — each run is independent | Stateful — evidence accumulates across runs |
| Output | Scores (faithfulness, relevance) | Structured VerificationReport with provenance |
| Logic Leaps | Not addressed | CONCLUSION_JUMP / OVERSTATED detection |
| Human Review | Manual review of score dashboards | needs_human_review routing with analyst override |
| Audit Trail | Execution logs | Every verdict links to exact cited_span with full lineage |
Evaluation Framework
Graphite ships with a built-in eval harness for structured benchmarking across models and domains.
from graphite.eval import EvalRunner
runner = EvalRunner.from_json("src/graphite/eval/datasets/base.json")
run = runner.run(model="gemini-2.5-flash", output_path="results.json")
print(run.metrics())
# {'total': 4, 'claim_verdict_accuracy': 0.75, 'overall_pass_rate': 0.5, ...}
The eval runner supports domain filtering (domain="medical"), custom prompts via PromptSet, latency tracking, error capture, and JSON result persistence for cross-model comparison.
Golden test cases from src/graphite/eval/datasets/base.json:
| Test Case | Type | Expected Claim | Expected Argument |
|---|---|---|---|
| Paraphrased contradiction | Semantic | CONFLICTED | GROUNDED |
| Numeric mismatch (10× error) | Factual | CONFLICTED | GROUNDED |
| Temporal mismatch (stale CEO) | Temporal | CONFLICTED | GROUNDED |
| Unsupported revenue prediction | Reasoning Leap | CONFLICTED | CONCLUSION_JUMP |
Add your own domain-specific eval cases by extending base.json or creating new dataset files with EvalCase schema.
See
evals/verify_eval.pyfor a runnable eval script. A larger-scale evaluation suite (100+ cases across finance, medical, legal) is on the roadmap.
Core Primitives
| Object | What it does |
|---|---|
VerificationReport |
Top-level summary of the entire review, ready for product UI integrations |
Verdict |
Claim-level judgment (SUPPORTED, CONFLICTED, INSUFFICIENT) with structured rationale |
ArgumentVerdict |
Argument-level judgment (GROUNDED, CONCLUSION_JUMP, OVERSTATED) |
ClaimStore |
Persistent verification memory — deduplicates claims, merges evidence, and preserves review history across runs |
PromptSet |
Configurable system prompts for each pipeline stage — swap in domain-specific prompts without forking |
EvalRunner |
Structured benchmarking — run datasets, collect metrics, compare models, filter by domain |
Reference Applications
Graphite is designed as the verification engine for high-stakes workflows across multiple domains:
- Compliance & Legal Review: Checking internal policy documents or marketing copy against regulatory guidelines.
- Healthcare & Scientific Fact-checking: Cross-referencing generated medical or scientific summaries against peer-reviewed journals.
- Investment & Research QA: Verifying AI-generated analyst memos against SEC filings or earnings call transcripts.
(See examples/quickstart_verification/ for end-to-end verification, examples/evidence_accumulation/ for stateful memory, and examples/lineage_override_demo/ for analyst override workflows.)
Optional extras
Core (always included): pydantic
pip install -e ".[llm]" # LLM support (OpenAI-compatible providers)
pip install -e ".[all]" # Everything
Set
GEMINI_API_KEYto get started. To use other providers, setOPENAI_API_KEYandOPENAI_BASE_URL.
License
Apache-2.0 — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file graphite_engine-0.4.0.tar.gz.
File metadata
- Download URL: graphite_engine-0.4.0.tar.gz
- Upload date:
- Size: 67.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f3b8993013ca3ef26eda4e58b5d2b25411d1c52d713c4ecc9b78812b927479b
|
|
| MD5 |
8f143e2db469207e169611d1b7eedda3
|
|
| BLAKE2b-256 |
47738eee5c7e3110b4e32c322ce5aa820b59617b14eac899c0ce5f6cfea008a6
|
Provenance
The following attestation bundles were made for graphite_engine-0.4.0.tar.gz:
Publisher:
publish.yml on minjun1/graphite-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
graphite_engine-0.4.0.tar.gz -
Subject digest:
6f3b8993013ca3ef26eda4e58b5d2b25411d1c52d713c4ecc9b78812b927479b - Sigstore transparency entry: 1168046227
- Sigstore integration time:
-
Permalink:
minjun1/graphite-core@908ebba53f3ff9dd9b1baaebeaa94f7a68df0968 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/minjun1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@908ebba53f3ff9dd9b1baaebeaa94f7a68df0968 -
Trigger Event:
release
-
Statement type:
File details
Details for the file graphite_engine-0.4.0-py3-none-any.whl.
File metadata
- Download URL: graphite_engine-0.4.0-py3-none-any.whl
- Upload date:
- Size: 51.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
173b3b7ca043006f95b687ca876706b7e36582fc7447e102e74377d6a7da095c
|
|
| MD5 |
2a5c4b2d110e374bf2c474a35945405a
|
|
| BLAKE2b-256 |
c163ea753965c2c5c12d8ef41cafa19d1cabe4c9ccf48e9002f9e4373d2724a6
|
Provenance
The following attestation bundles were made for graphite_engine-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on minjun1/graphite-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
graphite_engine-0.4.0-py3-none-any.whl -
Subject digest:
173b3b7ca043006f95b687ca876706b7e36582fc7447e102e74377d6a7da095c - Sigstore transparency entry: 1168046444
- Sigstore integration time:
-
Permalink:
minjun1/graphite-core@908ebba53f3ff9dd9b1baaebeaa94f7a68df0968 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/minjun1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@908ebba53f3ff9dd9b1baaebeaa94f7a68df0968 -
Trigger Event:
release
-
Statement type: