tinyeval
Test your Elixir app's AI calls the way you test the rest of it: write test cases, run mix tinyeval, and see which replies pass.
Install
Add it to mix.exs, then run mix deps.get:
def deps do
[{:tinyeval, "~> 0.11", only: [:dev, :test], runtime: false}]
end
Write an eval
evals/support.sh lists the test cases. Its worker line starts your app once and sends it every input:
worker mix run --no-start evals/worker.exs
test_case "refund after the window" "Can I still return my shoes? They arrived 40 days ago."
contains "30 days"
evals/worker.exs answers each input:
Tinyeval.worker(fn input ->
if System.get_env("ANTHROPIC_API_KEY") in [nil, ""],
do: raise(Tinyeval.CouldntRun, "ANTHROPIC_API_KEY is not set")
MyApp.Support.answer(input)
end)
Replies go to stdout, so Tinyeval.worker/1 sends everything else your app prints, Logger included, to stderr. It does this first and then starts your app. That's why the worker runs mix run --no-start: with a plain mix run, your app's start-up logs would end up in the first reply.
Run it
mix tinyeval
Options pass through, such as mix tinyeval -n 3 -k refund. mix tinyeval -h lists them. It compiles your project first, so the workers have nothing to compile. Press Ctrl-C twice to stop it.
Couldn't run
Raise Tinyeval.CouldntRun when the AI call itself failed: no key, a 401, a 429, a 5xx, a timeout. tinyeval then counts the run apart from the failures, and still exits 1. Any other error becomes the reply, so the eval fails, and its stack trace goes to stderr.
Elixir has no official Anthropic or OpenAI SDK, so Tinyeval.CouldntRun is the only error the worker reads this way. With Req, map the responses yourself:
case Req.post(req, json: request) do
{:ok, %{status: 200, body: body}} -> reply_text(body)
{:ok, %{status: status}} when status in [401, 429] or status >= 500 ->
raise Tinyeval.CouldntRun, "anthropic: #{status}"
# A 400 comes from the request your app built, so it's graded.
{:ok, %{status: status, body: body}} -> "error: #{status} #{inspect(body)}"
{:error, exception} -> raise Tinyeval.CouldntRun, Exception.message(exception)
end
Needs bash
tinyeval is a bash script. It needs bash 3.2 or later, which macOS and Linux have. On Windows, install Git for Windows.
Updating
mix deps.update tinyeval
Dependabot and Renovate see new versions in mix.lock and open the pull request for you. A repo that commits its own ./tinyeval keeps running that file: delete it to run this package's.
Links
- tinyeval.com
- Writing evals: every grading line, the judge and the options
- elixir-llm-evals: a Req app with its evals