用 Agentic Fitness Functions 守护架构意图:把演进式架构治理变成持续反馈

2026-08-17 30 预计阅读时间: 1 分钟
来源: infoq.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:12 分钟

演进式架构通常依靠 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 替换为调用模型的函数,但仍然要求它返回 scoresevidencerisksconfidence。在 CI 中,建议把“低分阻断”和“低置信度转人工复核”分开处理:低分意味着可能违反架构意图,低置信度意味着评估本身还不够可靠。

三类值得持续观察的信号

边界保真度

边界保真度关注代码组织是否仍然表达原有的架构边界。agent 可以将目录结构、依赖关系、公开端口、事件定义和 ADR 放在一起分析,寻找“形式上合规、语义上越界”的变化。

输出必须引用具体证据,例如文件路径、符号名、接口名或 ADR 段落。没有证据的“边界似乎变模糊了”不适合作为流水线反馈。

语义契约漂移

契约漂移不一定表现为字段删除或类型变化。字段仍存在,但业务含义改变,同样会破坏调用方的假设。评估时可以比较接口定义、事件文档、示例 payload、消费者代码和近期变更说明。

这类检查尤其需要版本化语义标准。团队应记录什么算“兼容”、什么算“语义变化”,并为争议案例保留人工裁决结果。

过时的 ADR 假设

ADR 记录的是决策及其上下文,不是永久真理。agent 可以检查 ADR 中的前提是否仍出现在系统现实里,例如流量规模、数据一致性要求、团队所有权或基础设施能力。

不过,agent 只能提出“假设可能失效”的信号。是否废弃或修订 ADR,仍应由负责该领域的工程师确认。架构决策的责任不能通过自动评分转移给模型。

让反馈循环真正可用

Agentic fitness function 的难点通常不是生成第一份报告,而是控制噪声。可以建立一条渐进式反馈路径:

  1. 在报告模式运行,只记录评分、证据和人工结论。
  2. 收集误报、漏报和争议案例,调整 rubric 与上下文输入。
  3. 对高置信度、低评分的问题设置非阻断告警。
  4. 当结果稳定后,只对少数高价值检查启用流水线阻断。
  5. 定期回顾 rubric 版本、模型版本和历史评分,确认反馈仍与架构目标一致。

校准不能只看平均分。更有用的指标包括人工接受率、误报率、相同变更的评分稳定性、从告警到修复的时间,以及 agent 是否能持续给出可验证证据。

采用清单

  • 先用确定性规则覆盖能精确表达的硬约束。
  • 为每个 agentic fitness function 定义清晰范围和版本化 rubric。
  • 强制输出证据、风险、评分和置信度。
  • 把代码、ADR、契约和变更记录作为上下文来源,而不是只发送单个文件。
  • 保存人工裁决,持续校准 rubric。
  • 低置信度结果进入人工复核,不要直接阻断发布。
  • 不让模型独立决定架构决策的废弃、接受或责任归属。

Agentic fitness functions 的合理定位,是架构治理中的一层持续观察能力。它们帮助团队发现确定性规则难以表达的意图偏移,并用版本化标准把判断过程变得可追踪。只有当规则、证据、人工复核和反馈循环同时存在时,AI 评估才会从一次性的代码评论,变成可以长期依赖的架构信号。


相关推荐