Agentic AI

Warum ich keine eigene Agent-Loop geschrieben habe: Das Argument für AgentCore Harness

17 min Lesezeit
· Zuletzt aktualisiert: 31. August 2026
Warum ich keine eigene Agent-Loop geschrieben habe: Das Argument für AgentCore Harness

Hinweis: Dieser Artikel wurde mit Unterstützung von KI aus dem englischen Original übersetzt.

TL;DR: Ich habe darauf verzichtet, eine eigene Agent-Loop zu schreiben, und dieses Projekt stattdessen auf AWS Bedrock AgentCore Harness aufgesetzt, weil eine selbstgebaute Loop mich Einrichtungsaufwand, langsame Iteration und Tool-Integrations-Klempnerarbeit gekostet hätte, die nichts mit der Qualifizierung eines Sales-Deals zu tun hat. Eine Harness braucht nur zwei Pflichtparameter, einen Namen und eine Execution Role, und jeder weitere Block (Modell, Prompt, Tools, Skills, Memory) wird später angehängt und in rund 20 Sekunden per Update aktualisiert. Der schärfste Befund: Eine Harness für einen dateisystembasierten Skill container-backed zu machen, muss nicht bedeuten, dem Modell Shell-Zugriff zu gewähren – ich habe diese beiden Entscheidungen bewusst getrennt gehalten.

Teil 2 der Serie „Einen Partner-Sales-Agent auf Amazon Bedrock AgentCore bauen“, aufgebaut um ein reales Projekt: ein dialogbasierter Agent, der HubSpot CRM und AWS Partner Central für das Sales-Team eines AWS-Partners verbindet. Artikel 1 hat die gesamte Architektur durchlaufen, während dieser Artikel für das Teil in ihrer Mitte argumentiert, die verwaltete Agent-Loop, bevor überhaupt irgendetwas konfiguriert wird. Alles, was hier beschrieben wird, ist deployt und läuft, und jedes Setup wird zuerst konsolenbasiert dargestellt, mit Terraform und boto3 hinter meinem eigenen Build.

Inhaltsverzeichnis

Das Problem, das eine Harness löst

Die Agent-Loop selbst ist ein Wochenendprojekt. Die Konversation plus die Tool-Definitionen an ein Modell schicken, entweder Text oder einen Tool-Call zurücklesen, das Tool ausführen, das Ergebnis anhängen, wiederholen, bis das Modell keine Tools mehr anfragt. Ich habe diese Loop schon einmal geschrieben. Wäre das die ganze Aufgabe, gäbe es diesen Artikel nicht.

Die Kosten stecken in allem rund um die Loop. Als ich durchgerechnet habe, was diese Demo ohne eine verwaltete Runtime bräuchte, zerfiel die Liste in drei Kategorien.

Setup. Bevor die Loop auch nur einmal läuft, brauchen Sie eine Modell-Anbindung, ein Orchestrierungs-Framework, eine Runtime-Umgebung, die die Loop hostet, einen Deployment-Pfad für diese Runtime und obendrauf eine Memory-Integration.

Iterationsgeschwindigkeit. Eine selbstgebaute Loop backt ihre Konfiguration in einen Service ein, den Sie selbst betreiben, sodass jede Änderung ein Redeploy dieses Service bedeutet: ein neues Tool, ein umformulierter System-Prompt, ein anderes Modell. Dieser Build hat seinen System-Prompt wiederholt gegen Live-Testergebnisse überarbeitet, und weil der Prompt Harness-Konfiguration statt Anwendungscode ist, war jede Überarbeitung ein Update-Apply, das in rund 20 Sekunden abgeschlossen war, ohne dass irgendetwas neu deployt wurde. Dieser Unterschied summiert sich. Prompt-Tuning mit 20 Sekunden pro Versuch ist eine andere Tätigkeit als Prompt-Tuning mit einem Container-Build pro Versuch.

Tool-Integration. Memory, Retrieval, Browser, Code-Ausführung und externe APIs docken alle unterschiedlich an, und jede Quelle bringt ihre eigene Transport- und Auth-Geschichte mit. Bei einer selbstgebauten Loop gibt es keine gemeinsame Connector-Schicht, die man geschenkt bekommt. Diese eine Demo verbindet sechs Gateway-vermittelte Tools über vier Targets, einen dateisystembasierten Skill und einen Memory-Store. Jede dieser Integrationen ist Konfiguration auf der Harness statt Code, den ich pflege, und der Code, der tatsächlich existiert, liegt hinter dem Gateway, niemals innerhalb der Loop.

Konkret: Ohne eine Harness hätte dieses Projekt eine eigene Agent-Loop, eine eigene Tool-Dispatch-Logik, eine eigene Session- und Memory-Anbindung und eine eigene Container-Orchestrierung gebraucht, bevor der Agent auch nur eine einzige BANT-Qualifizierungsfrage (Budget, Authority, Need, Timeline) beantwortet hätte. Der Wert der Demo steckt in ihren Tools, ihren Guardrails und ihrem Prompt. Nichts davon steckt in der Loop.

Diese drei Kategorien sind auch der übertragbare Kern. Prüfen Sie sie als Checkliste gegen Ihren eigenen geplanten Build. Wenn Sie ein Tool haben, keinen Memory-Bedarf und einen bestehenden Service, der die Loop hosten kann, ist eine selbstgebaute Lösung vertretbar und lässt Sie die volle Kontrolle über das Innenleben der Loop behalten. Dieser Build ist bei allen drei Punkten durch die Checkliste gefallen, weshalb AgentCore Harness, inzwischen generell verfügbar [1], im Zentrum der Architektur meines ersten Artikels steht.

Was eine Harness tatsächlich ist

Eine Harness ist eine vollständig verwaltete Agent-Loop. Sie übergeben AgentCore eine Konfiguration: welches Modell, welcher System-Prompt, welche Tools und Skills, welches Memory. AgentCore führt die Loop aus, die entscheidet, wann geantwortet und wann ein Tool aufgerufen wird [2]. Es gibt keinen Framework-Code zu schreiben und keinen eigenen Service am Leben zu halten.

In der AWS Management Console liegt die Harness in der Amazon-Bedrock-AgentCore-Konsole unter Build, neben Runtime, Gateways, Memory, Policy und Identity; ein eigener Test-Bereich enthält den Harness-Playground, der später in diesem Artikel verwendet wird.

AgentCore Harness

Die API verlangt genau zwei Dinge, einen Harness-Namen und eine Execution-Role-ARN, und das Erstellungsformular der Konsole spiegelt genau diese Aufteilung. Alles andere in diesem Formular ist optional: Modell, System-Prompt, Tools, Skills, Memory, Timeouts, Umgebungseinstellungen. All das kann später per Update ergänzt werden, und das meiste davon kann sogar pro Invocation überschrieben werden [2]. In der Management Console übernimmt AWS die Erstellung der Execution Role basierend auf dem Harness-Namen. Eigentlich wird für den Einstieg nur der Name der Harness benötigt.

AgentCore Harness

Die Zwei-Parameter-Behauptung gilt auch außerhalb der Konsole. Das Schema des Terraform-Providers für aws_bedrockagentcore_harness markiert nur zwei Top-Level-Attribute als erforderlich, harness_name und execution_role_arn, und ein boto3-Aufruf ist so einfach wie dieser [2]:

Python
import boto3client = boto3.client("bedrock-agentcore-control")harness = client.create_harness(    harness_name="MyFirstAgentWithHarness",    executionRoleArn="<your_harness_execution_role>")

Die vollständigere Form als boto3-Äquivalent, mit den optionalen Blöcken, die dieses Projekt nutzt, sieht so aus:

Python
harness = client.create_harness(    harness_name="MyFirstAgentWithHarness",    executionRoleArn="<your_harness_execution_role>",    system_prompt={"text": "You are a helpful assistant"},    model={"bedrockModelConfig": {        "modelId": "eu.anthropic.claude-sonnet-5"    }},    skills={"path": "<path_to_skill>"},    tools=[{        "type": "agentcore_gateway",        "name": "mygatewaytools",        "config": {"agentCoreGateway": {            "arn": "<gateway_arn>"        }}    }])

Die Modell-ID dort ist die, die dieses Projekt deployt: eu.anthropic.claude-sonnet-5, das EU-Cross-Region-Inference-Profil statt der nackten Modell-ID. Meine ausgelieferte Harness nutzt am Ende die meisten der großen optionalen Blöcke, die diese API bietet:

  • ein Modell-Block
  • ein langer, regelnummerierter System-Prompt
  • eine Gateway-Tool-Bindung
  • ein Skill
  • eine Memory-Anbindung
  • eine explizite Tool-Allowlist

Keiner davon war nötig, um die erste Harness zum Laufen zu bringen. Ich habe nahe an der Zwei-Parameter-Form angefangen und die Konfiguration Apply für Apply erweitert, und ich würde diese Reihenfolge empfehlen: ein Name und eine Role beim ersten Deploy, dann jeder optionale Block erst dann, wenn der Build ihn verlangt. Es gibt außerdem einen CLI-Mittelweg: agentcore create erzeugt ein neues Agent-Projekt-Gerüst, wobei ein Harness-Projekt einer der Typen ist, die der Wizard anbietet, nicht-interaktiv erstellbar mit Flags [3].

Control Plane versus Data Plane

AgentCore teilt die Harness-API in zwei Teile. Fünf Control-Plane-Operationen verwalten die Harness als Ressource: CreateHarness, GetHarness, ListHarnesses, UpdateHarness, DeleteHarness. Eine Data-Plane-Operation führt sie aus: InvokeHarness [4]. Boto3 liefert diese Trennung als zwei separate Clients aus, bedrock-agentcore-control und bedrock-agentcore. Ich habe das zu Beginn des Builds abgebildet, indem ich die verfügbaren Services des installierten SDKs aufgelistet habe (boto3 1.43.56), statt der Dokumentation zu vertrauen, weil der Service neu genug war, dass SDK und Doku sich widersprechen konnten.

Diese Trennung zeigt sich physisch in meinem Build. Terraforms Ressource aws_bedrockagentcore_harness kapselt die Control Plane: Plan und Apply übersetzen sich in Create-, Get- und Update-Aufrufe. Die Streaming-Relay-Lambda aus dem „Dynamic Content“-Abschnitt von Artikel 1 spricht nur die Data Plane, über den InvokeHarnessCommand des JavaScript-SDKs, zur Laufzeit der Anfrage. Zwei SDK-Oberflächen, zwei Clients, keine Überschneidung.

Diese Trennung erkauft eine Sicherheitseigenschaft. Die Execution Role des Relays trägt das Data-Plane-Invoke-Recht und nichts aus der Control Plane, sodass die Komponente, die den Agent für Endnutzer betreibt, den Agent nicht umkonfigurieren kann. Terraform hält die Control-Plane-Credentials und läuft niemals zur Laufzeit einer Anfrage. Eine Harness zu konfigurieren und eine Harness auszuführen sind zwei getrennte Operationen gegen zwei getrennte APIs, weshalb der Terraform-Code und die Relay-Lambda sich niemals gegenseitig in die Aufrufe kommen – und, was wichtiger ist, gar nicht können.

Von der Konfiguration zum laufenden Agent

AgentCore Harness, ihre Konfiguration und Fähigkeiten

Von links nach rechts lesen. Die Agent-Konfiguration umfasst vier Zeilen: das Modell, den System-Prompt, Tools und Skills sowie alles Übrige (Timeouts, Iterationsgrenzen, Umgebung). Sechs Arten von Tool-Quellen können die Tools-Zeile speisen: ein Remote-MCP-Server, ein AgentCore Gateway, der verwaltete Browser, der verwaltete Code Interpreter, ein Inline-Tool, das clientseitig ausgeführt wird, und ein Skill. Die konfigurierte Harness greift dann rechts auf die Plattform-Fähigkeiten zurück: Runtime hostet sie, Memory sorgt für Persistenz über Sessions hinweg, Identity übernimmt die eingehende Authentifizierung, Observability trackt sie. Darunter liegen die Runtime-Features, die die Harness erbt: langlaufende Sessions, anhängbarer Storage, Shell-Befehlsausführung, microVM-Isolation und die Option, ein eigenes Container-Image mitzubringen [2].

Dieses Diagramm auf das Projekt zu übertragen, hält es ehrlich. Von den sechs Tool-Quellen nutze ich zwei: eine Gateway-Bindung, die alle sechs Gateway-Targets aus Artikel 1 vorschaltet (Artikel 4 öffnet das im Detail), und einen Skill. Von der Fähigkeiten-Spalte sind Runtime und Memory tragend (Artikel 3 konfiguriert beide), Observability lieferte die Tool-Call-Traces, die ich später zur Messung eines Prompt-Compliance-Problems genutzt habe (Artikel 5 setzt eine Zahl auf diese Geschichte), und Identity bleibt ungenutzt: Die Untersuchung zur eingehenden Authentifizierung in Artikel 1 erklärt, warum ein Token-validierendes Relay es geschlagen hat. Und die Container-Option in der unteren Zeile ist in diesem Build aus einem ganz bestimmten Grund vorhanden, nicht als Standard.

Dieser Grund sind Skills. Ein Skill ist ein Verzeichnis aus Instruktions-Markdown und begleitenden Dateien, manchmal einschließlich Skripten, das die Harness bei Bedarf für das Modell lädt, und der Parameter skills verweist, in der Pfad-Form, die dieses Projekt nutzt, auf Inhalte, die bereits im Dateisystem der Harness liegen. Er lädt und installiert selbst nichts [5]. Eine rein deklarative Harness hat kein Dateisystem, auf das verwiesen werden könnte, also muss das Skill-Verzeichnis auf anderem Weg dorthin gelangen, und es in ein eigenes Container-Image zu backen ist der Weg, auf dem dieses Projekt es ausliefert. Das gesamte Dockerfile besteht aus einem FROM und einem COPY; das Image ist rein eine Dateisystem-Schicht, niemals ein laufender Prozess von mir [6].

Der Skill selbst stammt nicht von mir, und das gehört klar festgehalten: Ich habe sales-methodology-implementer unverändert aus dem MIT-lizenzierten Repository github.com/OneWave-AI/claude-skills übernommen, auf einen festgepinnten Commit [7]. Seine Dateien decken auch MEDDIC, Sandler, Challenger und SPIN ab, und ich habe all das unangetastet gelassen. Die Demo auf BANT zu beschränken ist eine Anweisung im System-Prompt, keine Dateichirurgie am Skill eines anderen.

Das Anhängen des Containers brachte die erste Überraschung. Ich hatte erwartet, dass die Umwandlung einer deklarativen Harness in eine container-backed Harness ein Destroy-and-Recreate erzwingt, und hatte entsprechend um diesen Blast Radius herum geplant. Der Live-Plan las sich als 2 to add, 1 to change, 0 to destroy: das Hinzufügen des Container-Artefakts und des Skills, das Ändern des System-Prompts, alles als In-Place-Update. Der Bearbeitungs-Flow der Konsole nutzt dieselbe Update-API [4], das In-Place-Verhalten ist also keine Terraform-Eigenart; meine Planung lag beim Blast Radius schlicht falsch, ausnahmsweise in die gute Richtung. Artikel 3 geht die Umstellung im Detail durch, samt Konfiguration, Plan-Output und Build-Stolperfallen.

Die härtere Kante kam vom selben Skill-Mechanismus. Der Inhalt eines Skills wird auf das Dateisystem der Harness geholt und in den Kontext des Modells injiziert, und bei einem Methodik-Skill ist das die gesamte Aufgabe. Bündelt ein Skill jedoch ein Skript, ist der einzige AgentCore-native Mechanismus, der es serverseitig ausführt, das eingebaute shell-Tool der Harness, das innerhalb der microVM der Harness mit den Credentials der eigenen Execution Role der Harness läuft. Es gibt keine separate, eingeschränkte Skill-Execution-Role und keinen Tool-Typ „nur dieses eine Skript ausführen“ [8]. Das habe ich nicht einfach geglaubt. Ich habe einen zweiten, read-only Skill gebaut, partner-central-lookup, ihn als zweiten Skill-Block verdrahtet, seine eine Abhängigkeit dem Image hinzugefügt und der Harness eine eng gefasste sts:AssumeRole-Berechtigung gegeben. Ihn ausführbar zu machen, erforderte dann, shell zu den allowed_tools der Harness hinzuzufügen, und diese Liste erwies sich als Allowlist im strengen Sinne, nicht als Filter: Weil meine Harness von der ersten Woche an eine explizite, restriktive Allowlist trug, waren die eingebauten Tools shell und file_operations die ganze Zeit stillschweigend ausgeschlossen.

shell zu gewähren hätte nichts wiederhergestellt, was bereits vorhanden war; es hätte eine ganz neue Fähigkeit hinzugefügt: beliebige Befehlsausführung im Container, auf einer Harness, die in derselben Session Knowledge-Base-Retrieval über gecrawlten Webinhalt und eine Cross-Account-Role nach Partner Central hält. Ich habe mich entschieden, die Fähigkeit dauerhaft inaktiv zu lassen, statt sie einzuschalten, und in einem späteren v1.1-Cleanup habe ich partner-central-lookup vollständig entfernt, da eine inaktive, nie ausgeführte Fähigkeit keinen fortlaufenden Wert hat. Der Skill sales-methodology-implementer ist davon nicht betroffen und bleibt der einzige aktive Grund, warum diese Harness überhaupt container-backed ist.

Eine benachbarte Warnung von derselben Doku-Seite: Die API InvokeAgentRuntimeCommand führt Befehle direkt in der microVM der Harness aus, ohne überhaupt durch das Modell oder das allowed_tools-Gate zu gehen [8]. Nirgendwo im IAM dieses Projekts wird das gewährt.

Die Entscheidungsregel, die ich daraus mitgenommen habe: Bevor Sie eine Harness für einen Skill container-backed machen, entscheiden Sie, ob der Skill überhaupt ein gebündeltes Skript ausführen muss, oder ob das Context-Injection-Verhalten allein reicht. Für dieses Projekt war Context Injection der gesamte Wert, und shell hat sein Risiko nie gerechtfertigt.

Die Harness aufrufen

Die Invocation-Oberfläche ist klein: Ein Prompt geht rein, die konfigurierte Loop läuft, eine Ausgabe kommt zurück.

In der Konsole treibt der Harness-Playground unter Test diesen Ablauf interaktiv an: Harness auswählen, eine Nachricht eintippen, der gestreamten Antwort zusehen. Dieser Playground war während des gesamten Builds mein zweitschnellster Verifizierungsweg.

AgentCore Harness Playground

Der schnellste ist ein Skript. Die erste Live-Invocation aufzusetzen hat mir drei Dinge beigebracht. Die Data-Plane-Operation heißt InvokeHarness, nicht der kürzere Name, den ich angenommen hatte. Sie will die vollständige ARN der Harness statt einer nackten ID, und die Antwort ist ein Event-Stream (messageStart, contentBlockDelta, contentBlockStop und Error-Events), kein einzelner Blob. Kondensiert aus dem ausgelieferten Skript, sieht der Aufruf so aus:

Python
import boto3client = boto3.client("bedrock-agentcore", region_name="eu-central-1")response = client.invoke_harness(    harnessArn=harness_arn,           # the full ARN, not a bare harness id    runtimeSessionId=session_id,      # one uuid4 per conversation    messages=[{"role": "user", "content": [{"text": prompt}]}],)text_chunks = []for event in response["stream"]:    if "contentBlockDelta" in event:        delta = event["contentBlockDelta"].get("delta", {})        if "text" in delta:            text_chunks.append(delta["text"])    elif "validationException" in event:        raise RuntimeError(f"Harness validation error: {event['validationException']}")

Zwei Anmerkungen dazu, was die Kondensierung verbirgt. Das ausgelieferte Skript meldet auch internalServerException- und runtimeClientError-Events als Fehler. Es hardcodet invoke_harness überhaupt nicht: Es löst den Operationsnamen aus der eigenen Methoden-Map des installierten Clients auf, weil sich der Name der Data-Plane-Operation über SDK-Revisionen hinweg verschoben hat.

Dieser allererste Smoke-Test scheiterte mit einer AccessDeniedException bei bedrock-agentcore:ListEvents: Die Execution Role konnte das Modell aufrufen, aber nicht auf das eigene, angehängte Memory der Harness zugreifen. Der zweite Versuch lieferte eine nicht-leere Claude-Sonnet-5-Antwort von der Live-Harness zurück, was das gesamte Walking Skeleton in einem einzigen Befehl bewies: von Terraform erstellte Harness, Execution Role, boto3-Invoke, gestreamter Modell-Output. Der gesamte Invoke-Pfad ist wirklich so einfach, wie das Diagramm behauptet.

Eine weitere Eigenschaft der Invoke-API verdient ihr eigenes Diagramm: Per-Invocation-Overrides. Die gespeicherte Konfiguration ist die Baseline, und ein einzelner Aufruf kann Modell, Prompt, Tools oder Memory-Einstellungen nur für diesen einen Aufruf überschreiben [4].

Die Overrides haben eine scharfe Kante, auf die ich live gestoßen bin: tools=[...] beim Invoke zu übergeben ersetzt das gesamte konfigurierte Toolset der Harness für diesen Aufruf. Es ergänzt es nicht. Als ich versucht habe, pro Invocation ein Approval-Tool zu injizieren, verschwanden für diesen Aufruf alle Gateway-Tools, und das Modell versuchte einen nackten Tool-Namen und bekam „Unknown tool“ zurück. Wenn Sie zusätzlich zu den konfigurierten Tools ein temporäres Extra-Tool brauchen, ist Invoke-Time-Injection nicht der richtige Mechanismus.

Der nächste Artikel öffnet die Box, die dieser Abschnitt als undurchsichtig behandelt hat: Session-Lifecycle und dessen Idle-Limits, das Container-Backing im Konfigurationsdetail, die Memory-Anbindung und das Execution-Role-IAM, das die Harness zur Laufzeit braucht.

Umstieg von Bedrock Agents

Wenn Sie Ihre Agents heute auf Amazon Bedrock Agents betreiben, positioniert AWS die Harness als den Weg nach vorn: dieselbe Idee der vollständig verwalteten Loop, mit mehr Flexibilität bei Tool-Integration, Memory und Skills [9]. Ich habe in diesem Projekt nichts migriert, ich habe also keine Migrationsgeschichte zu erzählen. Was dieser Build beweist: sechs Tool-Quellentypen, Per-Invocation-Overrides, dateisystembasierte Skills und Container-Backing haben alles abgedeckt, was dieser Agent brauchte, ohne einen einzigen Workaround auf Loop-Ebene. Wenn Sie neu anfangen statt zu migrieren, überspringen Sie den Vergleich komplett und nutzen Sie stattdessen die Drei-Kategorien-Checkliste vom Anfang dieses Artikels.

Übertragbare Muster

Drei Gewohnheiten aus diesem Artikel lassen sich über diese Demo hinaus auf jeden AgentCore-Build übertragen.

  • Zwei Pflichtparameter, dann wachsen. Starten Sie eine Harness allein mit harness_name und executionRoleArn und fügen Sie Modell, Tools, Skills und Memory schrittweise hinzu, sobald sie tatsächlich gebraucht werden. Jeder optionale Block, den Sie am ersten Tag auslassen, ist ein Block, den Sie am ersten Tag auch nicht falsch konfigurieren können, und Updates greifen in Sekunden in-place.
  • Verwaltete Loop versus selbstgebaute Loop ist eine Entscheidung, kein Standard. Kalkulieren Sie Ihren Build gegen die drei Kostenkategorien: Setup, Iterationsgeschwindigkeit, Tool-Integration. Greifen Sie zur Harness, wenn diese Kosten dominieren; schreiben Sie weiter Ihre eigene Loop, wenn Sie Verhalten brauchen, das die Konfigurationsoberfläche der Harness nicht bietet.
  • Container-Backing nur für Dateisystem-Artefakte, und Ausführung als eigene Entscheidung behandeln. Eine deklarative Harness deckt Modell, Prompt, Tools und Memory ab, ganz ohne Container. Greifen Sie gezielt zu einem eigenen Image, wenn ein Skill als Dateien im Dateisystem der Harness existieren muss, und behandeln Sie shell (oder jedes ausführungsgewährende Tool) als eigenes Security-Review, niemals als mitgelieferten Standard, den Container-Backing automatisch einschleppt. Mein Build hat den Container ausgeliefert und die Ausführung verweigert, und beide Hälften davon waren bewusste Entscheidungen.

Wenn Sie das nachbauen

Konsole zuerst: Erstellen Sie die Harness unter Build mit einem Namen über Quick Create (die Execution Role wird automatisch hinzugefügt), fügen Sie die optionalen Blöcke hinzu, sobald Sie sie brauchen, und testen Sie im Playground unter Test. Wer über die Konsole eine deklarative Harness baut, kommt nie mit Docker in Berührung und kann den Rest dieses Abschnitts überspringen.

Die container-backed Variante hat zwei Stolperdrähte, beide aus meiner eigenen Build-Historie. Erstens muss das Image linux/arm64 sein [6]. Mein lokaler Docker-Desktop-Daemon ist linux/amd64 und kann das nicht nativ bauen; die Ein-Schritt-Lösung ist docker buildx build --platform linux/arm64 --push -t <ecr-repo-url>:<tag> ., was per QEMU cross-buildet und im selben Befehl pusht, ohne Daemon-Neukonfiguration. Zweitens muss das Image in ECR existieren, bevor die Harness, die darauf verweist. In der Konsole ist die Reihenfolge natürlich (pushen, dann die Image-URI ins Formular einfügen), während mein Terraform-Build einen zweistufigen Apply mit einem expliziten -target zuerst auf das ECR-Repository brauchte. Die Einschränkung ist auf beiden Wegen dieselbe; Automatisierung macht es nur leichter, es in einem Rutsch falsch zu machen.

Nutzen Sie danach den Harness-Playground und führen Sie einen Smoke-Test direkt auf der Harness durch, komplett ohne API Gateway und Cognito, sodass sich ein Fehler auf die Harness und ihre Execution Role eingrenzen lässt, statt irgendwo in einer fünfteiligen Request-Kette zu stecken. Ich habe gelernt, das zuerst auf die günstige Art zu machen, nachdem ich einmal den langen Weg debuggt habe.

Ich hoffe, dieser Artikel war hilfreich für Sie. Ich freue mich über Feedback, was Ihnen gefallen hat und was nicht, damit ich künftige Artikel verbessern kann.


Quellen

[1] Allgemeine Verfügbarkeit von Amazon Bedrock AgentCore Harness. https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-bedrock-agentcore-harness-generally-available/

[2] AWS-Bedrock-AgentCore-Entwicklerhandbuch: Harness-Konzept und CreateHarness-Konfigurationsparameter, einschließlich der zwei Pflichtparameter und der Unterstützung für Per-Invocation-Overrides. https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/harness-get-started.html

[3] AWS-Bedrock-AgentCore-Entwicklerhandbuch: agentcore create erzeugt ein neues Agent-Projekt-Gerüst; Harness-Projekte werden interaktiv oder nicht-interaktiv mit Flags erstellt. https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/develop-agents.html

[4] AWS-Bedrock-AgentCore-API-Referenz: Control-Plane-Operationen (CreateHarness, GetHarness, ListHarnesses, UpdateHarness, DeleteHarness) und die Data-Plane-Operation InvokeHarness mit Konfigurations-Overrides zur Invoke-Zeit. https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_CreateHarness.html; https://docs.aws.amazon.com/bedrock-agentcore/latest/APIReference/API_InvokeHarness.html

[5] AWS-Bedrock-AgentCore-Entwicklerhandbuch, Harness Skills: dateipfadbasierte Skills verweisen auf Inhalte, die bereits im Dateisystem der Harness liegen, entweder in das Container-Image gebacken oder beim Session-Start installiert. https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/harness-skills.html

[6] AWS-Bedrock-AgentCore-Entwicklerhandbuch, benutzerdefinierte Harness-Umgebung (Container-Images): die linux/arm64-Anforderung, und dass die Harness ENTRYPOINT und CMD des Containers überschreibt. https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/harness-environment.html

[7] GitHub, OneWave-AI/claude-skills: Upstream-Quelle des übernommenen Skills sales-methodology-implementer, MIT-Lizenz. https://github.com/OneWave-AI/claude-skills

[8] AWS-Bedrock-AgentCore-Entwicklerhandbuch, Harness-Tools: die eingebauten Tools shell und file_operations, allowedTools als Einschränkungsmechanismus, und der Hinweis, dass InvokeAgentRuntimeCommand ausführt, ohne das allowedTools-Gate zu durchlaufen. https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/harness-tools.html

[9] AWS-Positionierung der Harness gegenüber Amazon Bedrock Agents. https://docs.aws.amazon.com/bedrock/latest/userguide/agents-classic-maintenance-mode.html