AI agents can reason, select tools, call external services, and generate responses dynamically. That flexibility is useful, but it creates a challenge that traditional software developers are already familiar with: how do you know the result is correct?
A conventional method usually produces a predictable result for the same input. An AI agent may produce different outputs, choose different tools, or take different paths while solving the same problem.
That means production AI systems need a verification layer.
The goal is not to make AI completely deterministic. Instead, deterministic software should verify the parts of an agent's behavior that can be objectively checked.
This article demonstrates how to build a practical verification pattern in .NET using C#, structured agent results, business rules, and deterministic validators.
Why AI Agents Need Verification
Consider an order-processing agent that receives this request:
Cancel order 10025 and refund the customer.The agent may correctly understand the request and call a cancellation tool. However, several things can still go wrong:
The order may not belong to the customer.
The order may already be cancelled.
The order may not be eligible for a refund.
The refund amount may be incorrect.
The agent may claim success when the external operation failed.
A language model is not the right component to make every one of these decisions.
A better architecture separates reasoning from verification:
User Request
|
v
AI Agent
|
v
Tool / Business Operation
|
v
Deterministic Verification
|
+---- Valid ----> Response
|
+---- Invalid --> Recovery / Human ReviewThe agent can determine what should happen, while deterministic application code verifies whether the resulting state is acceptable.
Deterministic vs Non-Deterministic Checks
Not every part of an AI response can be validated using simple rules.
| Area | Suitable for deterministic validation? | Example |
|---|---|---|
| Order ID format | Yes | ORD-10025 |
| Required fields | Yes | Customer ID must exist |
| Currency calculation | Yes | Refund must equal paid amount |
| Authorization | Yes | User must own the order |
| Database state | Yes | Order status must be Cancelled |
| Tool execution status | Yes | API returned success |
| Response grammar | Sometimes | Required sections exist |
| Answer quality | Not completely | "Is this explanation useful?" |
| Open-ended reasoning | No | "Is this the best approach?" |
This distinction is important.
Use traditional software validation wherever a fact can be objectively evaluated.
A Simple Agent Result Model
Instead of allowing an agent to return an unrestricted string, define a structured result.
For example:
public sealed record OrderActionResult(
string OrderId,
string Action,
decimal RefundAmount,
string Currency,
bool OperationSucceeded);The agent can populate this structure after performing the required operation.
The application can then validate it independently.
public sealed record VerificationResult(
bool IsValid,
IReadOnlyList<string> Errors);This creates a clean boundary:
AI Output
↓
Structured Result
↓
Deterministic Validator
↓
Verification ResultBuilding a Deterministic Validator
Suppose the business rule says that a refund can only be issued when:
The operation succeeded.
The order was cancelled.
The refund amount matches the amount actually paid.
The currency matches the order currency.
The validator can implement these rules without involving an AI model.
public static class OrderActionValidator
{
public static VerificationResult Validate(
OrderActionResult result,
Order order)
{
var errors = new List<string>();
if (!result.OperationSucceeded)
{
errors.Add("The order operation did not succeed.");
}
if (order.Status != OrderStatus.Cancelled)
{
errors.Add("The order is not cancelled.");
}
if (result.RefundAmount != order.PaidAmount)
{
errors.Add("The refund amount does not match the paid amount.");
}
if (!string.Equals(
result.Currency,
order.Currency,
StringComparison.OrdinalIgnoreCase))
{
errors.Add("The refund currency does not match the order currency.");
}
return new VerificationResult(
errors.Count == 0,
errors);
}
}The validator does not need to understand the agent's reasoning.
It only checks facts.
Verifying Agent Tool Calls
Verification becomes even more important when an agent can call tools.
For example, an agent might have access to:
GetOrder
CancelOrder
CalculateRefund
IssueRefund
SendEmailA model could select the wrong tool or call tools in an unsafe sequence.
A deterministic policy can restrict the allowed sequence.
public static bool IsValidToolSequence(
IReadOnlyList<string> tools)
{
var allowed = new[]
{
"GetOrder",
"CancelOrder",
"CalculateRefund",
"IssueRefund"
};
return tools.SequenceEqual(allowed);
}In a real system, the policy would usually be more flexible than an exact sequence.
For example:
public static bool CanIssueRefund(
string orderStatus,
bool refundCalculated)
{
return orderStatus == "Cancelled"
&& refundCalculated;
}The important principle is that the model should not be the final authority for security-sensitive business rules.
Validating Structured AI Output
Structured output makes verification easier.
For example:
public sealed class CustomerResponse
{
public string Summary { get; set; } = string.Empty;
public string OrderId { get; set; } = string.Empty;
public bool ActionCompleted { get; set; }
public decimal RefundAmount { get; set; }
}The application can verify required properties:
public static bool IsValid(CustomerResponse response)
{
if (string.IsNullOrWhiteSpace(response.OrderId))
return false;
if (string.IsNullOrWhiteSpace(response.Summary))
return false;
if (response.RefundAmount < 0)
return false;
return true;
}This does not prove that the response is completely correct.
It only proves that the response satisfies the deterministic constraints defined by the application.
That distinction is critical when designing AI verification systems.
Combining AI Evaluation with Deterministic Verification
Some properties cannot be validated with traditional rules.
Consider:
"Is the answer helpful to the customer?"There is no simple if statement that can reliably answer this question.
This is where a second AI evaluator can be useful.
A layered architecture might look like this:
AI Agent
|
v
Deterministic Validation
|
+--------+--------+
| |
Failed Passed
| |
v v
Recovery AI Evaluation
|
+-------+-------+
| |
Pass Review
| |
v v
Output Human ReviewThe deterministic layer should run first because it is cheaper, more predictable, and better suited for hard business constraints.
An AI evaluator can then assess softer characteristics such as relevance, completeness, or adherence to a natural-language requirement.
A Practical Verification Pipeline
A .NET service can combine these stages:
public async Task<VerificationResult> VerifyAsync(
OrderActionResult result,
Order order,
CancellationToken cancellationToken)
{
var deterministicResult =
OrderActionValidator.Validate(result, order);
if (!deterministicResult.IsValid)
{
return deterministicResult;
}
var evaluation =
await EvaluateResponseAsync(
result,
cancellationToken);
if (!evaluation.Passed)
{
return new VerificationResult(
false,
new[]
{
"The AI evaluation did not pass."
});
}
return new VerificationResult(true, []);
}The deterministic validator acts as a gate.
Only results that satisfy objective rules proceed to the more subjective evaluation stage.
Handling Verification Failures
A failed verification should not always result in an exception.
Different failures require different actions.
| Verification failure | Recommended action |
|---|---|
| Invalid field | Regenerate structured result |
| Wrong business state | Stop operation |
| Authorization failure | Reject request |
| Tool failure | Retry if safe |
| Incorrect calculation | Recalculate using application code |
| Low-quality explanation | Ask evaluator or agent to regenerate |
| High-risk action | Human review |
This creates a recovery strategy rather than treating every failed verification as the same problem.
Verification Before and After Tool Execution
Verification can happen at multiple points.
Before Tool Execution
Check whether the requested operation is allowed.
if (!authorizationService.CanCancelOrder(userId, order))
{
return Results.Forbid();
}During Tool Execution
Validate tool parameters.
if (refundAmount <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(refundAmount));
}After Tool Execution
Verify the resulting state.
var updatedOrder = await orderRepository.GetAsync(
order.Id,
cancellationToken);
if (updatedOrder.Status != OrderStatus.Cancelled)
{
throw new InvalidOperationException(
"Order cancellation could not be verified.");
}This is much safer than trusting the model's statement:
"The order has been successfully cancelled."The application should verify the database state instead.
Designing an Agent Verification Contract
A useful production pattern is to define explicit verification levels.
public enum VerificationLevel
{
None,
Structural,
Business,
Security,
HumanReview
}An operation can then declare the minimum required verification.
For example:
public sealed record AgentOperationPolicy(
VerificationLevel RequiredLevel,
bool RequiresHumanApproval);A low-risk informational query may require only structural validation.
A financial transaction may require business validation, security validation, and human approval.
This prevents every agent operation from receiving the same verification treatment.
Best Practices
Keep Deterministic Rules Outside the Model
If a rule can be represented with code, database constraints, or authorization policies, implement it there.
Verify State, Not Just Responses
Do not trust:
"Payment completed successfully."Verify the actual payment state from the authoritative system.
Make Validation Fail Closed
For sensitive operations, an uncertain verification result should normally stop the operation rather than automatically approve it.
Use Structured Results
Structured data is easier to validate than free-form text.
Separate Evaluation from Authorization
An AI evaluator can judge response quality, but it should not replace authentication or authorization mechanisms.
Keep Verification Observable
Log:
Operation identifier
Agent identifier
Verification result
Failed rules
Tool execution status
Recovery action
Avoid logging sensitive prompts, credentials, or customer data unnecessarily.
Common Mistakes
Trusting the Agent's Final Message
An agent saying that an operation succeeded does not prove that it actually succeeded.
Always verify the authoritative state.
Using an LLM for Simple Rules
There is no reason to ask an AI model:
Is 150 equal to 150?Use deterministic application code.
Verifying Only the Final Text
The final answer may look correct even if the agent used an unauthorized tool or accessed incorrect data.
Verification should cover the workflow, not just the generated sentence.
Automatically Retrying Failed Actions
Retrying an informational request is different from retrying a payment or order operation.
Make retry behavior operation-specific.
Advantages and Disadvantages
Advantages
Reduces the risk of incorrect agent actions
Keeps business rules deterministic
Makes agent workflows easier to test
Supports safer tool execution
Improves auditability
Allows AI evaluation where deterministic rules are insufficient
Makes human escalation possible for high-risk operations
Disadvantages
Adds implementation complexity
Verification introduces additional processing
AI-based evaluation can still produce inconsistent judgments
Maintaining verification rules requires ongoing development
Poorly designed validation can reject legitimate agent outputs
Troubleshooting Verification Problems
When an agent frequently fails verification, investigate the failure layer instead of immediately changing the model.
Check whether the structured output matches the expected schema.
Identify which deterministic rule failed.
Verify that the authoritative database or service state is correct.
Check tool parameters and execution results.
Determine whether the agent misunderstood the task or the validator is too restrictive.
Review whether a retry caused a repeated operation.
Check logs and correlation identifiers.
Test the validator independently from the AI agent.
A deterministic validator should be unit-testable without requiring an AI model.
For example:
[Fact]
public void RefundAmountMustMatchPaidAmount()
{
var order = new Order
{
Status = OrderStatus.Cancelled,
PaidAmount = 100,
Currency = "USD"
};
var result = new OrderActionResult(
"ORD-10025",
"Refund",
90,
"USD",
true);
var verification =
OrderActionValidator.Validate(result, order);
Assert.False(verification.IsValid);
}This makes the most important safety rules deterministic and repeatable.
Conclusion
AI agents introduce flexibility that traditional software does not have, but that flexibility should not mean giving an AI model unrestricted authority over application behavior.
A robust .NET architecture separates reasoning, execution, and verification.
The agent can interpret the user's request and decide which tools may help. Application code should enforce authentication, authorization, business rules, data integrity, and other deterministic constraints. AI-based evaluation can then be used for qualities that are difficult to express as traditional rules.
The most reliable pattern is therefore not to make AI deterministic. Instead, surround non-deterministic AI behavior with deterministic boundaries.
That approach makes AI agents easier to test, safer to operate, and more suitable for production systems where correctness matters.

Jasen FiciPosted Sep 14, 2026, 11:54 AM
We added this to DotNetNews here: https://dotnetnews.co/archive/the-net-news-daily-issue-539/