AutomationOpen SourceFreeActiveMachine-verified· beginner · ~10 min setup

Chat with a CSV, but pin a known-answer guardrail so a wrong query cannot pass

Ask a CSV or dataframe questions in plain English with PandasAI, but wrap it in a deterministic known-answer check so a confident-but-wrong generated query is caught instead of trusted.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 2/2 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

Anyone who asks a CSV or dataframe questions in English and needs to know the answer is right. CI loads a fixed CSV fixture and asserts a deterministic aggregation (average revenue by region) equals the known answer, proving the check that would catch a wrong query actually runs. No install, no key, no model call. The df.chat() step, where the model writes and runs the Python, is fenced.

Not for

  • Trusting the model's answer on faith, the whole point is to compare df.chat() against the known number and reject a mismatch
  • Python 3.12+, PandasAI pins 3.8 through 3.11 so it will not install on newer runtimes
  • Running untrusted generated Python unsandboxed, df.chat() executes model-written code, use its Docker sandbox (pip install pandasai-docker) for data you did not author
  • Building a product on the `ee/` enterprise directory assuming MIT, that directory carries its own license

The Stack

Tested Against

github.com/sinaptik-ai/pandas-ai v3.0.0 (2026-07)python@3.11node@20

Side effects & data flow

Network
none, local only
Writes
./companies.csv, ./guardrail.py
Credentials
none required

Prerequisites

  • Python 3.8-3.11 to actually run pandasai (it does not install on 3.12+)
  • An LLM provider key for the fenced df.chat() step (via pandasai-litellm)

Steps

  1. 1

    Load a fixed CSV and assert the aggregation matches the known answer

    This is the guardrail: a small CSV whose average-revenue-by-region you already know (EMEA=200, AMER=400, APAC=150), computed with pure stdlib so there is no model in the loop. CI asserts the aggregation equals that known answer. In real use you run df.chat() and check its reply against these same numbers, a reply that differs is a wrong query. The df.chat() call itself is fenced.

    cat > companies.csv <<'CSV'
    name,region,revenue
    Acme,EMEA,100
    Globex,EMEA,300
    Initech,AMER,200
    Umbrella,AMER,600
    Hooli,APAC,150
    CSV
    python3 - <<'PY'
    import csv, sys
    
    by_region = {}
    with open("companies.csv", newline="") as f:
        for r in csv.DictReader(f):
            by_region.setdefault(r["region"], []).append(float(r["revenue"]))
    
    avg = {reg: sum(v) / len(v) for reg, v in by_region.items()}
    golden = {"AMER": 400.0, "APAC": 150.0, "EMEA": 200.0}
    
    if avg != golden:
        print("BAD: aggregation drifted from the known answer; got " + str(avg))
        sys.exit(1)
    
    parts = ", ".join(reg + "=" + str(avg[reg]) for reg in sorted(avg))
    print("guardrail OK: avg revenue by region " + parts + " (matches the known answer); a df.chat() reply that differs is a wrong query and must be rejected")
    PY
  2. 2

    Wire the guardrail around df.chat() (the model step, not checked by CI)

    pip install pandasai pandasai-litellm, configure LiteLLM with your model and key, load the same CSV with pai.read_csv, then df.chat('What is the average revenue by region?'). Compare the reply against the golden numbers above and reject on mismatch. For data you did not author, run it inside the Docker sandbox (pip install pandasai-docker), since df.chat generates and executes Python. This step calls a model and runs generated code, so it is fenced.

Eval, 2 fixtures

Last passed: verified today
  • guardrail-okcontainstimeout 30s · max $0

    Expected: guardrail OK: avg revenue by region AMER=400.0, APAC=150.0, EMEA=200.0 (matches the known answer); a df.chat() reply that differs is a wrong query and must be rejected

  • clean-exitexit_codetimeout 30s · max $0

    Expected: 0

Results

PandasAI lets you point at a CSV, an Excel export, or a dataframe and ask questions in English, getting back numbers or charts. The catch the whole roundup is built around: it answers by generating and running Python, and a wrong query looks exactly like a right one. The fix is not to trust the reply, it is to keep an objective check the model cannot fake, a total you already know, next to it. This recipe makes that check the CI: a fixed CSV, a deterministic aggregation, and the known number it must equal. Two sharp gotchas, PandasAI pins Python to 3.8 through 3.11 (it will not install on 3.12+), and the `ee/` enterprise directory is not MIT.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Related workflows

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).