演进式架构通常依靠 fitness functions 持续检查系统是否仍满足关键约束。确定性规则非常适合验证依赖方向、接口数量、构建结果、响应时间等硬指标,但架构治理还有一类更难自动化的问题:模块边界是否仍然清晰,语义契约是否发生漂移,ADR 中的前提是否已经失效。
这正是 Agentic Fitness Functions 的切入点。它把 AI agent 与版本化 rubric 结合起来,让架构意图也能进入持续评估流程。重点不在于让模型替代所有规则,而是让模型处理需要上下文、解释和判断的检查,并通过校准反馈把判断逐渐变得可控。
确定性规则覆盖不到的区域
传统 fitness function 可以写成明确的断言:
if dependency(service_a, database_layer):
fail("service_a must not depend directly on database_layer")
这类规则的优势是结果稳定、执行成本低、容易阻断流水线。但它需要预先知道“什么是违规”。一旦问题涉及设计意图,单纯的静态规则就会变得笨重。
例如,下面几种情况很难只靠依赖图判断:
- 一个公共模块虽然没有新增依赖,但已经承载了多个业务领域的语义,边界正在变形。
- API 字段名称仍然兼容,但字段含义已经与原来的领域契约不同。
- 某条 ADR 仍然通过测试,但它依赖的流量规模、团队边界或基础设施假设已经改变。
- 一个模块表面上遵循分层结构,实际却通过事件、配置或共享数据库绕开了边界。
Agentic fitness function 可以读取代码、配置、ADR、接口文档和变更记录,再根据一份明确的 rubric 生成判断依据。它的价值是补充“规则无法完整表达的架构问题”,而不是把所有架构检查都交给一个不可解释的模型。
从“让模型看看代码”变成版本化评估
没有 rubric 的 agent 审查很容易变成风格偏好。不同时间运行相同检查,可能得到不同结论;团队也无法判断评分变化来自代码变化,还是来自提示词变化。
更稳妥的做法是把评估协议当作代码管理:
- 为每个 fitness function 设置唯一名称和版本号。
- 明确检查范围,例如某个目录、某组 ADR 或某个 API 契约。
- 定义评分维度、通过阈值和证据要求。
- 要求 agent 输出结构化结果,而不是只有一段自然语言评论。
- 保存输入摘要、rubric 版本、模型版本和人工复核结果。
一份可以这样实践的 rubric 如下。它是示例配置,实际项目需要根据自己的边界定义修改:
name: boundary-fidelity
version: 1
scope:
paths:
- services/orders
- services/payments
documents:
- docs/architecture/*.md
criteria:
- id: ownership
description: Each module exposes behavior owned by one business capability.
weight: 0.4
- id: dependency-direction
description: Dependencies point through published ports rather than internal details.
weight: 0.3
- id: semantic-stability
description: Public names and events preserve the meaning documented by the contract.
weight: 0.3
threshold: 0.8
required_evidence: 2
version 很重要。修改标准后,新旧结果不能直接混为一谈;否则团队会把“评估协议变了”误判成“架构退化了”。
一个可运行的最小评估器
下面的 Python 示例不调用外部模型,而是用一个可替换的 agent 函数模拟模型返回结果。这样可以直接运行,先验证数据结构、阈值和流水线行为,再接入实际的 LLM SDK。示例假设 agent 已经根据代码和文档完成分析,并返回 JSON 兼容对象。
from dataclasses import dataclass
from typing import Callable, Dict, List
@dataclass
class Criterion:
id: str
weight: float
description: str
RUBRIC_VERSION = "boundary-fidelity@1"
THRESHOLD = 0.8
REQUIRED_EVIDENCE = 2
CRITERIA = [
Criterion("ownership", 0.4, "Each module belongs to one business capability."),
Criterion("dependency-direction", 0.3, "Dependencies use published ports."),
Criterion("semantic-stability", 0.3, "Public contracts preserve their documented meaning."),
]
def evaluate(
repository_snapshot: str,
agent: Callable[[str], Dict],
) -> Dict:
prompt = f"""
You are an architecture review agent.
Rubric: {RUBRIC_VERSION}
Evaluate the repository snapshot against these criteria:
{chr(10).join(f"- {c.id}: {c.description}" for c in CRITERIA)}
Return JSON with:
- scores: criterion id -> number from 0.0 to 1.0
- evidence: at least two concrete file or document references
- risks: short explanations
- confidence: number from 0.0 to 1.0
Repository snapshot:
{repository_snapshot}
"""
result = agent(prompt)
scores = result.get("scores", {})
evidence = result.get("evidence", [])
weighted_score = sum(
scores.get(criterion.id, 0.0) * criterion.weight
for criterion in CRITERIA
)
passed = weighted_score >= THRESHOLD and len(evidence) >= REQUIRED_EVIDENCE
return {
"rubric": RUBRIC_VERSION,
"score": round(weighted_score, 3),
"threshold": THRESHOLD,
"evidence_count": len(evidence),
"passed": passed,
"agent_result": result,
}
def demo_agent(prompt: str) -> Dict:
# Replace this function with an LLM API call in a real pipeline.
return {
"scores": {
"ownership": 0.9,
"dependency-direction": 0.7,
"semantic-stability": 0.8,
},
"evidence": [
"services/orders/application.py",
"docs/architecture/orders-boundary.md",
],
"risks": ["payments adapter is imported by an internal orders module"],
"confidence": 0.82,
}
if __name__ == "__main__":
snapshot = "services/orders/application.py\ndocs/architecture/orders-boundary.md"
report = evaluate(snapshot, demo_agent)
print(report)
raise SystemExit(0 if report["passed"] else 1)
运行方式:
python3 agentic_fitness.py
接入真实 agent 时,重点是保持输出协议稳定。可以把 demo_agent 替换为调用模型的函数,但仍然要求它返回 scores、evidence、risks 和 confidence。在 CI 中,建议把“低分阻断”和“低置信度转人工复核”分开处理:低分意味着可能违反架构意图,低置信度意味着评估本身还不够可靠。
三类值得持续观察的信号
边界保真度
边界保真度关注代码组织是否仍然表达原有的架构边界。agent 可以将目录结构、依赖关系、公开端口、事件定义和 ADR 放在一起分析,寻找“形式上合规、语义上越界”的变化。
输出必须引用具体证据,例如文件路径、符号名、接口名或 ADR 段落。没有证据的“边界似乎变模糊了”不适合作为流水线反馈。
语义契约漂移
契约漂移不一定表现为字段删除或类型变化。字段仍存在,但业务含义改变,同样会破坏调用方的假设。评估时可以比较接口定义、事件文档、示例 payload、消费者代码和近期变更说明。
这类检查尤其需要版本化语义标准。团队应记录什么算“兼容”、什么算“语义变化”,并为争议案例保留人工裁决结果。
过时的 ADR 假设
ADR 记录的是决策及其上下文,不是永久真理。agent 可以检查 ADR 中的前提是否仍出现在系统现实里,例如流量规模、数据一致性要求、团队所有权或基础设施能力。
不过,agent 只能提出“假设可能失效”的信号。是否废弃或修订 ADR,仍应由负责该领域的工程师确认。架构决策的责任不能通过自动评分转移给模型。
让反馈循环真正可用
Agentic fitness function 的难点通常不是生成第一份报告,而是控制噪声。可以建立一条渐进式反馈路径:
- 在报告模式运行,只记录评分、证据和人工结论。
- 收集误报、漏报和争议案例,调整 rubric 与上下文输入。
- 对高置信度、低评分的问题设置非阻断告警。
- 当结果稳定后,只对少数高价值检查启用流水线阻断。
- 定期回顾 rubric 版本、模型版本和历史评分,确认反馈仍与架构目标一致。
校准不能只看平均分。更有用的指标包括人工接受率、误报率、相同变更的评分稳定性、从告警到修复的时间,以及 agent 是否能持续给出可验证证据。
采用清单
- 先用确定性规则覆盖能精确表达的硬约束。
- 为每个 agentic fitness function 定义清晰范围和版本化 rubric。
- 强制输出证据、风险、评分和置信度。
- 把代码、ADR、契约和变更记录作为上下文来源,而不是只发送单个文件。
- 保存人工裁决,持续校准 rubric。
- 低置信度结果进入人工复核,不要直接阻断发布。
- 不让模型独立决定架构决策的废弃、接受或责任归属。
Agentic fitness functions 的合理定位,是架构治理中的一层持续观察能力。它们帮助团队发现确定性规则难以表达的意图偏移,并用版本化标准把判断过程变得可追踪。只有当规则、证据、人工复核和反馈循环同时存在时,AI 评估才会从一次性的代码评论,变成可以长期依赖的架构信号。