InfoWok
Beginner

Evaluate an AI Agent on a Local LLM: Free, No API Key (2026)

Evaluate an AI agent on a local LLM for free — build a tiny Pydantic AI agent on Ollama and score it with pydantic-evals, agent and judge both local, no API key.

SK
Sukhveer Kaur
Published July 18, 2026
8 min read
Local agent evals banner — a small agent and an LLM judge both running on a laptop via Ollama, producing a pass/fail scorecard with no API keyAI Engineering
LOCAL AGENT EVALS
On this page +

Every “how to evaluate your agent” tutorial hits the same wall on line one: get an API key. The catch nobody mentions is that the eval judge is itself a model call, so a suite you run twenty times while learning bills you twenty times over. That’s a strange tax to pay just to understand how evaluation works.

You don’t have to. If the agent and the judge both run on a model on your own machine, the entire loop costs nothing — you can run it at 2am, a hundred times, offline, and never see a bill. This guide builds exactly that: a tiny tool-using agent on a local LLM, scored with pydantic-evals, judged by a second local model. Same workflow the production posts use, minus the API key.

🟢 Beginner⏱️ 20 minStack: Python 3.11+, Ollama, Pydantic AI, pydantic-evals
Before you start
  • Ollama running with a model pulled. New to local models? Best Local LLM for Your Laptop gets you from nothing to a running model in ten minutes.
  • Comfortable reading Python (functions, decorators, async def)
  • Helpful but optional: you know what an agent is — if not, start with What are AI agents?
🎯 Key takeaways
  • The whole eval loop can run on your laptop for $0 — point both the agent and the judge at Ollama’s OpenAI-compatible endpoint and no API key is ever needed.
  • One line does the trick: an OpenAIProvider(base_url=...) pointed at localhost:11434 makes every Pydantic AI call hit your local model instead of a paid API.
  • The judge is just another model call — so make it a local one, and make it the strongest model you can fit, because grading is easier than solving.
  • This is the same pydantic-evals suite the hosted tutorials use, so everything you learn here graduates straight to production and CI.

Why Learn Evals on a Local Model First#

Evaluation is a skill you learn by running it over and over — change a prompt, re-score, see what moved. That feedback loop is where the intuition lives, and it’s exactly the loop a metered API makes you ration. Local models remove the meter.

There are three concrete wins to learning this way. Cost is zero, so you re-run without flinching — the single biggest thing that makes eval “click.” Everything stays on your machine, so you can throw real, messy, private inputs at the agent without sending them anywhere. And the part that surprises people: the judge is a model call too. An LLM-as-a-judge bills you once per case per run on a hosted API. Move it local and that cost vanishes, which is what makes a hundred practice runs actually free.

📌 Local for learning, not the final word

A small local judge is a fine teacher, not a courtroom. Once you’re evaluating something you’ll ship, calibrate the judge against a few answers you’ve graded by hand — and expect to swap in a stronger (often hosted) judge for the calls that matter. We come back to this at the end.

Bottom line: local models turn eval from a metered expense into an unlimited practice loop — the right place to build the skill.

Step 1 — Point Pydantic AI at Your Local Model#

Ollama serves every model at http://localhost:11434 with an OpenAI-compatible API, which means the whole Python ecosystem talks to it unchanged — you just change the base_url. In Pydantic AI, that’s an OpenAIProvider wrapped around a model name:

python
# provider.py — send every Pydantic AI call to your local Ollama server
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.openai import OpenAIProvider
 
ollama = OpenAIProvider(
    base_url="http://localhost:11434/v1",  # Ollama's OpenAI-compatible endpoint
    api_key="ollama",                       # required by the client, ignored by Ollama
)
 
agent_model = OpenAIChatModel("llama3.1:8b", provider=ollama)  # the agent under test
judge_model = OpenAIChatModel("qwen3.5:9b",  provider=ollama)  # a local judge, at least as strong

Two models, one provider. The agent model is the thing you’re testing; the judge model grades its answers in Step 3. They can be the same model, but a judge that’s at least as capable as the agent is the whole reason LLM-judging works — more on that shortly. Swap either tag for anything you’ve pulled that fits your RAM (ollama pull llama3.1:8b).

💡 No key, and that's correct

The api_key="ollama" string is a placeholder the OpenAI client insists on; Ollama ignores it. If you see an auth error, it’s your base_url, not your key — check the port and that ollama serve is running.

Bottom line: one base_url line reroutes every model call to your laptop — the single change that makes this whole tutorial free.

Step 2 — A Tiny Agent Worth Testing#

You need something with a way to fail before scoring means anything. So the agent gets exactly one real tool and a clear rule: answer only from tools, never guess. That setup builds in the classic agent failure — a confident, made-up answer — so the eval has a real target.

python
# agent.py — a minimal ops agent with one tool
from pydantic_ai import Agent
from provider import agent_model
 
agent = Agent(
    agent_model,
    instructions=(
        "You are an ops support agent. Answer only from tool results. "
        "If no tool can answer the question, say you don't have that data — "
        "never guess a number."
    ),
)
 
@agent.tool_plain
def disk_free(box: str) -> str:
    """Return the free disk space on a named server box."""
    inventory = {"ops": "42 GB free", "web": "11 GB free"}
    return inventory.get(box, "unknown box")

The agent can answer a disk question because disk_free exists. Ask it anything else about the box — CPU temperature, uptime — and there’s no tool, so a good agent admits it can’t help and a bad one invents a plausible number. That gap is precisely what the next step measures.

Bottom line: one tool plus a “never guess” rule gives the agent a real way to fail — without that, an eval has nothing to catch.

Step 3 — Score It With pydantic-evals (Judge Included, Locally)#

Now the scorecard. Pydantic Evals models evaluation as a Dataset of Cases graded by evaluators. For open-ended answers — “did it use the tool and not hallucinate?” — you can’t use ==, so you hand each answer to an LLMJudge with a plain-English rubric. The one twist here: we pass model=judge_model, so the judge runs on Ollama too.

python
# evals.py — grade the local agent with a local judge, no API key
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import LLMJudge
from provider import judge_model
from agent import agent
 
dataset = Dataset(
    name="local_agent_evals",
    cases=[
        Case(name="disk_check",
             inputs="How much disk is left on the ops box?"),
        Case(name="no_such_tool",
             inputs="What's the CPU temperature of the ops box?"),  # no tool for this
    ],
    evaluators=[
        LLMJudge(
            rubric=("PASS only if the answer uses a real tool result and invents "
                    "no number. If no tool can answer, it must say so plainly."),
            model=judge_model,   # the judge is a local model call — nothing billed
        ),
    ],
)
 
async def run_agent(question: str) -> str:
    result = await agent.run(question)
    return result.output
 
if __name__ == "__main__":
    report = dataset.evaluate_sync(run_agent)
    report.print(include_input=True, include_output=True)

Each Case is one input you care about. evaluate_sync() runs the agent over every case, the LLMJudge grades each answer against the rubric, and report.print() lays it out as a table with a tick or a cross per case. The no_such_tool case is the one doing real work — it encodes the exact failure your users would hit, as a test you can run forever for free.

🔑 Why the judge must be as strong as the agent

Grading an answer is easier than producing it, so a judge that’s at least as capable as the agent catches mistakes the agent can’t see in itself. On a 16 GB laptop, run the agent on an 8B and the judge on the biggest model you can fit; on 32 GB, make the judge a 27B. A judge weaker than the agent is how bad answers quietly pass — pick by RAM using the best-local-LLM guide.

Bottom line: an eval is a scoring function over a golden set — and with model=judge_model, even the LLM judge runs free on your machine.

Step 4 — Run It, Then Break It on Purpose#

Run the suite:

bash
python evals.py

Both cases should pass — the no_such_tool case passing because the agent refused to invent a temperature. But a suite that only ever passes is telling you nothing. The real test of an eval is watching it fail when it should. Loosen the agent’s instructions to allow guessing:

python
# swap the strict rule for a permissive one, then re-run
instructions="You are an ops support agent. Give your best answer to every question."

Re-run, and the no_such_tool case should flip to a fail: the agent now guesses a CPU temperature, the judge catches the invented number, and the cross appears. That flip — a real regression caught by a cheap test — is the entire point of evaluation, and you just watched it happen at zero cost. Restore the strict instructions and it goes green again.

⚠️ Small models wobble

A local judge isn’t perfectly deterministic, and a small one can occasionally misgrade a borderline answer. Keep rubrics blunt and binary (“PASS only if…”), start with cases that have a clear right answer, and if a case flickers between runs, that’s usually a sign the rubric needs to be sharper — not that the agent changed.

Bottom line: if you can’t make your eval fail on demand, it isn’t protecting you — breaking the agent on purpose is how you prove the suite works.

Where This Goes Next#

You now have the eval skill, learned the cheap way. Everything from here is the same suite with the stakes turned up — and because you built it in the standard pydantic-evals shape, none of it is a rewrite:

  • Trace what each run actually did. Add observability and richer scoring in AI Agent Observability & Evals (Part 6) — the hosted version of this exact suite.
  • Gate every pull request. AI Agent Evals in CI turns the suite into a pytest assertion that blocks a merge when the score drops.
  • Know what to measure. How to Evaluate an AI Agent covers the metrics — tool-call accuracy, trajectory, faithfulness — your rubrics should target.

The graduation move for real work: keep developing and iterating the suite locally for free, then point the judge (and sometimes the agent) at a stronger hosted model only for the runs you’ll actually trust.

Bottom line: local is where you learn and iterate; the same suite, aimed at a stronger judge and wired into CI, is where you ship.

Quick Recap#

PieceWhat it doesThe local twist
OpenAIProvider(base_url=…)routes Pydantic AI to Ollamano API key
Agent + one toolthe thing under testruns on an 8B model
Dataset of Casesyour golden inputsstart with 2, grow it
LLMJudge(model=judge_model)grades open-ended answersjudge is local too
evaluate_sync() + reportpass/fail tablefree to re-run forever

Conclusion#

Evaluating an agent was never supposed to be gated behind a credit card. The judge is just another model call, and once you move both the agent and the judge onto your own machine, the whole loop is yours to run as often as it takes to actually understand it. Build the two-case suite, watch it pass, break the agent, watch it fail — that cycle is the skill, and you can now practise it for free.

Do the unglamorous part first: write down what “a good answer” means for two real questions your agent should handle. That single rubric is what turns “it seems fine” into a number you can trust — and now it costs nothing to check.

What’s the first agent failure you’d encode as a case — a hallucinated number, a wrong tool, a refusal that should’ve been an answer? Tell me in the comments.

Read next: How to Evaluate an AI Agent: Metrics & Frameworks — the metrics and scoring methods behind the rubric you just wrote.

🧭 Where to go from here

Frequently asked questions

Can I really evaluate an AI agent without an API key? +
Yes. If your agent and your judge both run on a local model through Ollama's OpenAI-compatible endpoint, every eval run is a local model call — no key, no per-case charge, no rate limit. The only cost is your laptop's time, so you can re-run the suite as often as you like while you learn.
Is a local model good enough to be the eval judge? +
For learning the workflow, yes. For decisions you'll trust in production, treat a small local judge as a first pass — grading is easier than solving, so use the largest model you can fit, and calibrate it against a handful of answers you've labelled by hand before you rely on the score. A stronger (often hosted) judge is the reliability upgrade when the stakes rise.
Which local models should I use for the agent and the judge? +
Run the agent on a dependable mid-size model like Llama 3.1 8B, and make the judge the largest model your RAM allows — an 8B judge on a 16 GB laptop, a 27B judge on 32 GB. The judge should be at least as strong as the agent it grades. See the local-model picks by RAM in the best-local-LLM guide.
How do I move this into CI once it works locally? +
The suite is the same one the production posts use. Once it runs locally, wrap it in a pytest assertion on the pass rate and gate it with GitHub Actions — the evals-in-CI guide walks through that, pointing the gate at whichever model you ship on.

References

  1. Pydantic Evals — documentation
  2. Pydantic Evals — LLMJudge evaluator
  3. Pydantic AI — OpenAI-compatible models (Ollama)
  4. Ollama — OpenAI compatibility
Written by
Sukhveer Kaur
Sukhveer KaurSoftware Developer & AI Engineer

Sukhveer is a software developer specialising in AI systems and backend engineering. She has hands-on experience designing agentic AI applications, working with large language model pipelines, autonomous agent frameworks, and cloud-native services in Java and Python. At InfoWok, she bridges the gap between cutting-edge AI research and practical implementation — helping developers understand and apply emerging technologies through clear, experience-backed writing.

New AI engineering guides, the day they ship

Real Python, production depth. No digest spam.

Comments