Pour qu’un agent LangGraph tourne sur AWS, il faut un moteur : un modèle de langage accessible par API. Sur AWS, c’est Amazon Bedrock — une API unique pour des dizaines de modèles. Ce deep-dive montre comment le brancher à LangGraph, comment fonctionne son tool calling, et comment exploiter ses spécificités (streaming, routage de modèles, Guardrails).

La Converse API : l’inférence unifiée

Historiquement, chaque modèle Bedrock avait son format de payload. La Converse API unifie tout : un seul schéma de messages, le même pour Claude, Nova, Llama… On l’appelle directement avec boto3 pour comprendre ce qui circule.

import boto3

bedrock = boto3.client("bedrock-runtime", region_name="eu-west-1")

reponse = bedrock.converse(
    modelId="eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
    messages=[{"role": "user", "content": [{"text": "Explique le tool calling en une phrase."}]}],
    inferenceConfig={"maxTokens": 512, "temperature": 0.2},
)
print(reponse["output"]["message"]["content"][0]["text"])
print("tokens:", reponse["usage"])     # inputTokens / outputTokens — pour le coût

Notez la structure des messages : content est une liste de blocs (texte, image, document, usage d’outil). C’est ce modèle qui permet le multimodal et le tool use de façon homogène.

Le tool calling avec la Converse API

La Converse API gère le tool use nativement via toolConfig. On déclare les outils par un schéma JSON, le modèle renvoie un bloc toolUse, on exécute, on renvoie un bloc toolResult. C’est exactement la boucle ReAct, au niveau du protocole.

outils = {"tools": [{
    "toolSpec": {
        "name": "meteo",
        "description": "Renvoie la météo actuelle pour une ville.",
        "inputSchema": {"json": {
            "type": "object",
            "properties": {"ville": {"type": "string"}},
            "required": ["ville"],
        }},
    }
}]}

reponse = bedrock.converse(
    modelId="eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
    messages=[{"role": "user", "content": [{"text": "Météo à Lyon ?"}]}],
    toolConfig=outils,
)
# stopReason == "tool_use" → le modèle demande un outil ; on lit le bloc toolUse :
for bloc in reponse["output"]["message"]["content"]:
    if "toolUse" in bloc:
        print(bloc["toolUse"]["name"], bloc["toolUse"]["input"])

On voit ici la mécanique brute. En pratique, on ne l’écrit pas à la main : LangChain l’enveloppe.

Brancher Bedrock sur LangGraph : ChatBedrockConverse

Le paquet langchain-aws fournit ChatBedrockConverse, un modèle de chat standard LangChain adossé à la Converse API. Il s’utilise exactement comme n’importe quel modèle dans LangGraph — bind_tools, create_react_agent, tout fonctionne à l’identique.

from langchain_aws import ChatBedrockConverse
from langgraph.prebuilt import create_react_agent
from langchain_core.tools import tool

modele = ChatBedrockConverse(
    model="eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
    region_name="eu-west-1",
    temperature=0.2,
    max_tokens=1024,
)

@tool
def meteo(ville: str) -> str:
    """Renvoie la météo actuelle pour une ville donnée."""
    return {"Lyon": "22°C, ensoleillé"}.get(ville, "Pas de données.")

agent = create_react_agent(modele, [meteo])
print(agent.invoke({"messages": [{"role": "user", "content": "Météo à Lyon ?"}]}))

Choisir et router les modèles

Bedrock expose une même API pour toute une gamme. On exploite ça pour le routage de modèles — le levier de coût n°1 du deep-dive contexte & coûts.

# Modèle économique pour le routage / la classification (fort volume, tâche simple)
mini = ChatBedrockConverse(model="eu.amazon.nova-lite-v1:0", region_name="eu-west-1")

# Modèle puissant pour le raisonnement difficile
pro = ChatBedrockConverse(model="eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
                          region_name="eu-west-1")

def router_modele(state) -> str:
    difficulte = mini.invoke(f"Difficile ? oui/non : {state['messages'][-1].content}")
    return "pro" if "oui" in difficulte.content.lower() else "mini"

La majorité du trafic part vers Nova Lite (bon marché) ; seule la minorité difficile mobilise Claude. Sur Bedrock, ce routage ne coûte qu’un changement d’identifiant de modèle.

Le streaming

Pour l’UX temps réel (voir le deep-dive streaming), ChatBedrockConverse supporte le streaming de tokens via la Converse Stream API, exposé par les modes de stream habituels de LangGraph.

for fragment, meta in agent.stream(entree, stream_mode="messages"):
    if fragment.content:
        print(fragment.content, end="", flush=True)

Attacher des Guardrails

Bedrock Guardrails s’attache à l’inférence : filtres de contenu, déni de sujets, caviardage de PII, vérification d’ancrage. On passe l’identifiant et la version du guardrail au modèle — la protection s’applique alors à chaque appel, sans toucher la logique de l’agent.

modele = ChatBedrockConverse(
    model="eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
    region_name="eu-west-1",
    guardrail_config={
        "guardrailIdentifier": "abcd1234",
        "guardrailVersion": "3",
        "trace": "enabled",      # journalise les interventions du guardrail
    },
)

C’est une couche de défense en profondeur, à combiner avec les garde-fous applicatifs du deep-dive sécurité.

Observabilité : LangFuse + Bedrock

L’instrumentation LangFuse fonctionne à l’identique : le CallbackHandler capture les appels ChatBedrockConverse. Côté AWS, activez en parallèle le model invocation logging de Bedrock (vers CloudWatch ou S3) pour l’audit et la facturation. Les deux sont complémentaires : LangFuse pour le débogage agentique, CloudWatch pour la gouvernance.

Bonnes pratiques & pièges

Bonnes pratiques
  • Utilisez la Converse API (ou ChatBedrockConverse) : une seule API pour tous les modèles.
  • Préférez les profils d'inférence cross-region (préfixe eu./us.) pour le débit et la dispo.
  • Routez les modèles : Nova Lite pour le volume, Claude pour le raisonnement difficile.
  • Attachez un Guardrail à l'inférence : protection systématique, sans toucher la logique.
  • Gérez les quotas et le throttling (retries avec backoff) — Bedrock impose des limites de débit.
  • Combinez LangFuse (débogage) et model invocation logging Bedrock (audit/coût).
Pièges à éviter
  • Oublier d'activer l'accès au modèle (Model access) : erreur AccessDenied à l'invocation.
  • Coder en dur un modelId régional brut : préférez un profil cross-region.
  • Ignorer le throttling : sous charge, sans backoff, l'agent échoue en rafale.
  • Choisir un gros modèle partout : la facture explose là où Nova suffirait.
  • Croire qu'un Guardrail remplace les garde-fous applicatifs : c'est une couche, pas tout.

Ce qu’il faut retenir

  • La Converse API unifie l’inférence Bedrock (texte, multimodal, tool use) ; ChatBedrockConverse la branche à LangGraph sans changer votre logique.
  • Le tool calling est natif (toolConfig / bind_tools) — c’est la boucle ReAct.
  • Profils cross-region pour la robustesse ; routage Claude/Nova pour le coût.
  • Guardrails s’attache à l’inférence comme couche de défense en profondeur.
  • LangFuse + CloudWatch couvrent débogage et gouvernance.

Le moteur est en place. Attaquons la récupération — et pas n’importe laquelle : le RAG hybride sur AWS, qui combine sens et mots-clés.

#aws#bedrock#langgraph#converse-api#tool-use