SourceScore

Integration guide

LlamaIndex + SourceScore VERITAS

Custom retriever for curated claim records plus a node post-processor that attaches candidates for review. Similarity does not create a verification badge.

Install

pip install llama-index requests

Custom VERITAS retriever

Subclass BaseRetriever and translate VERITAS search hits into LlamaIndex nodes. Each node carries the claim id, confidence, and a back-link to the canonical page in metadata so downstream prompts can render review links.

import requests
from typing import List
from llama_index.core.retrievers import BaseRetriever
from llama_index.core.schema import NodeWithScore, TextNode

VERITAS = "https://sourcescore.org/api/v1"

class VeritasRetriever(BaseRetriever):
    def __init__(self, top_k: int = 5):
        super().__init__()
        self.top_k = top_k

    def _retrieve(self, query_bundle) -> List[NodeWithScore]:
        r = requests.get(
            f"{VERITAS}/search",
            params={"q": query_bundle.query_str, "limit": self.top_k},
            timeout=8,
        )
        r.raise_for_status()
        out = []
        for c in r.json().get("results", []):
            node = TextNode(
                text=c["statement"],
                metadata={
                    "claim_id": c["id"],
                    "confidence": c["confidence"],
                    "url": f"https://sourcescore.org/claims/{c['id']}/",
                    "vertical": c.get("vertical", "ai-ml"),
                    "tags": c.get("tags", []),
                },
            )
            out.append(NodeWithScore(node=node, score=c.get("matchScore", c["confidence"])))
        return out

Wire into a QueryEngine

from llama_index.core import PromptTemplate
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.response_synthesizers import get_response_synthesizer
from llama_index.llms.openai import OpenAI

qa_template = PromptTemplate("""You are a precise assistant. The records below are retrieval
candidates, not truth verdicts. Use a record only when its exact statement supports
your assertion; otherwise say the supplied evidence does not cover the question.

Candidate records:
{context_str}

Question: {query_str}
Answer (cite [claim_id] only after exact-statement comparison):""")

retriever = VeritasRetriever(top_k=5)
synthesizer = get_response_synthesizer(
    llm=OpenAI(model="gpt-4o-mini", temperature=0),
    text_qa_template=qa_template,
)
engine = RetrieverQueryEngine(retriever=retriever, response_synthesizer=synthesizer)

resp = engine.query("Who introduced the Transformer architecture?")
print(resp)
for n in resp.source_nodes:
    print(f"  → [{n.metadata['claim_id']}] confidence {n.metadata['confidence']:.2f} {n.metadata['url']}")

Candidate annotation (NodePostProcessor)

For chains that already have a different primary retriever, you can layer VERITAS in as a post-processor that annotates each node with a possible catalog record. It must not approve or drop content from similarity alone; a downstream entailment or human review decides.

import requests
from typing import List, Optional
from llama_index.core.postprocessor.types import BaseNodePostprocessor
from llama_index.core.schema import NodeWithScore, QueryBundle

class VeritasCandidatePostprocessor(BaseNodePostprocessor):
    min_confidence: float = 0.85

    def _postprocess_nodes(
        self,
        nodes: List[NodeWithScore],
        query_bundle: Optional[QueryBundle] = None,
    ) -> List[NodeWithScore]:
        out = []
        for n in nodes:
            r = requests.post(
                "https://sourcescore.org/api/v1/verify",
                json={"claim": n.node.text, "minConfidence": self.min_confidence},
                timeout=8,
            ).json()
            best = r.get("bestMatch")
            if best:
                n.node.metadata["veritas_candidate_id"] = best["id"]
                n.node.metadata["veritas_candidate_url"] = best["detailUrl"]
                n.node.metadata["veritas_requires_review"] = True
            out.append(n)  # similarity alone never approves or rejects the node
        return out

Next steps