Menguji performa model LLM pada repositori skala monorepo (jutaan baris kode) seperti benchmark SWE-bench atau Databricks memunculkan tantangan unik: eksekusi kode acak dari model berisiko merusak sistem host, pencarian konteks melampaui batas context window dan RAM, serta waktu eksekusi unit test yang lambat.
Untuk memperoleh metrik evaluasi yang deterministik tanpa membahayakan infrastruktur, diperlukan arsitektur evaluasi berbasis sandbox terisolasi, mekanisme context retrieval ringan, dan harness testing otomatis berbasis Git worktree.
Arsitektur Sandbox: Rootless Podman dan MicroVM
Coding agent sering kali menghasilkan instruksi sistem yang destruktif (misalnya rm -rf / atau instalasi dependensi arbitrer). Menjalankan agent langsung pada host adalah risiko keamanan kritis. Pendekatan standar industri menggunakan rootless container (Podman) atau microVM (seperti Firecracker).
Rootless Podman memberikan pemisahan user namespace: pengguna root di dalam container dipetakan ke UID non-root pada host. Dengan membatasi memory, CPU, dan akses jaringan eksternal, container aman dari risiko breakout dan network abuse.
Spesifikasi Containerfile Sandbox
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
git \
python3 \
python3-pip \
python3-venv \
universal-ctags \
bubblewrap \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -m -s /bin/bash evaluator
USER evaluator
WORKDIR /workspace
CMD ["/bin/bash"]Jalankan runner sandbox dengan batas resource eksplisit dan jaringan terputus (air-gapped) selama fase evaluasi:
podman run --rm -it \
--network none \
--memory 4g \
--cpus 2.0 \
--cap-drop ALL \
--volume /tmp/workspace:/workspace:rw \
sandbox-evaluator:latestContext Retrieval Hemat Memori: ctags vs Language Server Protocol (LSP)
Pada repositori jutaan baris, memuat full AST (Abstract Syntax Tree) ke dalam memori via LSP sering kali memicu Out-Of-Memory (OOM). Penggunaan Universal Ctags atau SCIP (SCIP Code Intelligence Protocol) menghasilkan indeks simbol berbasis tag teks yang jauh lebih hemat RAM.
Ctags membaca definisi fungsi, kelas, dan variabel tanpa memerlukan analisis tipe mendalam yang memakan pulangan gigabyte memori. File tags yang dihasilkan dapat di-query secara efisien menggunakan binary search oleh runner agent.
Eksekusi Indeksasi ctags
ctags --recurse=yes \
--languages=Python,Java,Go \
--exclude=.git \
--exclude=build \
--exclude=node_modules \
--fields=+ne \
--output-format=json \
-f symbols.json .Agent memanfaatkan symbols.json untuk menemukan referensi file dan line number sebelum mengambil irisan kode sumber yang relevan, menjaga konsumsi memori runner tetap di bawah 200MB terlepas dari ukuran repositori.
Isolasi Repositori: Git Worktree Ephemeral
Melakukan git clone berulang kali untuk jutaan baris kode menghabiskan bandwidth dan disk I/O. Solusi deterministik adalah mempertahankan satu bare repository atau main checkout lokal, lalu menggunakan git worktree terisolasi per task evaluasi.
Setiap evaluasi membuat branch sementara dari basis commit benchmark, mengaplikasikan patch yang dibuat oleh LLM, menjalankan verifikasi test suite, lalu menghapus worktree tanpa mengubah state master repository.
Script Runner Evaluasi
Script Python berikut mengorkestrasi pembuatan worktree, validasi sintaks patch, eksekusi test runner di dalam sandbox Podman, dan penghitungan metrik (Resolved / Unresolved).
import subprocess
import sys
import os
import shutil
REPO_DIR = "/srv/repo-master"
WORKTREE_BASE = "/tmp/eval-runs"
def run_command(cmd, cwd=None):
return subprocess.run(cmd, cwd=cwd, shell=True, text=True, capture_output=True)
def evaluate_task(task_id, base_commit, patch_content, test_command):
task_dir = os.path.join(WORKTREE_BASE, task_id)
os.makedirs(WORKTREE_BASE, exist_ok=True)
# 1. Siapkan worktree terisolasi
run_command(f"git worktree add -b {task_id}-eval {task_dir} {base_commit}", cwd=REPO_DIR)
try:
# 2. Terapkan patch LLM via git apply
patch_path = f"/tmp/{task_id}.patch"
with open(patch_path, "w") as f:
f.write(patch_content)
apply_res = run_command(f"git apply {patch_path}", cwd=task_dir)
if apply_res.returncode != 0:
return {"status": "PATCH_FAILED", "error": apply_res.stderr}
# 3. Jalankan test runner di rootless Podman
podman_cmd = (
f"podman run --rm \
" f"--network none \
" f"--memory 2g \
" f"--volume {task_dir}:/workspace:ro \
" f"sandbox-evaluator:latest \
" f"bash -c 'cd /workspace && {test_command}'"
)
test_res = run_command(podman_cmd)
# 4. Verifikasi exit code pengujian
resolved = test_res.returncode == 0
return {
"status": "RESOLVED" if resolved else "TEST_FAILED",
"stdout": test_res.stdout,
"stderr": test_res.stderr
}
finally:
# Cleanup worktree
run_command(f"git worktree remove --force {task_dir}", cwd=REPO_DIR)
run_command(f"git branch -D {task_id}-eval", cwd=REPO_DIR)
if os.path.exists(patch_path):
os.remove(patch_path)
if __name__ == "__main__":
# ponytail: evaluasi minimalis; ganti dengan multi-worker runner pada production.
res = evaluate_task(
task_id="T101",
base_commit="HEAD",
patch_content="""--- a/calc.py\n+++ b/calc.py\n@@ -1,2 +1,2 @@\ndef add(a, b):\n- return a - b\n+ return a + b\n""",
test_command="pytest tests/test_calc.py"
)
print(res)Pipeline CI/CD untuk Evaluasi Coding Agent
Pipeline Continuous Integration bertugas menjalankan benchmark otomatis setiap kali prompt template, retrieval layer, atau engine model diperbarui. Determinisme dicapai dengan menetapkan timeout ketat dan seeding nilai pseudo-random jika runtime bahasa membutuhkannya.
# .gitlab-ci.yml / GitHub Actions workflow core step
name: Benchmark Agent
on: [workflow_dispatch]
jobs:
evaluate:
runs-on: self-hosted
steps:
- name: Mount Shared Bare Repo
run: |
git --git-dir=/srv/repo-master.git fetch origin
- name: Execute Evaluation Matrix
run: |
python3 run_eval.py \
--dataset benchmark_tasks.json \
--concurrency 4 \
--timeout-seconds 180
- name: Publish Pass@1 Metrics
run: |
python3 generate_report.py --input results.jsonTrade-off dan Limitasi
- Network Isolation vs Dependency Fetching: Flag
--network nonemencegah exfiltration, namun menggagalkan test yang membutuhkan dependensi online. Solusi: build base image yang telah memiliki cache package lokal (misal:wheelhousepip atau local Maven repository). - IOPS Bottleneck: Pembuatan puluhan Git worktree secara paralel pada monorepo jutaan baris membebani storage. Gunakan memory-backed filesystem (tmpfs) atau ZFS/Btrfs snapshot untuk instant zero-copy branching.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!