传统确定性单元测试在并发、状态机幂等性、实体验证规则上存在盲区;AI 智能体擅长为自己生成的代码写测试,需转向不变量验证(Invariant Verification)框架。
软件工程师过去对"正确软件"的定义很简单:一个确定性的二元结果——预期输出。所有测试都通过了就完事。但这套范式正在崩塌:CI 流水线亮起绿灯已不再能保证软件正确。AI 生成的代码看起来语法完美、测试合规,却在语义上是错的——而且这些错误只在生产环境中才会暴露。软件工程的瓶颈已不再是写代码,而是验证代码的执行意图。
过去,传统软件依赖确定性的断言。我们写代码时已知代码路径、控制输入,并验证精确结果:
[Fact]
public void CalculateDiscount_StandardUser_ReturnsTenPercent()
{
var calculator = new DiscountCalculator();
var result = calculator.GetDiscount(UserType.Standard, orderTotal: 100);
Assert.Equal(10, result);
}
这种方式在过去运转良好,因为代码是我们自己写的,大多数 bug 来自遗漏的边界情况或小失误。但 AI 生成的代码不同——它遵循的是训练语料中的模式与用户 prompt 的引导。一个 Agent 会写出 100% 通过我们单元测试的代码,却在非功能性、隐式的系统边界上悄然违反规则:
于是我们得到了语法正确、测试通过的代码,却在架构层面不正确。
AI Agent 很擅长为它刚生成的代码编写测试。如果一个 Agent 写出了一个有缺陷的实现,它也会生成同样有缺陷的、配套的断言套件。

当测试镜像了生成引擎的假设时,单元测试就成了一台确认偏见的机器。
要治理 AI 生成的代码,我们必须将正确性的定义从输出相等(Assert.Equal)转变为系统不变量(运行时执行时的约束验证)。
在 AI 原生的工程工作流中,正确性由受限的运行时 guardrails 和架构 fitness functions 来定义。验证引擎不再测试某个函数是否返回了 10,而是持续在整个代码库的执行模型上强制执行结构性约束。借助这种方式,我们不只是检查测试结果——而是在运行时强制执行规则,并检查系统设计是否保持有效。
让我们构建一个架构验证流水线的实践实现。
不再信任 AI 生成的测试,我们将强制执行系统必须始终遵循的规则:
using NetArchTest.Rules;
using Xunit;
public class ArchitectureVerificationTests
{
[Fact]
public void DomainEntities_MustBeImmutable_AndNeverBypassedByAgents()
{
// Enforce that AI-generated code cannot introduce mutable state into the Core Domain
var result = Types.InCurrentDomain()
.That()
.ResideInNamespace("OrderSystem.Domain")
.Should()
.BeImmutable()
.GetResult();
Assert.True(result.IsSuccessful, "AI generated mutable entities in the domain layer!");
}
[Fact]
public void Handlers_MustEnforceIdempotencyDecorator()
{
// Ensure every generated Command Handler implements IIdempotentCommand
var result = Types.InCurrentDomain()
.That()
.HaveNameEndingWith("CommandHandler")
.Should()
.ImplementInterface(typeof(IIdempotentCommand))
.GetResult();
Assert.True(result.IsSuccessful, "AI generated a command handler lacking explicit idempotency execution!");
}
}
对于在生产环境中运行或后台任务中尝试修改代码或数据的 AI Agent 工作流,我们在允许其行动之前验证其意图,确保:
using Microsoft.SemanticKernel;
using Microsoft.Extensions.Logging;
public record ExecutionIntent(string TaskDescription, string TargetNamespace, string ProposedDiff);
public record VerificationResult(bool IsValid, string StructuralDivergenceReason);
public class AgentVerificationEngine
{
private readonly Kernel _kernel;
private readonly ILogger<AgentVerificationEngine> _logger;
public AgentVerificationEngine(Kernel kernel, ILogger<AgentVerificationEngine> logger)
{
_kernel = kernel;
_logger = logger;
}
public async Task<VerificationResult> VerifyAgentActionAsync(ExecutionIntent intent)
{
// Define hard system invariants that the LLM engine cannot negotiate
var verificationPrompt = """
You are an Architectural Verification Engine. Evaluate the proposed code change against the system invariants:
SYSTEM INVARIANTS:
1. No direct database access outside Infrastructure/Repositories.
2. Memory allocations on critical paths must avoid heap overhead (no boxing, use ReadOnlySpan<T> where applicable).
3. All external state modifications MUST emit an IntegrationEvent.
PROPOSED CHANGE:
Target: {{$target}}
Diff: {{$diff}}
Respond ONLY in JSON format:
{"is_valid": true|false, "reason": "Detailed failure justification"}
""";
var arguments = new KernelArguments
{
["target"] = intent.TargetNamespace,
["diff"] = intent.ProposedDiff
};
var result = await _kernel.InvokePromptAsync(verificationPrompt, arguments);
var responseJson = result.GetValue<string>();
// System parses verification evaluation deterministically
return System.Text.Json.JsonSerializer.Deserialize<VerificationResult>(responseJson)!;
}
}
将此验证流程直接部署在 Azure DevOps Pipeline 或 GitHub Actions 引擎内部,并配合 Azure Container Apps 实现隔离:

转向不变量驱动的验证架构会引入真实的工程权衡:
CI 执行延迟增加:评估结构性 AST 并执行动态 LLM 驱动的验证门禁,与简单的语法编译相比,每个 Pull Request 会增加 30-90 秒的开销。
前期建模成本高:定义系统不变量需要深厚的领域专业知识。你不能要求 AI 来编写你的系统不变量——这样做会重新引入确认偏见的循环。
过度约束的演化:过于严格的架构 fitness functions 会产生误报,阻止 Agent 或人类工程师产生的有效边界情况重构任务。
AI 并没有消除软件工程的需求——它是在抬高抽象层次。
当写代码变得毫无摩擦时,高级工程师的核心价值从语法编写转向了系统边界定义。不要再仅依赖传统的单元测试来验证 AI 生成的代码了。去构建验证引擎,强制执行不可变的架构不变量,审计非确定性输出,并保护运行时稳定性。
软件正确性不再关于通过单元测试。它关于证明你的系统无法违反其核心不变量。
你是如何改造 CI/CD 流水线来处理 AI 生成的代码的?你是依赖静态单元测试,还是在构建验证边界?欢迎在评论区分享你的想法!