Ein LangGraph Agent auf AWS Bedrock AgentCore schrittweise einrichten
Umhüllen Sie einen bestehenden LangGraph-Agent für AgentCore, strukturieren Sie das Projekt mit der CLI, testen Sie es lokal, deployen Sie es auf AWS und rufen Sie es mit intakten Sessions und Speicher auf.
Quellen: How to Deploy a LangGraph Agent on AWS Bedrock AgentCore
Viele LangGraph-Agenten funktionieren gut auf einem Laptop, stocken jedoch beim Übergang in die Produktivumgebung. AWS Bedrock AgentCore schließt diese Lücke durch serverloses Hosting, das skaliert und keine Neugestaltung erfordert. Die folgenden Abschnitte behandeln das Umhüllen eines bestehenden Agenten für AgentCore, die Erstellung eines Projekts, den lokalen Betrieb, den Versand an AWS sowie den Aufruf des Agenten, sobald er online ist.
Was AgentCore ist
AgentCore ist ein von AWS bereitgestellter Hosted-Runtime, in dem Agenten ohne Serververwaltung bereitgestellt, skaliert und ausgeführt werden. Frameworks wie LangGraph, Strands, CrewAI und LlamaIndex funktionieren genauso wie Modelle von OpenAI, Google und Anthropic – dadurch bleibt der Agentencodex unverändert. Sitzungsisolation, persistente Speicherung, Überwachungsfunktionen sowie Identitätsmanagement sind bereits integriert.
Alles wird durch die AgentCore CLI gesteuert. Es handelt sich um ein Node.js-Programm, das das Projektgerüst erstellt, den Agent lokal bereitstellt und ihn unter Verwendung von CDK auf AWS deployt.
Voraussetzungen
- Python 3.12 oder neuer
uvoderpipzur Verwaltung von Python-Paketen- Node.js 20 oder neuer, da die CLI über npm verteilt wird
- AWS CDK, das global mit
npm install -g aws-cdkinstalliert ist - Ein AWS-Konto mit Anmeldedaten, die lokal über
aws configurekonfiguriert sind - Bestehender LangGraph-Code, der einen kompilierten StateGraph erzeugt
Schritt 1: Die CLI installieren
Ein einziges Befehlszeilenwerkzeug steuert alles: die Erstellung des Projekts, den lokalen Betrieb der Anwendung sowie das Deployment auf AWS.
npm install -g @aws/agentcore
Bestätigen Sie, dass die Installation erfolgreich war:
agentcore --help
Schritt 2: Abhängigkeiten hinzufügen
Zwei Pakete müssen zu den Abhängigkeiten des Agents hinzugefügt werden. bedrock-agentcore ist die Python-SDK, die die Wrapper-Klasse BedrockAgentCoreApp bereitstellt, und aws-opentelemetry-distro ist die von AWS erstellte Version der OpenTelemetry-Instrumentierung für Python.
# pyproject.toml
[project]
name = "my-agent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"aws-opentelemetry-distro==0.17.0",
"bedrock-agentcore>=1.6.3",
"boto3>=1.42.0",
"langgraph>=1.1.0",
"langchain-core>=1.2.0",
# ... your other existing dependencies
]
Installieren Sie es mit dem für das Projekt üblichen Workflow:
uv sync
# or: pip install -e .
Schritt 3: Der Eingangspunkt in main.py schreiben
AgentCore erwartet eine Python-Datei als Eingangspunkt, die eine BedrockAgentCoreApp-Instanz sowie eine mit @app.entrypoint dekorierte Funktion enthält. Die Logik von LangGraph ändert sich kaum – sie wird lediglich in einen kleinen Laufzeit-Eingangspunkt eingebettet.
# main.py
from langchain_core.messages import HumanMessage
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from graphs.my_agent_graph import build_my_agent # your existing graph builder
# 1. Instantiate the AgentCore app and logger
app = BedrockAgentCoreApp()
log = app.logger
# 2. Build your graph at module load time (startup)
# AgentCore initialises the module once, then handles concurrent invocations.
# Any failure here will prevent a broken agent from going live.
def create_agent():
log.info("Initialising agent...")
graph = build_my_agent() # returns your compiled LangGraph StateGraph
log.info("Agent ready")
return graph
try:
graph = create_agent()
except Exception as e:
log.error(f"Critical failure during agent initialisation: {e}")
raise # fail fast - don't let a broken agent start serving requests
# 3. Async helper that drives the LangGraph streaming loop
async def run_agent(user_input: str, session_id: str = "default-session") -> str:
responses = []
config = {"configurable": {"thread_id": session_id}}
async for chunk in graph.astream(
{"messages": [HumanMessage(content=user_input)]},
config=config,
stream_mode="values",
):
messages = chunk.get("messages", [])
if messages:
last = messages[-1]
if getattr(last, "type", None) == "ai":
responses.append(last)
if not responses:
return "No response"
content = getattr(responses[-1], "content", "")
return content if isinstance(content, str) else str(content)
# 4. The entrypoint - this is what AgentCore calls on every invocation
@app.entrypoint
async def invoke(payload, context):
try:
log.info("Invoke received")
user_input = payload.get("prompt", "")
session_id = payload.get("session_id", "default-session")
if not user_input.strip():
return {"error": "Prompt cannot be empty"}
response = await run_agent(user_input, session_id)
return {"response": response}
except Exception as e:
log.error(f"Error: {e}")
return {"error": str(e)}
# 5. Run the app (only executed when running locally using agentcore dev)
if __name__ == "__main__":
app.run()
Was in dieser Datei wichtig ist
BedrockAgentCoreApp()liefert dem Laufzeitumfeld seine Grundstruktur: einen HTTP-Server, Health-Check-Routen sowie strukturierte Protokolle – alles bereits vorkonfiguriert.- Das Graphen wird im Modulbereich erstellt, einmal bei der Importierung und nicht bei jedem Aufruf. Dadurch treten alle Startprobleme sofort zutage, und eine fehlerhafte Anwendung erhält niemals Traffic.
@app.entrypointkennzeichnet den Handler für eingehende Anfragen. Ihm wirdpayload, der decodierte JSON-Body, zusammen mitcontextfür die AgentCore-Anfrage übergeben. Das zurückgegebene Ergebnis muss ein einfaches Dictionary sein, das in JSON serialisierbar ist. Einfache Zeichenketten oder benutzerdefinierte Klassen reichen nicht aus.- Die übergebene
session_idwird zu LangGraphsthread_id; dadurch behältMemorySaverfür jede Sitzung ein eigenes Speicherpuffer.
Schritt 4: Projekt erstellen
Danach kommt die Projektstruktur. Führen Sie den Initialisierungs-Assistenten von einem sauberen Root-Verzeichnis aus und lassen Sie ihn das Skelett erstellen:
agentcore create
Der Assistent fragt nach Details wie dem Projektnamen, der Sprache, der Python-Version sowie der Eingabestellen-Datei. Die Eingabestelle und die Python-Version müssen der Anwendung entsprechen. Anschließend entsteht eine agentcore.json-Datei im agentcore-Ordner, die AgentCore mitteilt, wo sich der Code befindet und wie er ausgeführt werden soll.
{
"name": "MyAgentOnAgentcore",
"runtimes": [
{
"name": "my-agent",
"build": "CodeZip",
"entrypoint": "main.py",
"codeLocation": "app/my-agent/",
"runtimeVersion": "PYTHON_3_12",
"networkMode": "PUBLIC",
"protocol": "HTTP",
"envVars": []
}
]
}
Schritt 5: Platziere den Code an der Stelle, an der AgentCore nachschaut
Verlege oder kopiere die Quelldatei des Agents in das Verzeichnis, das in agentcore.json unter codeLocation angegeben ist. Es ist leicht, einen Fehler zu machen, und eine falsche Position macht die Bereitstellung unnötig schwierig. Ein häufiger Fehler ist es, den Code direkt in das agentcore-Verzeichnis selbst zu legen, was viel Zeit kosten kann. Die Struktur sollte wie folgt aussehen:
MyAgentOnAgentcore/
├──agentcore
└── agentcore.json
├──app/
└──my-agent/ ← codeLocation
├── main.py ← entrypoint (matches agentcore.json)
├── pyproject.toml ← or requirements.txt
├── src/
│ └── my_agent_graph.py ← your LangGraph graph builder
│ └── tools.py ← your tools, utilities, etc.
└── .env ← your configuration variables
main.py muss sich auf der obersten Ebene von codeLocation befinden und exakt mit dem Eingangspunkt in agentcore.json übereinstimmen.
Umgebungsvariablen
AgentCore kann Umgebungsvariablen an den Laufzeitcontainer weitergeben. Lokal ist eine .env-Datei der einfachste Weg. In der Produktion können die Werte in agentcore.json unter envVars gespeichert werden, wobei auch eine .env-Datei funktioniert. Geheime Informationen wie Passwörter und API-Schlüssel sollten besser im AWS Secrets Manager aufbewahrt und zur Laufzeit geladen werden; in diesem Fall benötigt die Ausführungsrolle von AgentCore Berechtigungen zum Lesen dieser Daten. Beachten Sie, dass envVars ein Array von JSON-Objekten ist, von denen jedes über die Felder name und value verfügt.
Schritt 6: Überprüfen
Lassen Sie die CLI vor dem Ausführen irgendetwas die Konfiguration überprüfen:
agentcore validate
Einfache Fehler wie ein fehlendes Eingangspunkt-Datei oder ein falscher Pfad in der Konfiguration werden genau hier erkannt.
Schritt 7: Lokal ausführen und testen
Starten Sie die lokale Laufzeitumgebung mit:
agentcore dev
Es startet einen lokalen HTTP-Server, der der Produktionsumgebung sehr ähnlich ist. Wenn alles richtig konfiguriert ist, zeigt die Ausgabe an, dass die Anwendung bereit ist und auf einem lokalen Port lauscht.
Aufruf des lokalen Servers
Ein Aufruf kann über die CLI erfolgen:
agentcore invoke "Summarise last month sales"
oder über curl:
curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d '{"prompt": "Summarise last month sales", "session_id": "test-001"}'
Eine gute Antwort ist JSON mit der Antwort des Agents darin:
{"response": "Last month, total sales were $1.2M across 3 regions..."}
Schritt 8: Deployment auf AWS
Sobald die lokalen Tests erfolgreich waren, führen Sie das Deployment auf den AgentCore Runtime durch:
agentcore deploy
Hinter den Kulissen packt die CLI den Code zusammen, stellt einen S3-Bucket für die direkte Code-Deployment bereit, erstellt eine IAM-Exekutionsrolle und deployt den AgentCore Runtime mit CDK. Die erste Deployment dauert einige Minuten, während spätere Deployment in der Regel schneller ablaufen.
Sobald die Deployment abgeschlossen ist, überprüfen Sie den Status des Runtimes. Die Ausgabe zeigt den ARN des Runtimes sowie die HTTP-URL zur Aufrufung des deployten Agents an.
agentcore status
Schritt 9: Den bereitgestellten Agent aufrufen
Die CLI ist die einfachste Möglichkeit, die bereitgestellte Version auszuprobieren:
agentcore invoke --prompt "Who are the top 5 customers by revenue?" --session-id "session-id-with-length-greater-than-or-equal-33"
Der Aufruf über HTTP erfordert die Signierung der Anfrage mit AWS SigV4:
curl -X POST "https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/arn-of-MyAgentOnAgentcore-xxxx/invocations" \
--user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \
--aws-sigv4 "aws:amz:us-east-1:bedrock-agentcore" \
-H "Content-Type: application/json" \
-H "x-amzn-bedrock-agentcore-runtime-session-id: session-id-with-length-greater-than-or-equal-33" \
-d '{"prompt": "Who are the top 5 customers by revenue?"}'
Verwenden Sie die HTTP-URL aus agentcore status.
Für Aufrufe aus anderem Python-Code ist das SDK in der Regel die beste Option. Speichern Sie den Laufzeit-ARN in einer Umgebungsvariable, übergeben Sie die Anweisung und senden Sie die vorherige Sitzungs-ID bei jedem weiteren Aufruf erneut.
# invoke_agent.py
import json
import boto3
import os
from dotenv import load_dotenv
load_dotenv()
client = boto3.client("bedrock-agentcore", region_name="us-east-1")
runtime_arn = os.getenv("AGENTCORE_RUNTIME_ARN")
def invoke(prompt: str, session_id: str) -> str:
payload = json.dumps({"prompt": prompt, "session_id": session_id})
response = client.invoke_agent_runtime(
agentRuntimeArn=runtime_arn,
payload=payload,
contentType="application/json"
)
body = json.loads(response["response"].read().decode())
return body["response"]
if __name__ == "__main__":
session_id = ""
print("Ready. Type 'exit' to quit.")
while True:
prompt = input("Your question: ").strip()
if prompt == "exit":
break
if not prompt:
continue
params = {
"agentRuntimeArn": runtime_arn,
"payload": json.dumps({"prompt": prompt}),
"contentType": "application/json"
}
if session_id:
params["runtimeSessionId"] = session_id
try:
response = client.invoke_agent_runtime(**params)
body = json.loads(response["response"].read().decode())
session_id = response.get("runtimeSessionId", session_id)
print(f"Agent: {body['response']}\n")
except Exception as e:
print(f"Error: {e}")
Setzen Sie AGENTCORE_RUNTIME_ARN in der .env-Datei:
AGENTCORE_RUNTIME_ARN=arn:aws:bedrock-agentcore:us-east-1:123456789012:agent-runtime/MyAgentOnAgentcore-xxxx
Beibehaltung des Sitzungszustands über mehrere Aufrufe hinweg
Betrachten Sie runtimeSessionId im boto3-Beispiel. AgentCore gibt diesen Wert bei jeder Antwort zurück. Durch die Übermittlung dieses Wertes im nächsten Anfrage wird der weitere Austausch im selben Sitzungskontext abgewickelt. In Kombination mit LangGraphs MemorySaver behält der Agent somit das gesamte Gesprächsmemory über getrennte HTTP-Aufrufe hinweg.
Häufige Fallstricke
- Startfehler sind beabsichtigt. Wenn
create_agent()zur Zeit der Importierung Fehler auslöst, startet AgentCore den Laufzeitbetrieb nicht. Dieses Verhalten schützt davor, dass ein falsch konfigurierter Agent, beispielsweise mit fehlenden Zugangsdaten oder einer fehlerhaften Datenbank-URL, stillschweigend in Betrieb genommen wird. - Es müssen Berechtigungen hinzugefügt werden. Die von der Ausführungsrolle AgentCore erstellte Rolle benötigt expliziten Zugriff auf alle von dem Agenten genutzten AWS-Dienste, einschließlich Secrets Manager und S3. Fügen Sie diese Berechtigungen nach der ersten Bereitstellung hinzu.
- Die Versionen müssen übereinstimmen. Die in
pyproject.tomlangegebene Python-Version muss mit der Laufzeit-Einstellung inagentcore.jsonübereinstimmen. - Es müssen einfache Wörterbücher zurückgegeben werden. Wenn der Eingangspunkt einen String oder ein benutzerdefiniertes Objekt zurückgibt, wird dies von der Laufzeitumgebung abgelehnt.
Was tatsächlich ändert sich
Um von einem lokalen LangGraph-Agenten zu AgentCore überzugehen, sind nur wenige Änderungen notwendig: Zwei zusätzliche Pakete installieren, das Graph in BedrockAgentCoreApp einpacken, ein Projekt erstellen, lokal testen und anschließend bereitstellen sowie aufrufen. Das Graph, die Tools, die Modellaufrufe sowie die Speicherkonfiguration bleiben größtenteils unverändert. AgentCore kümmert sich um die Infrastruktur, während LangGraph weiterhin für die Agentenlogik verantwortlich ist.
Verwandte Artikel
- Your Agent Graph Belongs in YAML: Compiling a 17-Agent LangGraph at Startup — Wie eine kleine Laufzeitumgebung eine YAML-Spezifikation in einen LangGraph StateGraph kompiliert: erzeugter Zustand, importlib-Plugins, Label-Routen, adaptive Aufrufe sowie Node-Austausche pro Sitzung.