AI Agent Evaluation, Guardrails and Human Approval Gates in Production
Make agents safe to ship by testing trajectories and answers, blocking bad inputs with guardrails and pausing risky tool calls for human approval.
Why agents need a different kind of testing
Google's ADK documentation explains the core issue: agents are probabilistic, so classic pass or fail unit tests do not fit them well. The same input can produce different but acceptable answers, and an agent can reach a right answer by a wrong path. ADK therefore evaluates two things. The trajectory is the sequence of steps and tool calls compared with an expected sequence. The final response is judged for quality, relevance and correctness.
This idea applies whichever framework you use. For a clinic appointment agent in Chennai, a correct trajectory might be check availability, then book the slot, then send a confirmation by SMS. If the agent books before checking, the final message may look perfectly polite while the calendar now holds a double booking. Testing the path catches that, and it also shows you where the agent wastes steps and tokens.
Building an evaluation set
ADK stores evaluation cases in two formats. Test files hold one session each and suit fast, unit style checks during development. Evalsets hold many, possibly multi turn, sessions and suit integration tests that run less often. Both record the user query, expected tool calls, expected intermediate responses and a reference final response. You can run them from the adk web interface, from pytest, or with the adk eval command in a build pipeline.
Two default metrics show the pattern. tool_trajectory_avg_score checks an exact match of the tool call trajectory, with a default threshold of 1.0. response_match_score measures ROUGE-1 similarity to the reference answer, with a default threshold of 0.8. ADK also offers model judged metrics, and efficiency metrics such as token usage that report values without passing or failing. Whatever tool you use, the habits below are the same.
- Collect 20 to 50 real user requests, including awkward and multilingual ones.
- Write the expected tool path and a reference answer for each.
- Add adversarial cases, such as prompt injection hidden in a document.
- Run the set on every prompt, tool or model change, and track scores over time.
Guardrails on inputs, outputs and tools
Guardrails are checks that run around the agent. In the OpenAI Agents SDK, input guardrails check the user's first input, output guardrails check the final output, and tool guardrails wrap individual function tools. When a check sets tripwire_triggered, the SDK stops the run and raises an exception such as InputGuardrailTripwireTriggered. Input guardrails run in parallel with the agent by default for speed; set run_in_parallel to False if the agent must never start, so no tokens are spent and no tools run.
The example below, adapted from the SDK docs, uses a small checking agent with a structured output type to decide whether a message asks for a refund above a set limit. If it does, the tripwire fires, the support agent stops, and the application routes the customer to a person instead. In a real system you would log the guardrail result so you can review false positives later.
Human approval gates for risky actions
Some actions should never run without a person saying yes: payments, refunds, emails to clients, production deployments. The OpenAI Agents SDK marks such a tool with needs_approval. When the model calls it, the run pauses and result.interruptions lists the pending calls. You convert the result to a RunState, call approve or reject for each item, and resume with Runner.run. The state can be serialised, so the reviewer can answer hours later from a different process.
The SDK docs add advice that applies to every framework. Keep paused state on the server and send reviewers only what they may see. Authenticate reviewers and prevent the same approval being replayed. Approval does not guarantee a tool runs exactly once after a crash, so use idempotency keys for consequential actions such as bank transfers. Store a version marker with saved state, so a pause that spans a deployment resumes with matching code.
Permissions, tracing and a production checklist
Other frameworks offer the same building blocks under different names. LangGraph uses interrupt() for approval pauses. The Claude Agent SDK combines allow and deny rules with permission modes and hooks that run before or after tool calls. Microsoft Agent Framework and the OpenAI Agents SDK both include tracing. Whatever you pick, make every run observable: log the prompt version, model, each tool call with arguments and the final answer, with personal data masked. XDQ Labs teams review a sample of traces each week alongside the evaluation scores.
- Separate read and write tools; gate every write tool that moves money or contacts people.
- Set step, time and spending limits per run.
- Treat documents, web pages and tool outputs as untrusted input.
- Version prompts and tools, and rerun the evaluation set on every change.
- Give each agent the narrowest credentials it needs.
- Evaluate both the tool trajectory and the final answer.
- Keep a versioned evaluation set and rerun it on every change.
- Guardrails can stop a run before or after the agent acts; blocking mode avoids side effects.
- Approval gates pause risky tool calls until a verified person decides.
- Use idempotency keys, tracing and narrow credentials in production.
Write ten evaluation cases for an order support agent, each with an expected tool path and reference answer, including two prompt injection attempts. Add a needs_approval gate to the refund tool and a blocking input guardrail, then run all ten cases and record which ones pass.
Check your understanding
1. What does ADK's tool_trajectory_avg_score measure?
2. Why set run_in_parallel to False on an OpenAI Agents SDK input guardrail?
3. Why use idempotency keys with approved tool calls?
From USD 49 or INR 2,999 a month. A person approves every step.