Direkt zum Hauptinhalt
Ankündigungen

Benchmarking von Coding-Agenten auf der Codebasis von Databricks mit mehreren Millionen Zeilen

von Vinay Gaba, Ankit Mathur, Rishabh Singh, Patrick Wendell und Matei Zaharia

Bei Databricks verändert sich die Art und Weise, wie wir Software entwickeln, rasant, da wir AI im Engineering-Bereich offensiv einsetzen. Die Landschaft der Modelle und Harnesses für die Code-Erstellung hat sich im letzten Jahr rasant vergrößert, sodass Entwickler mehr Auswahl als je zuvor haben. Mit mehr Optionen wird es immer wichtiger zu verstehen, welche Coding Agents die beste Performance bei realen Programmieraufgaben bieten und wie diese Performance mit dem Preis variiert.

Dieser Artikel stellt die Ergebnisse und die Methodik des internen Coding-Benchmarks vor, den wir bei Databricks entwickelt haben. Er evaluiert Tools anhand tatsächlicher Programmieraufgaben, die unsere Engineers in der Databricks-Codebasis durchgeführt haben. Die Aufgaben umfassten Änderungen an einer Codebasis mit mehreren Millionen Zeilen, die viele beliebte Sprachen (Python, Go, Typescript, Scala usw.) abdeckt. Sowohl die Aufgaben als auch die Lösungen wurden sorgfältig überprüft, um die Genauigkeit sicherzustellen. Dies soll keine vollständige Analyse sein, aber die Untersuchung hat Erkenntnisse geliefert, die unser Engineering-Team beim Einsatz von Coding Agents bereits deutlich effizienter gemacht haben. Unten sehen Sie, wie die Modelle und Harnesses im Gesamt-Benchmark abgeschnitten haben:

Kosten vs. Performance in unserem Benchmark

Abbildung 1: Kosten vs. Performance in unserem Benchmark

Die wichtigsten Schlussfolgerungen aus unserer Analyse waren:

  1. Die Pareto-Grenze für Programmieraufgaben (d. h. die beste Qualität für bestimmte Kosten) umfasst Modelle von OpenAI, Anthropic und Open Source. Das bedeutet, dass heute nur ein Mix aus verschiedenen Tools Spitzenleistungen erbringen kann.
  2. Offene Modelle, und insbesondere GLM 5.2, sind mittlerweile in der Lage, selbst Aufgaben mit dem höchsten Schwierigkeitsgrad zu bewältigen.
  3. Der Token-Preis eines Modells ist ein schlechter Indikator für die tatsächlich anfallenden Kosten bei End-to-End-Aufgaben. Größere Modelle können weitaus token-effizienter sein und geringere Gesamtkosten verursachen.
  4. Das Harness, aus dem ein Modell aufgerufen wird, hat einen drastischen Einfluss auf Kosten und Qualität. In vielen Fällen schnitten einfache Harnesses wie Pi bei unseren Workloads am besten ab.

Lassen Sie uns auf jeden dieser Punkte etwas näher eingehen.

Modelle gruppieren sich in grobe „Leistungsstufen“

Dass spezifische Ergebnisse um einige Punkte abweichen, gleicht sich in der Praxis oft aus. Wir haben uns mehr auf die thematischen Muster konzentriert, die uns bei der Entscheidung helfen, welche Modelle wir für verschiedene Aufgaben einsetzen. Tatsächlich zeigten die Ergebnisse eine klare Gruppierung der Modelle und Harnesses in 3 Leistungsstufen.

Leistungsstufen für Modelle

Abbildung 2: In unseren Gesamtergebnissen zeichneten sich drei verschiedene Leistungsstufen ab, mit feinen Unterschieden darin, welche Modelle in der jeweiligen Gruppe effektiv waren

Am oberen Ende der Performance sehen wir, dass die intelligentesten Modelle sehr effektiv bei der Lösung aller Arten von Problemen sind, aber sie sind sehr teuer. Modelle mittlerer und geringerer Intelligenz sind bei den gängigen Aufgaben immer noch hochgradig effektiv und in vielen Fällen auch deutlich günstiger.

Im Alltag tun Engineers viele verschiedene Dinge, die sich in ihrer Komplexität stark unterscheiden: Einfache operative Aufgaben wie das Umlegen eines Flags oder das Aktualisieren von Konfigurationen erfordern keine extrem intelligenten Modelle, tiefere Design-Untersuchungen hingegen schon. In der Vergangenheit waren unsere Standardmodelle jedoch immer die teuersten . Basierend auf dieser Analyse haben wir beschlossen, mehr Arbeit an Modelle der Haiku- und GPT 5.4 Mini-Klasse zu übergeben.

Offene Modelle sind bereit für das Coding

Es gab viel Begeisterung um GLM 5.2, und unsere Ergebnisse zeigen, dass GLM für viele unserer Entwickler ein Modell für den täglichen Einsatz sein kann. Es landete in der obersten Leistungsstufe, statistisch gleichauf mit Opus 4.8 in Bezug auf die Qualität, kostete jedoch 1,28 $ pro Aufgabe im Vergleich zu 1,94 $ bei Opus.

Die Qualitätsbewertungen von GLM decken sich mit dem qualitativen Feedback, das wir von internen Entwicklern erhalten haben, die GLM für die tägliche Entwicklung testen. Aufgrund seiner hervorragenden Performance bei alltäglichen Programmieraufgaben haben wir uns darauf konzentriert, GLM mit der besten Performance bereitzustellen, und die Ergebnisse zeigen, dass es an der Zeit ist, diese Modelle als Standard-Tools für das Coding einzusetzen.

Preis pro Aufgabe vs. Preis pro Token

Entwickler schätzen Token-Kosten oft grob ab, um zu bestimmen, wie teuer ein Modell bei der Erledigung von Programmieraufgaben sein wird. Wir haben jedoch festgestellt, dass Token-Kosten aufgrund von Unterschieden in der Argumentationseffizienz der Modelle oft ein schlechter Indikator für die Gesamtkosten einer Aufgabe sind. Dies unterstreicht die Notwendigkeit von Benchmarks auf Aufgabenebene, da die Art und Komplexität der Aufgaben in verschiedenen Kontexten unterschiedlich sein können.

Beispielsweise ist Sonnet 5 pro Token ca. 1,7-mal günstiger als Opus 4.8. Bei unseren Aufgaben stellten wir jedoch fest, dass Sonnet 2,09 $ pro Aufgabe kostete, verglichen mit 1,94 $ bei Opus, während es bei der Aufgabenerfüllung sechs Punkte schlechter abschnitt (81 % vs. 87 %). Dies lag hauptsächlich daran, dass Sonnet 5 länger arbeitete und mehr las, um ans Ziel zu gelangen, was 1,9-mal mehr Token verbrauchte.

Harnesses haben einen großen Einfluss auf die Effizienz

Als wir dasselbe Modell mit demselben Denkaufwand über zwei verschiedene Harnesses (Claude Code/Codex vs. Pi) laufen ließen, stellten wir fest, dass sich die Kosten pro Aufgabe erheblich unterschieden (in einigen Fällen um mehr als das Zweifache), während die Qualität gleich blieb. Der Hauptunterschied lag darin, wie viel Kontext das jeweilige Harness dem Modell in jedem Durchgang übermittelte.

Einfluss des Harnesses auf die Effizienz

Pi sendete etwa 3-mal weniger Kontext pro Durchgang. Es verwaltete den Kontext besser, hielt das Working Set kompakter und schloss die Aufgaben in weniger Durchläufen ab.
Gesamter Kontext, der dem Modell pro Aufgabe erneut übermittelt wurde

Die Lehre daraus ist nicht, dass ein Harness immer günstiger oder dass native Harnesses schlechter sind. Stattdessen ist die Modellwahl nur ein Teil des Puzzles. Die Etablierung dieser Flexibilität ist der Grund, warum wir in Omnigent investiert haben, um den Wechsel von Modellen und Harnesses nahtlos zu gestalten.

Warum einen eigenen Benchmark erstellen?

Öffentliche Benchmarks wie SWE-Bench und TerminalBench sind nützlich, aber sie können die Fragen, die wir hatten, nicht beantworten. Dafür gibt es einige Gründe:

  • Die Aufgaben sind öffentlich, sodass die Lösungen im Laufe der Zeit in die Trainingsdaten einfließen.
  • Wir haben festgestellt, dass die Ergebnisse für unsere Codebasis nicht repräsentativ waren, da diese mehr als 10 Sprachen und viele in Scala, Go, Rust, Java und Python geschriebene Dienste, Bazel, Protobuf und mehr umfasst.

Indem wir einen Benchmark auf Basis unserer eigenen PRs erstellen, können wir diese Entscheidungen mit größerer Sicherheit treffen, ohne unsere Entwickler durch die Einführung von Optimierungen zu behindern.

Wie wir den Benchmark aufgebaut haben

Wir haben das Unity AI Gateway genutzt, um Protokolle all unserer Coding-Interaktionen zu erfassen. Dies ermöglichte uns, die Komplexität der Aufgaben zu analysieren, die Engineers mithilfe von Coding Agents bewältigen. Die Aufgabenkomplexität war sehr unterschiedlich: Etwa ein Viertel wurde als Arbeit mit geringer Komplexität eingestuft und ca. 60 % als mittlere Komplexität.

Was unsere Engineers tatsächlich von Coding Agents verlangen

Da teure Modelle jedoch die Standardmodelle sind, die Engineers verwenden, gab es hier eindeutig ein riesiges Potenzial zur Effizienzsteigerung.

Erstellung der Aufgaben

Unsere Engineers führen täglich Tausende von Codeänderungen zusammen, sodass wir bereits über einen hervorragenden Datensatz verfügen, auf dem wir aufbauen können. Ein guter Pull Request ist ein wertvolles Artefakt mit Commits, die die Iteration des Entwicklers, die Überprüfung durch Menschen und Tests zeigen, die bestätigen, dass eine Codeänderung ihrer Absicht entspricht. Wir benötigten jedoch mehrere Qualitätsprüfungen und Filter, um daraus einen qualitativ hochwertigen Benchmark zu erstellen:

  • Aktualität: Wir greifen auf die jüngere Vergangenheit zurück, damit die Aufgaben widerspiegeln, wie wir heute entwickeln, einschließlich der aktuell verwendeten Frameworks, Muster und Konventionen.
  • Von Menschen geschrieben: Bot-Commits, Service-Konten, vollständig AI-generierte Änderungen und automatisch generierte Änderungen wurden herausgefiltert.
  • Zugehörige qualitativ hochwertige Testsuite: Wir haben nach PRs gefiltert, die qualitativ hochwertige Tests zur Validierung der Codeänderungen enthielten.
  • In sich geschlossen: Die Änderungen beschränkten sich auf wenige Module.
  • Repräsentativ für typische Aufgaben: Wir haben PRs aus einer Verteilung von Aufgaben über den gesamten Stack ausgewählt: Scala-Backend-Services, Rust-Systemcode, das React- und TypeScript-Frontend, Protobuf- und gRPC-Contracts sowie Bazel-Konfigurationen.
Schritt-für-Schritt-Plan zur Aufgabenerstellung

Sobald wir geeignete PR-Kandidaten hatten, konzentrierten wir uns darauf, präzise spezifizierte Aufgaben zu erstellen, indem wir:

  1. Die Absicht erfassen und als Prompt zusammenfassen. Wir haben den PR gelesen, um zu verstehen, worum es eigentlich ging, und dann das gewünschte Ergebnis beschrieben. Normalerweise bedeutete dies, die PR-Beschreibung neu zu schreiben, indem wir das Problem oder Ziel nannten, etwaige Einschränkungen angaben und die Beschreibung der Lösung entfernten. Es ist wichtig, beispielsweise Erklärungen darüber zu entfernen, warum eine Fehlerbehebung die richtige ist, da dies die Aufgabe zu einfach macht.
  2. Die relevanten Tests herausfiltern. Die Nicht-Test-Dateien stellten die Änderung dar, die das Modell selbstständig reproduzieren muss. Daher haben wir die Testdateien beiseitegelegt und sichergestellt, dass wir den Code kompilieren konnten. Unser Build-System kann bereits ermitteln, welche Tests von den im ursprünglichen PR geänderten Dateien abhängen, sodass wir all diese Test-Targets vollständig ausgeführt haben.

Das Ergebnis dieser Übung war eine einzelne Aufgabe im Benchmark. Hier ist ein vereinfachtes Beispiel:

Obwohl wir Skripte und AI verwendet haben, um potenzielle Aufgaben zu generieren, haben wir jede einzelne Stichprobe manuell ausgewertet. In einigen Fällen stellten wir fest, dass Tests im ursprünglichen PR umgeschrieben werden mussten, um eine alternative Implementierung zu ermöglichen oder strenger zu sein, was wir manuell (ohne AI) taten. Ebenso fanden wir Fälle, in denen die Aufgabenbeschreibung verbessert werden musste, um sie präzise zu spezifizieren.

Vorher-Nachher-Vergleich aus der Testsuite

Abbildung 3: Ein Vorher-Nachher-Vergleich aus unserer Testsuite: Der vorherige Test basierte auf der Überprüfung einer exakten String-Übereinstimmung, was zu einigen Fehlern führte, als das Modell versuchte, die Aufgabe zu lösen. Dies war keine gute Methode, um nicht-deterministische Ausgaben zu testen, weshalb der Test umgeschrieben wurde, um stattdessen das Verhalten zu bewerten.

Wir haben die Coding-Agent-Harnesses und -Modelle in ihren Standard-Setups („out of the box“) instanziiert, mit allen gängigen Tools, die auch Databricks-Engineers zur Verfügung stehen würden.

Setup- und Überprüfungsprozess

Als der Agent explizit erklärte, dass er die Aufgabe abgeschlossen hat, haben wir diesen Code per Checkpoint gesichert, die zurückgehaltenen Tests eingespielt und die Tests ausgewertet, um festzustellen, ob diese Aufgabe für diese Kombination aus Modell und Harness ein „Bestanden“ ist. Wir haben keinen LLM-Judge verwendet, um die Korrektheit zu bewerten, da wir festgestellt haben, dass dies belohnt, wenn etwas richtig klingt, anstatt tatsächlich richtig zu sein.

Zusätzliche Guardrails

Zusätzliche Guardrails

In unseren frühen Experimenten sahen einige Modell-Scores zu gut aus, um wahr zu sein. Daher haben wir die Traces manuell untersucht, um zu verstehen, was in diesen Agenten-Trajektorien passiert ist. Wir stellten fest, dass aufgrund unseres ursprünglichen Setups die „korrekte“ Implementierung in der Git-Historie des Worktrees immer noch rekonstruierbar war! Jede Aufgabe stammte aus einem gemergten Commit, sodass nichts einen Agenten mit einer Shell daran hinderte, in der Git-Historie vorwärts zu gehen, um sie zu finden. Um dieses Problem zu beheben, haben wir die Git-Historie versiegelt: Für die Dauer jedes Durchlaufs haben wir die Arbeitskopie vollständig vom Repository getrennt.

Wie geht es weiter?

Wir haben mit einer einfachen Frage begonnen: Können wir Coding-Agenten effizienter nutzen? Die Antwort ist ein klares Ja. Und da wir datengestützt arbeiten können, können wir damit beginnen, Funktionen zu entwickeln, um automatisch die richtigen Modelle auszuwählen und die Effizienz zu verfolgen.

Jedes Unternehmen kann das Gleiche tun. Jedes Team mit einem Backlog an gemergten PRs verfügt bereits über einen Benchmark, mit dem noch kein Modell trainiert wurde, bewertet durch die von Ihrem Team geschriebenen Tests. Wir fügen aktiv weitere Aufgaben hinzu (insbesondere schwierigere) und planen, jeden neuen Agenten/Harness damit zu testen, um mehr Vertrauen in unsere Entscheidungen zu gewinnen.

Bei Databricks waren wir schon immer vorsichtig gegenüber einem Lock-in – nicht nur bei Anbietern, sondern auch bei Annahmen, die Teams im Laufe der Zeit unflexibler machen. Derselbe Instinkt prägte unsere frühen Wetten auf offene Formate und Standards, und er prägt auch unseren heutigen Umgang mit AI: Wir messen, was bei dem von uns ausgelieferten Code tatsächlich funktioniert, geben Engineers den Freiraum, zwischen Modellen und Harnesses mit konsistenten Guardrails zu wechseln, und nehmen Optimierungen vor, um AI effektiv zu nutzen.

In einem folgenden Blogbeitrag werden wir näher darauf eingehen, wie wir intelligente Routing-Funktionen in Unity AI Gateway und in Omnigent nutzen, um unseren Entwicklern dabei zu helfen, die intelligentesten Agenten effizient einzusetzen.

(Dieser Blogbeitrag wurde mit KI-gestützten Tools übersetzt.) Originalbeitrag

Erhalten Sie die neuesten Beiträge in Ihrem Posteingang

Abonnieren Sie unseren Blog und erhalten Sie die neuesten Beiträge direkt in Ihren Posteingang.