Govern when agents search, when they answer, and what it cost. Governance is tuned on your query mix — not one-size-fits-all thresholds. Two decisions per request: how much to search (cost) and whether to answer (risk).
Swipe chart → to read full pipeline
Blue steps route spend. Gold steps gate risk. Both paths end with an audit_id and structured policy reasons.
Probe / fanout — cost router
Scores the first result batch, then decides whether to fan out. Starting defaults: 1 query above ~78% probe score, up to 3 above ~55%, full fanout below — derived from our 125-task Tavily benchmark corpus, not tuned for your tenant out of the box.
Thresholds are overrideable per deployment. Calibrate on your logs (below) before trusting them in production.
Policy / allow_answer — risk gate
Runs on whatever evidence was retrieved. Checks overall confidence, qualifying source count, authority, and conflicts.
This is what legal and compliance stakeholders review — independent of probe routing.
Retrieval governance is not enough if the agent layer free-formats answers. Every cleared response is wrapped in a synthesis contract (also returned as synthesis_contract JSON on POST /evidence):
| REQUIRED | WHAT THE AGENT GETS |
|---|---|
| Citations | Claim + URL/title + per-source confidence and authority |
| Uncertainty statement | High / moderate / low band derived from overall confidence |
| Conflict disclosures | Each detected disagreement with confidence and authority gap |
| No-answer phrasing | Preset-specific lead when allow_answer: false (legal, support, research variants) |
Your agent should render synthesis_contract.body or map the structured fields directly — not paraphrase from raw retrieval snippets.
Detection: pairwise compare qualifying evidence items. When title-token overlap is high and snippet polarity diverges (positive vs negative framing), we record a Conflict with confidence (max of the two items) and authority gap.
| RULE | DEFAULT THRESHOLD | ACTION |
|---|---|---|
| High-confidence conflict | conflict ≥ 65% (legal: 60%) | block — opposing claims too strong to clear |
| Low-confidence conflict | conflict ≤ 45% (research: 50%) | search_more — retrieve before answering |
| Authority-tier conflict | authority gap ≥ 20% (support: 15%) | escalate — human review across source tiers |
When multiple rules fire, the strictest action wins (block > escalate > search_more). legal blocks on high-confidence conflicts; support escalates; research warns but still allows (unless confidence or source-count thresholds fail).
Start with a named preset. Override thresholds via YAML or API for your workload.
POST /policy/evaluate)Partners bring their own retrieval (Tavily, Exa, internal RAG, etc.). Query Fanout scores each chunk’s URL for authority and applies the preset you pass. You do not set min_authority per request on the hosted API — pick the preset, optionally add authority_overrides for internal doc hosts.
support (default on /policy/evaluate) — customer-facing agents, mixed external search. No authority bar; escalates when evidence is thin.research — internal drafting and cost routing. Permissive; conflicts warn instead of block.legal — compliance / legal workflows. Requires high-authority URLs (.gov, courts, firm filings via overrides). Open web at 55% authority will block often — that is expected.calibrated — always answer with confidence band + warnings; never hard-block.Authority overrides: one-time domain patterns in your integration, e.g. {"internal://filing": 0.92}. Match how you label chunk URLs. Include a url on every source — empty URLs score 40%.
Policy does not count raw search hits. It counts qualifying sources after our evidence pass:
That is why legal can block at “2 qualifying sources; minimum is 3” even when the search API returned more raw results.
Each evidence item gets an authority score from the result URL’s domain —
a fixed tier table, not PageRank or a legal citation graph. Scores are attached in the audit trail
and returned on POST /evidence citations.
| DOMAIN PATTERN | AUTHORITY | BAND |
|---|---|---|
courtlistener.com | 97% | institutional |
law.cornell.edu | 96% | institutional |
*.gov | 95% | institutional |
gov.uk | 94% | institutional |
legislation.gov.uk | 94% | institutional |
eur-lex.europa.eu | 93% | institutional |
europa.eu | 92% | institutional |
justia.com | 92% | institutional |
canlii.org | 90% | institutional |
findlaw.com | 90% | institutional |
nature.com | 90% | institutional |
ncbi.nlm.nih.gov | 90% | institutional |
who.int | 90% | institutional |
arxiv.org | 88% | institutional |
austlii.edu.au | 88% | institutional |
bailii.org | 88% | institutional |
iso.org | 88% | institutional |
*.edu | 86% | institutional |
aicpa.org | 85% | institutional |
pci.org | 85% | institutional |
wikipedia.org | 84% | reference |
owasp.org | 82% | reference |
britannica.com | 78% | reference |
github.com | 75% | official docs / community |
anthropic.com | 72% | official docs / community |
cloud.google.com | 72% | official docs / community |
developer.mozilla.org | 72% | official docs / community |
docs.aws.amazon.com | 72% | official docs / community |
docs.langchain.com | 72% | official docs / community |
kubernetes.io | 72% | official docs / community |
learn.microsoft.com | 72% | official docs / community |
openai.com | 72% | official docs / community |
python.org | 72% | official docs / community |
stackoverflow.com | 72% | official docs / community |
| all other domains | 55% | default web |
| missing URL | 40% | missing URL |
Bands: institutional (85%+) for courts, .gov, journals, and .edu;
reference (78–84%) for Wikipedia and encyclopedias;
official docs (72%) for vendor documentation your agents hit daily;
everything else defaults to 55% (most blogs, forums, SEO).
How policy uses it: after qualifying-source filtering, we take the
highest authority among remaining items and compare it to the preset’s
min_authority (e.g. 75% on legal). Official docs at
72% improve research / support confidence but
do not clear legal on a single source. Conflict detection
can escalate when disagreeing sources sit in different authority tiers
(gap ≥ 15–20%).
How confidence uses it: authority is 25% of per-item confidence
(alongside cross-query consensus, query–snippet relevance, and provider score). A blog or vendor
URL at 55% authority can still contribute to source count but may fail a legal gate on
its own.
What you can tune today: raise or lower min_authority per preset, or
add tenant-specific authority_overrides in policy YAML or on POST /evidence.
Overrides use the same host/suffix matching as the table above and always win over built-in tiers
(longest suffix wins among overrides).
policy:
name: legal
min_authority: 0.75
authority_overrides:
docs.acme.com: 0.90
help.acme.com: 0.82
| PRESET | MIN CONF | MIN SOURCES | MIN AUTH | ON FAIL | USE CASE |
|---|---|---|---|---|---|
default |
50% | 1 | — | allow | General agents; returns draft synthesis tagged as not policy-cleared |
support |
60% | 2 | — | escalate | Customer support; hand off to human when thin evidence |
legal |
70% | 3 | 75% | block | Legal / compliance; blocks on conflict; no answer if bar not met |
research |
55% | 2 | — | search_more | Internal research; expand retrieval instead of hard-blocking |
calibrated |
55% | 2 | 50% | allow + tag | Draft / internal tools — always answers with confidence band + policy warnings, never hard-blocks |
Thresholds should be tuned on your query mix. Run the offline benchmark locally, or send 3–7 days of JSONL logs for a design-partner autopsy (48h report).
Example block response (legal preset):
{
"allow_answer": false,
"audit_id": "99c08409-28ec-4427-...",
"policy": {
"profile": "legal",
"action": "block",
"reasons": ["only 2 qualifying source(s); minimum is 3"]
}
}
False block (too strict)
Legal preset blocks a helpful support answer because evidence is thin or authority scores are low.
Mitigation: use support + escalate, lower min_sources in YAML, or run an autopsy to measure block rate on real queries.
Over-spend (probe too cautious)
Probe scores low on a factual query and fans out to 5 searches when 1 would suffice — policy may still allow the answer, but you paid extra.
Mitigation: calibrate probe thresholds on your corpus; autopsy quantifies over-search patterns by agent.
Under-search (probe too aggressive)
Probe stays at 1 query; evidence is thin; policy escalates or blocks. Spend is low but allow_answer is false — correct for risk, frustrating if preset is wrong for the workflow.
You do not need to send production logs to start evaluating the architecture.
| PATH | TRUST REQUIRED | WHAT YOU GET |
|---|---|---|
| Offline benchmark | None — runs locally | python examples/gaia-baseline/run_benchmark.py --demo — mock backend, instant naive vs governed diff. Wikipedia + legal preset blocks 4/12 tasks in our published demo set. |
| CLI autopsy | Your machine only | query-fanout-validate-logs + query-fanout-autopsy on any JSONL export — no hosted upload. |
| Design-partner autopsy | Send redacted logs | 48h report: spend model, block/escalate patterns, recommended preset thresholds for your agents. |
Published live benchmark: 125 production-style tasks, 625→173 searches (~72% reduction) on Tavily — see field study and landing stats. Numbers vary by corpus; treat as reference, not a SLA.
Tavily is our reference benchmark preset. The control plane sits above your search API:
mock — offline control plane: deterministic fake results for CI, local dev, and running probe/policy/audit without any search API key. Not just a test double; full pipeline works end-to-end.wikipedia — offline real retrieval for demos and benchmarkstavily — live paid search (reference benchmark)http backend in YAML for Exa, Brave, Serper, or internal searchPolicy, audit, and allow_answer are provider-agnostic. Swap the adapter; keep the governance layer.
| METHOD | WHO | NOTES |
|---|---|---|
API param policy=legal | App engineers | Named preset on POST /evidence |
YAML policy_file | Platform / compliance | Wins over policy= when both are set — deterministic override |
| Hosted dashboard | Operators | /dashboard — read-only audit metrics; does not change policy |
Precedence: policy_file (YAML) > policy API param > preset defaults. Set one source of truth per environment to avoid surprises.
from query_fanout import RetrievalClient
client = RetrievalClient(preset="tavily", policy="legal", agent_id="support-bot")
report = await client.retrieve("How do refund policies work?")
if report.allow_answer:
answer(report.synthesis)
else:
escalate(report.audit_id, report.policy.reasons)
Need soft answers instead of hard blocks? Use calibrated for draft generation (confidence band + warnings, always allow_answer: true), default for permissive general use, or research to expand retrieval before failing.
Ready with logs? Autopsy submission guide · autopsy@queryfanout.dev