메뉴
HN
Hacker News 51일 전

연구 중심 에이전트: 코딩 전 논문을 읽을 때

IMP
8/10
핵심 요약

코드만 분석하던 기존 AI 에이전트에 '논문 및 경쟁 프로젝트 리서치' 단계를 추가했더니, 사람이 놓칠 수 있는 핵심 최적화(OOM 문제 해결 등)를 찾아냅니다. 실제로 llama.cpp 프로젝트에 적용해 약 3시간 만에 x86 환경에서 15%, ARM에서 5%의 속도 향상을 달성하며 그 성능을 입증했습니다. 이는 단순한 코딩 도구를 넘어, 도메인 지식을 활용하는 시니어 엔지니어처럼 동작하는 에이전트의 가능성을 보여줍니다.

번역된 본문

목차

  • 코드 컨텍스트만으로 작동하는 경우
  • 코드 컨텍스트만으로 한계에 부딪히는 경우
  • 리서치 단계 추가
  • 실험 로그
  • 리서치 결과
  • 전환: 연산(Compute)에서 메모리(Memory)로
  • 성공한 최적화들
    1. 소프트맥스 퓨전 (Softmax fusion)
    2. RMS 정규화 퓨전 (RMS norm fusion)
    3. 적응형 from_float 병렬화 (Adaptive from_float parallelization)
    4. 그래프 수준 RMS_NORM + MUL 퓨전 (Graph-level RMS_NORM + MUL fusion)
    5. 플래시 어텐션 KQ 퓨전 (Flash attention KQ fusion)
  • 결과
  • 작동하지 않았던 것들
    • 실패한 실험들
    • 벤치마크 버그
    • 클라우드 VM의 노이즈
  • 코드 리뷰
  • 코딩 에이전트를 위한 시사점
  • 여러분의 프로젝트에 직접 적용해보기

TL;DR (요약): 코딩 에이전트는 코드를 작성하기 전에 논문을 읽고 경쟁 프로젝트를 학습할 때 더 나은 최적화를 생성합니다. 우리는 autoresearch / pi-autoresearch 루프에 문헌 검색 단계를 추가하고, 4개의 클라우드 VM을 사용해 llama.cpp를 대상으로 실행했습니다. 그 결과 약 3시간 만에 5가지 최적화를 도출하여 x86에서 플래시 어텐션 텍스트 생성 속도를 +15%, ARM(TinyLlama 1.1B)에서 +5% 향상시켰습니다. 전체 설정은 벤치마크와 테스트 스위트가 있는 모든 프로젝트에서 작동합니다.

핵심 요약:

  • 코드를 작성하기 전에 논문과 경쟁 프로젝트를 학습하는 에이전트는 코드만 다루는 에이전트가 놓치는 최적화를 찾아냅니다.
  • 문헌 연구는 CUDA/Metal 백엔드에는 있지만 CPU에는 없는 연산자 퓨전(operator fusion)을 에이전트가 파악하게 해주었습니다.
  • 30개 이상의 실험 중 5개가 성공했습니다: 4개의 커널 퓨전(kernel fusion)과 1개의 적응형 병렬화.
  • 가장 큰 성과는 플래시 어텐션의 QK 타일에 대한 3번의 패스를 단일 AVX2 FMA 루프로 퓨전한 것입니다.
  • arXiv를 검색하는 것보다 프로젝트 포크(fork)와 다른 백엔드를 연구하는 것이 더 생산적이었습니다. ik_llama.cpp와 CUDA 백엔드는 최종 5가지 최적화 중 2개에 직접적인 영감을 주었습니다.
  • 총 비용: 약 $29 (CPU VM $20, API 호출 $9) / 4개의 VM으로 약 3시간 소요.

코드 컨텍스트만으로 작동하는 경우

Karpathy의 autoresearch는 코딩 에이전트가 자율적으로 신경망 학습 스크립트를 개선할 수 있음을 보여주었습니다. 우리의 이전 글에서는 이를 16개의 GPU로 확장하여 8시간 동안 약 910개의 실험을 실행하도록 관찰했고, val_bpb를 2.87% 감소시켰습니다. 이 에이전트는 코드 컨텍스트만으로 아이디어를 냈으며, 모든 실험은 동일한 train.py에 대한 변형이었습니다. 그 이후로 pi-autoresearch는 이 루프를 벤치마크 가능한 모든 대상에 사용할 수 있는 재사용 가능한 확장으로 일반화했습니다.

Shopify CEO인 Tobi Lütke는 연간 $292B의 상품 거래량을 처리하는 Ruby 템플릿 엔진인 Liquid에서 이를 실행했습니다. 에이전트는 약 120개의 실험을 실행하여 93개의 커밋을 생성했고, 974개의 단위 테스트에서 회귀(regression) 없이 파싱 및 렌더링 시간을 53%, 할당을 61% 줄였습니다 (Simon Willison의 글, Tobi의 글). 이 경우 최적화 대상이 소스 코드상에 보였습니다. Liquid 에이전트는 토크나이저를 읽고 StringScanner가 병목 현상임을 파악한 다음, 코드베이스만으로 대안을 브레인스토밍할 수 있었습니다.

코드 컨텍스트만으로 한계에 부딪히는 경우

모든 최적화 문제가 이런 식으로 작동하는 것은 아닙니다. 코드베이스는 코드가 무엇을 하는지는 알려주지만, 왜 느린지 또는 이 코드베이스 밖에 어떤 대안이 있는지는 알려주지 않습니다. (예를 들어, 시니어 엔지니어가 가지고 있을 도메인 지식인 arXiv 논문이나 경쟁 프로젝트에 답이 있는 경우) 소스 코드만으로 작업하는 에이전트는 얕은 수준의 가설만 세우게 됩니다.

우리는 에이전트를 llama.cpp의 CPU 추론 경로로 향하게 했을 때 이 문제를 보았습니다. 최적화 탐색 공간은 '다른 학습률(learning rate)을 시도해보라'가 아닙니다. '이 두 메모리 패스를 퓨전해야 하는가?', '이 워크로드가 연산 집중적인가(Compute-bound) 아니면 메모리 집중적인가(Memory-bound)?', 'ik_llama.cpp는 이미 무엇을 시도했는가?'와 같은 질문들입니다.

에이전트의 첫 번째 실험 웨이브(wave)는 문제를 보여주었습니다. 코드 컨텍스트만으로 작업한 결과, GGML의 행렬 곱셈 핫 패스에 있는 양자화된 닷 프로덕트 내의 SIMD 마이크로 최적화로 바로 직행했습니다. 다음을 시도했습니다:

  • Q4_0 닷 프로덕트 이너 루프에서의 AVX2 프리페칭 (+0.8%)
  • 듀얼 누산기(dual accumulators)를 사용한 2x 루프 언롤링 (+0.9%)
  • mul_mat의 임시 버퍼 제거 (-2.8%, 성능 회귀 발생)
  • 블록 경계 계산 외부로 추출(Hoisting) (+0.6%)

이 모든 것은 노이즈 오차 범위 내에 불과했습니다. 에이전트의 사후 분석(postmortem) 결과는 다음과 같습니다: "웨이브 1 결과는..."

원문 보기
원문 보기 (영어)
Table of Contents Where code-only context works Where code-only context breaks down Adding a research phase The experiment log What the research turned up The pivot: from compute to memory Optimizations that landed 1. Softmax fusion 2. RMS norm fusion 3. Adaptive from_float parallelization 4. Graph-level RMS_NORM + MUL fusion 5. Flash attention KQ fusion Results What didn’t work Experiments that failed The benchmark bug Cloud VMs are noisy The code review What this means for coding agents Try it on your own project TL;DR: Coding agents generate better optimizations when they read papers and study competing projects before touching code. We added a literature search phase to the autoresearch / pi-autoresearch loop, pointed it at llama.cpp with 4 cloud VMs, and in ~3 hours it produced 5 optimizations that made flash attention text generation +15% faster on x86 and +5% faster on ARM ( TinyLlama 1.1B ). The full setup works with any project that has a benchmark and test suite. Key takeaways: Agents that read papers and study competing projects before writing code find optimizations that code-only agents miss. The literature research pointed the agent at operator fusions present in CUDA/Metal backends but absent from CPU. 5 of 30+ experiments landed: 4 kernel fusions and an adaptive parallelization. The biggest win fused three passes over flash attention’s QK tile into a single AVX2 FMA loop. Studying forks and other backends was more productive than searching arxiv. ik_llama.cpp and the CUDA backend directly informed two of the five final optimizations. Total cost: ~$29 ($20 in CPU VMs, $9 in API calls) over ~3 hours with 4 VMs. Where code-only context works # Karpathy’s autoresearch showed that a coding agent can autonomously improve a neural network training script. In our previous post , we scaled that to 16 GPUs and watched the agent run ~910 experiments in 8 hours, driving val_bpb down 2.87%. The agent brainstormed ideas from code context alone, and the experiments were all variations on the same train.py . Since then, pi-autoresearch generalized the loop into a reusable extension for any benchmarkable target. Shopify CEO Tobi Lütke ran it on Liquid , the Ruby template engine that processes $292B in annual merchandise volume. The agent ran ~120 experiments, producing 93 commits that cut parse+render time by 53% and allocations by 61% with zero regressions across 974 unit tests ( Simon Willison’s writeup , Tobi’s post ). In that case, the optimization surface was visible in the source. The Liquid agent could read the tokenizer, see that StringScanner was the bottleneck, and brainstorm alternatives from the codebase alone. Where code-only context breaks down # Not every optimization problem works this way. A codebase tells you what the code does , but not why it’s slow or what alternatives exist outside of this codebase . When the answer lives outside the source (in arxiv papers, in competing projects, e.g. in the domain knowledge a senior engineer would bring), an agent working from code alone will generate shallow hypotheses. We saw this when we pointed the agent at llama.cpp ’s CPU inference path. The optimization search space isn’t “try a different learning rate.” It’s “should I fuse these two memory passes?”, “is this workload compute-bound or memory-bound?”, “what has ik_llama.cpp already tried?” The agent’s first wave of experiments showed the problem. Working from code context alone, it went straight for SIMD micro-optimizations in the quantized dot products that sit in GGML’s matrix multiplication hot path. It tried: AVX2 prefetching in the Q4_0 dot product inner loop (+0.8%) 2x loop unrolling with dual accumulators (+0.9%) Eliminating a temporary buffer in mul_mat (-2.8%, regression) Hoisting block boundary calculations (+0.6%) All within noise. The agent’s postmortem: “Wave 1 results show that micro-optimizations in the compute path give negligible returns because text generation is memory-bandwidth bound, not compute bound.” A 606 MiB model at ~49 tokens/s consumes ~30 GB/s of memory bandwidth, close to the c6i.2xlarge’s DRAM limit. No amount of SIMD tricks will help when the CPU is stalled waiting for model weights to arrive from DRAM. But the code alone doesn’t tell you this. You need to know the memory bandwidth of the target hardware, understand the roofline model, and recognize that batch-size-1 inference is memory-bound. That’s domain knowledge the agent didn’t have. Adding a research phase # If the bottleneck is hypothesis quality, give the agent better inputs. Before running any experiments, have it read papers, study forks, and look at what other projects have already tried. The same preparation a senior engineer would do before touching unfamiliar code. The original autoresearch loop is: edit code -> run experiment -> check metric -> keep or discard. pi-autoresearch generalized this to any project with a benchmarkable metric. Our version builds on that and adds a research step and parallel cloud execution: The agent writes its own benchmark script ( autoresearch.sh ) and correctness checks ( autoresearch.checks.sh ), then uses SkyPilot to fan out experiments across cloud VMs. Each experiment runs on its own VM: build the project, run the benchmark, run correctness checks, report metrics. The agent checks results via sky logs , commits winners, and queues the next wave. experiment.yaml : SkyPilot task template for one experiment resources : cpus : 4 + memory : 8 + workdir : . envs : EXPERIMENT_ID : baseline EXPERIMENT_DESC : "baseline measurement" BUILD_CMD : "make -j$(nproc)" BENCH_TIMEOUT : 300 CHECK_TIMEOUT : 300 setup : | cd ~/sky_workdir if [ -f setup_deps.sh ]; then bash setup_deps.sh else eval "${BUILD_CMD}" fi run : | cd ~/sky_workdir # Build, benchmark, run checks, report METRIC lines eval "${BUILD_CMD}" 2>&1 | tail -30 BENCH_OUTPUT=$(timeout "${BENCH_TIMEOUT}" bash autoresearch.sh 2>&1) echo "$BENCH_OUTPUT" # ... extract METRIC lines, run autoresearch.checks.sh ... echo "EXPERIMENT_STATUS: done" No GPU needed for CPU-bound code optimization. Override with --gpus if your target needs GPU benchmarking. The experiment log # We pointed Claude Code at llama.cpp, gave it 4 AWS VMs via SkyPilot, and told it to make CPU inference faster. Target: CPU inference throughput for TinyLlama 1.1B (Q4_0 quantization), benchmarked on two architectures: x86: AWS c6i.2xlarge (Intel Xeon Ice Lake, 8 vCPUs, AVX-512) ARM: AWS c7g.2xlarge (Graviton3, 8 vCPUs, NEON) Metric: tokens/second for prompt processing (pp) and text generation (tg), measured with llama-bench -p 512 -n 128 -t 8 -r 5 . It started with 4 x86 VMs to establish baselines and run experiments. Later it provisioned ARM VMs to check portability; each kernel fusion includes both AVX2/FMA and NEON paths, with scalar fallbacks. What the research turned up # Between experiment waves, the agent ran two parallel research threads: Competing projects: ik_llama.cpp (a performance-focused fork), llamafile’s tinyBLAS, PowerInfer, ExLlamaV2 (the author of this post wasn’t even aware of some of these projects) Arxiv papers: FlashAttention (IO-aware tiled attention), Blockbuster (block-level operator fusion), LLM Inference Acceleration via Efficient Operation Fusion , Online normalizer calculation for softmax , Inference Performance Optimization for Large Language Models on CPUs (Intel’s cache-aware thread partitioning) The top findings: ik_llama.cpp’s row-interleaved quantization repacking gave 2.9x PP improvement. It was already upstreamed to mainline llama.cpp via the Q4_0_8x8 repack format. The agent confirmed it was active in the benchmark. The Blockbuster paper proposes fusing the entire FFN block (RMSNorm + gate matmul + up matmul + SwiGLU + down matmul)