前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8732
  • Meta Muse macOS 应用零日漏洞遭修复
  • 小米6天烧2000万训练开源模型MiMo,跃居开放模型榜首
  • LLM应用输入输出Guardrails实战指南
  • Claude发现libheif堆缓冲区溢出:HEIC图片供应链安全研究
  • 多模型调度与反馈闭环:基元律动CTO谈Agent持续进化
  • 阮一峰科技周刊第413期:再见了React Native
  • 用Python/ChromaDB/Gemini搭建轻量级RAG实战
  • 生产环境中降低LLM成本的七种实战方法
  • AI驱动开发反思:过度规格化反而拖累AI编程
  • AMD ROCm:AI Agent正在降低GPU编程门槛
  • 小米MiMo-V2.6-Pro登顶开源权重模型榜首,300万美元预训练
  • 四Agent并行:状态文件是保持一致性的关键
  • 长任务前何时压缩上下文:Claude Code实战经验
  • 5美元/月自建Qwen2.5 72B推理服务:vLLM+AWQ量化部署指南
  • Prompt缓存失效的根因:工作流在悄悄破坏精确前缀匹配
  • NVIDIA SoL-Pi:编码Agent的Token流量降低49%的Auto-Research框架
  • Grok 4.7 发布:更大基座、同价位,编程与 Agent 任务升级
  • vibe coding 两小时后质量崩塌的根因分析
  • 用 git 在多设备间同步 Claude Code 和 Codex 会话
  • 小米 MiMo-V2.6-Pro 开源:科研任务效率提升 10 倍
  • 评估Agent代码补丁前先清点测试面
  • 阿里云栖大会:Qwen4训练中,全模态模型新版本亮相
  • Qwen4.5后参数扩展至5-10T,Qwen4和视频模型均在训练
  • 阿里云栖大会正式发布Qwen4
  • 凌晨3点LLM路由崩溃排查:上游回收引发的级联故障
  • Hugging Face Transformers现已支持运行llama.cpp量化模型
  • Jev:按输入计费的决策模型,输出免费
  • Langflow OSS 认证 RCE 漏洞 CVE-2026-17633
  • 小米 MiMo-V2.6 开源:AA 指数最高开源模型
  • xAI发布Grok 4.7:编程强化模型,百万词元2美元起
  • Meta AI 助手 Muse 存在关键 0-day 漏洞,ClickFix 攻击可劫持
  • AWS发布Strands Harness:开源Agent框架,Token成本降28%
  • Spec-Driven 开发:摆脱 Vibe Coding 的工程化实践
  • AI 编程助手 CSS 好看但上生产就崩的根因与修复
  • Agent 诊断结果上线前如何验证:分离决策与执行
  • OpenAI 成立数学顾问组,AI 已解决逾百开放难题
  • Grok Build vs Claude Code:记忆能力实战对比测评
  • AI编码导致CI成瓶颈?我们重新设计了CI流程
  • AI Agent 在无需文字的决策上浪费大量 Token
  • Grok 4.7长时运行失败率仍高,编程Agent可靠性堪忧
  • 在自有硬件上运行前沿 AI 模型
  • 从氛围记忆到确定性自主:AI 原生基础设施设计思路
  • 用 Agent 流程开发简单 SPA 的实战经验
  • AI 生成 React UI 的真实问题:从第二页开始组件漂移
  • vLLM 深度解析:高吞吐 LLM 推理的性能瓶颈
  • xAI Grok 4.6 登陆 Amazon Bedrock
  • AWS 开源 AI 编程助手,成本比 Claude Code 低 45%
  • 生产级 AI 工作流:构建 Prompt 测试框架实战
  • Google 确认 Gemini 模型今年5月入侵三家公司
  • Grok 4.7低价发布,但基准测试大幅落后Claude和GPT-6
  • 用Docker Compose构建可复现的AI Agent评测环境
  • 已加载 51 / 8732
8.0
热点
AI SCORE
编程提效2026-09-22 11:47

评估Agent代码补丁前先清点测试面

dev.to · AI#AI Agent#代码审查#测试工程
Editor brief · 编辑速览

AI agent能修改测试文件导致CI通过≠真正修复;作者提出三清单协议(节点清单、断言清单、跳过清单)来客观评估补丁质量,防止测试面被悄然缩减。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

绿色 pytest 退出码不是分数。如果 Agent 能够编辑测试、fixtures、markers 或 skip 列表,该退出码只是与其补丁自身叙事的一致性度量。要用一份独立的 witness pack 作为依据来评分。数断言数量。把 flaky 测试记到账本里——那份账本 Agent 无法重写。

本文其余部分是一份具体的 inventory 协议。它不是模型评审。它不声称任何 gate 是完整的。它声称的是:在你讨论生产 diff 之前,就可以因为测试表面收缩而拒绝一个补丁。

绿色运行能隐藏什么

Agent 补丁以无聊的方式失败。它删掉一个失败的节点。它把一个断言包裹在 pytest.mark.skip 里。它把属性 campaign 从 200 个例子缩短到 5 个。它用一个空列表替换 fixture 文件。它把 API 延迟检查从 p99 降为单个预热请求。

这些都不需要精巧的漏洞利用。它只需要对你 CI 所视为神谕的那些文件拥有写权限。在 PR 树内部运行 pytest 的 job,无法区分一个被修复的 bug 和一个更安静的测试套件。

你需要三份 inventory,不是一个退出码。

节点 inventory。父节点与补丁上的收集到的测试 id。

断言 inventory。AST 级别的 assert 计数、属性示例预算和性能样本大小。

神谕 inventory。Fixture 字节、契约 schema,以及一份位于 Agent 写集之外的 flaky 账本。

步骤 1:构建 PR 无法编写的 witness pack

保留一个签名产物,它不签出到 Agent 可能编辑的工作空间中。Pack 是评分表面。PR 树是候选对象。

最小布局如下:

witness-pack/
  MANIFEST.sha256
  tests/                    # read-only copies used for scoring
  fixtures/
  contracts/
    http_v1.json
  properties/
    campaign.toml
  flakes/
    ledger.json

campaign.toml 是预算,不是口号。示例计数和截止日期在这里锁定,这样补丁就不能通过降低 max_examples 来"通过属性检查"。

# properties/campaign.toml
[http_handler]
max_examples = 200
deadline_ms = 4000
seed_source = "pack"   # never read from the PR

[parse_money]
max_examples = 400
deadline_ms = 6000
seed_source = "pack"

将每个文件 hash 到 MANIFEST.sha256。将 pack 存储在 scoring job 按摘要获取的 ref 或对象存储上。如果摘要不匹配,fail closed。不要回退到 PR 的 tests/。

Fixtures 作为字节进入 pack,而不是作为"请勿触碰 tests/data"的注释。如果 Agent 重写 conftest.py 使其指向一个更小的 JSON 文件,它仍然会在 PR 树上变绿。但如果评分用绝对路径挂载 pack 的 fixtures,它不会变绿。

步骤 2:清点节点和断言

收集测试两次。一次在有 witness pack 的父提交上。一次在补丁上,仍然使用相同的 pack。然后比较 PR 树本身,因为静默是在那里被编写的。

将以下标记为本地协议,而非已发布的基准。在信任这些数字之前,在你自己的仓库上运行它。

# inventory.py — proposal for a CI helper, not a shipped product
from __future__ import annotations

import ast
import json
import subprocess
from pathlib import Path

SKIP_MARKERS = {"skip", "skipif", "xfail"}

def collect_node_ids(cwd: Path) -> list[str]:
    out = subprocess.check_output(
        ["pytest", "--collect-only", "-q", "--noconftest"],
        cwd=cwd,
        text=True,
    )
    return sorted(
        line.strip() for line in out.splitlines()
        if line.strip() and not line.startswith("=")
    )

class SurfaceVisitor(ast.NodeVisitor):
    def __init__(self) -> None:
        self.asserts = 0
        self.markers = 0
        self.max_examples = []

    def visit_Assert(self, node: ast.Assert) -> None:
        self.asserts += 1
        self.generic_visit(node)

    def visit_Call(self, node: ast.Call) -> None:
        func = node.func
        name = getattr(func, "attr", None) or getattr(func, "id", None)
        if name in SKIP_MARKERS:
            self.markers += 1
        if name == "given" or name == "settings":
            for kw in node.keywords:
                if kw.arg == "max_examples" and isinstance(kw.value, ast.Constant):
                    self.max_examples.append(kw.value.value)
        self.generic_visit(node)

def scan_tree(root: Path) -> dict:
    asserts = markers = 0
    examples: list[int] = []
    files = 0
    for path in root.rglob("*.py"):
        if "test" not in path.name and "tests" not in path.parts:
            continue
        tree = ast.parse(path.read_text(encoding="utf-8"))
        v = SurfaceVisitor()
        v.visit(tree)
        asserts += v.asserts
        markers += v.markers
        examples.extend(v.max_examples)
        files += 1
    return {
        "files": files,
        "asserts": asserts,
        "skip_markers": markers,
        "min_max_examples": min(examples) if examples else None,
    }

def main() -> None:
    parent = scan_tree(Path("parent/tests"))
    patch = scan_tree(Path("pr/tests"))
    report = {
        "parent": parent,
        "patch": patch,
        "assert_delta": patch["asserts"] - parent["asserts"],
        "marker_delta": patch["skip_markers"] - parent["skip_markers"],
    }
    print(json.dumps(report, indent=2))
    if report["assert_delta"] < 0 or report["marker_delta"] > 0:
        raise SystemExit("silence detected on the PR test surface")

if __name__ == "__main__":
    main()

以下任何一项都导致 gate 失败,除非 witness pack 中有经人工审查的 waiver 文件命名了确切的节点 id:

节点 id 被删除或重命名,但账本中没有条目。

skip / skipif / xfail 计数上升。

max_examples 或性能样本大小下降。

pytest.ini、conftest.py 或 fixture hash 在 PR 中被更改。

保留断言体的重命名仍是表面变更。将其视为失败,直到 witness pack 在独立变更中更新。Agent 擅长将一个失败的测试重命名为一个通过的测试。

步骤 3:把 flaky 测试放入账本,而不是 markers

冻结 flaky 测试不等于 pytest.mark.skip。Skip markers 是可编辑的。账本是评分 runner 查阅的数据,Agent 的树不允许提交一个新的 skip。

{
  "version": 1,
  "entries": [
    {
      "node_id": "tests/test_parse.py::test_money_roundtrip",
      "first_seen": "2026-09-18",
      "expires": "2026-10-02",
      "signature": "AssertionError: cents != 0",
      "owner": "payments",
      "allowed_action": "quarantine"
    }
  ]
}

Runner 规则:

仅从 witness pack 加载 flakes/ledger.json。

Quarantine 意味着"不为此节点评分",而非"重写测试"。

如果 expires 已过,该节点回到评分集。仍然 flaky 的节点导致 job 失败。它不会自我续期。

如果 PR 向不在账本中的节点添加 skip 或 xfail,则失败。

如果 PR 编辑了账本,则失败。账本编辑是对 pack ref 的人类 PR。

signature 字段是失败形状,不是测试名。名称会变。匹配已知 flake 的 traceback 可以被 quarantine。不匹配的 traceback 是新的失败。新失败对补丁进行评分。

步骤 4:在两个 job 中离树评分

不要在同一个 checkout 中生成和评分。拆分 pipeline。

# proposal: ci-score.yml — scoring job only
name: score-agent-patch
on:
  pull_request:
jobs:
  score:
    runs-on: ubuntu-latest
    steps:
      - name: Fetch candidate source only
        run: git fetch origin "$PR_SHA" && git checkout "$PR_SHA" -- src
      - name: Fetch witness pack by digest
        run: |
          aws s3 cp "s3://oracles/witness-pack-${PACK_DIGEST}.tar" pack.tar
          echo "$PACK_SHA256  pack.tar" | sha256sum -c -
          tar -xf pack.tar
      - name: Inventory PR test surface
        run: python inventory.py
      - name: Replay pack tests against candidate src
        run: |
          PYTHONPATH=src pytest pack/tests \
            --override-ini="cache_dir=/tmp/pytest-cache" \
            -o "pythonpath=src"
      - name: Property campaign from pack budget
        run: python pack/run_campaign.py --config pack/properties/campaign.toml

候选对象可能更改 src/。它不能更改 pack/ 下的文件。如果你的 Agent runner 挂载了完整仓库,它会把测试视为可编辑的源代码。这就是 bug。评分 job 甚至不应该看到 PR 的 tests/ 目录——除非作为 inventory.py 的输入。

然后属性检查意味着:用 pack 的生成器针对候选对象的公共函数运行,使用 pack 的示例预算。Fixtures 意味着:来自 pack 的字节,以只读方式挂载。Flakes 意味着:账本查找,而非模型可以输入的 marker。

免费模型访问和免费服务器应该放在哪里

披露:本文是 MonkeyCode 产品推广的一部分。

该协议不依赖 vendor。它依赖隔离。一种实用的拆分是:在包含 src/ 和简短任务文件的工作空间中,用免费模型访问提出补丁,然后在只挂载 witness pack 和候选 src/ 的免费服务器上运行 inventory 加上 pack replay。

这是这里整个与产品相关的声明。免费模型访问用于生成。免费服务器选项用于从不将神谕作为可写文件交给 Agent 的评分 job。不要将其中任何一个视为持久性保证、配额或硬件规格。如果服务器能看到 PR 的 tests/,你就回到了对 Agent 自己叙事的评分。

通过 inventory 不等于通过 merge。它是阅读补丁的许可。

该协议不检测什么

该协议不检测保持相同 assert 计数的重言式。Agent 可以将 assert result == expected 替换为 assert True 或 result == expected,并在简单的 AST 计数下存活。加强 visitor 以拒绝其 test 为常量 true 的 Assert 节点,并对不带名称的断言 AST 进行 hash。即使这样, equivalence rewrites 仍然存在。

它不能替代 mutation testing。补丁可以保留每个节点,但如果 pack 从未调用那个函数,仍然实现了错误的函数。用触及你关心的公共表面的契约和属性扩展 pack。不要将"inventory 是稳定的"与"行为是正确的"混为一谈。

它对非 hermetic 测试很弱。如果 fixtures 调用网络,账本将充满环境噪音,然后过期为假失败。网络、时钟和 RNG 应放在 pack 控制的 fake 后面。如果无法将测试 hermetic 化,它就不应该在评分集中。

性能测试是一个特殊的静默目标。将 duration、样本大小和百分位断言作为一等 inventory 字段来监控。一个将 30 秒 p99 检查降为单个请求的补丁看起来是绿色的,但仍然会交付回归。用数 assert 的方式一样数这些数字。

谁不应该使用它

不要将其作为安全或金钱路径审查的替代品。Inventory gate 是一个过滤器。它不是审计。

如果团队无法维护 pack ref,不要使用它。过时的 pack 评分错误的产品。跟踪 PR 1:1 的 pack 只是带额外步骤的 PR 树。

不要让同一个 bot 在一次变更中更新 src/、witness pack 和 flake ledger。那会 collapse split。Ledger 和 pack 更新是人工编写的,否则就不是 freeze。

如果你已经在 CODEOWNERS 中禁止测试编辑,并用一个实际阻止 merge 的 required review 来强制执行,则跳过额外的 job。Inventory 仍然有帮助,但第一个要修复的 bug 是写访问权限,不是 pytest 标志。

核心结论不变

评分 pack。清点表面。将 flakes 保留为数据。如果你已经将生成与评分拆分,则在 witness pack 从不落入 Agent checkout 的地方运行 inventory job。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
小米 MiMo-V2.6-Pro 开源:科研任务效率提升 10 倍
下一篇
阿里云栖大会:Qwen4训练中,全模态模型新版本亮相