Passer au contenu principal
Découvrez comment instrumenter une application agentique sur plusieurs tours de conversation à l’aide du SDK W&B Weave afin de pouvoir visualiser, déboguer et évaluer le comportement de votre agent. Ce guide s’adresse aux développeurs qui créent ou intègrent des agents et souhaitent disposer d’une visibilité structurée sur les conversations, les tours de conversation, les appels LLM et les exécutions d’outils. Le SDK Weave pour Agents modélise le cycle de vie complet d’une conversation agentique sur plusieurs tours de conversation : l’agent qui gère plusieurs conversations, la conversation qui regroupe les tours de conversation, chaque échange utilisateur-agent (tour de conversation), les appels LLM au sein d’un tour de conversation et les exécutions d’outils déclenchées par un LLM. Les traces apparaissent dans l’onglet Agents de votre projet Weave. Chaque conversation affiche une chronologie sur plusieurs tours de conversation avec des appels d’outil imbriqués, l’utilisation des jetons et le feedback. Weave s’appuie sur OpenTelemetry (OTel), la norme ouverte du traçage distribué. Chaque tour de conversation, appel LLM et appel d’outil émet un span OTel (un enregistrement structuré d’une opération). Chaque span est tagué avec des attributs de convention sémantique GenAI comme gen_ai.agent.name et gen_ai.conversation.id. Si vous tracez des fonctions individuelles en tant qu’opérations avec le décorateur @weave.op, consultez plutôt Tracer des applications LLM.

Avant de commencer

Pour commencer, installez le package weave et initialisez votre projet. Cette étape enregistre votre équipe et votre projet auprès de Weave afin que le SDK achemine les spans vers le bon emplacement dans l’interface utilisateur.
pip install weave
Remplacez [YOUR-TEAM] par le nom de votre équipe W&B et [YOUR-PROJECT] par le nom de votre projet W&B.
import weave

weave.init("[YOUR-TEAM]/[YOUR-PROJECT]")
Appelez weave.init() avant tout appel à start_conversation(), start_turn(), start_llm(), start_tool() ou start_subagent(). Toutes les fonctions de traçage des agents ne font silencieusement rien lorsque le traçage est désactivé ou que l’appel à init est absent. Vous pouvez donc laisser l’instrumentation dans le code de production et la contrôler via la configuration.

Le modèle de données des agents

Weave modélise le comportement des agents sous forme d’une hiérarchie de relations de type un-à-plusieurs. Chaque agent peut avoir plusieurs conversations, chaque conversation peut avoir plusieurs tours de conversation, chaque tour de conversation peut avoir plusieurs appels LLM, et chaque appel LLM peut déclencher plusieurs appels d’outil.
Conceptclasse du SDK Weavetype de span OTelDescriptionPage de référence
Agent(aucune classe)(aucun span, regroupé par l’attribut agent_name)Une application agentique dans l’onglet Agents qui contient une ou plusieurs conversations.
ConversationConversation(aucun span, les tours de conversation sont regroupés par l’attribut conversation_id)Une conversation ou une exécution qui contient un ou plusieurs tours de conversation.Python
TypeScript
Tour de conversationTurninvoke_agentUn message utilisateur et la réponse complète de l’agent.Python
TypeScript
appel LLMLLMchatUn appel à une API de modèle de langage.Python
TypeScript
appel d’outilToolexecute_toolUn appel d’outil déclenché par une réponse LLM.Python
TypeScript
appel de sous-agentSubAgentinvoke_agentUn appel d’agent imbriqué, généralement lorsqu’un agent délègue à un autre.Python
TypeScript
Le diagramme suivant montre comment un agent englobe plusieurs conversations, une conversation englobe plusieurs tours de conversation, et ainsi de suite. Une conversation regroupe les tours de conversation à l’aide d’un attribut conversation_id partagé plutôt que d’un span parent. Ainsi, chaque tour de conversation démarre sa propre trace OTel. Cette conception prend en charge le traçage distribué et l’exécution en parallèle. Le client envoie les spans directement au collecteur OTel, sans agrégation côté serveur.
Pour intégrer Weave à des SDK ou harnesses, comme le Claude Agent SDK ou Codex, voir Intégrations de traçage des agents. Weave applique automatiquement des patchs à plusieurs SDK de création d’agents et harnesses d’agents pour une intégration rapide.

API de traçage des agents

Les sections suivantes décrivent chaque fonction de traçage de premier niveau ainsi que les arguments qu’elle accepte. Utilisez-les pour instrumenter les couches conversation, tour de conversation, appel LLM et appel d’outil du modèle de données décrit dans la section précédente. Weave expose les fonctions de premier niveau suivantes. Chaque fonction renvoie un objet qui sert de gestionnaire de contexte (avec with en Python, ou try/finally en TypeScript), ou que vous pouvez fermer manuellement en appelant .end().

Démarrer une conversation

start_conversation() (Python) ou startConversation() (TypeScript) ajoute un attribut conversation_id à chaque span enfant afin que les tours de conversation soient regroupés dans l’onglet Agents. Si vous fournissez un conversation_id / conversationId, il doit rester stable pendant toute la durée de la conversation. Réutilisez le même ID pour ajouter de nouveaux tours de conversation à une conversation existante. Si vous l’omettez, le SDK génère automatiquement un UUID. La conversation active est stockée dans le contexte (un ContextVar Python ou AsyncLocalStorage de Node.js). Ainsi, tout code exécuté dans le même contexte asynchrone peut la récupérer avec weave.get_current_conversation() / weave.getCurrentConversation() sans passer explicitement l’objet conversation.
conversation = weave.start_conversation(
    agent_name="my-agent",    # Facultatif : identifie l’agent dans l’interface utilisateur. Si vous l’omettez, la conversation n’est pas regroupée sous un agent nommé.
    conversation_id="",       # Facultatif : ID stable pour regrouper les tours de conversation ; généré automatiquement lorsqu’il est vide.
    model="",                 # Facultatif : modèle par défaut pour les tours de conversation de cette conversation.
    conversation_name="",     # Facultatif : libellé lisible affiché dans l’interface utilisateur.
    include_content=True,     # Facultatif : définissez False pour exclure le contenu des messages des spans.
    continue_parent_trace=False,  # Facultatif : se rattache à une trace OTel existante au lieu d’en démarrer une nouvelle.
)

Démarrer un tour de conversation

start_turn() (Python) et startTurn() (TypeScript) créent un nouveau span invoke_agent qui devient la racine d’une nouvelle trace OTel. Weave utilise ce span pour représenter un échange complet entre l’utilisateur et l’agent dans la vue chronologique. Vous pouvez l’appeler de deux façons :
  • Comme fonction autonome (weave.start_turn(...) / weave.startTurn(...)), comme illustré dans les exemples ci-dessous. Elle détermine la conversation active à partir du contexte et hérite de son ID de conversation. Si aucune conversation n’est active, le tour de conversation est créé sans conversation_id et n’est pas regroupé avec d’autres tours de conversation.
  • Comme méthode d’instance sur une conversation dont vous détenez une référence (conversation.start_turn(...) / conversation.startTurn(...)). Cela est utile lorsque vous avez un objet conversation explicite dans la portée, par exemple à l’intérieur d’un bloc de gestionnaire de contexte. L’exemple « Gestionnaire de contexte ou schéma try-finally » ci-dessous utilise cette forme. Voir le tableau du modèle de données ci-dessus pour des liens directs vers les pages de référence Conversation, Turn, LLM, Tool et SubAgent dans les deux SDKs.
turn = weave.start_turn(
    user_message="What is the weather in Tokyo?",  # Texte saisi par l’utilisateur.
    agent_name="my-agent",   # Facultatif : redéfinit le nom de l’agent défini au niveau de la conversation.
    model="gpt-4o",          # Facultatif : modèle utilisé pour ce tour de conversation.
)

Démarrer un appel LLM

start_llm() / startLLM() crée un span chat imbriqué sous le tour de conversation en cours. Weave utilise ce span pour afficher l’utilisation des jetons, le nom du modèle, les messages d’entrée et de sortie, ainsi que le raisonnement dans la vue Agents.
llm = weave.start_llm(
    model="gpt-4o",             # L'ID du modèle.
    provider_name="openai",     # Facultatif : nom du fournisseur, par exemple "openai", "anthropic". Voir la note ci-dessous.
    system_instructions=["Be concise."],  # Facultatif : chaînes de caractères du prompt système.
)
Une fois l’appel LLM terminé, attribuez les données de réponse à l’objet llm avant qu’il ne se ferme :
with weave.start_llm(model="gpt-4o", provider_name="openai") as llm:
    response = openai_client.chat.completions.create(...)
    llm.input_messages = [Message(role="user", content="...")]
    llm.output_messages = [Message(role="assistant", content=response.choices[0].message.content)]
    llm.usage = Usage(
        input_tokens=response.usage.prompt_tokens,
        output_tokens=response.usage.completion_tokens,
    )
Passez provider_name / providerName explicitement. Weave ne le déduit pas de la chaîne du modèle.

Démarrer un appel d’outil

start_tool() / startTool() crée un span execute_tool. Le span devient l’enfant du span OTel actif dans le contexte (généralement le span chat de l’appel LLM qui a généré l’appel d’outil).
tool = weave.start_tool(
    name="get_weather",                  # Nom de l’outil tel que déclaré au LLM.
    arguments='{"city": "Tokyo"}',       # Chaîne JSON des arguments de l’outil.
    tool_call_id="call_abc123",          # Facultatif : identifiant de l’appel d’outil provenant de la réponse du LLM.
)
Attribuez le résultat de l’outil avant de le fermer :
with weave.start_tool(name="get_weather", arguments='{"city": "Tokyo"}') as tool:
    result = get_weather_api("Tokyo")
    tool.result = result  # Accepte un dictionnaire, une liste ou une chaîne. Encodé automatiquement en JSON.

Schémas d’utilisation pour le traçage des agents

Les sections suivantes décrivent comment combiner ces fonctions en fonction de la structure du code de votre agent. Les exemples suivants utilisent deux types du SDK Weave :
  • Message (Python · TypeScript) représente une seule entrée dans une conversation : une entrée de l’utilisateur, une réponse de l’assistant, un prompt système ou le résultat d’un outil. Affectez une liste de messages à llm.input_messages / llm.inputMessages pour enregistrer ce que le modèle a reçu, et à llm.output_messages / llm.outputMessages pour enregistrer ce qu’il a produit.
  • Usage (Python · TypeScript) capture le nombre de jetons dans la réponse du LLM et doit être affecté à llm.usage.
Weave utilise les deux pour alimenter la vue Agents avec les entrées, les sorties et l’utilisation des jetons de chaque appel LLM.

Gestionnaire de contexte ou schéma try-finally

Pour la plupart des agents, utilisez un gestionnaire de contexte en Python ou un schéma try-finally en TypeScript. Le span se ferme et est envoyé à la fin du bloc, même si une exception se produit. Weave stocke la conversation active, le tour de conversation et l’appel LLM dans le contexte. Ainsi, toute fonction appelée dans un bloc peut appeler start_llm() / startLLM() ou start_tool() / startTool() sans avoir à conserver de référence explicite au parent. Cela fonctionne d’un module à l’autre tant que le code s’exécute dans le même contexte asynchrone. Pour récupérer les objets actifs depuis n’importe quel point de la pile d’appels, utilisez weave.get_current_conversation() / weave.getCurrentConversation(), weave.get_current_turn() / weave.getCurrentTurn(), et weave.get_current_llm() / weave.getCurrentLLM().
import weave
from weave.conversation import Message, Usage

# Fonctions fictives : remplacez-les par vos propres implémentations.
def call_openai(*args, **kwargs):
    pass  # Remplacez par votre appel au client LLM.

def get_weather_api(city: str) -> str:
    return "24°C, sunny"  # Remplacez par votre appel à l’API météo.

weave.init("[YOUR-TEAM]/[YOUR-PROJECT]")

with weave.start_conversation(agent_name="weather-bot") as conversation:
    with conversation.start_turn(user_message="What is the weather in Tokyo?") as turn:

        # Premier appel LLM : renvoie un appel d’outil.
        with weave.start_llm(model="gpt-4o", provider_name="openai") as llm:
            response = call_openai(...)
            llm.input_messages = [Message(role="user", content="What is the weather?")]
            llm.think("User wants weather data, I should call get_weather.")
            llm.output("Let me check the weather for you.")
            llm.usage = Usage(input_tokens=100, output_tokens=20)

            # Appel d’outil : enfant de l’appel LLM qui l’a demandé.
            with weave.start_tool(name="get_weather", arguments='{"city":"Tokyo"}') as tool:
                tool.result = get_weather_api("Tokyo")  # Renvoie "24°C, sunny".

        # Deuxième appel LLM : synthétise la réponse finale.
        with weave.start_llm(model="gpt-4o", provider_name="openai") as llm:
            llm.input_messages = [Message(role="user", content="What is the weather?")]
            llm.output("It is 24°C and sunny in Tokyo today.")
            llm.usage = Usage(input_tokens=150, output_tokens=30)

Démarrage et arrêt manuels

Utilisez .end() explicitement lorsque vous ne pouvez pas recourir à des blocs with ou à try/finally. Par exemple, lorsque des spans sont ouverts et fermés dans des appels de fonction distincts, ou lorsque vous gérez le cycle de vie asynchrone en dehors d’une coroutine. Il vous incombe d’appeler .end() sur chaque objet que vous créez, afin que les spans se ferment et soient envoyés au collecteur.
conversation = weave.start_conversation(agent_name="weather-bot")
turn = conversation.start_turn(user_message="What is the weather?")

llm = weave.start_llm(model="gpt-4o", provider_name="openai")
llm.input_messages = [Message(role="user", content="What is the weather?")]
llm.output("Let me check.")
llm.usage = Usage(input_tokens=100, output_tokens=20)

tool = weave.start_tool(name="get_weather", arguments='{"city": "Tokyo"}')
tool.result = "24°C, sunny"
tool.end()   # end() est idempotent — vous pouvez l'appeler plusieurs fois sans risque.

llm.end()

llm2 = weave.start_llm(model="gpt-4o", provider_name="openai")
llm2.output("It is 24°C and sunny in Tokyo.")
llm2.usage = Usage(input_tokens=150, output_tokens=30)
llm2.end()

turn.end()
conversation.end()

Conventions sémantiques

Le SDK Weave émet des spans OTel conformes aux conventions sémantiques GenAI et aux conventions de span d’agent GenAI. Weave accepte tout span OTel, stocke tous les attributs et permet de les interroger. Vous pouvez ajouter des attributs arbitraires aux spans à l’aide de l’API standard des spans OTel, en plus des objets de traçage de Weave.

Comment les données apparaissent dans l’interface Weave

Après avoir instrumenté votre agent selon les approches précédentes et l’avoir exécuté, vos traces apparaissent dans l’onglet Agents de votre projet Weave à l’adresse https://wandb.ai/[YOUR-TEAM]/[YOUR-PROJECT]/weave/agents.
  • L’onglet Conversations affiche toutes les conversations avec une mini-carte de l’activité des tours de conversation.
  • La vue détaillée de la conversation s’ouvre lorsque vous cliquez sur une conversation et affiche tous les tours de conversation, les appels LLM, les exécutions d’outils, le nombre de jetons et tout feedback joint.
Pour en savoir plus sur l’affichage des données Agents dans Weave, voir Voir l’activité des agents.