1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 title: "使用卡尔曼滤波器减少服务器请求(或关于过度设计的愉悦)" date: 2026-03-12T19:00:00+01:00 draft: false slug: "bayesian-estimator-adaptive-polling-battery" slug_en: "bayesian-estimator-adaptive-polling-battery" description: "如何通过一个简单的卡尔曼滤波器减少80%的网络请求,应用于一个菜单栏应用,省电、自动适应电池状态,在你无操作时自动休眠。" tags: ["卡尔曼", "贝叶斯", "轮询", "电池", "macos", "swift", "工程"] categories: ["项目"] translation: hash: "" last_translated: "" notes: | - "关于卡尔曼的使用介绍以及通过轮询优化减少请求次数" --- 我有一个菜单栏应用,需要知道一个数字。一个从 0 到 100 的百分比。为了得到这个数字,我必须每30秒访问一次服务器。 我们来算一笔账:30秒一次请求等于1分钟2次请求,1小时120次,一天工作的8小时里就是960次。每天为了获取**一个有时候20分钟都不变的数字**发送将近1000个HTTP请求…… 这根本不是监控!简直就是对服务器的骚扰。 ## 真正的问题其实不是技术问题,而是政治问题。 当你依赖一个你无法控制的API时——它既不是公开的,也没有明确的速率限制文件,同时属于一家随时可能变更服务条款的公司——每一条不必要的请求都带着风险。这风险不仅是*超时*的风险,还有被切断访问权限的风险。 我用的服务端 *endpoint* 并没有公开的文档支持。它目前是可用的,已经运行了几个月了。但我知道,我发出的每一条请求,都会增加Anthropic某台服务器日志里的条目,假以时日,可能某天他们会决定第三方应用制造的"噪声"已经太多了,直接把我的服务切断。 所以问题的关键不是“怎样更快地轮询”,而是**“怎样尽量少地轮询,同时还不遗漏关键信息?”** 这时候,一个理性的工程师可能写一个简单的`if`,但一个对自嘲式过度设计充满*愉悦感*的工程师,可能最终选择实现一个卡尔曼滤波器。 ## 最简单的解决方案(以及它为何失败) 最直接的想法很简单:如果这个数字没变,就别问了。 如果 当前值 == 上一个值: 增加等待时间 否则: 回到30秒轮询 ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 title: "/loop 在 Claude Code 中:一个与终端共存的 cron" date: 2026-03-09T12:00:00+01:00 draft: false slug: "loop-cron-claude-code" slug_en: "claude-code-loop-vs-cron-scheduling" description: "Claude Code 2.1.71 带来了 /loop,这是一个内嵌的定时任务调度器。它的功能、用途及为什么它无法替代一个真正的 cron。" tags: ["claude-code", "anthropic", "生产力", "自动化", "定时任务"] categories: ["观点"] translation: hash: "" last_translated: "" notes: | - "de aquella manera": 意思是“有点像/勉强/做得很粗糙”,不宜直译。 - "ojo": “注意”/“重点在这里”,不是身体器官的眼睛。 - "chapuza": “粗糙的解决方式”,临时的简单解决方案。 - "barra del bar": 可以翻译为“酒吧柜台”,比喻一种随意的对话场景。 - "chupar banquillo": 运动术语,意为“坐冷板凳”或“等待而不用”。 --- 几个月来,我一直用自制的 cron 来执行 Claude Code 的任务。一个 Bash 脚本启动一个 headless 会话,给它一个 prompt,等待任务完成后关闭。它能运作,虽然运作得勉强,但能用。如果有需要,我把代码放在 [GitHub](https://github.com/frr149/claude-cron) 供大家参考。 而上周五,Anthropic 发布了 2.1.71 版本,引入了 `/loop`。一个原生的调度器,就直接内置在 Claude Code 会话中。 我的第一反应是:“我的项目凉了。” 试用之后的第二反应是:“嗯...还没死,但离死不远了。” ## /loop 的功能 语法相当简洁: /loop 5m check the deploy status ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 title: "Claude Code Remote Control 的结构解析:尚未开放的隐藏 API" date: 2026-02-27T18:00:00+01:00 draft: false slug: "claude-code-remote-control-hidden-api" slug_en: "claude-code-remote-control-hidden-api" description: "Anthropic 宣布了适用于 Claude Code 的 Remote Control 功能。我们研究了 bridge API、WebSocket、磁盘上的痕迹,以及为什么直到 2026 年 2 月,这项功能仍未对所有 Max 用户开放。" tags: ["claude-code", "anthropic", "api", "websocket", "remote-control", "逆向工程"] categories: ["观点"] translation: hash: "" last_translated: "" notes: | - "grifo": 比喻 "开启访问权限" / "关闭访问权限"("tap/faucet")。不要翻译成“格里芬”。 - "culo al aire": 意思是“被抓个现行” / “暴露”。在此语境下并不粗俗。 - "dicho en cristiano": 意为“用简单的话说”。无宗教含义。 - "chapuza": 意为“临时解决方案” / “粗糙的修复”。非贬义,指快速或简陋的解决方案。 - "barra del bar": 比喻“随意讨论”。不是指字面上的“酒吧吧台”。 - "mola": 西班牙俚语,意为“很酷/很棒”。翻译为 “很酷” 或类似的词。 - "pinta": 此处意为“看起来像”,而不是 “一品脱”。 --- 2026 年 2 月 25 日,Anthropic 宣布了针对 Claude Code 的 *Remote Control* 功能。构思是这样的:你在终端启动 Claude Code,然后拿着手机躺在沙发上,通过 claude.ai 继续你的会话。无需 SSH。无需 *tmux*。也不需要远程终端窗口。 听起来很酷,对吧? 但实际上,当我在终端输入 `/rc` 激活后,它给了我一个 URL。我打开手机,登录进去... 然后 claude.ai 提示我 "this feature is not active in your organization"(此功能尚未在您的账户中启用)。2026 年 2 月,我订阅的是 Max 5x 账户,每月按时付款。但什么都没用。 于是,我决定做任何理性人都会做的事:反编译 API,弄清楚后台到底发生了什么。 ## 什么是 Remote Control(官方说法) 本质上:它是一个连接本地 CLI 和 claude.ai 网页的桥梁。Claude Code 的 CLI 仍在你的机器上运行(可以访问你的代码、终端和文件),但你可以通过任何浏览器查看它、批准 *tool calls*,并发送消息。 Anthropic 将它作为一项 "*research preview*"(研究预览)推出,仅面向 Max 用户。官方的期望是,你可以启动一个长任务(`/rc` + 提示词),关上笔记本电脑,去健身房,然后通过手机查看任务进度。 然而,正如我们接下来要讨论的,现实要微妙得多。 ## 我们发现的底层真相 当你运行 `/rc` 时,Claude Code 会在后台做很多事情。而且,这些行动会留下大量的痕迹——在 JSONL 文件中、在 *debug logs* 里、在 API 响应里。让我们逐一拆解。 ### 1. Bridge API CLI 首先通过 Anthropic 的 API 注册一个 "*环境*": POST https://api.anthropic.com/v1/environments/bridge ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 title: "Codex CLI 没有 worktrees(教你手动实现!)" date: 2026-03-11T23:45:00+01:00 draft: false slug: "codex-cli-worktrees-shoudong-duogongneng" slug_en: "codex-cli-worktrees-manual-parallelism" description: "Codex CLI 没有 --worktree 和 --tmux,但通过手动创建 git worktree 和一些小技巧,也能实现真正的并行操作。本教程详细讲解,并揭露你可能遇到的 bug。" tags: ["codex", "openai", "git", "worktrees", "代理", "效率"] categories: ["工具"] translation: hash: "" last_translated: "" notes: | - "montártelo": 口语化表达,意为 "自己设置" 或 "自己动手搞定"。 - "te la pegas": 口语化表达,意为 "失败了" 或 "碰壁了"。 - "ñapa": 修补,草草处理的对策/临时解决方案。术语不带贬义,而是略带亲切含义。 - "currar": 西班牙口语,意为 "工作"。 - "ir tirando": 口语化表达,意为 "勉强过得去" 或 "凑合着过"。 - "el ajo": 意为 "大蒜",但在短语 "meterse en el ajo" 指 "参与其中" / "深入其中"。 - "tela marinera": 惊叹语,意为 "了不起" 或 "不简单"。 social: publish: true scheduled_date: 2026-03-14 platforms: ["twitter", "linkedin"] excerpt: "Codex CLI 没有 --worktree 或 --tmux 来实现并行操作。但通过手动 worktree 和解决共享会话 bug,就能实现真正的并行操作。本教程手把手教你。" wordpress: publish: true categories: [1] tags: ["codex", "openai", "git", "worktrees", "效率"] video: generate: false style: "educational" --- 如果你读过我之前写的 [关于 Claude Code 中 worktrees 的文章](/zh/posts/claude-code-worktrees-parallel-agents-tips/),你应该知道这个功能的核心就是一个小小的参数:`--worktree`。执行这个参数之后,每个代理都能在一个隔离的代码仓库副本中运行。每次启动一个代理程序,就在独立的目录中操作。三个代理同时跑也互不干扰,仿佛魔术一般。 现在打开 Codex CLI,想找一下等效的参数,结果发现它根本不存在。 没有 `--worktree`。没有 `--tmux`。也没有支持自定义代理的 `isolation: worktree` 参数。而且,尽管[issue #12862](https://github.com/openai/codex/issues/12862) 在 GitHub 上已经开了很久,并且已经有人在 fork 中实现了这些功能,但官方始终没有合并代码。到目前为止,Codex CLI 还是无法原生支持多个代理并行操作。 这是否意味着无法使用 Codex 实现并行工作?答案是否定的。这只是意味着你需要自己动手 “折腾” 一下。而这件事说穿了,不过是几个 git 命令和一些预防措施。 ## 计划:手动 worktrees + 每个目录运行一个 Codex 整体思路跟 Claude Code 中的方法类似,只是没有自动化功能。简单来说,就是你自己创建 worktree,自己启动代理程序,事情完了也需要自己清理。这工作听上去有点人工,但它确实管用。 ```bash # 从你的主仓库目录开始 cd ~/code/mi-proyecto # 为每个任务创建一个 worktree git worktree add ../mi-proyecto-feat-auth -b feature/auth git worktree add ../mi-proyecto-fix-tests -b fix/tests-rotos git worktree add ../mi-proyecto-refactor -b chore/refactor-db 现在你有四个目录:一个主目录和三个 worktree,每个 worktree 都是相互独立的。每个 worktree 拥有自己的分支、暂存区 (staging area) 和 HEAD,但共享仓库的元数据(.git/ 目录),其他一切隔离。 ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 --- title: "无需 Codex 的 Codex Automations:用 Claude Code 和 systemd 打造夜班代理" date: 2026-03-11T20:00:00+01:00 draft: false slug: "wuxu-codex-de-codex-automations-claude-code-systemd" slug_en: "diy-codex-automations-claude-code-systemd" description: "实用教程:使用 Claude Code、systemd 定时器和 Gitea 复制 OpenAI 的 Codex Automations。无需任何桌面应用,打造可在你睡觉时自动工作的代理。" tags: ["claude代码", "自动化", "systemd", "gitea", "openai", "codex", "教程"] categories: ["教程"] translation: hash: "" last_translated: "" notes: | - "níapa": 表示“快速解决”“凑活着用”,不是贬义。 - "chapuza": 同“ñapa”,是一个简单的、快速但可能不完美的解决办法。 - "dicho en cristiano": 表示“用通俗易懂的语言来说”。 - "currar": 西班牙俚语,意思为“工作”。 - "barra del bar": “酒吧柜台”,比喻随意闲聊的情境。 - "madrugón": 指早起,这在英语中指的 "early morning"。 - "irse por las ramas": 比喻“跑题”/“兜圈子”。 - "otro gallo cantaría": 表示“事情将会不同”/“会是另一种情形”。 --- 两周前,OpenAI 推出了 Codex Automations。简单来说:你定义一个触发器(如 cron、代码 push 或新 issue),写下自然语言指令,一个代理在独立的 worktree 中自动执行这一切。整个过程无需人类介入。在你睡觉时,代理自动整理 issues、总结 CI 错误、生成发布文档,甚至优化自身的指令。 ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 --- title: "我再次宣布邮件破产,这次我有计划了" date: 2026-03-11T21:30:00+01:00 draft: false slug: "you-jian-po-chan-ji-yi" slug_en: "email-bankruptcy-memento-reminders" description: "电子邮件是一个任何人都可以填满垃圾的收件箱。我多次宣布邮件破产。这次,我决定不再承诺会更好地管理收件箱,而是停止将其作为提醒系统使用。" tags: ["效率", "电子邮件", "工具", "linear", "cli"] categories: ["效率"] translation: hash: "" last_translated: "" notes: | - "bancarrota de emails": "email bankruptcy"—知名术语,由劳伦斯·莱西格提出。按原样保留。 - "dicho en cristiano": "用简单明了的语言来说"。不带宗教含义。 - "coñazo": "令人抓狂的事情" / "繁琐的任务"。日常用语,在西班牙语中并不粗俗。 - "culo al aire": "被抓了个现行" / "暴露"。比喻,非字面。 - "ñapa": "临时补救" / "权宜之计"。非贬义。 - "me la suda": 粗俗语,用"我完全不在乎"转译。 - "barra del bar": "吧台" — 喻指随意的聊天场景。 --- 2004年,劳伦斯·莱西格(Lawrence Lessig)给他的所有联系人发了一封群发邮件,大意是:“抱歉,我把你们所有的邮件都删了。如果有什么重要的事情,请再发一次。” 当时,他已经花了整整80个小时清空从2002年积累下来的收件箱。他每天收到200封邮件。 莱西格并不是个不善管理的人——他是斯坦福大学法律学院的教授。然而,即便如此,他仍然败给了电子邮件。 我至少宣布过三次邮件破产。第一次让我感到如释重负。第二次让我觉得自己很狼狈。第三次让我意识到问题根本不在我自己。 ## 电子邮件是一个任何人都可以填满的收件箱 好好想想。你的收件箱是一个**地球上任何人都可以随意修改的任务列表**。你的老板、你的银行、你四年前在某次会议上认识的一个人、你醉酒时订阅的某个电子邮件新闻简报,还有Jira的一个机器人提醒你某人刚刚把一个任务从“待处理”挪到了“进行中”。 所有人都可以往你的任务列表里塞东西。没有人会问你是否有时间。 就好像你把家门敞开,门口挂个牌子写着“想让我干什么就放这儿吧”。然后你还会惊讶地发现门口堆满了包裹。 ## 被过度滥用的工具 电子邮件的发明初衷是用来传递消息的。一条消息。从一个点到另一个点。就像信件,只是更快罢了。到这一步,一切都好。 但问题是,人类把它变成了什么: | 电子邮件本来的用途 | 我们把它变成了什么 | |---|---| | 一个消息传递系统 | 一个任务列表 | | 异步通信 | “你有没有看到我5分钟前发给你的邮件?” | | 点对点沟通 | 抄送47个人,“以防万一” | | 纯文本邮件 | 带有追踪像素和动态GIF的HTML邮件 | | 沟通工具 | CRM、文件管理器和法律档案库的集合 | 用通俗点的话说:我们拿了一把锤子,却把它当成螺丝刀、黄油刀和开瓶器来用。然后又抱怨它的把手坏了。 ## 混乱的数字 加州大学尔湾分校的一项研究发现,我们在被严重打扰后需要花**23分钟15秒**才能重新集中注意力。而普通员工平均每小时检查电子邮件36次。也就是说,每小时就可能有36次干扰。 算一算账:如果你每次查看电子邮件都会损失2分钟的工作状态转换时间,那你每天仅仅因为查看新邮件,就可能浪费超过1小时。不是为了阅读邮件,也不是为了回复邮件,仅仅是切换注意力。 这就像是每100米就突然猛转方向盘。这确实可以前进,但却是耗费了双倍的油,同时精疲力尽。 ## 邮件破产行不通(你也知道) 每次我宣布电子邮件破产时,循环总是一样的: 1. **第一周:** 收件箱变为空,无比平静,精神得以解脱。“这次我一定行。” 2. **第二周:** 收件箱里有47封未读邮件。“我一会儿再看。” 3. **第三周:** 收件箱有200封邮件。一些很重要。我开始眯着眼扫主题。 4. **第四周:** 500封邮件。我已经不知道哪些看过哪些没看。焦虑突升。 5. **第三个月:** 又宣布破产。 问题不是你不够有条理。问题在于,把电子邮件当作任务管理和提醒系统是**结构性地站不住脚的**。这个系统既没有优先级,也没有截止日期,更没有状态变化。它无法区分“有空再看”和“今天不回复你就丢了大单”。 一切内容都会以相同的形式,通过同一个入口,排成一条以“最近有人联系你”为顺序的无限列表。这不是什么生产力系统。这是一个时间消耗的垃圾场。 ## 更好的解决方案并不是更好地管理 email 我尝试过各种方法。Gmail的过滤器。像地铁线路图一样的颜色编码标签。邮件“稍后提醒”。文件夹命名为“今天要回复”“这一周要处理”“闲时阅读”(剧透一下:所谓的“闲时”从来不会来)。我还用过FollowUpThen,你可以把一封邮件转发到`3days@followupthen.com`,然后它会在3天后把邮件发回你的收件箱。 你知道用FollowUpThen后会发生什么吗?那就是:现在你的收件箱里不仅有原始邮件,还有提醒邮件。解决邮件过量问题的方法,反而制造了更多邮件。这就像想用汽油灭火一样。 真正的解决方法是:**将提醒和跟进行动从邮件里完全分离出来。** 没有模棱两可,只能彻底剥离。 ## Memento:虽无趣却有效的解决方法 我的第一个解决方案叫做**Memento**。它不是一个带漂亮界面和订阅计划的应用程序。它是一个只有120行代码的Python脚本,用来查询Linear(我的任务管理工具),告诉我有哪些事项超出了截止日期。 ```python # GraphQL 查询:筛选出过期但未完成或取消的任务 issues(filter: { dueDate: { lte: "2026-03-11" }, state: { type: { nin: ["completed", "canceled"] } } }) 就是这样了。一段简单的查询字符串:“有哪些我本该做但却没做的事情?” ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 title: "我的AI在for循环中从磁盘读取JSON 900次(为什么没有静态代码检查工具能拯救你)" date: 2026-02-24T14:00:00+01:00 draft: false slug: "ai-read-json-900-times-in-for-loop" slug_en: "llm-read-json-900-times-loop-performance" description: "一个LLM写了段代码,在一个包含900个文件的循环中,每次迭代都从磁盘读取并解析一个JSON文件。这是个新手犯的错误,没有任何静态代码检查工具能察觉到它。" tags: ["AI", "LLM", "性能", "Swift", "Tokamak", "对抗性开发"] categories: ["观点"] translation: hash: "" last_translated: "" notes: | - "de primero de carrera": 可以理解为“新手错误”/“初学者的错误”,不必直接翻译成“职业生涯的第一年”。 - "enseño a mis alumnos al mes de empezar": 可译为“我会在学生入门后的第一个月教这个”,表示这是一项非常基础的内容。 - "marear la perdiz": 翻译为“拖延问题”/“绕圈子”。猎人隐喻来源。 - "chapuza": 表示粗糙的解决方案,可译为“临时方案”/“hack”。 - "burrada": 可翻译为“明显的错误”,语气强于“mistake”,弱于“atrocity”。 - "barra del bar": 可译为“酒吧柜台”,表示非正式的场景,不是字面意义的菜单操作。 - "ojo al dato": 翻译为“请注意”。 - "dicho en cristiano": 翻译为“简单来说”。无宗教意味。 --- 上周,我的AI写了一段代码,每次都从磁盘读取一个JSON文件,对其解析后再进行一次**查找**,然后总共重复了900次。这意味着每次迭代里都会经历:打开文件,解码JSON,找到某个值,再全部丢弃从头开始。 这个错误是我在教学生编程的第一个月就会告诉他们千万不要犯的。 ## 发生了什么事(长话短说) 我在开发Tokamak,一个用于macOS的菜单栏应用,用来监控Claude Max的配额使用情况。它的一部分功能需要扫描约900个Claude Code会话数据生成的JSONL文件(JSON Lines)。对于每个文件,它需要知道在上一次的扫描中读取的**字节偏移量**(增量读取——只读取新数据)。 偏移量都保存在一个JSON文件中: ```json { "version": 1, "offsets": { "proyecto-a/sesion-1.jsonl": 48231, "proyecto-b/sesion-2.jsonl": 12044 } } 一个Dictionary<String, UInt64>包含了900条记录,约55KB,但并不算大。 ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 title: "从 /simplify 到绝地委员会:如何与 Kent Beck、Martin Fowler 和 Mike Acton 一起进行代码审查" date: 2026-03-09T18:00:00+01:00 draft: false slug: "simplify-jedi-council-ai-code-review" slug_en: "simplify-jedi-council-ai-code-review" description: "/simplify 是 Claude Code 提供的自动代码审查工具,使用三个通用代理检查代码。虽然有亮点,但也带来了不少噪音。我换用绝地委员会:Kent Beck、Martin Fowler 和 Mike Acton 基于真实决策规则的模式。发现更少的问题,无误报,还找到一个原工具漏掉的 bug。" tags: ["claude-code", "代码审查", "生产力", "AI", "重构"] categories: ["观点"] translation: hash: "" last_translated: "" notes: | - "绝地委员会": 是 Star Wars(星球大战)的典故,保持英文 "Jedi Council"。 - "dicho en cristiano": 翻译为 "用简单直白的语言说出"。 - "cosplay superficial": 译为 "表面角色扮演" 或 "肤浅模仿"。 - "no se trata de vibes": 直译为 "这不是氛围问题,而是基于明确规则的决策"。 Claude Code 提供了一个名为 /simplify 的 slash command,可以自动审查你的代码。我用它检查了一个大幅变更——大约 8 个文件、500 行代码——结果让人有些意外。它确实发现了些我可能漏掉的点,但也带来了不少无用信息,让我浪费了不少时间。 ...

Fernando

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 title: "33,000 行 XML 告诉你 heavyWork() 函数耗时过长:如何驯服 xctrace 应对大语言模型 (LLM)" date: 2026-03-08T14:00:00+01:00 draft: false slug: "ztrace-xctrace-compact-summary-llm" slug_en: "ztrace-xctrace-compact-summary-llm" description: "xctrace 导出包含 33,000 行的 XML 文档,会超出任何 LLM 的上下文窗口。ztrace 将其浓缩为 10 行有用信息。本文讲解其中的缘由与方法。" tags: ["xctrace", "instruments", "性能分析", "大语言模型", "Claude Code", "Python", "性能优化"] categories: ["观点"] translation: hash: "" last_translated: "" notes: | - "以大白话来说": "in plain language". No religious connotation. - "驯服": used metaphorically as "to tame" (a tool/output). Not literal. - "临时解决方案": "quick-and-dirty solution". Neutral term. - "无用信息": means "filler/fluff/noise" in this context. - "注意这一点": "here's the key point" / "pay attention to this". --- 上周,我在用 *Instruments* 工具对一个 Swift 应用进行性能分析。没什么稀奇的:运行 `xctrace record`,再运行 `xctrace export`,然后把导出的 XML 拷贝到 Claude Code 的上下文,让它帮忙分析热点。 结果 Claude 跟我说:`"XML 文件太大,无法可靠地处理。"` 33,553 行 XML,只为分析一个只有两个函数的程序。 ## 真正的问题 `xctrace export` 是一个很棒的工具。它什么都给你:每一个采样点、每一个调用栈、每一帧的二进制信息、内存地址、UUID,简直面面俱到,精准无比,完美无缺。 但问题,也正是源于它的完美无缺。 对一个应用程序进行性能分析时,我并不需要所有的 3,044 个细节采样点。我不需要知道第 1,847 个采样点在 00:02.847.882 捕捉到了 `libswiftCore.dylib` 内存地址为 `0x1027ec9a8` 的内容。我只需要知道 `heavyWork()` 花掉了 70% 的时间,而 `lightWork()` 只用了 30%。 用大白话来说:我需要的是 **10 行总结**,而不是 33,000 行繁文缛节。 ## 为什么 XML 格式是正确的选择(但噪音不可取) 在有人提出“2026 年了还用 XML 才是问题”之前——并不是这样。 XML 对于 xctrace 的功能来说,是非常理想的格式。试想一下: - **层次结构**:一个调用栈是一个框架的树状结构。一个采样点包含了一个调用栈,一个线程,一个进程。XML 自然而然地可以建模这些内容。 - **自描述性**:每个元素都有名字、带类型的属性,并且结构可以被验证。你不用去猜 CSV 第七列的内容代表什么。 - **优雅的去重**:xctrace 使用了 `id` 和 `ref` 系统,首次定义一个框架时是这样的:`id="59" name="heavyWork()"`,后续只需引用 `ref="59"`。可以看作是一种序列化的 *flyweight pattern*。 - **可以用标准工具解析**:XPath、`xmllint`、`xml.etree.ElementTree`…… 不需要专属解析器。 xctrace 的 XML 格式并不是*冗余*。它是 *Instruments* 所需的结构化信息,用来重建交互式调用树、对比运行情况,以及按线程和进程进行筛选。它是专门为一个可以展开和折叠节点的 GUI 工具设计的。 问题在于,试图将这些信息塞进大语言模型的上下文窗口时,情况就糟糕了。试图读取《堂吉诃德》全文,仅仅为了找到“风车”的那一句话,这样的信息虽然都在,但信号与噪声的比例使得有效提取变得几乎不可能。 ## 解决方案:ztrace 于是我构建了一个名为 `ztrace` 的工具。这是一段 Python 脚本,用来接收 `.trace` 文件并生成一个精简版的摘要。 核心思路很简单: 1. 执行 `xctrace export --toc` 获取元数据(进程、时长、模板) 2. 执行 `xctrace export --xpath` 提取 `time-profile` 表格 3. 解析 XML 并解析 `id` 和 `ref` 系统 4. 过滤掉系统框架的调用(所有位于 `/usr/lib/` 或 `/System/` 下的部分) 5. 按函数聚合数据并生成摘要 注意这一点:第 3 步比看起来重要得多。xctrace 并不会在每次调用栈中重复定义一个框架,它只会首次定义然后通过 `ref="59"` 的引用。在不解析引用的情况下,你会丢失大部分信息。 ## 结果 在一个用于测试的样例中(一个简单程序,`heavyWork()` 占用约 70%,`lightWork()` 占用约 30% 的 CPU): $ ztrace summary sample.trace ...

Fernando