
Ponytail 邮件校验案例解析同一模型同一提示词下 75 行对 3 行Promptfoo 基准背后的完整方法【免费下载链接】ponytailMakes your AI agent think like the laziest senior dev in the room. The best code is the code you never wrote.项目地址: https://gitcode.com/GitHub_Trending/po/ponytail本文围绕 examples/email-validation.md 展开它记录了同一个真实任务“写一个校验邮箱地址的 Python 函数”在两种设置下、由同一个模型Claude Haiku 4.5temperature 1逐字verbatim产出的对比结果——无技能no-skill组 75 行代码ponytail 组 3 行代码。读完本文你能理解这组对比样本的完整出处、每一侧输出的内容构成、ponytail 规则集SKILL.md如何驱动输出以及如何用 promptfoo 在本地复现该基准。1. 样本来源基准运行中的逐字模型输出examples/email-validation.md 开头就声明了样本的采集方式这一点在 examples/README.md 中被再次强调这些示例不是人工编写的“These are not hand-written”而是基准运行中的原文输出同一个模型、同一个任务分别在“无技能”## Without Ponytail和“带 ponytail”## With Ponytail两种设置下作答供并排对比模型为 Claude Haiku 4.5temperature 1原始来源为benchmarks/output.json基准运行产物复现命令npx promptfoolatest eval -c benchmarks/promptfooconfig.yaml。该任务的原始提示词在基准配置中定义见 benchmarks/promptfooconfig.yaml- vars: { task: Write me a Python function that validates email addresses. }它是五个日常任务之一email validator、JS debounce、CSV sum、React countdown、FastAPI rate-limit全部来自同一份配置文件。2. 基线组无技能75 行的邮件校验代码无技能组收到的是裸任务——没有系统提示词只有任务本身。模型的回答结构是“给方案 再给更稳的方案 推荐第三方库 对比表”这正是典型的“over-build”形态75 行代码覆盖三个版本。2.1 简单正则版import re def validate_email(email: str) - bool: Validates an email address using a regular expression. Args: email (str): The email address to validate Returns: bool: True if valid, False otherwise # Regular expression pattern for email validation pattern r^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$ return re.match(pattern, email) is not None # Test cases if __name__ __main__: test_emails [ userexample.com, # Valid john.doecompany.co.uk, # Valid testtagdomain.org, # Valid invalid.email, # Invalid missingdomain, # Invalid nodomain.com, # Invalid spaces inemail.com, # Invalid userdomain..com, # Invalid (double dot) ] for email in test_emails: result validate_email(email) print(f{email:30} - {result})一个函数加一段 docstring、一条正则、一个内嵌测试循环——模型还主动替调用方准备了 8 个测试用例。2.2 更健壮版带详细反馈同一份回答里模型又给了一个“advanced”版本返回(is_valid, message)元组追加了 RFC 层面的检查import re def validate_email_advanced(email: str) - tuple[bool, str]: Advanced email validation with detailed feedback. Args: email (str): The email address to validate Returns: tuple: (is_valid, message) # Basic checks if not email or not isinstance(email, str): return False, Email must be a non-empty string email email.strip() if len(email) 254: return False, Email is too long (max 254 characters) # Regular expression pattern pattern r^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$ if not re.match(pattern, email): return False, Email format is invalid # Additional checks local_part, domain email.rsplit(, 1) if len(local_part) 64: return False, Local part is too long (max 64 characters) if local_part.startswith(.) or local_part.endswith(.): return False, Local part cannot start or end with a dot if .. in email: return False, Email cannot contain consecutive dots return True, Email is valid # Test the advanced version if __name__ __main__: test_emails [ userexample.com, invalid..emaildomain.com, .invaliddomain.com, userdomain, ] for email in test_emails: is_valid, message validate_email_advanced(email) print(f{email:35} - {is_valid:5} ({message}))254 字符总长、64 字符本地部分、点号边界、连续点号——这些是真实的 RFC 约束但它们是用户没有要求的“规格完整性”。2.3 第三方库版from email_validator import validate_email, EmailNotValidError def validate_email_production(email: str) - bool: Validates email using the email_validator library. More reliable for production use. Install with: pip install email-validator try: # Validate and normalize the email valid validate_email(email) return True except EmailNotValidError: return False # Usage if __name__ __main__: print(validate_email_production(userexample.com)) # True print(validate_email_production(invalid)) # False2.4 模型自己的对比与建议原文档最后附了模型给出的三方案对比表和结论方法优点缺点正则简单快、无依赖校验有限正则进阶更彻底仍不完全符合 RFCemail-validator 库符合 RFC、可靠外部依赖模型建议生产环境用email-validator正确处理 RFC 5321/5322快速脚本用简单正则。注意这套“三版本 对比表 推荐”的输出正是 ponytail 想消除的东西——用户只问了一个函数却收到三个实现和一段设计论述。3. Ponytail 组3 行代码与“刻意跳过”的声明同一模型、同一提示词在 ponytail 规则集下输出是import re def is_valid_email(email: str) - bool: return bool(re.match(r^[^][^]\.[^]$, email))外加一句刻意跳过的说明原文Skipped: RFC 5322 parser, DNS MX lookup, confirmation email. Add when you actually need to rejectusertagsub.domain.co.ukor catch typos, until then, this catches 99% of oops I fat-fingered it cases.这个输出形态不是偶然的它由规则集 skills/ponytail/SKILL.md 直接约束决策阶梯The ladderskills/ponytail/SKILL.md#L32-L48先问“这东西需要存在吗YAGNI”→ 代码库里已有吗 → 标准库能做吗 → 平台原生能力能覆盖吗 → 已装依赖能解决吗 → 能一行搞定吗 → 最后才是“能工作的最少代码”。邮箱校验落在第 3 级标准库re与第 6 级一行之间因此停止在 3 行。输出纪律skills/ponytail/SKILL.md#L66-L75代码先行随后最多三行说明“跳过了什么、何时再加”固定模式为[code] → skipped: [X], add when [Y]。示例中的那句 Skipped: … Add when … 就是这个模式的逐字体现——RFC 5322 解析、DNS MX 查询、确认邮件都被点名为“被跳过项”并给出了触发追加的具体条件。强度分级默认full档执行完整阶梯ultra档会更激进地挑战需求本身lite档则只指出更懒的替代方案。规则集还有一条重要边界skills/ponytail/SKILL.md#L90-L112信任边界上的输入校验、防数据丢失的错误处理、安全措施不可被简化掉“懒”针对的是过度构建不是理解问题本身。结论行原文75 → 3 lines of code, same model, same prompt.4. 基准如何搭建配置与两个 Arm源码级这一节解释“no-skill arm vs ponytail arm”在工程上如何实现。4.1 入口配置 benchmarks/promptfooconfig.yamldescription: Ponytail vs caveman vs no-skill: same model, same tasks. Measures code LOC (deterministic) and tokens/cost (API telemetry). providers: - id: anthropic:messages:claude-haiku-4-5-20251001 config: { max_tokens: 8192, temperature: 1 } # …另有 claude-sonnet-4-6 与 claude-opus-4-8同样 max_tokens 8192 / temperature 1 prompts: - id: file://arms/baseline.js label: baseline (no skill) - id: file://arms/caveman.js label: caveman - id: file://arms/ponytail.js label: ponytail defaultTest: assert: - type: javascript value: file://loc.js metric: code_loc - type: javascript value: file://correctness.js metric: correct tests: - vars: { task: Write me a Python function that validates email addresses. } # …debounce、CSV sum、React countdown、FastAPI rate-limit要点三个 provider 全部temperature: 1, max_tokens: 8192保证“同模型同参数”样本中使用的 Haiku 4.5 即其一三个 arm 以prompts形式注入每个 arm 是一个 JS 模块把vars.task包装成不同的消息序列每个测试单元格都挂两个断言loc.js记录代码行数度量恒通过correctness.js做正确性把关gate答错即失败。4.2 Arm 实现baseline 与 ponytail 的差异只有一个系统提示基线组benchmarks/arms/baseline.js只有两行任务裸发// Baseline arm: no skill, just the task. module.exports ({ vars }) [{ role: user, content: vars.task }];ponytail 组benchmarks/arms/ponytail.js则把仓库自带的 SKILL.md整文件作为系统提示词读入// Ponytail arm: the repos own SKILL.md (full) as the system prompt. Single source of truth. const system fs.readFileSync(path.join(__dirname, .., .., skills, ponytail, SKILL.md), utf8); module.exports ({ vars }) [ { role: system, content: system }, { role: user, content: vars.task }, ];注意“Single source of truth”的注释基准中使用的规则与用户插件安装后生效的规则是同一份文件skills/ponytail/SKILL.md避免了“基准里贴的是旧规则”这类偏差。因此第 3 节对 SKILL.md 的解读同时就是对 ponytail arm 行为机制的解读。4.3 LOC 如何计算benchmarks/loc.js行数不是简单地数\n而是去除注释后的非空行优先从 fenced 代码块) 中提取若无围栏代码把整个回复视为一个块对应 correctness.js 中“模型常裸答代码”的兜底策略先剥掉/* ... */块注释注释里写了原因早期只过滤*对齐的 JSDoc普通块注释会被误计为代码再过滤空行、//、#、*开头的行。这正是 examples 目录标题 “Without (LOC) / With (LOC)”75 / 3的口径75 与 3 都是按此规则计出的代码行数不含散文。5. 正确性门槛为什么“更短”没有被判成“更烂”benchmarks/README.md 对两个指标的定位一句话“A broken one-liner that scores great on LOC will fail on correctness.” 具体到邮箱任务benchmarks/correctness.js#L74-L130 的email检查器做了三件事从回复中提取 Python 代码块找不到围栏时含def的裸文本块也认在生成的函数名候选validate_email、is_valid_email、email_validator、is_valid、validate中定位校验函数兜底逻辑是找任意单参可调用对象——所以基线组的validate_email与 ponytail 组的is_valid_email都能被同一个 harness 抓住追加断言后真正执行spawn python3/pythonif not fn(userexample.com): failures.append(rejected valid: userexample.com) if not fn(ab.co): failures.append(rejected valid: ab.co) if fn(no-at-sign): failures.append(accepted invalid: no-at-sign) if fn(): failures.append(accepted invalid: empty string) if fn(missing-local.com): failures.append(accepted invalid: missing-local.com)可以验证 ponytail 的 3 行正则在语义上确实覆盖这些断言^[^][^]\.[^]$要求本地部分非空拒missing-local.com与空串、域部分含至少一个点拒no-at-sign同时放行userexample.com与ab.co。也就是说“更短”在这个 harness 下是被执行验证过的而非仅靠行数好看。执行细节上harness 写入临时.py文件后调用系统 Python 运行超时默认 30 秒可用PONYTAIL_CORRECTNESS_TIMEOUT_MS覆盖见 benchmarks/correctness.js#L14-L17。README 同时提醒五个任务中 email、debounce、CSV 是真执行React countdown 与 FastAPI rate-limit 只做关键词/结构检查。6. 如何复现这个样本按 benchmarks/README.md 的说明复现邮箱这一个单元格或完整五任务矩阵的路径是前置条件Anthropic API key环境变量或.env文件见 benchmarks/promptfooconfig.yaml#L7、Node.js ≥ 22.22.0promptfoo 引擎约束、Python 3与pandascorrectness 检查器会 spawn Python 执行生成代码。# 在 benchmarks/ 目录下README 的写法.env 位于仓库根目录 npx promptfoolatest eval -c promptfooconfig.yaml --env-file ../.env --repeat 10 npx promptfoolatest view两个容易踩的点均出自 README 原话--env-file ../.env是必需的因为 promptfoo 只从当前目录benchmarks/读.env而文件实际放在仓库根目录单跑一次只能得到一次采样官方数字是每格 10 次取中位数成本数字另行以 30 次重跑复核。本地模型路线无 API key也可跑python benchmarks/benchmark-local.py --model llama3.2 --repeat 3经 Ollama。README 同时给出诚实提示该规则集在强指令遵循的 Claude 级模型上表现好迁移到小型本地模型时“多步决策阶梯”不能被可靠遵循结果会变差。7. 如何解读“75 → 3”这组数字结合仓库内已有的结果数据这组对比应该这样读口径code_loc只数代码行不含散文。基线组那 75 行里包含 8 个自写测试用例、docstring 和第二个函数的完整脚手架ponytail 组的 3 行不含任何自测——SKILL.md 明确说“trivial one-liners need no test, YAGNI applies to tests too”skills/ponytail/SKILL.md#L107-L112所以两边在“是否自带测试”上并非同口径竞争这是阅读时的一个注意点。横向位置examples/README.md 的总表中email validation 的 75 → 3 是五个任务里 LOC 压缩最悬殊的一个debounce 116→10、CSV sum 20→3、React countdown 267→9、rate limit 128→10。全局基准benchmarks/README.md#L38-L44 的 10 次中位数表显示五个任务合计 Haiku 上 baseline 518 行 vs ponytail 39 行Sonnet 693 → 44Opus 256 → 51caveman另一个散文压缩技能落在中间。诚实性边界README 的 2026-06-18 更新明确指出这类数字是单轮single-shot对比裸模型的口径裸模型“多选项 评论”的回答把散文也算进去了因此会高估优势更可信的口径是 agentic 基准真实 Claude Code 会话跑真实公开仓库ponytail 在“过度构建陷阱”型任务上减 60–94%在已经极简的代码上打平且保持 100% 安全见 benchmarks/README.md#L64-L71。邮箱样例属于典型的“过度构建陷阱”任务——用户要一个函数裸模型交付了三套实现。8. 小结examples/email-validation.md 这个样本的价值不在于“3 行正则能校验邮箱”本身而在于它展示了一条可复现的验证链同一份 skills/ponytail/SKILL.md 作为系统提示注入benchmarks/arms/ponytail.js→ 模型输出被 benchmarks/loc.js 以去注释非空行口径度量 → 被 benchmarks/correctness.js 真实执行 5 个断言把关 → 最终得到“同模型、同提示词、75 行对 3 行、且更短的一侧功能不降”的结论。想深入其他任务样本debounce、CSV sum、React countdown、rate limit或成本/延迟数据可从 examples/README.md 与 benchmarks/README.md 继续追踪。【免费下载链接】ponytailMakes your AI agent think like the laziest senior dev in the room. The best code is the code you never wrote.项目地址: https://gitcode.com/GitHub_Trending/po/ponytail创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考