发布时间:2026/9/5 16:41:03
Ponytail 邮件校验案例解析:同一模型同一提示词下 75 行对 3 行,Promptfoo 基准背后的完整方法 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),仅供参考

相关新闻

2026/9/5 16:41:03

Atlas:多模态世界模型如何实现像素级相机控制与3D重建

World Labs 这次发布的 Atlas,核心不是“又一个能生成视频的模型”,而是把多模态世界模型、像素级相机控制和 3D 重建这三件事放到一个系统里处理。这个方向很值得关注:以前我们要么用文本生成视频,要么用多视角照片做三维重建&am…

2026/9/5 16:41:03

流行歌如何改造成诵经版?音频二创完整技术流程拆解

把一首节奏明确、情绪偏江湖气的流行歌改成“诵经版”,听起来只是把一个唱法换掉,实际上涉及音色、速度、伴奏配器、空间感甚至视频封面的整体重构。这次我们就以《天涯》诵经版 Cover(任贤齐)这个二创方向为案例,拆一…

2026/9/5 17:41:06

C#源生成器在Unity UI中的真正用途:把隐式连接变成编译期契约

看到“Source Generator 用在 Unity UI”这个方向,我第一反应不是“终于不用写一堆属性了”,而是最近在项目里连续处理了两个热词级问题——TextMeshPro 被 UI 挡到、以及 UI 上动态画线后节点引用动不动断掉。这两件事表面看和源代码生成八竿子打不着&a…

2026/9/5 17:41:06

SpringBoot3+Vue3+MySQL校园旧书交易漂流系统全栈实战

这次我们来看一个校园旧书交易与漂流场景的全栈项目。核心诉求不复杂:学生手里有不再使用的教材、专业书、小说,放在系统里展示;其他同学可以搜索、收藏、申请交易,或者发起“漂流”,让书在校园内按标记的轨迹继续流动…

2026/9/5 17:41:06

SpringBoot3+Vue3校园旧书漂流系统:状态流转与预约并发实现

校园旧书漂流交易系统,放在 Java 技术栈里最典型的实现是:SpringBoot3 提供后端接口,Vue.js3 提供前端页面,MySQL 负责把用户、书本和订单记录持久化。这个题目真正值得做的点,不是把增删改查写完,而是让一…

2026/9/5 2:46:54

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/5 2:46:52

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/5 2:44:34

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/5 0:04:47

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流在大模型流式输出(Streaming)与智能体实时推流的架构中,生产环境中经常出现一种“上下游生产消费速率严重失衡”的极端情况: 生产端极速产出:大模型…

2026/9/5 2:45:13

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/5 2:30:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/5 2:46:50

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…