SuperAPI AI 工具集

blog-cost-charts

写作与研究

查看项目

更新于 10-27 16:29

技能介绍

用途

该技能帮助把一篇博客文章中的排名表格(每行含数值分数、成本、时间,或任意三个可比较的数值轴)转换成两张配套图表,用于视觉化地比较“哪个方案最划算”,而不是只呈现原始表格。两张图分别是:成本-分数气泡散点图,以及 score/(cost×time) 价值排名条形图。两者均为深色主题,按文章发布的每种语言各生成一张 PNG(通常为 pt 和 en),并嵌入排名表格之后。

该技能源自 v4 LLM 基准测试文章(content/2026/09/15/novo-llm-benchmark-v4-*),当时需要这一对图表让 39 行的表格更易浏览。这里的脚本是那篇文章一次性脚本的通用化版本。

何时使用

  • 文章中有表格,每行含数值分数、成本和时间(或任意三个可比较的数值轴),用户希望得到视觉化的“哪个最划算”比较,而非仅看原始表格。
  • 用户明确要求:“在表格后加图表”“让比较更直观”“成本效益图”等。

工作流程

1. 选择数据集与范围

大表格中并非每一行都适合放进图表。需要做出判断,并在图表脚注中说明:

  • 哪些行有真正可比的成本数字?排除免费、未承诺或固定费率套餐的条目,它们无法有意义地放在美元轴上($0 点会破坏对数刻度;固定费率套餐根本没有单次运行的美元数字)。应在脚注中点名说明,而不是悄悄丢弃。
  • 如果成本来自不同的测试框架/定价基础(例如真实的按 token API 成本 vs. 固定订阅的名义分摊),不要隐藏这一点——按分组着色(见下文),并在脚注和文章正文中说明,正如源表格本身应当做的那样。
  • 精选子集(15-25 个点)的可读性远好于塞进全部 39+ 行;优先限制在文章正文实际讨论的层级/类别(例如“仅 Tier A”),而不是试图容纳所有内容。

2. 构建 JSON 配置

复制 scripts/config.example.json 并编辑。结构:

{
  "slug": "v4",                    // 输出 PNG 的文件名前缀
  "x_log": true,                    // 对数刻度成本轴(通常为是:成本范围跨越 100 倍以上)
  "x_lim": [0.7, 160],               // 根据实际数据范围调整,留少量边距
  "y_lim": [84.5, 102.2],
  "x_ticks": [1, 3, 10, 30, 100],
  "x_tick_fmt": "${}",
  "group_colors": { "codex": "#5fd35f", "claude": "#e8965a", "...": "..." },
  "models": [
    {"name": "GPT-6 Astra", "score": 100.0, "cost": 30.55, "minutes": 100, "group": "codex"}
  ],
  "text": {
    "pt": { "scatter_title": "...", "scatter_subtitle": "...", "scatter_xlabel": "...",
            "scatter_ylabel": "...", "groups": {"codex": "Codex (OpenAI)"},
            "footnote": "...", "ranking_title": "...", "ranking_subtitle": "...",
            "ranking_xlabel": "...", "ranking_footnote": "..." },
    "en": { /* 相同键,英文文案 */ }
  }
}

text.<lang> 下的每个键都必须按语言填写——脚本中没有翻译步骤,它只渲染你提供的字符串。两种语言都要匹配站点的语气规则(PT-BR:Akita 直接、怀疑的语气,不用破折号;EN:New Yorker 语气,相同规则)——这些字符串是可见的图表文案,不是一次性标签。

3. 调整标签偏移以避免重叠

多个模型成本/分数相近的气泡图在首次渲染时必然发生碰撞。运行一次脚本,实际查看输出图像(用 Read 工具,而不只是“运行无错误”),为任何标签与其他标签重叠的名称在配置中添加 label_offsets 映射:

"label_offsets": { "GPT 5.6 sol": [14, -22], "GPT 5.6 terra": [-14, 20] }

值是从气泡中心出发的 [dx, dy](单位:点)。预计需要 2-3 轮渲染 → 查看 → 微调才能干净。这是整个工作流程中最耗时的部分;要为此预留时间,而不是直接交付首次渲染结果。

4. 生成

python3 scripts/make_charts.py path/to/config.json --outdir /path/to/scratchpad/charts

为 text 中的每个语言键输出 <slug>-cost-score-<lang>.png 和 <slug>-value-ranking-<lang>.png。在继续之前读回每张图像——检查:标签重叠、标题/副标题碰撞、图例压在数据上,以及价值排名数字是否合理(手动抽查一两个:score / (cost * minutes) * 1000)。

5. 上传到 S3——不要跳过

静态博客文章无法引用本地文件。每张 PNG 必须先上传才能嵌入:

set -a; source ~/.config/zsh/secrets 2>/dev/null; set +a
for f in <slug>-cost-score-pt.png <slug>-cost-score-en.png <slug>-value-ranking-pt.png <slug>-value-ranking-en.png; do
  aws s3 cp "/path/to/scratchpad/charts/$f" "s3://new-uploads-akitaonrails/YYYY/MM/DD/$f" \
    --region us-east-2 --content-type image/png
done

使用文章自身的发布日期作为 YYYY/MM/DD 路径,匹配文章图片已使用的约定。上传后,验证每个 URL 确实可解析(不要只信任上传退出码):

curl -s -o /dev/null -w "%{http_code}\n" \
  "https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/YYYY/MM/DD/<file>.png"

预期四个都返回 200。

6. 嵌入文章

插入到排名表格自身的脚注/注意事项之后(在进入叙述部分之前),每篇文章一张对应语言的图片,配一句简短引导语和描述坐标轴的通俗 alt 文本:

![Bubble chart: dollar cost on the X axis (log scale) against score on the Y axis, bubble size is wall-clock time, color is the harness](https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/YYYY/MM/DD/<slug>-cost-score-en.png)

在同一轮中同时处理 index.md(PT)和 index.en.md(EN)两个文件,各自指向自己语言的 PNG——绝不要在一篇文章的图片中混用语言。

7. 提交前重新构建并验证

hugo --minify
grep -o 'https://new-uploads-akitaonrails.s3[^")]*' public/<pt-path>/index.html
grep -o 'https://new-uploads-akitaonrails.s3[^")]*' public/en/<en-path>/index.html

确认构建无错误,且每种语言的页面引用自己的 PNG。然后一起提交两个 markdown 文件(它们是一对翻译——见站点的双语编辑规则),并按用户通常的发布流程推送。

设计说明(脚本为何如此)

  • 深色主题、对数刻度成本轴、气泡大小 = 时间:镜像用户之前使用过的参考图表风格(#0d1117 背景、彩色气泡、柔和网格线)。基准测试语境中的成本通常跨越两个以上数量级($0.90 到 $120+),因此线性成本轴会让便宜选项无法区分——始终使用对数刻度。
  • 颜色 = 分组,而非分数:按成本基础/测试框架着色(真实 API $ vs. 名义订阅 $ vs. 免费)在视觉上承载了文章正文已必须用文字陈述的“这些并非直接可比”的注意事项。不要改为按分数/层级着色;那会重复 Y 轴。
  • 价值指数 = score / (cost × time),乘以 1000 以获得可读数字:这个综合排名常常出人意料——一个分数尚可但成本极低且墙钟时间很快的模型,可能排名超过单一最高分的便宜模型。在文章正文中图表旁边明确说明这一点;这通常才是真正的新闻,而非填充内容。
  • 绝不自动化“包含哪些行”的决定:这是关于文章论点的编辑判断,不是数据清理步骤。