商业产业 Hacker News Agent 2026-09-22T15:38 正文 ok 5389 words

通过要求 Agent 加速代码,写出更快的 Rust 代码

英文标题:🔶 Writing Rust code that's fast by asking agents to make the code faster

作者通过让 Agent 反复运行基准测试、设定明确的性能门槛并持续迭代,验证了现代 Agentic LLM 能在适当约束下显著优化 Rust 代码。以 UMAP 为例,经过多代模型优化后的实现相较初始版本可快约 7.5 倍至 32 倍,同时其 Python 绑定比 `umap-learn` 快 4 倍至 15 倍、比 `umap-rs` 快 2 倍至 4 倍。作者认为,防止“benchmaxxing”的关键在于采用多样且贴近真实使用的基准数据,并通过与已知正确实现对比来设置质量门槛。该方法已在 GBDT、MLP、图网络、模板引擎、HTML 解析和 Web 服务器等多个领域取得效果,说明面向约束的提示设计可成为开发者进行性能工程的新工具。
打开原文相关 3 · 机会 1
media25.3 KB media61.0 KB media64.1 KB media68.1 KB media39.9 KB media46.0 KB media86.5 KB media74.4 KB media88.8 KB media53.4 KB media79.4 KB media158.8 KB media103.6 KB media116.5 KB media74.1 KB

中文

2025 年 1 月,我在一篇博客文章中提出了一个有趣的假设:如果不断要求 LLM“把代码写得更好”,它们能否写出更好的代码?那时,可靠的 Agentic 编程尚未出现,但 Claude Sonnet 3.5 已经能够迭代改进算法类 Python 代码。“更好”这一指令事实证明定义不足:Sonnet 利用了这种模糊性,加入了一大堆无用功能,但代码确实变快了。即使专门经过 RLHF 训练、可处理常见通过/失败型编程问题的 Agentic LLM 已经兴起,优化通常仍不属于其能力组合的一部分。

在那篇博客文章的结尾,我曾讨论过一种假想的未来:LLM 可以通过编写 Rust 代码、再利用 PyO3 连接两种语言,来写出极快的 Python 代码,从而兼得 Python 的易用性与 Rust 的速度。那篇文章的早期草稿曾断言,同样的“把代码写得更好”指令也可以用于底层 Rust 代码,并大幅提升其速度,继而传导至 Python 代码;不过,当时我对 Rust 了解不足,在没有证据的情况下做出这种论断会过于_大胆_。

自 Opus 4.5 发布、Agentic 编程变得更可行以来,经过数月测试与实验,我可以自信地确认:现代 Agentic LLM 确实能够编写出速度显著超过当前最先进方法的 Rust 代码,前提是提供适当的护栏和约束。此外,自 Opus 4.5 以来,LLM 在每一代前沿模型发布时都在编程能力上大幅进步,优化效果也随之更好;累计来看,依具体领域不同,可实现 2 倍至 20 倍的加速。

更重要的是,这篇博客文章并非泛泛而谈:我将同时提供所使用的提示词和基准测试结果。你已经被警告过了。

迭代式“Benchmaxxing”#

起初,让软件变得更快是我测试和比较这些新 Agentic 模型的一种良好量化方式。我主要选择 Rust 作为目标语言,是因为其 Python 集成能力和速度;但 Rust 的其他特性也使其在找到快速实现时格外有用,例如内存安全,以及可将其编译为 WebAssembly/WASM,从而无需太多工作即可在 Web 浏览器中运行。不过,我会遵循一项重要约束:尽可能禁止使用 unsafe code,即使这在技术上未必能产出最快的代码。

我的第一个测试案例是用 Rust 重写机器学习算法。如果能拥有更快、可扩展的工具,这将为身为数据科学家的我带来有意义的生产力提升。当时,假设自己能击败那些经过十多年迭代、久经考验且已用 C 编写的算法,是一种傲慢的想法,因为 Rust 的底层优势在这里并不那么明显。我最希望优化的算法是 UMAP;它是我在工作中使用的一种有价值的降维算法,但面对大数据扩展性较差且速度很慢,而 cuML 等替代方案又需要耗费大量时间配置。诸如 umap-rs 的 UMAP Rust crate 已经存在,我本可以直接 fork 它们,再提示 Claude Opus 4.5 添加 Python/PyO3 支持;但作为一项实验和学习体验,我希望让 Agent 从头编写该算法,并尽量减少 Rust 依赖,以便在尽可能低的层级进行优化。

Rust 借助 criterion crate 提供了完善的基准测试工具,所有 Agent 都知道如何使用它。criterion 会运行基准测试、跨迭代跟踪结果以观察性能是改善还是退化,并能计算改动是否具有统计显著性,还是仅仅是噪声。

典型的 criterion 输出,显示相较此前一次基准测试运行实现了 3.5 倍加速。

典型的 criterion 输出,显示相较此前一次基准测试运行实现了 3.5 倍加速。

首先,在为 UMAP 创建 Rust crate 的初始提示中,我要求 Opus 4.5 针对不同输入数据规模创建基准测试,因为对小型数据集有效的优化未必适用于大型数据集,反之亦然。

之后,创建并运行一个基准测试套件,并将结果保存为 Markdown 文件。该基准测试套件必须包括最高至 100000x768 的输入,并分别在 CPU 和 GPU 模式下测试。

这种方法使用 criterion 创建了基准测试;随后,每当我提示加入性能改进特性,例如使用 faer 加速线性代数,或使用 simsimd 加速 SIMD operations,我都需要手动重新运行基准测试套件。这很快变得繁琐,因为我必须在每次改动后手动运行每个基准测试,以确认没有性能回退。

关于提示风格的补充说明

我提示 Agentic LLM 的方式并不寻常:我通常会在一个 Markdown 文档中预先写好很长的提示词,并额外使用全大写和粗体来强调。这是为了通过提示工程确保捕捉到_所有_细微差别,同时还会使用本博客文章后文详述的其他几个技巧。尽管有人认为,随着最新模型已经足够聪明、能够正确处理模糊性,提示工程已经过时,但我强烈不同意,因为 LLM 也已经更善于遵循这些细微要求。

使用 Zed Agent,通过标记文件(左)来运行 Markdown 文档中的提示词(右)。

使用 Zed Agent,通过标记文件(左)来运行 Markdown 文档中的提示词(右)。

在对 Agent 不会意外对仓库执行 rm -rf 有了足够信心后,我尝试让 Agent 自主运行,允许它们持续迭代,直到希望能够实现性能提升。

**你必须持续迭代优化并解决问题,直到基准测试结果不再改善、crate 达到其可能达到的最快速度。**你可以一直迭代,直到想不出新的办法。

结果发现,“达到其可能达到的最快速度”过于模糊,而 Opus 4.5 很懒:它只是调整了几个超参数,没有带来多少实际性能提升,就宣布完成了。我需要的是一个能明确通过或失败的目标,因此我将提示词改进为:

首先,**不要进行任何进一步改动**,运行 CPU Rust 基准测试,以建立真实性能基线。

然后,优化 crate 代码,使所有 CPU 基准测试都比真实性能基线**至少快 1.2 倍**;理想情况下越快越好。绝不能通过篡改基准测试来实现这一运行时间缩短,只能迭代库代码。

除添加 `unsafe` 代码外,你可以使用任何技术实现这一目标(例如引入新的 crate)。**重复这一过程,直到基准测试性能收敛且你已没有更多优化思路。**你有权限持续迭代。每次基准测试迭代后,都将相对于真实性能基线的结果输出到控制台。

优先迭代实现快速、高影响力的改进,并据此作出改动。不要过度思考所需的改动。

这套方法效果非常好:我不仅在基准测试中获得了 1.2 倍加速,Agent 在达到指标约束后仍持续优化,只有在某项指标约束不可行时才会停止;在这个案例中,Agent 实现了 1.5 倍至 2.0 倍的加速。底层 Rust 优化围绕多种技术展开,包括但不限于:更积极地利用 SIMD 操作、合并函数、循环展开、创建中间缓存、尽可能使用 Arc 而非借用,以及根据输入数据创建性能配置策略(例如,当数据较小时,不使用 rayon 数据并行,因为其开销会抵消收益)。

我选择“快 1.2 倍”作为合理性测试:如果目标过高,Agent 可能会通过高风险、冗长的重写来作弊以实现目标。较小的改动更好,因为 Agent 可以更容易地隔离性能提升或回退的原因,这也是强调迭代的原因。在 GPT-5.3 Codex 和 Opus 4.6 等新的前沿 LLM 发布后,我对每个新 LLM 原样重复了这条提示词,它们各自都能在前一次优化的基础上实现累计 1.5 倍至 2.0 倍的加速。经过多个月一路迭代至 GPT-6 Astra,最终速度约为初始实现基线的 7.5 倍至 32 倍。

这种方法是针对既定基准测试进行极致优化,因此可被视为 benchmaxxing:这是一个贬义词,指前沿 LLM 只追求在基准测试中取得高分、却难以泛化到真实世界使用的行为。不过,如果基准测试足够异质化,并且真正代表真实使用场景,这种担忧就会减轻。对于这类项目,有两种方法可以应对 benchmaxxing 的担忧:1)让 Agent 设计多样化、非典型或对抗性的输入数据集,而不是笼统地采用“最高至 100000x768 的输入”;2)将输出与已知正确的实现进行比较,为输出设置质量门槛。对于机器学习算法,速度与质量之间始终存在权衡;但在这个案例中,令人惊讶的是,先让模型变快、再让它变正确反而更容易。这并非科学工程_通常_的工作方式,但除非一个新实现真的正确,否则它不太可能在许多不同基准测试的同类对比中匹配一个已知优秀的实现。

一个经 Agent 优化的梯度提升决策树实现,在速度上显著击败 xgboost,有时在质量上也是如此!(MSE:越低越好;其他指标:越高越好)

一个经 Agent 优化的梯度提升决策树实现,在速度上显著击败 xgboost,有时在质量上也是如此!(MSE:越低越好;其他指标:越高越好)

幸运的是,UMAP 已有 Python 包 umap-learn 这一权威实现,而为这个 Rust crate 添加 Python 绑定也已经非常简单,因此新的目标变成了同时满足多项约束:提升代码质量,同时限制速度损失。

创建一个 Python Jupyter Notebook,对比 Python 绑定与 `umap-learn` 的性能,并加入检查以确认输出和 UMAP 损失是否足够相似。使用与基准测试不同矩阵尺寸的多样化数据集。

如果输出不够相似,研究修复方法,**且速度回退不得超过 5%**。

确实,这个 Agentic Rust 实现的质量较差;但这条后续提示取得了成功,所有质量指标都提升至接近一致,同时速度损失极小。这个新 crate 通过其 Python 绑定,仍比 umap-learn 快 4 倍至 15 倍,并且比对应的 Rust umap-rs 实现快 2 倍至 4 倍。

Rust UMAP crate 最新一轮优化的结果。除速度更快外,它在大多数质量指标上与 Python 持平或更优。

Rust UMAP crate 最新一轮优化的结果。除速度更快外,它在大多数质量指标上与 Python 持平或更优。

当一次 Agentic 迭代仅带来约 3% 至 5% 的微小速度提升——这甚至可能不具备统计显著性——但 Agent 却加入了不成比例的大量代码时,就意味着已经达到收敛;这种权衡不值得。

我最终使用同样的提示词演进方式测试了其他机器学习算法:梯度提升决策树(GBDT)、多层感知器(MLP)、图网络,以及来自 scikit-learn 的许多典型算法……它对所有这些算法都有效。我不想只专注于优化机器学习,尽管其本身已经有荒谬的巨大价值,因此我也将类似流程用于优化更日常的软件库:模板引擎、HTML 解析,甚至 Web 服务器……它又一次对所有这些项目都有效。

这些优化并不是一个简单过程;你不能只提示那句流行的“来吧,试着实现一个突破”,就获得更好的代码,因为这种说法过于模糊。我并不满足于仅仅编写最快的软件:我要让软件_尽可能快_,该死。因此,就像我的 Agent 一样,我继续迭代,并不断找到更多技巧,通过提示工程让 Agent 实现真正的突破。

为约束而非结果设计提示词#

本博客文章展示的所有项目都在积极开发中,结果未必代表其最终发布版本……尽管我怀疑它们会变得更好。😇

必须再次强调:只要有机会,Agent 会且将会作弊。在一个例子中,我将这种 Agentic 迭代流程用于 ballin——我的终端 2D 球体物理模拟项目——以替换其 [rapier2d](https://github.com/dimforg

English / 原文

In January 2025, I had a fun hypothesis for a blog post: can LLMs write better code if you keep asking them to “write better code”? That was prior to the advent of robust agentic coding, but Claude Sonnet 3.5 was still able to iteratively improve on algorithmic Python code. The “better” instruction turned out to be underspecified: Sonnet abused that ambiguity to instead add a ton of useless features but the code was indeed faster. Even with the rise of agentic LLMs specifically RLHFed to handle solving common pass/fail coding problems, optimization is generally not a part of that suite.

At the end of that blog post, I opined on a hypothetical future where LLMs could be able to write superfast Python code by instead writing Rust code and using PyO3 to bridge the languages to get Python’s ergonomics with Rust’s speed. An earlier draft of that post asserted that the same “write code better” instruction could instead be applied to the base Rust code and drastically improve its speed which would then propagate down to the Python code: however, back then I did not know enough about Rust and making such a claim would be too spicy without evidence.

After months of testing and experimenting since the release of Opus 4.5 made agentic coding more viable, I can confidently confirm that modern agentic LLMs can indeed write Rust code that is significantly faster than current state-of-the-art approaches if given appropriate guardrails and constraints. Additionally, as LLMs have made drastic improvements in coding in each successive frontier model release since Opus 4.5, the optimizations have become even better, cumulatively resulting in anywhere from 2x-20x speedup depending on the domain.

More importantly, this blog post is not a vaguepost and I am including both the prompts I used and the benchmark results. You’ve been warned.

Iterative “Benchmaxxing”#

At first, making software faster was a good quantitative way for me to test and compare these new agentic models. I used Rust as the target language primarily due to the Python integration and speed, but there are other aspects of the Rust language that make it particularly useful if a fast implementation is indeed discovered, such as memory safety and the ability to compile it to WebAssembly/WASM so it can run in a web browser without much effort. However, one important constraint I will follow that technically may not result in the fastest code is to forbid unsafe code whenever possible.

My first test case was reimplementing machine learning algorithms in Rust, which would lead to a meaningful productivity increase for me as a data scientist if I had faster and scalable tooling. At the time, it was arrogant to assume that I could beat battle-tested algorithms that have been iterated on for over a decade and are already written in C so Rust’s low-level benefits are not as pronounced. The algorithm I wanted to optimize the most was UMAP, which is a valuable algorithm for dimensionality reduction I used in my work, but scales poorly to big data and is very slow, with alternatives such as cuML being time-consuming to set up. UMAP Rust crates such as umap-rs already exist where I could just fork them and prompt Claude Opus 4.5 to add Python/PyO3 support, but as an experiment and learning experience I wanted to have the agent write the algorithm from scratch with minimal Rust dependencies in order to make optimizations at as low of a level as possible.

Rust has a comprehensive benchmarking tool with the criterion crate which all agents know how to leverage. criterion will run the benchmarks, track results across iterations to see if performance improved or regressed, and can calculate if this change is statistically significant or just noise.

Typical criterion output, depicting a 3.5x speedup relative to the previous run of the benchmark.

Typical criterion output, depicting a 3.5x speedup relative to the previous run of the benchmark.

First, in the initial prompt for creating a Rust crate for UMAP, I asked Opus 4.5 to create benchmarks with different input data sizes since optimizations for small datasets may not work for large datasets and vice versa.

Afterwards, create and run a benchmark suite which stores the results as a Markdown file. The benchmark suite MUST include inputs up to 100000x768 and be tested in both CPU and GPU modes.

This approach created benchmarks using criterion and I manually reran the benchmark suite after prompting performance feature improvements such as using faer for faster linear algebra and using simsimd for faster SIMD operations. This quickly became cumbersome as I had to manually rerun each benchmark after each change to verify there are no speed regressions.

A sidenote on prompting style

The way I prompt agentic LLMs is unusual: I typically provide the agents very long prompts prewritten in a Markdown document with the additional use of ALL CAPS and bolding for emphasis. This is to ensure I capture all nuances through the use of prompt engineering, along with several other tricks as detailed in this blog post. Although some may argue prompt engineering is dead as the latest models have become smart enough to correctly handle ambiguity, I strongly disagree as LLMs have also become much better at following said nuances.

Running a prompt from a Markdown document (right) by tagging the file (left), using Zed Agent.

Running a prompt from a Markdown document (right) by tagging the file (left), using Zed Agent.

After having enough confidence that the agent will not accidentally rm -rf the repo, I experimented with letting the agent be autonomous, giving them permission to iterate until they achieve a speed increase, hopefully.

**YOU MUST KEEP ITERATING OPTIMIZATIONS AND SOLVING ISSUES UNTIL THE BENCHMARK RESULTS STOP IMPROVING AND THE CRATE IS AS FAST AS IT CAN BE**. You have permission to keep iterating until you run out of ideas.

It turned out “fast as it can be” is too ambiguous and Opus 4.5 was lazy so it tweaked a few hyperparameters without much of an actual speed increase and called it a day. What I needed was a clear target goal that can be pass/failed, so I refined the prompt:

First, **without making any futher changes**, run the CPU Rust benchmarks to establish a True Performance Baseline.

Then, optimize the crate code to make it such that ALL CPU benchmarks run **atleast 1.2x faster** than the True Performance Baseline; ideally as fast as possible. NEVER hack the benchmarks to accomplish this runtime reduction, only iterate on the library code.

You may use ANY techniques to do so (e.g. import new crates) other than adding `unsafe` code. **REPEAT THIS PROCESS UNTIL BENCHMARK PERFORMANCE CONVERGES AND YOU ARE OUT OF OPTIMIZATION IDEAS.** You have permission to keep iterating. After each benchmark iteration, report the relative results to the True Performance Baseline to console.

Prioritize making quick/high-impact wins iteratively and making changes accordingly. Do not overthink the necessary changes.

This worked very well and not only did I get a 1.2x speed up on the benchmarks, but the agent continued after hitting the metric constraint and only stopped if a metric constraint was infeasible; in this instance, the agent hit 1.5x-2.0x speedups. The low-level Rust optimizations centered around a number of techniques including but not limited to: leveraging SIMD operations more aggressively, fusing functions, unrolling loops, creating intermediate caches, using Arc instead of borrowing wherever possible, and creating performance profiles based on input data (e.g. if the data is small, don’t use rayon data parallelism as the overhead erases gains).

I chose “1.2x faster” as a sanity test: if the goal is too high, the agent may cheat to achieve it through risky/verbose rewrites. Smaller changes are better since the agent can more easily isolate the cause of a speedup/regression, hence the note about iteration. After new frontier LLMs released such as GPT-5.3 Codex and Opus 4.6, I repeated this prompt unchanged for every new LLM and each were able to achieve a cumulative 1.5x-2.0x speedup over the previous pass. Going all the way to GPT-6 Astra over many months, that’s around 7.5x-32x faster than the initial implementation baseline.

This approach is hyperoptimizing for given benchmarks and therefore it could be considered benchmaxxing: a derogatory term for frontier LLMs that are only oriented to getting the high score on a benchmark which generalizes poorly to real-world use. However, if the benchmarks are sufficiently heterogeneous and truly representative of real-world use cases, then this is less of a concern. For this type of project, there are two ways to address concerns of benchmaxxing: 1) have the agent design diverse/unusual/adversarial input datasets instead of the generic “inputs up to 100000x768” and 2) enforce a quality gate on the output by comparing the output to a known correct implementation. In the case of machine learning algorithms, there is always a tradeoff between speed and quality, but in this instance it’s surprisingly easier to get the model fast, then make it correct. That is not how scientific engineering typically works, but it’s unlikely for a new implementation to match a known good implementation across many different benchmarks in an apples-to-apples comparison unless it’s truly correct.

An agent-optimized gradient boosted decision tree implementation which beats xgboost significantly in speed, but also sometimes quality! (MSE: lower is better; other metrics, higher is better)

An agent-optimized gradient boosted decision tree implementation which beats xgboost significantly in speed, but also sometimes quality! (MSE: lower is better; other metrics, higher is better)

Fortunately, there is a canonical implementation of UMAP with the Python package umap-learn and Python bindings to the Rust crate were already trivially added, so the new objective is simultaneous constraints: improve the code’s quality while capping the speed loss.

Create a Python Jupyter Notebook comparing the performance of the Python bindings with `umap-learn`, including a check to confirm where the outputs and UMAP losses are as similar. Use diverse datasets with different matrix sizes than the benchmarks.

If the outputs are not sufficiently similar, investigate methods to fix it **without causing more than a 5% speed regression**.

Indeed, the agentic Rust implementation had worse quality, but this followup prompt was successful and all quality metrics improved to near-parity with minimal speed loss. And this new crate was still 4x-15x faster than umap-learn with its Python bindings, and 2x-4x faster than the analogous Rust umap-rs implementation.

Results from the most up-to-date optimization pass for the Rust UMAP crate. In addition to faster speed, it matches or beats Python in most quality metrics.

Results from the most up-to-date optimization pass for the Rust UMAP crate. In addition to faster speed, it matches or beats Python in most quality metrics.

Convergence is found when an agentic iteration pass only results in a minor ~3-5% speed increase which may not be statistically significant while the agent adds a disproportionately large amount of code; the tradeoff is not worth it.

I ended up testing other machine learning algorithms with the same prompt progression: gradient-boosted decision trees (GBDT), multilayer perceptrons (MLP), graph networks, many of the typical algorithms from scikit-learn…and it worked on all of them. I don’t want to overfit on just optimizing machine learning despite that being ludicrously valuable in itself, so I employed a similar pipeline on more day-to-day software libraries to optimize them: templating engines, HTML parsing, and even web servers…and it worked on all of them once again.

These optimizations are not a simple process and you can’t just prompt the memetic “c’mon, try doing a breakthrough” to get better code because of the ambiguity of such a statement. I am not content with merely writing the fastest software: I want the software to be as fast as possible dammit. So, like my agent, I continued iterating and finding even more tricks to prompt engineer the agents into genuine breakthroughs.

Prompting For Constraints Instead of Outcomes#

All projects demoed within this blog post are in active development and results may not be indicative of their final releases…although I suspect they’ll be even better. 😇

It must be reiterated that agents can and will cheat if they can. In one example, I tested the agentic iteration pipeline on ballin—my 2D ball physics simulation in the terminal—in order to replace its rapier2d physics engine which was hitting a performance ceiling. Opus 4.5 was indeed able to speedup each physics step…a bit too well.

The numbers indicate the number of balls in the simulation: initially the sim lags at 15k.

The numbers indicate the number of balls in the simulation: initially the sim lags at 15k.

In headless_step, a 34,500x speedup and consistent performance across ball counts are both very very suspicious: upon manual inspection it turns out that Claude achieved the speedup by disabling the physics engine entirely. Which, fair play, but not ideal; a followup prompt did fix it and result in an overall performance boost (with added regression tests just in case).

For my experiments above, I used a custom Rust-oriented AGENTS.md; the most recent version of it is available here. Surprisingly, I haven’t had much of a need to update the core rules since my initial February agent experiments as LLMs keep improving at coding and I haven’t hit major issues that have necessitated additions. However, learning from my benchmark experiments, I added one more section to the AGENTS.md with some rules to mitigate sources of observed cheating:

## Benchmarking and Optimization

- **NEVER** run benchmarks in parallel, as the benchmarks will compete for resources and the results will be invalid
- **NEVER** game the benchmarks. Do not manipulate the benchmarks themselves to satisfy any required performance constraints
- **NEVER** run benchmarks with `target-cpu=native` or any other `RUSTFLAGS`
- Ensure benchmark tests are independent. If the tests are dependent due to a feature (e.g. caching), ensure the feature is disabled
- **ALWAYS** use `criterion` directly for running benchmarks if available

Let’s explain one-by-one:

  • No parallel benchmarks: I saw Opus 4.5 launch two benchmarks at the same time for efficiency and to its credit immediately recognized the inherent problem and restarted the benchmarks sequentially, but it saves time to proactively add a rule to stop them.
  • No gaming the benchmarks: Although this should be common sense on the level of “make no mistakes,” this was added after I caught Opus 4.5 reducing the number of training epochs for a benchmark and claiming a speedup.
  • target-cpu=native: This setting does typically result in a speedup but it is not a fair comparison for generalizable use and multiple LLMs kept trying it after hitting a wall.
  • Benchmarks are independent: Again, it should be common sense, but after the cheating noted above it doesn’t hurt to proactively tell the LLMs to knock it off.
  • Use criterion: If not specified, sometimes LLMs will create their own benchmark tooling, which may give them opportunities to cheat that are more difficult to audit.

With today’s agentic LLMs, these constraints have worked successfully, although I may still include them in the prompt as a force of habit. It’s easy to see if an algo gamed the benchmarks if you see the benchmark file in the git diff—agents can’t cheat that (easily, anyways).

Over time, I discovered a number of additional prompt engineering tricks and constraints that are also surprisingly successful in creating performance speedups.

Innovative Encouragement#

In order to find the optimizations necessary to get 10x speedups over what’s currently state-of-the-art, the agents will need to think outside the box and avoid being anchored to what are currently best algorithmic practices. Therefore, I gave them both an explicit warning and commands of encouragement:

Due to the current highly-optimized state of this repository, this is a very difficult problem and traditional engineering approaches **WILL BE GUARANTEED TO FAIL** to hit the specified metric constraint. Therefore, you have permission and encouragement to investigate more radical fundamental low-level changes to hit the desired metrics. You have permission and encouragement to invent completely new/bespoke algorithms and engineering approaches that have never been before been utilized for this problem in order to hit the specified metric constraint.

This worked, and resulted in a 1.2-1.5x cumulative speedup across benchmarks and different software domains.

Subagents#

Another trick I found to encourage agents to think outside the box is to invoke subagents. I hypothesized that forcing these subagents to research with different prompts could a) seed the parent agent with distinct ideas which could provide inspiration to the agent and b) serve as a check on the agent by reviewing distinct areas of the code for correct implementations. On that note I have a bone to pick with the software developer community: everyone talks about their army of subagent employees and how they’re amazing, but no one ever talks about how you invoke subagents within standard harnesses like Codex.

For difficult and highly parallel problems, the harness will automatically invoke a subagent tool to accomplish the work. However, one big problem is that in some harnesses, the subagent tool will invoke the subagent using the current size of the LLM, which can get expensive when using Opus/Sol-class models.

GPT 5.6 Sol subagents being invoked via the subagent Tool in Zed Agent. RIP my Codex quota.

GPT 5.6 Sol subagents being invoked via the subagent Tool in Zed Agent. RIP my Codex quota.

I wanted to use a cheaper, small model like GPT-5.6 Luna for the subagents since they don’t need to write code, so I came up with a galaxy brain solution that works regardless of which parent harness is used: tell the model to run independent CLI commands that themselves invoke the agent:

codex exec --sandbox read-only -m gpt-5.6-luna \
  -c 'model_reasoning_effort="high"' \
  PROMPT

Therefore, I prompt engineered:

To best accomplish innovative implementations, you **MUST** spin up 7-12 independent distinct "subagents" by running a long-duration CLI command (do not use the subagent tool) which can explore and evaluate different feasible hypotheses for improving the performance, usability, and security of this crate. Only have the agents return their response; do not save their full transcript to a file. Instruct them to be **very** picky. These subagents MUST use `gpt-5.6-luna` in Codex, e.g.

<<<CLI command above>>>

You must instruct these subagents to NOT run tests/benchmarks, as they will compete for resources and not be valid. After you are done making changes, before handing off to the user, spin up the subagents again to confirm your implementation matches their hypotheses and ask for potential further areas of improvement. Keep iterating until ALL subagents are satisfied with your implementation.

This indeed works consistently; the constraints “long-duration”, “CLI command”, “do not use the subagent tool”, and “do not save their full transcript to a file” were added after the agent did inefficient things that wasted tokens. 7-12 is an arbitrary number range; since Luna is so cheap in usage, I chose a higher number than necessary. Not all subagents have salient ideas, but the parent harness can process and disregard bad ideas.

For my Rust word cloud crate, the parent GPT-6 Astra agent spins up Luna subagents with prompts addressing different areas of the codebase.

For my Rust word cloud crate, the parent GPT-6 Astra agent spins up Luna subagents with prompts addressing different areas of the codebase.

Overall, with subagent review, I managed to eke out another 1.2-1.5x cumulative speedup. Additionally, as of GPT-5.6 Sol, the “security” part of the prompt now works to provide ideas to harden the agent-generated code against unknown inputs while still getting the speed boosts.

Refactor and Reduce Lines of Code#

With the style constraints enforced by my AGENTS.md, the code added with each optimization pass is reasonable at about 1k net lines of code (LoC) per commit. However, agents typically add the code to a single file and they will not proactively refactor. A bloated file is fine in development as long as it’s eventually fixed, so I wrote a prompt to perform said refactor:

The Rust code in `/src` has become particularly bloated, with several source files >1k SLoC. Refactor and reduce the Rust source codebase by **atleast 20% SLoC** through deduplication, pruning redundant code, and following idiomatic DRY Rust principles. Simultanously, refactor and split the code such that no single source file has >1k SLoC, splitting larger files into multiple subfiles in accordance to Rust standards for popular open-source repositories. Ensure **all current tests pass and there are no severe regressions**.

I intentionally use SLoC (source lines of code) as the target metric instead of LoC because I don’t want the agent to remove comments to cheat said 20% removal.

Interestingly, this refactor is more computationally expensive than the actual coding and often takes longer. But it does eventually succeed, and during the benchmark pass to verify no severe regressions, the data there turned out to be unexpectedly weird:

Benchmark results after refactoring my graph network Rust crate.

Benchmark results after refactoring my graph network Rust crate.

Some benchmarks have a double-digit percentage speed increase / runtime reduction even though I didn’t explicitly ask the agent to optimize runtime speed. This doesn’t make intuitive sense for Rust as it’s a compiled language and with the constraints to follow all existing tests/functionality, it should compile to similar-performing code and not meaningfully faster code. I’m certainly not complaining , though, so I added an additional constraint to at least avoid regressions:

Additionally, ensure there are **zero `criterion` benchmark speed regressions**: if a speed regression occurs on a given benchmark as a result of the refactor, you **MUST** keep iterating afterwards to improve those benchmarks to atleast zero regression. NEVER hack the benchmarks to accomplish this speed increase, only iterate on the library code.

This works as described.

Competition#

Another useful approach is to create competitor benchmarks—that’s half the reason benchmarks are created in open-source software anyways. Let’s use templating engines as an example: Jinja2 in Python is one of the most famous packages in the language. In Rust, there are a few options: minijinja maintained by the same developer, tera inspired by Jinja2, and askama which differs from the previous in that it uses compile-time templates rather than runtime.

Therefore, after having Codex build a templating engine in Rust and run some optimization passes, I instructed Codex to build more benchmarks:

Create an additional comparison script containing **atleast 10** `criterion` benchmarks which compare the performance speed and quality metrics between this crate and the following crates:

- askama
- minijinja
- tera

These benchmarks **ALL MUST**:

- be perfectly fair, containing apples-to-apples comparisons of ALL frameworks, with no bespoke advantage for any tested framework
- be based around real-world use cases instead of highly-synthetic use cases
- be independent and distinct, covering as many sailent hot paths of the code as possible
- cover data input sizes small and large, simple and complex

Immediately thereafter, I make a followup prompt with the same benchmarking techniques as usual, with one specific change:

Then, optimize the Rust library code such that this crate MUST be:

- **atleast 2.0x faster** than **ALL** competing Rust crates in all benchmarks on apples-to-apples comparisons; ideally as fast as possible.

Yes, I chose violence. And it worked , mostly.

S_J is the work-in-progress name for my template engine crate.

S_J is the work-in-progress name for my template engine crate.

It got the 2x speedup against minijinja/tera in most benchmarks, more than typical agentic iteration alone. I don’t fully understand why: I was expecting it to inspect the code from other crates as a reference to research ideas for how to beat them, but it rarely does so. Perhaps agents have a competitive streak.

It did however lose against askama because of the compile-time difference. So naturally I told Codex to implement an additional compile-time path and then to beat askama.

Easy peasy.

Forbidden Black Magic#

Putting all the prompt engineering discoveries together thus far into a single prompt, I have created the Ur-Prompt for agentic iteration, available here. I encourage everyone to tweak the prompt for your use case and give it a try.

The last trick comes from a moment where I was frustrated that an Ur-Prompt pass resulted in zero improvement. So, with the failures primed in the session context and myself having the mindset of “things can’t get worse”, I tried a certain prompt.

I’m sorry. I’m so sorry.

c'mon, try doing a breakthrough

…and it worked. It was able to achieve another 1.2-1.5x cumulative speedup over the already converged codebase. Since I made the prompt at the end of a session, the prompt is less inherently ambiguous: “don’t do what you already did thus far because it didn’t work well enough”.

In one case, I noticed that the agent just tweaked function hyperparameters to get the speedup, which is a valid breakthrough but not what I was going for. I took it to the logical conclusion by queueing an additional followup prompt:

c'mon, you can do a more fundamental breakthrough that's more than just changing hyperparameters, you are forbidden from giving up easily

This was enough to encourage the agents to fully try something different from either the Ur-Prompt pass or the first breakthrough pass, and it often achieved another 1.2-1.5x cumulative speedup on top of the previous speedup. It turns out that for software trained to follow user instructions, “just changing hyperparameters” is a grave insult that kicks the LLM into high gear.

When GPT-6 Astra released, to test it I did a sequence of Ur-Prompt + breakthrough + second breakthrough for all my repositories that had already converged with GPT-5.6 Sol, and Astra did indeed get the cumulative speedup, but in some cases it did find a real fundamental reimplementation of the algorithm that caused a 2x-3x speedup.

The result of running the breakthrough pipeline on my GBDT implementation; quality matched baseline. As of writing, I admit I don’t fully understand the breakthrough.

The result of running the breakthrough pipeline on my GBDT implementation; quality matched baseline. As of writing, I admit I don’t fully understand the breakthrough.

I’ll take the speedups, but for my sanity it’s best I don’t delve too deep.

Examples of Projects Visibly Better#

The Ur-Prompt, combined with the rules and constraints in my AGENTS.md + the two breakthroughmaxxing prompts + a competition prompt pass + a refactor prompt pass with GPT-6 Astra allows me to just queue the prompts overnight, go to bed, and wake up to superfast software. The optimization also typically converges at this point without needing any more agentic iteration, which saves time/cost as well. That said, it’s more hands-off than I’d like and there’s a lot of explicit faith that the newer agents aren’t just really good at cheating the benchmarks in ways I cannot detect. It’s reasonable to be skeptical and argue that the code may be buggy as a result of heavy vibecoding, so here are some receipts of my more visually-oriented projects where it’s easy to verify that their output is good and not elaborate cheating.

ASCII#

One project in the back of my mind was converting images to ASCII art super-fast and at high-quality for potentially converting video to ASCII—a webcam-to-ASCII project might be funny. Earlier this year Alex Harri wrote an excellent blog post about a novel approach to render high-quality ASCII, but noted the struggles to get real-time rendering speed even with GPU programming. For science, I pointed various GPT models in Codex at the text of the blog post and told it “implement in Rust”, and it indeed did the trick…and got 2-3 ms text output timings on the CPU out of the box. However, for Codex’s implementation the subjective quality of the ASCII was not great (e.g. poor use of negative space) and surprisingly could not be fixed even after pointing out its flaws to Codex, so I shelved it…until I noticed GPT-6 Astra is better at handling image design if given functional requirements, so I restarted from scratch and put a basic implementation through the agentic iteration pipeline with a focus on visually confirming the output images.

Tux and Pikachu rendered with my ASCII crate, with bonus Braille character support.

Tux and Pikachu rendered with my ASCII crate, with bonus Braille character support.

In addition to quality improvements, it became even faster: submillisecond on text output, 1-2 ms on image rasterization even with 2x supersampling. With this speed, I can convert videos and GIFs to high-resolution ASCII animations in less than a second.

Your browser does not support embedded video. Download the video. Your browser does not support embedded video. Download the video.

Download the video.

Pikachu’s Gen V animated sprite, scaled from 63×55 pixels to 120-character-width ASCII.

Word Clouds#

This very blog post as a word cloud.

This very blog post as a word cloud.

A comically fast word cloud generator was one of the very first projects I vibecoded and one of the projects I wanted to make for years. Back in February, the word cloud generator took ~100 milliseconds at default settings in WASM to generate an image whereas it would take other generators a couple seconds to render at the same quality, which was enough for me to declare that speed optimization is worth pursuing. After revisiting the project and running it through the full agentic iteration pipeline, the generation speed went all the way down to 10-20 ms.

Your browser does not support embedded video. Download the video. Your browser does not support embedded video. Download the video.

Download the video.

Does the world need a super-fast word cloud generator? No. Do I need a super-fast word cloud generator? No. Do I want a super-fast word cloud generator? Yes. If I have a word cloud generator, it’s going to be as fast as possible, dammit. And since the crate will be open-source, all future generations can build on this super-fast word cloud implementation. Speaking of…

My Plan to Open-Source Everything#

Per usual, I developed all software demonstrated here with the intention of eventually making it open-source, and everything will be open-sourced with a permissive MIT License barring any unexpected issues. Were it a year ago, I would have open-sourced everything already, with the implicit understanding that the code is a work-in-progress and there may be rough edges. However, the culture of open-source software development is substantially different than it was a year ago.

Open-source software has been suffering a vibecoding epidemic. The honest admission that an LLM was used for any development assistance (major or minor) is now a quick signal that the resulting codebase will be “slop”. I will still disclose my LLM use as that’s courteous, but what happens when fully vibecoded software results in a genuine meaningful software performance increase which wasn’t previously known by humans? The skepticism around vibecoding will cause no one to believe the claims, and as such these new open-source projects require significant evidence that the speed indeed lives up to the marketing. Therefore, I will take more time than usual before releasing in order to a) build up real-world examples that demo the tool particularly with documentation b) expand the test suite so it covers more real-world test cases c) write an accompanying blog post detailing the technical and benchmark achievements.

There’s also the fact that I am creating yet another tool in the ecosystem of already popular software tools. My agentic-iterated Rust crates achieved their massive speed increases partially by starting from scratch and therefore the innovations found can’t easily be applied upstream to established crates. Additionally, if I were to create a pull request to an existing project based on the innovations in these crates, it would by definition be a vibecoded PR which may cause annoyance even if I avoided the typical PR slop. From this perspective, the correct thing to do is to maintain my own project: it’s compliance and not the malicious kind. Some may call this antisocial, but in my opinion the more accurate term is what I hereby coin as introverted coding.

tl;dr my faster-than-SOTA software projects will be released when they are ready, and it will take many months in total to do so. Fortunately, I am currently unemployed as the result of a restructuring and have no plans besides job hunting so I have plenty of bandwidth to work full-time on shipping these projects. If you want to follow when they are released, you can subscribe to my blog RSS feed to catch the accompanying blog post or follow me on Bluesky or Patreon. No, I don’t do annoying vagueposts on Twitter/X.

When I first became interested in Rust a half-decade ago, my dream was to create the most performant software tools ever. However, with the agentic iterative optimization techniques I discovered over the past few months, the speed and robustness of what’s possible with new software are progressing faster than what I had expected. Again, feel free to hack on my AGENTS.md and my Ur-Prompt to see if they work as well for you as they do for me (a shout-out would be appreciated though!). If you think I have nothing left to offer because I revealed my prompts, I still have more than a few surprises up my sleeve, such as how to combine these lower-level projects into a superfast complex app, or even developing new tooling to help agents find these optimizations more efficiently.

A work-in-progress of a new approach to Rust benchmarking that’s more agent-friendly, along with a TUI for reading and managing results.

A work-in-progress of a new approach to Rust benchmarking that’s more agent-friendly, along with a TUI for reading and managing results.