Tips & Tricks

Harness Engineering: Der vollständige Leitfaden zum Bau von KI-Agenten nach Claude-Code-Vorbild

Mit Prompts allein beherrscht man kein LLM. Lerne, wie Werkzeuge, Kontext und Kontrollschleifen zu einem Harness verwoben werden – mit lauffähigem Code und Claude Codes eigener Architektur.

Die Ära des „einfach einen Prompt an ChatGPT werfen” ist vorbei. Seit 2025 verlagert sich der Schwerpunkt der KI-Entwicklung rasant hin zum Harness Engineering. In den internen Blogs von Anthropic und in der Agenten-Forschung von OpenAI gehört der Begriff zu den am häufigsten genannten.

Doch fragt man jemanden „Was ist ein Harness?”, bleibt die Antwort meist vage. Dieser Artikel seziert Harness Engineering anhand von lauffähigem Code und der Architektur von Claude Code selbst. Am Ende hast du alles, um deinen eigenen Agenten von Grund auf zu bauen.

Ein Harness ist das „Gerüst” rund um die KI

„Harness” heißt ursprünglich Pferdegeschirr oder Sicherheitsgurt. In der Softwarewelt denken wir an das Testharness: die äußere Konstruktion, die etwas überhaupt zum Laufen bringt.

Im KI-Kontext ist ein Harness die Wrapper-Schicht um ein LLM. Konkret bündelt sie alles, was das Modell für reale Aufgaben braucht:

  • Werkzeuge: Dateien lesen, Kommandos ausführen, APIs aufrufen
  • Kontextmanagement: Was merken, was vergessen, was komprimieren?
  • Kontrollschleife: Wann aufrufen, wann stoppen, wann erneut versuchen?
  • Berechtigungen und Sicherungen: damit destruktive Aktionen nicht ungefragt laufen
  • Gedächtnis: Wissen, das sitzungsübergreifend bleibt

Der Prompt ist nur ein Input in dieses Harness. Ist das Harness schwach, stößt selbst der klügste Prompt an eine Leistungsgrenze. Genau deshalb heißt es: „Prompt Engineering allein reicht nicht mehr.”

Warum der Harness entscheidend ist: die OODA-Schleife

Ein LLM allein kann nur „den nächsten Token erzeugen”. Reale Aufgaben verlangen eine OODA-Schleife (Observe → Orient → Decide → Act) aus der Militärstrategie.

PhaseInhaltZuständig
Observe (Beobachten)Umgebung lesen (Dateien, DB-Abfragen)Harness
Orient (Einordnen)Informationen aufbereiten und dem LLM gebenHarness
Decide (Entscheiden)Nächsten Schritt wählenLLM
Act (Handeln)Ausführen (Kommandos, API-Calls)Harness

Wie man sieht, liegen drei von vier Phasen beim Harness. Das LLM glänzt nur beim Entscheiden. Die Qualität des Gerüsts rundherum bestimmt die Gesamtqualität des Agenten.

Drei Harness-Stufen im Beispiel

Lösen wir dieselbe Aufgabe „Blogartikel generieren” auf drei Eskalationsstufen.

Stufe 1: Nackter API-Aufruf (nahezu kein Harness)

import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();

const res = await client.messages.create({
  model: "claude-opus-4-6",
  max_tokens: 4096,
  messages: [{ role: "user", content: "Schreibe einen Blogartikel" }],
});
console.log(res.content[0].text);

Ergebnis: allgemeiner, hohler Text. Thema und Struktur variieren jedes Mal.

Stufe 2: Werkzeuge einführen (mittleres Harness)

const tools = [
  {
    name: "read_existing_posts",
    description: "Liste vorhandener Blogartikel mit ihren Titeln liefern",
    input_schema: { type: "object", properties: {} },
  },
  {
    name: "write_post",
    description: "MDX-Datei schreiben",
    input_schema: {
      type: "object",
      properties: {
        slug: { type: "string" },
        frontmatter: { type: "object" },
        body: { type: "string" },
      },
      required: ["slug", "frontmatter", "body"],
    },
  },
];

async function runAgent(userGoal: string) {
  let messages = [{ role: "user", content: userGoal }];
  while (true) {
    const res = await client.messages.create({
      model: "claude-opus-4-6",
      max_tokens: 4096,
      tools,
      messages,
    });
    if (res.stop_reason === "end_turn") break;

    // Das Harness führt den Tool-Aufruf aus
    const toolUse = res.content.find((c) => c.type === "tool_use");
    const result = await executeTool(toolUse.name, toolUse.input);
    messages.push({ role: "assistant", content: res.content });
    messages.push({
      role: "user",
      content: [{ type: "tool_result", tool_use_id: toolUse.id, content: result }],
    });
  }
}

Ergebnis: Es wird ein nicht-redundantes Thema gewählt und ein formal korrektes MDX erzeugt. Allein das Hinzufügen von Werkzeugen verändert die Qualität drastisch.

Stufe 3: Ein vollwertiges Harness im Claude-Code-Stil

  • Autonome Schleife (Benutzerfreigabe, Fehler-Retry)
  • Kontextkompression (lange Gespräche zusammenfassen, Tokens sparen)
  • Subagent-Delegation (Übersetzung in isoliertem Kontext)
  • Prompt Caching (statischen Präfix nicht erneut senden)
  • Hooks (automatisches Lint vor dem Commit)

Das alles selbst zu bauen ist ein Großprojekt. Genau deshalb lohnt es, Claude Code als Referenzimplementierung zu studieren.

Das Harness von Claude Code zerlegt

Claude Code ist das am besten ausgearbeitete Agenten-Harness innerhalb von Anthropic. Es lässt sich in fünf Schichten zerlegen.

Schicht 1: Werkzeugdesign

Ab Werk gibt es Read, Edit, Write, Bash, Glob, Grep, Agent usw. Bemerkenswert ist die Granularität:

  • Grep ist kein simples grep, sondern ein ripgrep-Wrapper – präzise und schnell
  • Edit schreibt nicht die ganze Datei neu, sondern ersetzt gezielt Strings – minimale Diffs
  • Agent startet einen Subagenten mit isoliertem Kontext

Tool-Qualität schlägt direkt auf Agenten-Qualität durch. „Hauptsache es läuft” reicht nicht. Werkzeuge müssen idempotent sein, klare Fehlermeldungen liefern und eine einzige Verantwortung tragen.

Schicht 2: Geschichteter Kontext

~/.claude/CLAUDE.md         ← globale Regeln
./CLAUDE.md                 ← Projektregeln (automatisch geladen)
~/.claude/memory/           ← Langzeitgedächtnis (sitzungsübergreifend)
  ├── user_profile.md
  ├── feedback_xxx.md
  └── project_xxx.md
Gesprächsverlauf             ← letzte Züge
Tasks/Plan                   ← Fortschritt der aktuellen Sitzung

Jede Schicht hat andere Lebensdauer und Rolle. Schreibt man an die falsche Stelle, verschwindet Information sofort oder – schlimmer – veraltete Daten bleiben hartnäckig. „Nur diese Sitzung” gehört in Tasks, „immer wieder nötig” gehört ins Memory.

Schicht 3: Subagent-Delegation

Mit dem Agent-Werkzeug startet man einen Agenten in separatem Kontext.

# Der Haupt-Agent gibt Anweisungen, die Schwerarbeit macht der Subagent
Agent(
  subagent_type: "general-purpose",
  prompt: "blog/harness.mdx ins Englische und in 8 weitere Sprachen übersetzen,
           jeweils unter blog-{lang}/ speichern, danach berichten"
)

So bleibt der Hauptkontext frei von Log-Lärm. Lange Build-Logs, Zwischen-Übersetzungen, Suchauszüge – alles, wovon man nur das Ergebnis braucht, lässt sich komplett auslagern.

Schicht 4: Hooks (deterministische Verarbeitung)

In .claude/settings.json kann man Shell-Kommandos vor und nach Tool-Aufrufen einhängen.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "npx tsc --noEmit" }
        ]
      }
    ]
  }
}

Nach jeder Bearbeitung läuft automatisch der Typ-Check. Was „besser deterministisch als bei jedem Aufruf vom LLM erledigt” werden sollte, gehört in einen Hook.

Schicht 5: Berechtigungsmodi

{
  "permissions": {
    "allow": ["Read", "Grep", "Glob"],
    "deny": ["Bash(rm -rf*)", "Bash(git push --force*)"],
    "ask": ["Write", "Edit", "Bash"]
  }
}

Destruktive Kommandos explizit verbieten, Schreibvorgänge zur Bestätigung vorlegen. Unfälle passieren, wenn etwas unbeaufsichtigt ausgeführt wird – daher entscheidet diese Schicht über die Betriebssicherheit.

Fünf klassische Stolperfallen

1. Zu viele Werkzeuge Mit 30 Tools verzettelt sich das Modell und wird ungenauer. Faustregel: 5 bis 15. Fehlende Funktionen gehören in Subagenten.

2. Prompt-Caching bleibt ungenutzt Wer cache_control der Claude-API ignoriert, schickt den langen System-Prompt jedes Mal komplett – und zahlt dafür. TTL von fünf Minuten im Blick behalten und statische Teile cachen.

messages: [{
  role: "system",
  content: [
    { type: "text", text: longStaticInstructions,
      cache_control: { type: "ephemeral" } },   // ← genau das
    { type: "text", text: dynamicContext },
  ],
}]

3. Fehlermeldungen, die das LLM nicht versteht Liefert ein Tool nur Error: undefined, kann sich das Modell nicht selbst reparieren. Schreib hinein, was schiefgelaufen ist und wie es zu beheben ist.

throw new Error(
  `Datei '${path}' existiert nicht. ` +
  `Aktuelle Dateien in scripts/: ${list.join(", ")}`
);

4. Menschliche Freigabe auslassen Automatisch genehmigte destruktive Aktionen (Löschen, Force-Push, DB-Update) führen zwangsläufig irgendwann zum Unfall. Standard: „Schreiben fragt, Löschen verboten.”

5. Gedächtnis nie entrümpeln Veraltete Informationen ziehen den Agenten zu falschen Annahmen. Auch Memory braucht regelmäßiges Ausmisten (in Claude Code per /compact oder manueller Bearbeitung).

Bau dir dein eigenes Mini-Harness

Zum Schluss ein lokal lauffähiges Mini-Harness in Node.js + TypeScript.

// mini-harness.ts
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync, writeFileSync } from "fs";

const client = new Anthropic();

const tools = [
  { name: "read_file",
    description: "Eine Textdatei lesen",
    input_schema: { type: "object", properties: { path: { type: "string" } }, required: ["path"] } },
  { name: "write_file",
    description: "Eine Textdatei schreiben",
    input_schema: { type: "object", properties: { path: { type: "string" }, content: { type: "string" } }, required: ["path", "content"] } },
];

const executors = {
  read_file: ({ path }) => readFileSync(path, "utf-8"),
  write_file: ({ path, content }) => { writeFileSync(path, content); return `written ${path}`; },
};

async function loop(goal: string, maxSteps = 10) {
  const messages: any[] = [{ role: "user", content: goal }];
  for (let i = 0; i < maxSteps; i++) {
    const res = await client.messages.create({
      model: "claude-opus-4-6", max_tokens: 4096, tools, messages,
    });
    messages.push({ role: "assistant", content: res.content });
    if (res.stop_reason === "end_turn") return res.content;

    const toolUse = res.content.find((c: any) => c.type === "tool_use") as any;
    if (!toolUse) return res.content;
    const result = executors[toolUse.name](toolUse.input);
    messages.push({
      role: "user",
      content: [{ type: "tool_result", tool_use_id: toolUse.id, content: String(result) }],
    });
  }
}

await loop("Lies README.md und speichere eine dreizeilige Zusammenfassung in TL;DR.md");

Damit steht bereits ein Mini-Agent, der bestehende Dateien lesen und neue schreiben kann. Ergänzt um Grep-, Bash- und Agent-Werkzeuge entsteht ein Claude Code im Kleinformat.

Fazit: Vom Prompt-Autor zum Harness-Architekten

Alte SichtweiseNeue Sichtweise
Guter Prompt, gutes ErgebnisGutes Harness, gutes Ergebnis
Modell auswählenModell + Werkzeuge + Kontext + Rechte entwerfen
Einzelne FragenFortlaufender Schleifenbetrieb

Claude Code ist das beste Lehrbuch, um diesen Perspektivwechsel zu erfahren. Nicht bloß benutzen – zerlegen und die Ideen in den eigenen Agenten übertragen. Das ist die Haltung, die KI-Ingenieur:innen ab 2026 verlangt wird.

Kopiere zuerst das obige Mini-Harness und starte es. Zehn Minuten später hast du den ersten Schritt zu deinem eigenen Agenten gemacht.

Verwandte Artikel

Weiterführende Quellen

#claude-code #agent-sdk #harness #prompt-engineering #llm #anthropic

Bring deinen Claude-Code-Workflow aufs nächste Level

50 in der Praxis erprobte Prompt-Vorlagen zum direkten Copy-and-paste in Claude Code.

Kostenlos

Kostenloses PDF: Claude-Code-Spickzettel in 5 Minuten

Trag einfach deine E-Mail-Adresse ein – wir senden dir den A4-Spickzettel als PDF sofort zu.

Wir behandeln deine Daten sorgfältig und senden niemals Spam.

Masa

Über den Autor

Masa

Ingenieur, der Claude Code intensiv nutzt. Betreibt claudecode-lab.com, ein Tech-Medium in 10 Sprachen mit über 2.000 Seiten.