Cet article construit une récupération agentique d'entreprise sur une base de connaissances Amazon Bedrock gérée avec l'AWS Cloud Development Kit (AWS CDK). Pour comprendre pourquoi cela vaut la peine d'être construit, il est utile de commencer par là où la génération augmentée de récupération (RAG) ordinaire montre ses limites. La plupart des systèmes RAG démarrent de la même manière : ils vectorisent la question, récupèrent les morceaux les plus proches dans un seul index, les remettent à un modèle et renvoient la réponse. Une récupération, une génération. Pour une large catégorie de questions, c'est le bon design, et il n'y a aucune raison de construire quoi que ce soit de plus compliqué.
Cela échoue de manière reconnaissable. Posez une question dont la réponse s'étend sur deux corpus, et une seule récupération renvoie la moitié de ce dont le modèle a besoin, ce qui est pire que ne rien renvoyer, car la réponse revient fluide et incomplète. Posez une question où la bonne source dépend de la question, et un seul index n'a aucun mécanisme pour choisir. Posez une question qui nécessite un second regard sur le corpus après avoir vu le premier résultat, et il n'existe nulle part où ce second regard puisse se produire.
La récupération agentique d'entreprise répond à ces trois problèmes en plaçant un agent de raisonnement dans la boucle. L'agent décide s'il faut effectuer une récupération, quelle base de connaissances consulter, et s'il faut revenir chercher plus avant de composer une réponse. C'est la direction dans laquelle Amazon Bedrock Knowledge Bases a évolué. Avec le lancement de la base de connaissances gérée (Managed Knowledge Base), la récupération n'est plus un simple appel embed-and-fetch. Elle est devenue une capacité agentique : planification multi-tours, récupération pilotée par des outils et réponses fondées et citées. L'API AgenticRetrieveStream offre cela comme une fonctionnalité de service de premier ordre plutôt que comme quelque chose que vous assemblez vous-même. Cela fonctionne, mais cela introduit aussi un problème opérationnel véritablement plus difficile. Un pipeline à tirage unique est une fonction que vous pouvez comprendre en la lisant. Un agent qui raisonne et récupère en boucle emprunte un chemin différent à chaque question. Par défaut, vous ne pouvez voir ni le chemin qu'il a suivi ni savoir si la réponse qu'il a produite était bonne. L'observabilité cesse d'être un luxe pour devenir le seul moyen de savoir que le système fonctionne.
En août 2024, Créez une solution RAG de bout en bout à l'aide des Knowledge Bases for Amazon Bedrock et de l'AWS CDK déployait le design à tirage unique sous la forme d'une application CDK : un corpus Amazon Simple Storage Service (Amazon S3) , une collection et un index Amazon OpenSearch Serverless , une base de connaissances et une source de données, provisionnés sous forme de piles CDK dont vous séquenciez l'ordre à la main. Trois choses ont changé depuis sa publication.
- Amazon Bedrock propose désormais une base de connaissances gérée (Type : MANAGED), qui prend en charge elle-même l'ingestion, le stockage, l'indexation et la récupération. La collection et l'index OpenSearch Serverless que cet article provisionne ne sont plus quelque chose que vous devez créer, dimensionner ou payer en OpenSearch Compute Units (OCUs).
- Amazon Bedrock AgentCore fournit la moitié agentique, une passerelle (Gateway) qui expose chaque base de connaissances comme un outil Model Context Protocol (MCP), un Runtime qui héberge l'agent de raisonnement, et AgenticRetrieveStream, qui reclasse en interne et renvoie une réponse synthétisée et citée. La récupération agentique est disponible uniquement sur la base de connaissances gérée.
- L'observabilité et l'évaluation sont désormais quelque chose que vous pouvez provisionner, et non quelque chose que vous ajoutez après coup. Cette solution est livrée avec deux tableaux de bord Amazon CloudWatch couvrant sept couches de télémétrie, plus deux formes d'évaluation, à la demande et continue, à partir du même déploiement.
Cet article construit ce système : un agent qui route entre deux bases de connaissances, effectue la récupération via la passerelle et renvoie une réponse fondée et citée, avec chaque couche de son comportement instrumentée, sous la forme d'une seule application AWS CDK en Python. Une seule commande déploie le tout, et CDK dérive l'ordre.
Si vous avez lu le billet de 2024, le chemin allant d'un compartiment Amazon S3 à la base de connaissances vous semblera familier, et tout ce qui suit est nouveau : le magasin de vecteurs a disparu, la récupération est agentique, et environ la moitié de ce que l'application provisionne existe pour vous dire ce que l'agent a fait. Si ce n'est pas le cas, ce billet se suffit à lui-même.
Les services impliqués et le chemin parcouru par une question à travers eux : l'agent décide s'il faut effectuer une récupération et quelle base de connaissances consulter, la Gateway expose chaque base de connaissances comme un outil qu'il peut appeler, les bases de connaissances gérées effectuent les recherches et citent leurs sources, et la boucle se répète autant de fois que la question le nécessite. Tout ce que fait l'agent en cours de route est enregistré dans Amazon CloudWatch.
Figure 1 : Les services impliqués et le chemin parcouru par une seule question à travers eux
Contexte
Avant la démonstration, il est utile d'établir trois choses : ce qui rend la récupération agentique, pourquoi la base de connaissances gérée en est le bon fondement, et pourquoi l'observabilité et l'évaluation font partie intégrante de la conception plutôt que d'être ajoutées après coup.
Du RAG à la récupération agentique d'entreprise
Le RAG (Retrieval Augmented Generation) classique effectue une seule récupération et une seule génération. La récupération agentique d'entreprise place un agent de raisonnement dans la boucle : il décide s'il faut et quoi récupérer, peut récupérer plusieurs fois pour affiner, choisit quelle base de connaissances est pertinente (routage sémantique), et seulement ensuite compose une réponse fondée avec des citations. Avec la base de connaissances gérée, il s'agit d'une capacité de service de premier ordre : l'API AgenticRetrieveStream effectue la planification multi-tours, exécute la récupération et renvoie une réponse avec citations, plutôt qu'une couche d'orchestration que vous devez construire et maintenir au-dessus d'une recherche vectorielle brute. Cela produit de meilleures réponses sur les questions complexes, mais aussi un système plus complexe à exploiter, et c'est précisément pourquoi l'observabilité et l'évaluation sont intégrées dès le départ.
Base gérée comparée aux bases de connaissances à faire soi-même
Amazon Bedrock propose désormais une base de connaissances gérée (Type : MANAGED) : Amazon Bedrock gère pour vous l'ingestion, le stockage, l'indexation et la récupération , y compris l'embedding et le reranking avec des modèles gérés par le service par défaut, de sorte qu'il n'y a aucune base de données vectorielle à provisionner, dimensionner ou corriger. Cela diffère d'une base de connaissances gérée par le client (DIY), où vous choisissez et exploitez vous-même le magasin vectoriel (par exemple, Amazon OpenSearch Serverless).
Deux différences comptent le plus pour cette solution :
| Capacité | Amazon Bedrock géré | Géré par le client (DIY) |
| Récupération agentique (AgenticRetrieveStream) | Pris en charge | Non pris en charge |
| Intégration à AgentCore Gateway | Pris en charge | Non pris en charge |
| Magasin de données | Mise à l’échelle automatique, entièrement gérée par Amazon Bedrock | Vous provisionnez, mettez à l’échelle et maintenez vous-même |
| Embedding + reranking | Modèles gérés intégrés, sans coût supplémentaire | Vous les configurez |
| Infrastructure à gérer | Aucune | Base de données vectorielle + plus |
Comme la récupération agentique et le connecteur AgentCore Gateway ne sont disponibles que sur la base de connaissances gérée, celle-ci constitue le socle naturel de la récupération agentique d’entreprise. Cela signifie également qu’Amazon Bedrock gère pour vous le stockage et l’indexation, de sorte qu’aucune collection OpenSearch Serverless ni capacité OCU n’est à provisionner dans cette conception. L’option gérée par le client reste le bon choix lorsque vous souhaitez sélectionner et exploiter votre propre magasin de vecteurs, par exemple pour réutiliser une collection OpenSearch Serverless existante ou pour répondre à des exigences spécifiques de résidence des données, de réglage ou de conformité. Pour la récupération agentique d’entreprise, c’est la base de connaissances gérée qui rend cette capacité possible.
Pourquoi l’observabilité et l’évaluation
Un système agentique qui renvoie une réponse ne suffit pas pour la production. Vous devez observer son comportement (latence, volume d’appels, utilisation de jetons), la qualité de la récupération et des réponses, et disposer de ces signaux en continu. Cette solution fournit deux tableaux de bord CloudWatch couvrant sept couches de télémétrie, plus deux formes d’évaluation (à la demande et continue), le tout provisionné par la même application CDK. Les couches d’ancrage, de citations et d’évaluation soutiennent également un usage responsable. Les réponses citées sont traçables jusqu’à leurs passages sources afin que les réponses restent auditable, et les scores de fidélité et d’exactitude vous permettent de détecter les réponses qui dérivent de leurs sources plutôt que de le découvrir en production.
Pourquoi CDK pour cette solution en particulier
N’importe quel outil d’infrastructure en tant que code peut créer ces ressources. CDK mérite sa place ici pour une raison propre à cette architecture : les quatre piles sont étroitement interréférencées. La passerelle a besoin des deux identifiants de bases de connaissances. L’agent a besoin de l’URL et de l’ARN de la passerelle. Les tableaux de bord ont besoin des identifiants KB, de l’ARN de la passerelle, et de l’identifiant du runtime de l’agent, soit sept valeurs traversant les frontières des piles, chacune étant une dimension d’une métrique ou une cible d’un connecteur.
Écrits sous forme de gabarits bruts, c'est un ensemble d'exports de piles et de recherches inter-piles maintenus manuellement en cohérence, plus un script qui déploie dans le bon ordre et propage les sorties en aval, et les deux divergent dès que quoi que ce soit est renommé. Avec CDK, vous passez le construct, et l'export ainsi que l'arête de dépendance découlent de ce seul acte de le passer. La solution de 2024 comptait trois piles et une chaîne de dépendances essentiellement linéaire. À quatre piles avec sept valeurs circulant entre elles, la différence cesse d'être stylistique.
Présentation de la solution
Voici le chemin parcouru par une seule question dans le système, de bout en bout. Cela mérite un examen attentif, car le reste de l’article la parcourt de gauche à droite.
Le schéma suivant retrace le flux de travail agentique de bout en bout. La question d’un utilisateur entre dans l’agent sur l’AgentCore Runtime, qui la route via l’AgentCore Gateway vers l’un des deux outils AgenticRetrieveStream, un par base de connaissances gérée, financière et météorologique, chacune ingérée depuis Amazon S3. L’outil sélectionné renvoie une réponse fondée et sourcée, et chaque étape est diffusée en continu vers Amazon CloudWatch et AWS X-Ray. Les badges numérotés correspondent au parcours détaillé suivant.
Figure 2 : flux de travail agentique de récupération de bout en bout pour une seule question
Les étapes numérotées du schéma correspondent au flux de travail, qui est le suivant.
Étape 0 — ponctuelle, au déploiement. Avant même qu’une question soit posée, chaque corpus dans Amazon S3 est ingéré dans sa propre Managed Knowledge Base : Amazon Bedrock l’analyse, le découpe, génère ses embeddings et l’indexe automatiquement. Cela se produit une seule fois lors du déploiement des piles, cela ne fait pas partie du chemin par question, donc c’est représenté par une flèche en pointillés et marqué étape 0. Chaque question suit ensuite les étapes 1 à 6 :
- Un utilisateur envoie une question à l’agent hébergé sur l’Amazon Bedrock AgentCore Runtime. Le Runtime instrumente automatiquement toute la boucle raisonner-agir avec des spans OpenTelemetry (OTEL), si bien que le système est observable dès le premier appel.
- Le modèle de raisonnement de l’agent planifie et route entre les bases de connaissances. Comme chaque base de connaissances est exposée comme son propre outil de récupération, l’agent sélectionne l’outil dont le sujet correspond à la question, financier ou météorologique, plutôt que de chercher dans un index mélangé.
- L’appel d’outil sélectionné est relayé par l’AgentCore Gateway via MCP, autorisé par le rôle de tâche IAM de l’agent et signé avec SigV4, qui invoque l’API AgenticRetrieveStream de cette base de connaissances sur la Managed Knowledge Base.
- AgenticRetrieveStream effectue le travail au sein de la base de connaissances : il décompose la question en sous-requêtes, récupère de manière itérative depuis le magasin de données géré par Amazon Bedrock (ingéré depuis les corpus dans Amazon S3) et synthétise une réponse fondée et sourcée qui est diffusée en continu à travers le Gateway.
- L’agent vérifie si le contexte renvoyé est suffisant. Si ce n’est pas le cas, il boucle, en routant et récupérant à nouveau, avant de composer sa réponse finale. Si c’est le cas, il renvoie la réponse sourcée à l’utilisateur.
- Tout au long du processus, le Runtime émet des spans, des décomptes de tokens et des métriques vers Amazon CloudWatch et AWS X-Ray, alimentant les sept couches d’observabilité et fournissant les scores d’évaluation aussi bien à la demande que continus.
En interne, ce flux de travail est une seule application CDK, app.py, qui déclare quatre piles. Vous ne choisissez pas l’ordre, CDK le déduit des références de construct que vous passez :
kb_stack = KnowledgeBasesStack(app, f"{project}-kb", env=env)
gateway_stack = AgenticGatewayStack(
app, f"{project}-gateway", env=env,
financial_kb=kb_stack.financial_kb, # ← the reference creates the dependency
weather_kb=kb_stack.weather_kb,
)
agent_stack = AgentRuntimeStack(
app, f"{project}-agent", env=env,
gateway=gateway_stack.gateway,
)
DashboardsStack(
app, f"{project}-dashboards", env=env,
financial_kb=kb_stack.financial_kb,
weather_kb=kb_stack.weather_kb,
gateway=gateway_stack.gateway,
agent_runtime=agent_stack.agent_runtime,
)
C’est l’intégralité du câblage. Ces quatre appels de constructeur remplacent la gestion des export/import et le script de déploiement.
| # | Pile | Ce qu’elle crée | Remarque |
| 1 | -kb | Bucket S3, téléversement des corpus, deux KB de Type : MANAGED, sources de données, IAM, ingestion | Les KB passent à ACTIVE, corpus ingérés |
| 2 | -gateway | Gateway (AWS_IAM / MCP), cibles AgenticRetrieveStream par KB | pas besoin de Cognito |
| 3 | -agent | ECR, CodeBuild, agent Strands instrumenté sur Runtime, logs/traces fournis, éval en ligne | ~8–10 min (construction de l'image) |
| 4 | -dashboards | tableaux de bord agentic-observability + kb-observability | vides tant que vous ne générez pas de trafic |
L'agent exécute une boucle raisonner-agir : il réfléchit (un appel à un grand modèle de langage (LLM)), décide quel outil de KB appeler, lit ce qui est renvoyé via la Gateway, et récupère souvent à nouveau avant de composer sa réponse finale avec citations. Chaque étape est automatiquement instrumentée par le Runtime, de sorte que les sept couches d'observabilité se remplissent à partir du trafic réel.
Les sept couches. L1 métriques natives KB, L2 ingestion, L3 qualité de la récupération agentique, L4 métriques Gateway/MCP, L5 arbre de spans OTEL , L6 consommation de tokens, et L7 scores d'évaluation. Les couches 1, 4 et 5 sont émises automatiquement. Les couches 3, 6 et 7 sont publiées comme métriques personnalisées par le notebook pilote.
Tout ce qui est configurable se trouve dans un seul fichier, config.py:
| Configuration | Signification | Par défaut |
EnvSettings.PROJECT_NAME |
Préfixe de nom pour chaque pile et ressource | bmkb-obs-cdk |
EnvSettings.ACCOUNT_REGION |
Région AWS dans laquelle déployer | us-west-2 (ou celle de votre profil) |
KbConfig.EMBEDDING_MODEL_TYPE |
MANAGED (fourni ensemble) ou CUSTOM (apportez votre propre ARN) |
MANAGED |
AgentConfig.MODEL_ID |
Le modèle de raisonnement de l’agent, la dépense Layer 6 | Claude Haiku 4.5 |
EvalConfig.SAMPLING_PERCENTAGE |
Taux d'échantillonnage de l'évaluation en ligne, voir la clause de non-responsabilité | 100 |
Changement PROJECT_NAME vous donne une copie de la solution entière portant un nom indépendant, de sorte que deux déploiements peuvent coexister dans un même compte. Le notebook du pilote lit la même constante, il suit donc automatiquement le changement de nom ; il n'y a aucun nom de pile à maintenir synchronisé à la main.
Décrivez le jeu de données
La solution est livrée avec deux petits corpus, regroupés dans le dépôt sous data/ :
- Finances — Un 10-K synthétique d'Octank Financial (octank_financial_10K.pdf, ~198 Ko).
- Météo — A réelles et accessibles au public Rapport du Congressional Research Service du Congrès américain sur les tornades (IF12695, tornadoes_report.pdf, ~560 Ko).
À propos des données : Le corpus financier est synthétique. Octank est une société fictive et le 10-K est un exemple de données généré par un modèle (sous licence CC0). Il s'agitn’ données financières réelles. Le corpus météo est une œuvre réelle du domaine public du gouvernement américain, à savoir un rapport du Congressional Research Service, accessible publiquement à l'adresse sgp.fas.org/crs/misc/IF12695.pdf (les œuvres du gouvernement américain ne sont pas soumises au droit d'auteur). Pour utiliser vos propres données, déposez des fichiers sous data/ et ajustez les préfixes dans config.py, aucune autre modification n'est requise.
Les deux corpus sont volontairement distincts, de sorte que l'agent doit acheminer chaque question vers la bonne base de connaissances, c'est le principe du routage sémantique. Comme il s'agit de bases de connaissances gérées (Managed Knowledge Bases), nous ne configurons ni le découpage, ni l'embedding, ni un index : à l'ingestion, Amazon Bedrock analyse chaque PDF, le découpe, génère les embeddings avec son modèle géré et l'indexe automatiquement.
Nous utilisons deux bases de connaissances distinctes, chacune exposée par la passerelle (Gateway) comme son propre outil de récupération, plutôt qu'une seule base de connaissances regroupant les deux corpus, et ce choix est délibéré. Donner à l'agent deux outils nommés fait du routage un acte de raisonnement explicite qu'on peut observer : l'arborescence d'étendue (span tree) montre quel outil il a choisi pour une question donnée, et les métriques de qualité de récupération de la couche 3 restent séparables par base de connaissances, de sorte que la précision financière et la précision météo ne se fondent jamais en un seul chiffre. Un outil unique couvrant les deux corpus effacerait cette distinction : la décision de routage passerait dans le classement d'un seul index, hors de vue, et chaque signal de qualité serait une moyenne sur deux domaines sans rapport. Garder les corpus et leurs outils séparés est ce qui rend le comportement de l'agent lisible, et c'est là tout l'enjeu de l'exercice.
Dans CDK, le dépôt des corpus dans S3 se fait via un BucketDeployment :
s3deploy.BucketDeployment(
self, "FinancialCorpus",
sources=[s3deploy.Source.asset(str(ROOT / "data" / "financial"))],
destination_bucket=self.source_bucket,
destination_key_prefix=KbConfig.FINANCIAL_PREFIX,
)
BucketDeployment mérite qu'on s'y intéresse précisément parce que l'alternative est si tentante : sans lui, la ressource personnalisée qui déclenche l'ingestion a tendance à se doter d'une étape de téléversement, et une même ressource se retrouve alors propriétaire de deux tâches sans rapport. Ici, elle n'a qu'à ingérer.
L'ingestion gérée analyse, découpe, génère les embeddings et indexe chaque document automatiquement : un document indexé par base de connaissances, zéro échec.
Figure 3 : Résultats de l'ingestion gérée, un document indexé par base de connaissances avec zéro échec
Déployer la solution
Cette section décrit pas à pas le déploiement de toute la solution avec une seule commande. Une fois les prérequis satisfaits, cdk deploy --all provisionne les quatre stacks dans l'ordre de dépendance dérivé par CDK et transmet automatiquement toutes les valeurs inter-stacks.
Prérequis
- Un compte AWS avec des autorisations pour Amazon Bedrock, AgentCore (Runtime + Gateway), AWS Identity and Access Management (IAM), CloudWatch, AWS X-Ray, Amazon Elastic Container Registry (Amazon ECR), AWS CodeBuild, Amazon S3, AWS Lambda, et AWS CloudFormation.
- Le modèle de l’agent disponible dans le compte (par défaut
us.anthropic.claude-haiku-4-5-20251001-v1:0). - CloudWatch Transaction Search activé, afin que les spans OTEL arrivent dans aws/spans pour les couches 5–7.
- Node.js 18+ et la CLI CDK (
npm install -g aws-cdk), plus Python 3.13+. - Le compte et la région amorcés pour CDK (cdk bootstrap), une seule fois par compte/région.
- Pas de Docker local, l’image de l’agent est construite par CodeBuild (ARM64).
Une seule commande
Pour déployer la solution, clonez le dépôt, créez un environnement virtuel, installez les dépendances, puis exécutez cdk deploy --all. Exécutez les commandes suivantes depuis votre terminal :
git clone https://github.com/aws-samples/amazon-bedrock-samples.git
cd rag/managed-knowledge-bases/07-IaaC/managed-kb-observability-cdk/
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cdk bootstrap # once per account/region
cdk deploy --all
Les deux premières commandes clonent l’exemple et se placent dans le répertoire du projet. Les deux suivantes créent et activent un environnement virtuel Python et installent les dépendances de l’application CDK. cdk bootstrap prépare le compte et la région pour CDK (vous n’en avez besoin qu’une fois par compte/région), et cdk deploy --all provisionne les quatre stacks.
Le compte et la région proviennent de votre profil AWS (CDK_DEFAULT_ACCOUNT / CDK_DEFAULT_REGION), l’application se déploie donc sans modification.
Disponibilité par région : la base de connaissances gérée, la récupération agentique (AgenticRetrieveStream) et Amazon Bedrock AgentCore (Runtime et Gateway) ne sont pas disponibles dans toutes les régions AWS. Avant de déployer, confirmez que tout cela est proposé dans votre région cible et définissez ACCOUNT_REGION dans config.py en conséquence. La valeur par défaut est us-west-2. Pour connaître la disponibilité actuelle, consultez la documentation d’Amazon Bedrock et d’ Amazon Bedrock AgentCore ainsi que la AWS Regional Services List.
Il n'y a pas de script de déploiement dans cette version, et c'est justement le but : cdk deploy --all parcourt le graphe de dépendances qu'il a dérivé de app.py, déploie les quatre stacks dans l'ordre et transmet automatiquement chaque valeur inter-stack. Le terminal signale chaque stack au fur et à mesure : bmkb-obs-cdk-kb [1/4] (le PROJECT_NAME par défaut), puis gateway [2/4], puis agent [3/4], puis dashboards [4/4], et cet ordre est dérivé, non déclaré : il résulte des références de constructs entre les stacks, de sorte qu'ajouter une cinquième stack qui consomme une sortie existante réordonne le déploiement d'elle-même.
Stack -agent génère le conteneur de l'agent avec CodeBuild, prévoyez donc environ 8 à 10 minutes pour cette étape. Les trois autres sont rapides. Chaque stack affiche ses outputs à la fin, et c'est là que vous récupérez les identifiants de la base de connaissances, l'URL de la Gateway, l'ARN du runtime et les deux URL des tableaux de bord. Une fois le déploiement terminé, les quatre stacks sont achevées. La capture d'écran suivante montre la console AWS CloudFormation après une opération réussie. cdk deploy --all.
Figure 4 : console AWS CloudFormation après un déploiement réussi, avec les quatre stacks à l'état CREATE_COMPLETE
Sur la console, les quatre piles — kb, gateway, agent et dashboards — affichent CREATE_COMPLETE, chacune avec sa position [n/4] dans l'ordre de dépendance dérivé, indiquée dans sa description.
Une remarque sur les ressources de longue durée
Deux éléments de cette solution prennent bien plus de temps que le plafond de 15 minutes d'une fonction AWS Lambda ne le permet à un sondage naïf : la synchronisation d'ingestion de la KB et la construction de l'image CodeBuild. Le framework Provider de l'AWS CDK gère cela avec une on_event / is_complete séparation, où un gestionnaire démarre le travail et un second est interrogé jusqu'à ce qu'il signale que c'est terminé.
cr.Provider(
self, "IngestSyncProvider",
on_event_handler=on_event, # StartIngestionJob, return the job id
is_complete_handler=is_complete, # GetIngestionJob, report IsComplete
query_interval=Duration.seconds(30),
total_timeout=Duration.minutes(30),
)
Rien ne bloque, le protocole de réponse renvoyé à CloudFormation appartient au framework plutôt que d'être écrit à la main dans chaque gestionnaire, et le budget de 30 minutes est une propriété plutôt que quelque chose à contourner par des astuces d'ingénierie.
Lancement et test
Ouvrez notebooks/01-drive-and-observe.ipynb et exécutez-le de haut en bas (pip install -r requirements-notebook.txt d'abord). Il lit les sorties de la pile, puis envoie des invites spécifiques à chaque sujet à l'agent déployé, une session par KB, afin que vous puissiez voir à la fois les réponses et le routage sémantique au même endroit : les questions financières reçoivent des réponses tirées du 10-K d'Octank et les questions météo du rapport sur les tornades, chacune étant routée automatiquement vers l'outil AgenticRetrieveStream correspondant.
Le notebook découvre tout à partir des sorties de la pile, il n'y a donc rien à coller à la main :
# Stack names are derived from the same PROJECT_NAME the CDK app uses, so renaming the
# project in config.py cannot leave this notebook pointing at stale stacks.
from config import EnvSettings
PROJECT = EnvSettings.PROJECT_NAME
STACKS = {suffix: f'{PROJECT}-{suffix}'
for suffix in ('kb', 'gateway', 'agent', 'dashboards')}
def outputs(stack_name):
s = cfn.describe_stacks(StackName=stack_name)['Stacks'][0]
return {o['OutputKey']: o['OutputValue'] for o in s.get('Outputs', [])}
Le notebook importe le même config.py module que l'application, de sorte que les deux ne peuvent jamais être en désaccord sur les noms des piles.
Le pilote envoie des invites par KB via l'agent déployé. Les questions financières sont routées vers la KB financière et les questions météo vers la KB météo, chacune avec une réponse justifiée et citée.
Figure 5 : Invites par KB routées vers la base de connaissances correspondante, chacune retournant une réponse justifiée et citée
Le notebook calcule également les signaux de qualité de récupération de la couche 3 sans référence à partir de ce que l'agent a réellement récupéré et cité — pas de vérité terrain, pas de juge supplémentaire — et les publie dans CloudWatch.
Figure 6 : Signaux de qualité de récupération de la couche 3 sans référence par base de connaissances
Observe : les tableaux de bord à sept couches
Les deux tableaux de bord sont l'endroit où les sept couches deviennent visibles. La pile crée les deux tableaux de bord, et le trafic généré les remplit. La capture d'écran suivante montre les deux tableaux de bord tels qu'ils apparaissent dans la console CloudWatch.
Figure 7 : les deux tableaux de bord dans la console CloudWatch, observabilité agentique de bout en bout et observabilité par KB
Les deux tableaux de bord apparaissent dans la console CloudWatch : un pour l'observabilité agentique de bout en bout et un pour l'observabilité par KB (BMKB, Bedrock Managed Knowledge Base). Le reste de cette section détaille ce que montre chaque couche.
Dans cette version, les tableaux de bord sont construits à partir d'objets typés plutôt que d'une chaîne JSON. Une métrique est un Metric, un widget est un GraphWidget, et la mise en page est une liste de Rows :
cw.GraphWidget(
title="L4 — Gateway metrics (MCP)",
width=12, height=6, period=PERIOD, statistic="Sum",
left=[
self._gateway_metric("Invocations", gateway_arn, "tools/call Invocations"),
self._gateway_metric("SystemErrors", gateway_arn, "SystemErrors"),
self._gateway_metric("UserErrors", gateway_arn, "UserErrors"),
self._gateway_metric("Throttles", gateway_arn, "Throttles"),
],
)
L'avantage pratique n'est pas un nombre de lignes réduit, dashboards_stack.py atteint 400 lignes, soit plus que le DashboardBody JSON équivalent. C'est qu'une propriété mal orthographiée ou une combinaison de widgets invalide échoue à cdk synth, sur votre ordinateur portable, en environ une seconde. La même erreur à l'intérieur d'une chaîne DashboardBody se déploie avec succès et s'affiche sous forme de widget cassé sur la AWS Management Console, où vous ne la repérez qu'en la regardant.
Comme un Row accepte n'importe quel widget, la documentation fait partie de la mise en page plutôt que d'être une page wiki qui dérive. Chaque tableau de bord entrelace des TextWidgets avec les graphiques :
[cw.TextWidget(width=24, height=7, markdown=self._l3_explainer())],
[
self._quality_widget("L3 · Financial KB — agentic quality (reference-free, 0–1)", fin_id),
self._quality_widget("L3 · Weather KB — agentic quality (reference-free, 0–1)", wx_id),
],
_l3_explainer() renvoie un tableau markdown définissant chaque ratio et la manière de le lire, de sorte que le widget qui explique grounded_coverage est livré dans le même commit que le widget qui le trace, et un lecteur qui ouvre le tableau de bord à froid n'a pas besoin de deviner ce qu'est une métrique sans référence.
Tableau de bord A — observabilité agentique (de bout en bout). Le tableau s'ouvre avec une explication de la manière dont chaque couche compte une chose différente (pour N requêtes, vous verrez ~N invocations d'agent, ~2N récupérations, ~3N appels LLM, et ~5N opérations Gateway MCP, la boucle agentique rendue visible), puis montre les métriques KB (L1), les métriques et la latence Gateway (L4), l'utilisation des tokens (L6), et parce que l'agent utilise AgenticRetrieveStream, qui renvoie une réponse synthétisée et citée plutôt que des scores par chunk, les signaux de qualité de la couche 3 sans référence, définis en ligne et tracés par KB.
Sur le tableau de bord A, les signaux de qualité de la couche 3 sans référence sont tracés par base de connaissances. D'abord, la KB financière. Le graphique suivant trace son retrieval_utilization, grounded_coverage et duplicate_rate.
Figure 8 : qualité de la couche 3 de la KB financière, traçant l'utilisation de la récupération, la couverture ancrée et le taux de doublons
La KB météo montre les trois mêmes signaux, suivis séparément afin que les deux domaines ne se fondent jamais en un seul chiffre.
Figure 9 : qualité de la couche 3 de la KB météo, suivie séparément de la KB financière
Les deux graphiques tracent retrieval_utilization, grounded_coverage et duplicate_rate pour la KB financière (à gauche) et la KB météo (à droite), de sorte que la qualité de récupération de chaque base de connaissances reste séparable plutôt que d'être moyennée en un seul chiffre.
Tableau de bord B — observabilité par KB (BMKB). Les signaux opérationnels qui déterminent aussi les dépenses, par KB : taille de l'index (à partir des octets sources S3), volume de récupération, appels d'outils agentiques, utilisation des tokens de session et utilisation des tokens de génération par modèle, chacun avec une explication en ligne.
Les captures d'écran suivantes montrent les quatre widgets de métriques du tableau de bord B, remplis après une exécution. Le premier widget indique la taille de l'index, dérivée des octets sources S3, par base de connaissances.
Figure 10 : taille de l'index du tableau de bord B par base de connaissances, dérivée des octets sources Amazon S3
Le deuxième widget compte les appels retrieve par base de connaissances.
Figure 11 : Nombre d'appels de récupération par base de connaissances pour le tableau de bord B
Le troisième widget compte les appels d'outils agentiques via la Gateway. Celui-ci est partagé entre les deux KB plutôt que divisé.
Figure 12 : nombre d'appels d'outils agentiques du tableau de bord B via l'AgentCore Gateway, partagé entre les deux bases de connaissances
Le quatrième widget indique l'utilisation des jetons de session par base de connaissances.
Figure 13 : Utilisation du jeton de session du tableau de bord B par base de connaissances
Les quatre widgets affichent la taille de l'index (à partir des octets de la source S3), le volume d'appels de récupération, les appels d'outils agentiques via la Gateway et l'utilisation des jetons de session. Chacun est détaillé par base de connaissances, à l'exception du nombre d'appels d'outils de la Gateway, qui est partagé entre les deux.
Un détail de dimension mérite d'être signalé, car l'API typée ne le détectera pas pour vous : la AWS/Bedrock/KnowledgeBases l'espace de noms attend un identifiant préfixé, knowledge-base/<id>, tandis que celle de la solution elle-même BMKB/* les espaces de noms utilisent l'identifiant brut. Tous deux ne sont que des chaînes de caractères pour CDK.
# L1 — AWS/Bedrock/KnowledgeBases wants the prefixed form.
dimensions_map={"Operation": "Retrieve", "KnowledgeBaseId": f"knowledge-base/{kb_id}"}
# BMKB/* — our own namespaces use the bare id.
dimensions_map={"KnowledgeBaseId": kb_id}
Couche 5 : L'arbre d'envergure
La couche 5 est l'arbre brut de spans OTEL dans aws/spans, et c'est la couche qui vous montre directement la boucle agentique. Cela vaut la peine de la lire attentivement, car l'imbrication n'est pas évidente : un appel LLM produit trois spans. Le Strands invoke_agent span enveloppe le tour, un interne chat span enveloppe l'appel au modèle, et un chat <model> étendue du type CLIENT est l'appel réel, et les trois répètent la même gen_ai.usage.* attributs de jeton.
La capture d'écran suivante montre l'arborescence des spans en aws/spans, avec l'imbrication des trois spans visible dans les lignes du haut.
Figure 14 : arbre de spans de la couche 5 dans aws/spans, montrant l'imbrication en trois spans d'un seul appel LLM
Lecture des trois premières lignes : un agrégat invoke_agent Strands Agents, puis un span de chat interne, puis un span de chat CLIENT, tous rapportant un nombre identique de 7,299 tokens en entrée et de 268 tokens en sortie. C'est le même appel LLM apparaissant à trois niveaux de l'arbre, et c'est pourquoi l'agrégation exige de la prudence.
Cette structure compte au moment où vous agrégéz. Pour compter chaque appel de LLM une seule fois, filtrez sur le CLIENT feuille :
fields attributes.gen_ai.request.model as model,
attributes.gen_ai.usage.input_tokens as in_tok,
attributes.gen_ai.usage.output_tokens as out_tok
| filter ispresent(in_tok) and kind = 'CLIENT' and name like /^chat /
| stats sum(in_tok) as input_tokens, sum(out_tok) as output_tokens,
count(*) as llm_calls by model
Sans ce filtre, la même requête rapporte trois fois plus de jetons et trois fois plus d'appels.
En appliquant ce filtre CLIENT-leaf, la capture d'écran suivante montre l'utilisation des tokens de génération par modèle, chaque appel LLM étant compté une seule fois.
Figure 15 : Utilisation des tokens de génération par modèle, chaque appel LLM étant compté une seule fois
Avec le filtre en place, l'exécution affiche 14 appels LLM totalisant 60,472 tokens d'entrée et 2,709 tokens de sortie. Sans lui, la même requête signalerait trois fois plus d'appels et trois fois plus de tokens.
Évaluation : à la demande et continue
La qualité est mesurée de deux façons, et les deux sont provisionnées par l'application.
À la demande : Le notebook pilote appelle AgentCore Il n'y a pas de script de déploiement dans cette version, et c'est le but : (LLM-as-judge) sur les spans de chaque session pour les évaluateurs intégrés, Correctness, Faithfulness, Tool-Selection Accuracy, et publie les scores dans CloudWatch, où ils apparaissent en tant que Layer 7 sur le Dashboard A.
La capture d'écran suivante montre le Layer 7 sur le Dashboard A : les scores d'évaluation à la demande par base de connaissances, avec la table des spans OTEL du Layer 5 sur le même tableau de bord.
Figure 16 : Scores d'évaluation à la demande du Layer 7 par base de connaissances, à côté de la table des spans du Layer 5
Le Layer 7 affiche les scores d'évaluation à la demande par base de connaissances, avec la table des spans OTEL du Layer 5 à côté, de sorte que les scores et les spans qui les ont produits se lisent ensemble sur un seul tableau de bord.
Continu (en ligne) : La pile de l'agent provisionne également un AWS::BedrockAgentCore::OnlineEvaluationConfig qui échantillonne les sessions en direct et les note automatiquement, sans exécution de notebook. La configuration elle-même est visible dans la console Bedrock AgentCore sous Assess → Evaluations → Evaluation configurations. Les résultats arrivent dans le groupe de logs /aws/bedrock-agentcore/evaluations/results/<config-id>, et chaque score est également publié en tant que métrique CloudWatch dans le Bedrock-AgentCore/Evaluations namespace, indexé par nom d'évaluateur et id de configuration, de sorte que vous pouvez tracer les scores ou déclencher des alarmes dessus sans analyser les logs.
La capture d'écran suivante montre la configuration de l'évaluation en ligne dans la console AgentCore, sous Assess, puis Evaluations, puis Evaluation configurations.
Figure 17 : La configuration de l'évaluation en ligne dans la console AgentCore, avec quatre évaluateurs intégrés à 100 pour cent d'échantillonnage
La configuration liste quatre évaluateurs intégrés, Tool-Selection Accuracy, Faithfulness, Correctness et Response Relevance, réglés à 100 pour cent d'échantillonnage et affichés comme ACTIVE et activés.
Comme les scores sont des métriques CloudWatch ordinaires, ils se tracent comme tout le reste, sans analyse de logs, et le même widget pourrait porter une alarme. La capture d'écran suivante montre ces quatre scores d'évaluateurs tracés comme des métriques CloudWatch ordinaires.
Figure 18 : Les quatre scores d'évaluateurs continus tracés comme des métriques CloudWatch ordinaires
Les quatre scores d'évaluateurs apparaissent comme des métriques dans le Bedrock-AgentCore/Evaluations namespace, chacun indexé sur l'id de configuration d'évaluation et le nom de service de l'agent, de sorte que vous pouvez les tracer ou déclencher des alarmes dessus sans analyser les logs.
Les résultats en ligne n'arrivent qu'après la fermeture d'une session. La notation s'exécute sur la session terminée, de sorte que le groupe de logs de résultats reste vide pendant environ le délai d'inactivité de session (~30 minutes) après avoir généré du trafic. Un groupe vide juste après une exécution est attendu, ce n'est pas une erreur de configuration. Chaque événement de résultat porte session.id, il se joint donc à toutes les autres couches. Le chemin à la demande dans le notebook n'a pas une telle attente, c'est pourquoi les deux sont présents ici.
Sur les quatre évaluateurs intégrés de cette exécution, le chemin continu a obtenu 1.00 sur Correctness, Faithfulness, Response Relevance et Tool-Selection Accuracy, cinq traces notées par évaluateur, chaque résultat comportant une explication rédigée.
Échantillonnage et coût. Cette application définit SAMPLING_PERCENTAGE = 100 purement pour l'expérience du blog, de sorte que chaque session est évaluée et que les résultats sont immédiatement visibles. Ceci n'est pas une recommandation de production. L'évaluation en ligne invoque un LLM-as-judge pour chaque session échantillonnée, donc le coût évolue en fonction du taux d'échantillonnage et du volume de trafic. Pour un déploiement réel, choisissez un pourcentage d'échantillonnage adapté à vos besoins de surveillance de la qualité et à votre budget, et alignez la configuration sur les politiques et les exigences de gouvernance des coûts de votre organisation avant de l'activer. Le taux est une seule constante, EvalConfig.SAMPLING_PERCENTAGE, dans config.py.
Nettoyage
Une fois que vous avez terminé, supprimez la solution pour qu'elle cesse d'entraîner des frais, car les données KB stockées, l'image de l'agent dans ECR et l'évaluation en ligne toujours active coûtent tous de l'argent tant que les stacks restent inactives. Une seule commande démonte tout :
cdk destroy --all
CDK supprime les stacks dans l'ordre inverse des dépendances de lui-même : les dashboards, puis l'agent, puis la gateway, puis kb : le même graphe qu'il avait dérivé pour le déploiement, parcouru à rebours. Il n'y a pas de script de teardown à maintenir en cohérence avec le script de déploiement, ce qui est l'une des propriétés les plus discrètement précieuses de la modélisation des dépendances une seule fois.
Deux comportements de suppression méritent d'être connus, car tous deux remplacent du code de nettoyage écrit à la main :
self.source_bucket = s3.Bucket(
self, "SourceBucket",
removal_policy=RemovalPolicy.DESTROY,
auto_delete_objects=True, # replaces a list_object_versions delete loop
)
self.repository = ecr.Repository(
self, "AgentImageRepo",
removal_policy=RemovalPolicy.DESTROY,
empty_on_delete=True, # replaces an image-delete loop
)
Les deux sont définis pour l'hygiène de l'exemple ; pour tout ce qui compte pour vous, remplacez le bucket par RemovalPolicy.RETAIN.
La stack d'amorçage CDK (CDKToolkit) et son bucket de staging ne sont pas supprimés. Il s'agit d'une infrastructure partagée à l'échelle du compte dont d'autres applications CDK peuvent dépendre.
Ce qui a changé depuis la solution en une seule fois
Cet article et la solution de 2024 sont tous deux des applications CDK en Python, déployées avec cdk deploy. L'outil de création est la constante ici ; ce qui a changé, c'est l'architecture en dessous, et la plupart du changement est une soustraction :
| Aspect | 2024 : RAG en une seule fois | Cette solution |
| Magasin de vecteurs | Une collection et un index OpenSearch Serverless que vous provisionnez, dimensionnez et payez en OCU | Aucun. Type : MANAGED, Amazon Bedrock possède le stockage et l'indexation |
| Cycle de vie de l'index | Une ressource personnalisée crée l'index et attend qu'il devienne interrogeable | Rien à créer |
| Modèle d'embedding | Vous le sélectionnez et accordez l'accès au modèle | Géré par le service par défaut |
| Piles | 3 : rôle KB → infrastructure OpenSearch → KB + source de données | 4 : kb → passerelle → agent → tableaux de bord |
| Récupération | Un seul Retrieve, chunks top-k par similarité vectorielle | AgenticRetrieveStream, reclassé en interne, renvoie une réponse synthétisée avec citations |
| Choisir une base de connaissances | Sans objet, il n'y a qu'un seul index | L'agent route sémantiquement entre les deux |
| Second regard sur le corpus | Impossible en une seule passe | L'agent récupère à nouveau avant de répondre |
| Télémétrie | Aucune provisionnée | Sept couches, deux tableaux de bord |
| Évaluation | Manuelle : synchroniser, choisir un modèle, poser des questions | À la demande et continue, toutes deux provisionnées |
| Coût plancher au repos | Les frais d'OCU s'accumulent que vous interrogiez ou non | Stockage uniquement |
Le compromis est réel dans les deux sens. Un index unique répondant à des questions en une seule passe coûte moins cher par requête, est plus simple à raisonner et est entièrement suffisant lorsqu'un seul corpus contient la réponse. Optez pour cette conception quand ce n'est pas le cas.
Les constructions CDK qui font le travail
Quatre constructions portent l'essentiel du poids dans cette application, et il vaut la peine de les nommer car chacune remplace quelque chose que les gens écrivent sinon à la main :
- Fournisseur – Pour les ressources personnalisées qui dépassent la limite de 15 minutes d'une fonction AWS Lambda. Cette
on_event/is_completeséparation garantit que rien ne reste en attente dans une boucle de sondage, et le protocole de réponse vers CloudFormation relève du framework plutôt que d'unurllibcallback intégré dans chaque gestionnaire. - BucketDeployment – télécharge les corpora, de sorte que la ressource personnalisée d'ingestion ne fait qu'ingérer.
- auto_delete_objects=True et empty_on_delete=True, remplacez les boucles manuscrites de
list_object_versionset de suppression d'images dont une pile aurait sinon besoin pour pouvoir être détruite. - repository.grant_pull_push(project) – une ligne pour les huit
ecr:*actions dont CodeBuild a besoin, orthographiées correctement par construction.
Et des tableaux de bord typés, issus de la section Observe : des objets Metric / GraphWidget / Row au lieu d'une chaîne JSON DashboardBody, ce qui transforme une combinaison de widgets invalide de « s'affiche cassée sur la console » en « échoue à cdk synth.”
Deux choses que CDK ne change pas, et il vaut la peine de connaître toutes les deux avant de commencer :
- Le JSON libre reste en camelCase.
connector_parametersetparameter_valuessont transmis verbatim, de sorte que la conversion snake_case vers PascalCase d'AWS CDK ne s'applique pas à l'intérieur. Des clés commebucketNameetinclusionPrefixesdoivent être orthographiées exactement comme l'API s'y attend, et rien ne vous le dira sinon jusqu'à ce que la ressource échoue. - Les valeurs de type chaîne restent des chaînes. La différence de dimension
knowledge-base/<id>par rapport à<id>seule, issue de la section Observe, est invisible pour le système de types. Les constructions typées vérifient la structure, pas la sémantique.
Aucune de ces raisons ne justifie de préférer un outil à l'autre. Elles marquent la limite de ce que « typé » vous apporte, et connaître l'emplacement de cette limite est l'essentiel de ce qui rend CDK agréable plutôt que surprenant.
Conclusion
Nous avons construit une solution complète de récupération agentique d'entreprise sur une base de connaissances Amazon Bedrock Knowledge Base gérée et AgentCore : routage sémantique multi-KB, un agent de raisonnement, sept couches d'observabilité, et une évaluation à la fois à la demande et continue, le tout déployé comme une seule application AWS CDK.
Deux choses méritent d'être retenues. La base de connaissances gérée a supprimé de l'infrastructure plutôt que d'en ajouter : aucun magasin de vecteurs à provisionner, aucun index à créer et à attendre, aucune ligne OCU qui s'accumule pendant que le système est inactif. C'est aussi le type de base de connaissances qui prend en charge la récupération agentique et le connecteur AgentCore Gateway, comme décrit dans la documentation Amazon Bedrock. Et une fois que la récupération est devenue agentique, l'observabilité a cessé d'être optionnelle. Environ la moitié de ce que cette application provisionne existe pour répondre à ce que l'agent a réellement fait et à savoir si la réponse était bonne, ce qui n'est pas une charge supplémentaire pour un système agentique. C'est la partie qui le rend exploitable.
Le modèle de rédaction de CDK a gagné sa place sur les coutures. Sept valeurs traversent les limites de pile dans cette architecture, et chacune d'elles est une référence de construction plutôt qu'une paire export/import, ce qui explique également pourquoi il n'y a pas de script de déploiement, pas de script de démontage et pas d'ordre fixe à mémoriser.
À partir de là, vous pouvez pointer les sources de données vers vos propres corpora, placer l'agent dans un cloud privé virtuel (VPC), ajuster le taux d'échantillonnage de l'évaluation en ligne selon votre budget et vos politiques, ou ajouter d'autres bases de connaissances au routeur. Pour en savoir plus, consultez la Amazon Bedrock page de détail et la documentation d'Amazon Bedrock. L'application, le notebook du pilote et les utilitaires autonomes se trouvent tous dans le dépôt GitHub d'accompagnement, vous pouvez donc le cloner et déployer votre propre copie en une seule commande.