Ponytail 的走红并不是因为它增加了一套复杂的代码框架,而是因为它提供了一组指令文件,让编码代理在动手前先控制范围、复用现有能力,避免把简单任务扩展成大型工程。项目在九天内获得超过 44,000 个 GitHub stars,但它最醒目的数字也很快遇到了问题:最初宣称代码量减少 80% 至 94%,使用的 baseline 并不能代表一次真实的代理开发过程。
一位贡献者指出这一点后,维护者重新设计了基准测试,让代理真正执行任务,并公开了更低、但更可信的 54% 数字。这个过程比原始成绩更值得工程团队关注:对 agent skill 来说,测量方法本身就是产品的一部分。
Agent Skill 的价值不在“写更多”
Ponytail 是一个以 instruction files 为主的单作者仓库,而不是传统意义上的代码库。它改变的是代理的决策顺序,例如:
- 先检查仓库中是否已有组件、脚本或配置。
- 先确认需求边界,再决定是否创建新文件。
- 优先使用现有库和项目约定。
- 把“能运行”与“值得引入新抽象”区分开。
- 在提交前检查是否产生了未被需求要求的功能。
这类规则针对的是 coding agent 常见的过度实现问题。代理通常擅长生成代码,却不一定擅长判断哪些代码根本不需要生成。一个看似简单的需求,可能被扩展为新的服务层、重复的工具函数、额外的配置系统和不必要的测试矩阵。
因此,“少写代码”不能只理解为删除行数。更准确的目标是减少不必要的变更,同时保留需求所需的行为、可读性和验证结果。
为什么原始 baseline 会夸大结果
代码量比较很容易产生一个漂亮但脆弱的百分比。假设 baseline 是一份手写的最小实现,而实验组则由带有约束指令的代理完成,那么两边并没有模拟相同的开发条件。baseline 可能没有包含真实代理会遇到的探索、修改、测试和返工过程;实验组却可能记录了完整的工作结果。
另一种常见问题是比较对象不对等:
- 一边统计最终文件,另一边统计整个工作区变更。
- 一边允许复用现有实现,另一边从空目录开始。
- 一边包含测试和配置,另一边只计算核心逻辑。
- 一边运行一次,另一边使用多轮修复后的结果。
这会让百分比看起来比实际收益更大。重新进行真实 agentic run 的意义,在于把代理的浏览、编辑、测试和修复纳入同一个实验流程。重新测得的 54% 虽然低于 80% 至 94%,但它更接近团队真正能够复现和讨论的结果。
可以这样建立一个小型基准
下面的脚本是一个可运行的简化示例。它假设两个目录分别保存 baseline 和 skill-enabled agent 的最终工作区,并用 Git 风格的变更行数做粗略比较。这个示例不是 Ponytail 的原始测试实现,而是展示如何避免只比较两段理想化代码。
运行前准备两个目录:runs/baseline 和 runs/with-skill。目录中放入代理完成任务后的文件。然后执行:
python benchmark.py runs/baseline runs/with-skill
benchmark.py:
#!/usr/bin/env python3
import difflib
import pathlib
import sys
def snapshot(root: pathlib.Path) -> dict[str, str]:
files = {}
for path in sorted(root.rglob("*")):
if path.is_file() and ".git" not in path.parts:
files[str(path.relative_to(root))] = path.read_text(encoding="utf-8")
return files
def changed_lines(before: dict[str, str], after: dict[str, str]) -> tuple[int, int]:
added = removed = 0
for name in sorted(set(before) | set(after)):
old = before.get(name, "").splitlines()
new = after.get(name, "").splitlines()
diff = difflib.ndiff(old, new)
for line in diff:
if line.startswith("+ "):
added += 1
elif line.startswith("- "):
removed += 1
return added, removed
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} BASELINE_DIR SKILL_DIR", file=sys.stderr)
return 2
baseline = snapshot(pathlib.Path(sys.argv[1]))
skill = snapshot(pathlib.Path(sys.argv[2]))
added, removed = changed_lines(baseline, skill)
baseline_lines = sum(len(text.splitlines()) for text in baseline.values())
skill_lines = sum(len(text.splitlines()) for text in skill.values())
if baseline_lines == 0:
print("baseline contains no lines", file=sys.stderr)
return 1
reduction = (baseline_lines - skill_lines) / baseline_lines * 100
print(f"baseline final lines: {baseline_lines}")
print(f"skill final lines: {skill_lines}")
print(f"line reduction: {reduction:.1f}%")
print(f"diff added/removed: {added}/{removed}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
要让这个数字更有意义,还需要把任务描述、模型、工具权限、工作区初始状态、最大迭代次数和验收测试固定下来。一个实际的任务提示可以明确要求代理记录过程:
Implement only the requested behavior in the existing repository.
Before creating a file, search for an existing implementation that can be reused.
Run the repository's relevant tests after editing.
Do not add dependencies, abstractions, documentation, or features unless the task requires them.
Report changed files, test commands, and any unresolved failure.
真正的基准还应同时记录最终行为是否正确。代码行数只能作为成本指标,不能作为质量指标。至少应配合测试通过率、变更文件数、依赖变化、人工复核结果和任务完成时间一起观察。
对团队采用的建议
Ponytail 这类 skill 适合放在代理工作流的约束层,而不是被当作万能优化器。采用时可以遵循几个边界:
- 先在固定的小任务集上运行基线,包括新增功能、缺陷修复和重构任务。
- 保留每次运行的提示词、模型版本、工具调用记录和最终 diff。
- 同时评估代码规模与功能正确性,避免为了少几行代码而牺牲可维护性。
- 对需要探索性设计、性能优化或安全审计的任务放宽“少改动”规则。
- 把失败案例加入回归集,检查 skill 是否导致代理拒绝必要的设计工作。
最重要的信号不是某个百分比是否足够惊人,而是结果能否在相同条件下复现。维护者在质疑后下调成绩,说明一个成熟的 agent 项目应当允许外部挑战,并愿意修正自己的测量方式。对于准备在团队中推广 coding agent 的工程师,这比一条未经验证的营销数字更值得借鉴。