Sociomatica — Methodology

Agent Testing

A way to test AI agents so that a new model, a re-indexed knowledge base or a different vector database is validated by re-running tests that already exist — not by writing new ones every time.

Built and demonstrated on a working reference agent. The background and results are in the blog post; this page is the method itself. It's part of how we deliver AI implementation work.

The problem

Every change becomes a testing project

Agents sit on top of components that keep moving — model versions, embedding models, vector databases, chunking, documents, prompts, tools, frameworks. Each change can quietly break behaviour that worked yesterday, and when tests are coupled to exact outputs or implementation details, each change also means rewriting tests. Teams end up either freezing the agent or under-testing it. The fix is structural: decouple what an agent must do from how it's built.

The method

Seven principles

01Test the trace, not the agent

Every check reads a neutral record of one run — input, output, tool calls, retrieved context, usage, latency, errors — aligned with the OpenTelemetry GenAI conventions.

  • One small adapter per agent turns a run into a trace
  • Moving to another agent framework changes the adapter, not the tests
02Cases are data, checks are code

A test case is a few lines of YAML: input, checks, trials. The only code ever written is a new kind of check — which every case can then use.

  • Output, trajectory, retrieval, grounding, operational and judge-based checks
  • Existing evaluation metrics (Ragas, DeepEval) wrap in as one more check
03Behaviour and facts, never wording

Assert what a good result must have, not what yesterday’s result happened to say — that’s what lets a case survive a model swap or a re-index.

  • "Retrieved context contains EUR 1,800" — not "chunk 2 ranked first"
  • "Under the channel limit, links to the site" — not an output snapshot
04A contract for every swappable component

One reusable test class per interface — embedder, vector store, LLM, agent. A replacement is accepted when it honours the same contract as the original.

  • A new vector database is one fixture, not a new test suite
  • A model that can’t make valid tool calls fails in seconds, before a full run
05Baselines, not absolute thresholds

Every run produces a report; the production report is the baseline. A change ships when it’s not worse than what runs today, beyond an agreed tolerance.

  • Blocking: a passing case now fails, or a layer metric drops beyond tolerance
  • Each report records the exact model, embedder, store, prompt and corpus
06Declared non-determinism

Each case states how many trials to run and how many must pass — so model variance is a parameter, not a flaky build.

  • Safety cases hold on every trial
  • Behaviour cases may accept 2 of 3 while a model is new, then tighten
07New tests come from failures, not changes

A rejected output or a bad production trace becomes a case. Swapping a component never does.

  • The suite grows from evidence
  • Cases are never edited to make a change pass
Structure

Five layers

Each test case belongs to exactly one layer, so a change only re-runs the layers it can affect.

LayerQuestionWhat's checked
ComponentDoes each part honour its interface?Contract tests
RetrievalDoes the knowledge base return the facts a question needs?Facts and sources retrieved
BehaviourDoes the agent do the job the right way?Tool use, output properties, grounding, judge
SafetyDoes it refuse what the business must never say or do?Forbidden claims, grounding, every trial
OperationalIs it bounded in cost, latency and loop length?Steps, tokens, latency, errors
Change impact

What each change re-runs

Combined changes take the union. When in doubt, run everything — the matrix keeps routine changes cheap, it doesn't excuse skipping tests.

ChangeContractsLayers
ModelLLMBehaviour · Safety · Operational
Prompt—Behaviour · Safety
Embedding modelEmbedder · Vector storeRetrieval · Behaviour
Vector databaseVector storeRetrieval · Operational
Chunking—Retrieval · Behaviour
Knowledge base—Retrieval · Behaviour · Safety
ToolsAgentBehaviour · Safety · Operational
AI gateway routingLLM · GatewayBehaviour · Safety · Operational
FrameworkAllAll
Procedure

Every change, the same seven steps

  1. 01Classify the change, and let the impact matrix select contracts and layers
  2. 02Make the change as a diff — config, prompt, corpus or adapter wherever possible
  3. 03Run the component contracts; a failure stops here
  4. 04Run the selected layers against the production baseline, with the required trials
  5. 05Review regressions, and spot-read outputs even when everything passes
  6. 06Ship, fix and re-run, or waive with a written reason — never edit a case to pass
  7. 07Promote the new baseline, then sample production traces for new cases
Two lanes

Fast on every commit, real before every release

→

Offline lane. A deterministic stand-in model runs the full pipeline and the regression gate in under a second, with no GPU or API key. It proves the plumbing, not model quality.

→

Live lane. The same cases against the real models — local open-weight or hosted — with a separate judge model, compared to that configuration's own baseline.