Guides

AI Agent Evaluation in 2026: Task Completion, Tool Trajectory, Multi-Turn Quality, and Persona Simulation with Real Code

AI agent evaluation in 2026, step by step: score task completion, tool trajectory, multi-turn coherence and safety, then run persona simulations in Python.

· Updated
· 9 min read
agents evaluations agent-evaluation tool-trajectory persona-simulation multi-turn
AI Agent Evaluation 2026: task completion, tool trajectory, multi-turn quality, and persona simulation
Table of Contents

TL;DR for evaluating AI agents

AI agent evaluation is the practice of scoring an agent on the whole run: whether it finished the user’s task, called the right tools with the right arguments, stayed coherent across turns, and stayed safe. The table maps each dimension to where its check runs, from per-step tool grading to live production monitoring.

DimensionWhat it measuresWhere it runs
Task completionDid the agent reach the user goal end-to-endTrajectory + session scorer
Tool trajectoryRight tool, right arguments, right order, graceful recoveryPer-step LLM-as-judge
Response qualityFaithfulness, instruction adherence, toneFinal-turn evaluator
Multi-turn coherenceNo contradictions, state retained, clean session closeWhole-session evaluator
Persona simulationSynthetic users (impatient, ambiguous, adversarial) before launchfi.simulate.TestRunner
Safety + injectionToxicity, prompt injection, PII leakageInline guardrails + offline checks
Production monitoringLive scoring on every real sessionObserve continuous eval tasks

Why AI agent evaluation looks nothing like LLM evaluation

A 2024 evaluator scored input-output pairs: you handed it a prompt and a completion, and it returned a faithfulness number. A 2026 agent evaluator scores a trajectory. The agent receives a goal, plans, calls tools, reads results, replans, calls more tools, talks to the user, gets corrected, calls more tools, finishes (or fails). The thing you have to score is the whole graph, not one node.

Flow diagram of agent evaluation: persona simulation drives an agent run of goal, tool call, tool result and reply scored step by step, a session score set by the worst step, and production traces that become new personas.

That changes the failure modes you care about:

  • The agent picks the wrong tool. The final response sounds fine.
  • The agent passes the right tool name but wrong arguments. The response sounds fine.
  • The agent picks the right tool, gets an error, ignores the error, hallucinates. The response sounds fine.
  • The agent answers turn 1 confidently and turn 4 contradicts itself.
  • The agent passes every static test and falls over on a user who never finishes a sentence.

None of these surface on single-output scoring. All of them are routine in production traces. The 2026 stack splits agent evaluation into three layers:

  1. Trajectory-level checks that score each tool call as it happens.
  2. Session-level checks that score the whole multi-turn run after it closes.
  3. Persona simulation that runs synthetic users against the agent before any of this hits production.

This post walks each layer with working code against the Future AGI SDK and the traceAI instrumentation (Apache-2.0). Install the SDK with pip install agent-learning-kit; the code imports from fi.evals and fi.simulate. The persona simulation runs locally with no API key.

Five AI agent evaluation metrics for every run

1. Task completion

Did the agent finish the goal? The check is whether the user goal got done, however fluent or confident the reply sounded. This is the only metric users feel. It is also the hardest to score automatically because the ground truth is the user’s intent, which the agent does not always have access to.

Two ways to score it:

  • Reference-based, when you have a known-good expected outcome (a returned record, a created file, a final state). Compare the final state to the expected state.
  • Reference-free, when you only have the trajectory. Use an LLM-as-judge with the user goal and the trajectory as input, output a completion verdict or score with a written rationale.
from fi.evals import evaluate

trajectory_text = "User: book a flight from SFO to JFK for tomorrow morning under $400. Agent: calls search_flights(origin='SFO', dest='JFK', date='2026-12-15', max_price=400). Tool returns 3 options. Agent: presents the cheapest. User: confirms. Agent: calls book_flight(flight_id='UA-501'). Tool returns confirmation_id=ABC123. Agent: returns 'Booked, confirmation ABC123'."

result = evaluate("task_completion", input="book a flight from SFO to JFK for tomorrow morning under $400", output=trajectory_text, model="turing_flash")

print(result.score)
print(result.reason)

Cloud judge latency: turing_flash runs in roughly 1-2s, fast enough to gate replies in many flows. turing_small lands around 2-3s, turing_large around 3-5s for higher-stakes reviews. Every cloud template call needs FI_API_KEY and FI_SECRET_KEY in your environment, and traceAI reads the same two keys.

2. Tool trajectory

Tool trajectory is four checks rolled into one:

  • Tool selection. Did the agent call the right tool for the step? (Correct API, correct level of abstraction.)
  • Argument fidelity. Did the arguments match the user goal (right city codes, right date, right max price)?
  • Order. Did the agent perform dependent calls in the right order (search before book, not book before search)?
  • Recovery. When a tool returned an error, did the agent recover (retry with corrected args, ask the user, fall back to another tool) instead of confabulating?

Each step in the trajectory gets its own score. The session score is the worst-step score, not the mean. Public benchmarks formalize these exact checks: τ-bench runs multi-turn tool agents against a simulated user, and BFCL grades function calling for tool selection and argument correctness. They set the floor; your private trajectory set gates production.

from fi.evals import evaluate

# Score one tool call in the trajectory.
step = {
    "user_goal": "book a flight from SFO to JFK for tomorrow morning under $400",
    "prior_state": "no flights searched yet",
    "tool_call": {
        "name": "search_flights",
        "arguments": {
            "origin": "SFO",
            "dest": "JFK",
            "date": "2026-12-15",
            "max_price": 400,
        },
    },
}

trajectory_score = evaluate(
    "evaluate_function_calling",
    input=step["user_goal"] + "\nPrior state: " + step["prior_state"],
    output=str(step["tool_call"]),
    model="turing_small",
)

task_completion, evaluate_function_calling, context_adherence, conversation_coherence, toxicity, and prompt_injection are built-in cloud templates you call by name with a Turing model. The cloud evals reference lists the cloud templates with their required inputs, and evaluate_function_calling takes input and output. Local metrics such as function_call_accuracy and trajectory_score run with no API key.

3. Response quality

The user-facing turn is still scored, but now in context of the trajectory. Three checks apply:

  • Faithfulness. Does the response only state things supported by the tool returns and prior context? No fabricated record IDs, no fake confirmation numbers, no invented prices.
  • Prompt adherence. Did the response follow the system prompt’s rules (format, language, banned topics)?
  • Tone. Does it match the persona the system prompt called for?
faithfulness_result = evaluate(
    "context_adherence",
    output="Booked, confirmation ABC123.",
    context="Tool search_flights returned 3 options. Tool book_flight returned confirmation_id=ABC123.",
    model="turing_small",
)

If faithfulness_result.score is below your threshold, that turn is a failure regardless of how good the rest of the run looked. Context Adherence returns a 0 to 1 score with a plain-language reason, so the unsupported claim is easy to find.

4. Multi-turn coherence

Run the whole session through a single coherence judge. Three things to check:

  • No contradiction. Did any later turn contradict an earlier one?
  • State retention. Does the agent remember information shared earlier (the user’s name, the search parameters, the prior tool result)?
  • Clean close. Did the agent end the session intentionally (not abandon mid-task or loop)?
session_text = """
User: I need to book a flight from SFO to JFK for tomorrow morning, under $400.
Agent: Looking... here are 3 options under $400 leaving SFO tomorrow.
User: Pick the cheapest non-stop.
Agent: Booked UA-501, confirmation ABC123, departs 7:15 AM.
User: Wait, did you check seat availability for two passengers?
Agent: I only booked one seat. Should I add another passenger?
User: Yes, same row.
Agent: Done, both seats added, total $716.
"""

coherence = evaluate("conversation_coherence", conversation=session_text, model="turing_small")

5. Safety

Three categories you do not want to skip:

  • Toxicity. Score every final-turn response (cheap) and every agent message in adversarial persona runs (essential).
  • Prompt-injection resistance. Run a persona that explicitly tries to override the system prompt. Score whether the agent leaked instructions or executed the injected request.
  • PII leakage. Score whether the agent surfaced PII it should have redacted, even when retrieval served the unredacted version.
toxicity = evaluate("toxicity", output="Booked, confirmation ABC123.", model="turing_flash")

Inline-gate the response before it ships if toxicity fails. Run prompt_injection on each user message too: it reads the input and returns Fail when it detects an injection attempt, the check the adversarial persona below needs.

Code checks, LLM judges, and human review

Every check above needs a grader, and the grader decides cost and trust. Code-based graders such as exact match, regex, and JSON schema checks are deterministic and cheap, so use them wherever a right answer exists, like the tool name and arguments in a booking call. LLM-as-a-judge graders cover what code cannot: whether a reply finished the task, stayed coherent, or stuck to the tool returns.

Human review keeps the judges honest. Send a sample of judged sessions to annotators, compare their labels with the judge’s verdicts, and tighten the rubric where they disagree. Future AGI supports all three: Code Eval, LLM-as-Judge, and Agent Evaluator eval types, plus annotation queues that collect human scores and track annotator agreement.

Persona-driven agent simulation with fi.simulate

Persona simulation is one of the most useful agent evaluation workflows. Before you ship a release, you script a set of synthetic users with concrete goals and edge behaviors, run the agent end-to-end against each one, and score every session.

Future AGI simulation scenario builder for a support agent showing the conversation branch graph with per node prompts, the persona and situation template, and generated scenarios listing persona, situation, outcome and conversation_branch columns

The pattern:

import asyncio
from fi.evals import evaluate
from fi.simulate import Persona, Scenario, TestRunner, AgentInput, AgentResponse

def my_agent(agent_input: AgentInput) -> AgentResponse:
    # Stub: call your real agent here.
    last_user_msg = agent_input.messages[-1]["content"] if agent_input.messages else ""
    return AgentResponse(content=f"echo: {last_user_msg}")

scenario = Scenario(name="flight-booking-personas", dataset=[
    Persona(persona={"name": "Hurried business traveler"}, situation="Impatient. SFO to JFK tomorrow morning, under $400.", outcome="Flight booked."),
    Persona(persona={"name": "Ambiguous user"}, situation="Wants the East Coast next week, nothing more.", outcome="One trip chosen."),
    Persona(persona={"name": "Injection attempt"}, situation="Asks the agent to ignore previous instructions.", outcome="Agent refuses."),
    Persona(persona={"name": "Multilingual switch"}, situation="Switches from English to Spanish at turn 2.", outcome="Agent answers in Spanish."),
])

report = asyncio.run(
    TestRunner().run_test(agent_callback=my_agent, scenario=scenario, max_turns=8)
)

for case in report.results:
    coherence = evaluate("conversation_coherence", conversation=case.transcript, model="turing_small")
    print(case.persona.persona["name"], coherence.score, coherence.reason)

report.results holds one entry per persona with the full transcript, the message list, and any tool calls the agent made. Score each transcript with the same evaluators you run offline, then wire the script into CI so a release fails when a persona’s score drops below your threshold.

Personas show whether an agent that passes the test suite holds up against real user behavior. Common persona classes that catch real failures:

  • Impatient. Refuses to provide all parameters in turn 1.
  • Ambiguous. Goals require clarification.
  • Adversarial. Prompt injection, system-prompt extraction, off-topic pivots.
  • Multi-language. Code-switches mid-session.
  • Error-prone tool environment. The simulator returns tool errors on purpose, the agent must recover.
  • Reversal. User changes their mind at turn 4 and expects the agent to undo work.

Treat personas as a dataset that grows from production. Every odd real session you find in your Observe traces becomes a new persona for the next regression run. Future AGI Simulation closes that loop: a production trace you replay becomes a new test case.

Production monitoring with traceAI and Observe

Offline evals catch regressions on a fixed dataset before release. Online evals score live production traffic and catch the long tail of behaviors you never wrote a test for. You want both, and you want them connected so a failure found online becomes an offline test case.

Instrument the agent with traceAI, the Apache-2.0 tracing library. One register(...) call sets up the tracer provider, and a framework instrumentor then emits OpenTelemetry spans for every LLM call, tool call, and agent step. Those spans follow the OpenTelemetry Semantic Conventions for GenAI, so any OTel-compatible backend can read them.

Future AGI tracing view showing a research_orchestrator trace tree with a vendor_lookup span in ERROR status, the agent graph, and an attributes panel listing gen_ai.span.kind set to TOOL and gen_ai.trace.source set to traceai

# pip install fi-instrumentation-otel traceAI-openai
from fi_instrumentation import register
from fi_instrumentation.fi_types import ProjectType
from traceai_openai import OpenAIInstrumentor

tracer_provider = register(project_name="flight-agent-prod", project_type=ProjectType.OBSERVE)
OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)

Once spans flow, Observe does three things:

  • Live trace view. Every session, every tool call, every score, in chronological order.
  • Continuous eval tasks. A continuous task scores new spans as they arrive with the evals you attach, and results show on each span and can trigger alerts.
  • Replay into simulation. A failing production trace you replay in Simulation becomes a new test case, so production failures start feeding the eval suite.

Where this guide fits

This is the hands-on code path for trajectory scoring, persona simulation, and production gating, and one of three companion reads in this cluster. For the full side-by-side of the platforms that implement these checks, see agent evaluation frameworks in 2026 compared. For the methodology behind the six dimensions and the CI gate, see the definitive guide to agent evaluation. For scoring conversations that span many turns, see the multi-turn LLM evaluation guide.

What to do this week

If you have an agent in production but no trajectory evaluation:

  1. Instrument the agent with traceAI. One register(...) call plus your framework’s instrumentor.
  2. Open the traces in Observe and attach a continuous eval task.
  3. Pick three evaluators to start: task_completion, evaluate_function_calling, context_adherence. Score 100 recent production sessions.
  4. Pick two personas (one ambiguous, one adversarial). Run them through fi.simulate.TestRunner. Use the failing sessions to expand your evaluator thresholds.
  5. Add the personas to CI. Block release on a persona regression.

Those five steps cover every failure from the opening list: the wrong tool, the bad argument, the ignored error, the turn-4 contradiction, and the user who never finishes a sentence. Each one now has a score, a persona that reproduces it, and a CI gate that stops it from shipping twice.

Clone agent-learning-kit on GitHub and run your first persona sweep against your own agent.

Sources

Frequently Asked Questions

What is AI agent evaluation?

Agent evaluation measures whether an autonomous agent completes the user's task, picks the right tools with correct arguments, and stays coherent and safe across turns. It scores the whole trajectory of model outputs and tool calls, not one response, then repeats those checks on live traffic after launch.

What are the main AI agent evaluation metrics?

The core agent evaluation metrics are task completion, tool selection and argument accuracy, faithfulness to tool returns, conversation coherence, and safety checks such as toxicity and prompt injection. Score tool steps one by one and treat the worst step as the session score, because a mean hides the single bad call.

How do you write evals for AI agents?

Write evals for AI agents by turning each failure you care about into a scored check, using code for exact answers and an LLM judge for judgment calls. Start with task completion, tool selection, and faithfulness on 100 recent sessions, then add a persona for each new failure you find.

How do you test AI agents before production?

Test AI agents before production with persona simulation, where synthetic users with set goals and styles hold full conversations with your agent and every transcript gets scored. In Future AGI, fi.simulate runs these chats locally from Python, and the Simulation product runs chat and voice tests from the dashboard.

Which open-source agent evaluation library can I start with?

Future AGI's agent-learning-kit is an Apache-2.0 Python library for agent evaluation, simulation, and optimization that you install with pip install agent-learning-kit. Its quickstart runs offline with no API key, and traceAI, also Apache-2.0, adds OpenTelemetry tracing so production agent runs can be scored in Observe.

How is agent evaluation different from LLM evaluation?

LLM evaluation scores a single input and output pair, while agent evaluation scores the whole trajectory of plans, tool calls, tool returns, and replies across many turns. An agent can pass a faithfulness check on its final reply and still fail because it called the wrong tool or contradicted itself three turns earlier.
Related Articles
View all