Skip to main content

Yantraa Evidence

Does checking less evidence make AI decisions cheaper, without making them worse?

A Python package for measuring whether an AI that chooses which records to check can make decisions at a lower total cost than checking everything. It works for any domain: returns, claims, disputes, alerts or approvals.

Python 3.11+ License: Apache-2.0 Runs offline No UI lock-in


Contents

What is this? · Who it's for · Install and run · 1. Overview · 2. Experiment · 3. Evaluate · Bring your own domain · Configuration · Architecture · Development · Privacy & security · Limitations · License


What is this?

Before an AI approves, denies or escalates something, it usually needs to check records. Every check costs money and time, and every wrong decision costs more. Checking everything is safe but wasteful. Checking nothing is cheap but reckless. Yantraa Evidence gives you a controlled way to find the middle ground and to prove it with numbers.

You get three building blocks. Use them from Python, a notebook or the CLI, and build any app you like on top:

Step What you do Python CLI
1. Overview See the domain, evidence sources and costs, strategies, decision-makers, data and saved results overview() yantraa overview
2. Experiment Design and run a comparison: domain, cases, strategies, decision-maker, your costs and limits Experiment(...).run() yantraa experiment
3. Evaluate Score it against benchmark baselines and earlier experiments, with paired 95% intervals evaluate(...), compare_to_baseline(...) yantraa evaluate
flowchart LR
    A[Request] --> B{Strategy decides<br/>next step}
    B -- check a source --> C[(Evidence sources<br/>defined by the domain)]
    C -- evidence --> B
    B -- stop --> D[Shared decision-maker<br/>domain labels]
    D --> E[Grade vs answer key]
    E --> F[Total cost =<br/>checks + AI + mistake penalty]
    F --> G[Report · paired 95% CIs ·<br/>vs baselines and past runs]

Built-in guarantees:

  • 🔒 Strict information boundary. The decision-maker sees only what has been fetched, never the answer key or unfetched records. Tests enforce this.
  • ⚖️ Fair comparison. Every strategy shares the same decision-maker, instructions and limits.
  • 🧯 Fails safe and loudly. Limits are checked before each call. Any failure returns the domain's fallback label (for example escalate) with the reason recorded. There are no silent retries.
  • 📏 Honest statistics. Paired, seeded bootstrap intervals and penalty-sensitivity analysis. Unknown prices are reported as unknown, never as zero.
  • 🧾 Reproducible. Every run stores its config hash, seed, data and prompt versions, model version and full trace.

Who it's for

Industry Example decision Labels (fallback in bold)
Retail / e-commerce (built in) Approve a product return approve, reject, escalate
Insurance (example included) Triage a property claim pay, deny, refer
Banking / fintech Resolve a chargeback, clear an AML/KYC alert accept, reject, review
Lending Approve a loan exception approve, decline, manual underwriting
Healthcare administration Prior-authorization review approve, deny, clinician review
Telecom / SaaS Billing dispute credit credit, decline, escalate
Logistics Delivery exception claim reimburse, deny, investigate
IT / security operations Access request or alert triage grant, deny, escalate
If you are… It helps you…
An AI / ML engineer Benchmark an agent's retrieval policy, not just its answers, and trace every failure step by step.
A product or ops lead Enter what checks and mistakes cost your business and see whether a strategy still wins.
A risk / compliance officer Verify fallback behaviour, mistakes by label and which evidence supported each decision.
A researcher Start from a seeded, reproducible test bed with locked held-out data and exportable traces.
An app developer Build a review console, dashboard or service on plain Python objects, SQLite and CSV/JSONL.

More detail, with evidence sources and mistake costs for each industry: docs/use-cases.md.

Install and run

Prerequisites: Python 3.11 or newer, plus uv (recommended) or pip. No API key is needed: the built-in mock decision-maker is free and offline.

Install from PyPI (run the commands from the folder where you want data and results kept):

# With pip (inside a virtual environment)
pip install yantraa-evidence
yantraa overview

# With uv, as a dependency of your own project
uv add yantraa-evidence
uv run yantraa overview

# With uv, as a standalone tool (no project needed)
uv tool install yantraa-evidence     # or try it once: uvx --from yantraa-evidence yantraa overview
yantraa overview

Then continue with yantraa experiment and yantraa evaluate (see step 2 below), or import yantraa_evidence in Python.

From a source checkout (to change the code or run the tests):

  1. Get the code and install it:

    git clone https://github.com/Shalihotri/Yantraa.git
    cd Yantraa
    uv sync
    
  2. Run the three steps:

    uv run yantraa overview                  # what's available
    uv run yantraa experiment --limit 40     # run all strategies on 40 synthetic cases (data is generated on first run)
    uv run yantraa evaluate                  # report the latest experiment against the fetch_all baseline
    
  3. Or run the same flow from Python: uv run python examples/quickstart.py

  4. (Optional, for a real AI) copy .env.example to .env and set OPENAI_API_KEY=.... Then add --provider openai to an experiment. Always check the spend first with --estimate-only.

Source checkout without uv: python -m venv .venv, activate it, then run pip install -e .. After that, use yantraa ....

Real AI with a pip install: put a .env file containing OPENAI_API_KEY=... in the folder you run yantraa from, or set the variable in your shell.

1. Overview

from yantraa_evidence import overview
from yantraa_evidence.overview import to_text

info = overview()            # plain dict: domain, sources & costs, strategies, providers, data, saved results
print(to_text(info))

yantraa overview prints the same information. Add --json for machine-readable output, or --problems 20 for the latest logged failures.

2. Experiment

from yantraa_evidence import Experiment

exp = Experiment(
    domain="returns",                    # or "my_pkg.domains:CLAIMS" or "path/file.py:DOMAIN"
    split="dev",                         # tune on dev; keep test locked until the end
    strategies=["selective", "fixed_order", "fetch_all"],
    provider="mock",                     # "openai" (Decisions API) or "openai-responses"
    limit=40,
    overrides={"costs": {"get_inspection": 0.25}, "loss": {"approve": 50}},  # your economics
)
print(exp.estimate())                    # worst-case calls and spend, before anything runs
result = exp.run()                       # scored, saved to SQLite, exported to CSV / JSONL / JSON
trace = exp.run_case(0, "selective")     # one decision, fully traced

Built-in strategies: selective (the AI picks the next check: the idea being tested), fetch_all (reference baseline), fixed_order (checklist, stop early), confidence_threshold (stop when the AI is sure) and initial_only (no checks: the lower bound).

Add your own strategy in a few lines. It is then available to Experiment and the CLI:

from yantraa_evidence import register_strategy

@register_strategy
def cheapest_first(s):
    """Check sources from cheapest to most expensive; stop once the decision is no longer the fallback."""
    d = s.classify()
    for src in sorted(s.sources, key=lambda x: s.cfg.sources[x].cost):
        if d.action != s.domain.fallback:
            break
        s.fetch(src)
        d = s.classify()
    return d

CLI:

yantraa experiment --split dev --strategies selective,fetch_all --limit 40
yantraa experiment --provider openai --limit 10 --estimate-only
yantraa experiment --case 0 --strategies selective        # one traced decision
yantraa experiment --generate --seed 7                    # regenerate synthetic cases

3. Evaluate

from yantraa_evidence import evaluate, compare_to_baseline

report = evaluate(result)                 # or evaluate("b_2026...") for a saved experiment
print(report.to_text())                   # headline, scoreboard, paired verdicts vs fetch_all, caveats
report.metrics                            # accuracy, wrong_<label>, fallback_rate, checks, costs, latency
report.paired_comparisons                 # each strategy minus the baseline, with 95% intervals
report.penalty_sensitivity                # does the winner change if mistakes cost 0.25x to 4x?
report.accuracy_by_scenario, report.mistakes

compare_to_baseline(new_result, "b_2026...")   # new prompt / model / costs vs a saved benchmark, paired by case

CLI:

yantraa evaluate                          # latest experiment
yantraa evaluate --list                   # saved experiments
yantraa evaluate b_NEW --against b_OLD    # regression check against an earlier benchmark
yantraa evaluate --reference fixed_order --json

Every report repeats its caveats: synthetic data, assumed penalties, mock ≠ model quality, confidence ≠ calibration.

Bring your own domain

A domain is one class. Declare the sources, labels, fallback and penalties, then implement assess. That one function produces the answer key and drives the offline mock, so the two can never disagree.

from yantraa_evidence import Assessment, Domain, Source

class Chargebacks(Domain):
    name = "chargebacks"
    task = "Decide whether to accept a card chargeback."
    sources = (Source("get_transaction", "Transaction log", cost=0.01),
               Source("get_merchant_evidence", "Merchant's delivery proof", cost=0.20),
               Source("get_customer_history", "Prior disputes", cost=0.05))
    actions = {"accept": "...", "reject": "...", "review": "..."}
    fallback = "review"
    loss = {"accept": 80, "reject": 30, "review": 3}

    def assess(self, evidence):           # evidence = {source_id: [payload, ...]} for fetched sources
        ...
        return Assessment(action, conditions)

To use it, pass Experiment(domain="my_module:Chargebacks") or --domain path/to/file.py:DOMAIN. Alternatively, call register_domain(Chargebacks()).

  • Data: implement generate(seed) for synthetic cases, or write your own Case records (with the correct answer in oracle_action) to data/<domain>/<split>.jsonl. You can also pass Experiment(cases=[...]).
  • Full worked example: examples/insurance_claims.py covers claims triage with a generator, and runs in CI.
  • Another model: implement select(obs) and classify(obs), then pass Experiment(adapter_factory=...).

Configuration

What Where
API key and model overrides .env (copy .env.example). It is git-ignored.
Domain, source costs, mistake penalties, limits, threshold, paths config/default.yaml, or Experiment(overrides=...) per run
Model prices (USD per 1M tokens) config/pricing.yaml. Missing prices are reported as unknown.

Unknown source or label names in config fail loudly instead of being ignored.

Architecture

src/yantraa_evidence/
  overview.py      1. what is available (domains, strategies, providers, data, results)
  experiment.py    2. Experiment / ExperimentResult: design, estimate, run, save
  evaluate.py      3. scoring, metrics, paired bootstrap, sensitivity, Report, compare_to_baseline
  domain.py        Domain / Source / Assessment base classes and the domain registry
  domains/         built-in domains (returns: retail product returns, with a seeded generator)
  strategies.py    built-in strategies + @register_strategy
  adapters.py      decision-makers: mock (offline) and OpenAI (Decisions, Responses)
  runner.py        guarded execution engine: Session, limits, validation, tracing
  tools.py         case-data-backed evidence tools (same interface a live connector would use)
  datasets.py      case files (JSONL) and synthetic data generation
  storage.py       SQLite results + evidence graph, CSV/JSONL/JSON export
  schemas.py       typed contracts: Case, Observation, decisions, RunResult
  config.py        YAML config, domain defaults, pricing, .env
  logtracker.py    structured "what went wrong" log (keys redacted)
  cli.py           `yantraa overview | experiment | evaluate`
examples/          quickstart.py · insurance_claims.py (custom domain)
docs/              design.md (method, guarantees, findings log) · use-cases.md (industries and personas)
tests/             isolation, limits, failures, graph round-trip, known answers, custom domains, CLI

Read docs/design.md before citing a result.

Development

uv sync                                    # Python env with dev tools
uv run pytest                              # all tests, offline, no API key
uv run ruff check src tests examples       # lint
uv build                                   # wheel + sdist in dist/

CI (.github/workflows/ci.yml) runs lint and tests on Linux and Windows with Python 3.11 and 3.12. It also runs the Overview → Experiment → Evaluate flow offline for both domains, a wheel-install smoke test and a secret scan. See CONTRIBUTING.md.

Privacy & security

  • Everything runs locally. There is no server, no account and no telemetry.
  • Your API key stays on your machine. It is read from the environment or .env, and it is never logged or stored. Provider error messages are redacted before logging. .env, databases, logs and results are git-ignored.
  • Only live decision-makers send data out. With --provider openai, the fetched evidence for each case goes to OpenAI (store=False where the API allows). The mock sends nothing.
  • Bundled data is synthetic. It contains no real people, orders or personal information. If you use real records, anonymise them first and keep them in a git-ignored folder (for example private/).

Limitations

  • Synthetic data is balanced for debugging. It is not a production distribution.
  • Default mistake penalties are illustrative. Set your own, and read the sensitivity table.
  • The mock uses the same rule as the answer key: it validates mechanics, not model quality.
  • An AI's stated confidence is not calibrated correctness. The tool supports comparisons, not causal claims.
  • Live results so far are small-sample. See the findings log.

Roadmap

  • More built-in domains (chargebacks, access requests) and adapters for other model providers
  • Live evidence connectors behind the same tool interface
  • Larger live runs on the practice set, then a single locked run on the held-out set
  • External validation on real, anonymised decision logs

Contributing

Issues and pull requests are welcome. Please read CONTRIBUTING.md. In short: keep the information boundary intact, add tests, and keep negative findings visible.

License

Apache-2.0.

Metadata

Release files for yantraa-evidence 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yantraa-evidence 0.3.0
File Size Uploaded
yantraa_evidence-0.3.0.tar.gz 45.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yantraa-evidence 0.3.0
File Interpreter ABI Platform
yantraa_evidence-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 98.4 kB

Release files / yantraa_evidence-0.3.0.tar.gz

Download URL yantraa_evidence-0.3.0.tar.gz
Size 45.1 kB
Tags Source
SHA-256 checksum
How to use checksums
66e0359eb233bf09786677ca9f1011cf4cc1b94114ea0df9efb2ad13e12d52de
BLAKE2b-256 checksum
How to use checksums
a66d509bfc4c2a9cc9b712f389fce6f96c28d208a0b3020817d343448aee4369
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release files / yantraa_evidence-0.3.0-py3-none-any.whl

Download URL yantraa_evidence-0.3.0-py3-none-any.whl
Size 53.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
81768cba535dfc0b8af99b6b07108d8ca03dfbf0ea37dd7d3a39c0d7d03f25a5
BLAKE2b-256 checksum
How to use checksums
65a9e19b10f1f0736a507486d2e877296820fdb9389b1add8b8c352f854b75cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page