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:

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 Review

The 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.

AreaSuitable for deterministic validation?Example
Order ID formatYesORD-10025
Required fieldsYesCustomer ID must exist
Currency calculationYesRefund must equal paid amount
AuthorizationYesUser must own the order
Database stateYesOrder status must be Cancelled
Tool execution statusYesAPI returned success
Response grammarSometimesRequired sections exist
Answer qualityNot completely"Is this explanation useful?"
Open-ended reasoningNo"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 Result

Building a Deterministic Validator

Suppose the business rule says that a refund can only be issued when:

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
SendEmail

A 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 Review

The 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 failureRecommended action
Invalid fieldRegenerate structured result
Wrong business stateStop operation
Authorization failureReject request
Tool failureRetry if safe
Incorrect calculationRecalculate using application code
Low-quality explanationAsk evaluator or agent to regenerate
High-risk actionHuman 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:

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

Disadvantages

Troubleshooting Verification Problems

When an agent frequently fails verification, investigate the failure layer instead of immediately changing the model.

  1. Check whether the structured output matches the expected schema.

  2. Identify which deterministic rule failed.

  3. Verify that the authoritative database or service state is correct.

  4. Check tool parameters and execution results.

  5. Determine whether the agent misunderstood the task or the validator is too restrictive.

  6. Review whether a retry caused a repeated operation.

  7. Check logs and correlation identifiers.

  8. 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.