Passer au contenu principal
Il s’agit d’un notebook interactif. Vous pouvez l’exécuter en local ou utiliser les liens ci-dessous :

Utiliser l’API de service pour enregistrer et interroger des traces

Dans le guide suivant, vous apprendrez comment utiliser l’API de service de Weave pour enregistrer des traces. Plus précisément, vous utiliserez l’API de service pour :
  1. Créer une simulation d’un appel et d’une réponse LLM simples, et l’enregistrer dans Weave.
  2. Créer une simulation d’un appel et d’une réponse LLM plus complexes, et l’enregistrer dans Weave.
  3. Exécuter un exemple de requête de recherche sur les traces enregistrées.
Consulter les traces enregistrées Vous pouvez consulter toutes les traces Weave créées lorsque vous exécutez le code de ce guide en accédant à l’onglet Traces de votre projet Weave (spécifié par team_id\project_id), puis en sélectionnant le nom de la trace.
Avant de commencer, consultez les prérequis

Prérequis : définir les variables et les endpoints

Le code suivant définit les URL des endpoints qui seront utilisées pour accéder à l’API de service : De plus, vous devez définir les variables suivantes :
  • project_id: Le nom du projet W&B dans lequel vous souhaitez consigner vos traces.
  • team_id: Le nom de votre équipe W&B.
  • wandb_token: Votre clé API W&B.
import datetime
import json

import requests

# En-têtes et URLs
headers = {"Content-Type": "application/json"}
url_start = "https://trace.wandb.ai/call/start"
url_end = "https://trace.wandb.ai/call/end"
url_stream_query = "https://trace.wandb.ai/calls/stream_query"

# Variables W&B
team_id = ""
project_id = ""
wandb_token = ""

Trace simple

Les sections suivantes expliquent comment créer une trace simple.
  1. Démarrer une trace simple
  2. Terminer une trace simple

Démarrer une trace simple

Le code suivant crée un exemple d’appel LLM payload_start et le journalise dans Weave via l’endpoint url_start. L’objet payload_start simule un appel à gpt-4o d’OpenAI avec la requête Why is the sky blue?. En cas de succès, ce code affichera un message indiquant que la trace a été démarrée :
Appel démarré. ID : 01939cdc-38d2-7d61-940d-dcca0a56c575, Trace ID : 01939cdc-38d2-7d61-940d-dcd0e76c5f34
python
## ------------
## Démarrer la trace
## ------------
payload_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "simple_trace",
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            # Utilisez ce style "messages" pour générer l'interface de chat dans la trace développée.
            "messages": [{"role": "user", "content": "Why is the sky blue?"}],
            "model": "gpt-4o",
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    call_id = data.get("id")
    trace_id = data.get("trace_id")
    print(f"Appel démarré. ID : {call_id}, Trace ID : {trace_id}")
else:
    print("La requête de démarrage a échoué avec le statut :", response.status_code)
    print(response.text)
    exit()

Terminer une trace simple

Pour terminer la trace simple, le code suivant crée un exemple de charge utile d’appel LLM, payload_end, et l’enregistre dans Weave à l’aide de l’endpoint url_end. L’objet payload_end imite la réponse de gpt-4o d’OpenAI à la requête Why is the sky blue?. L’objet est formaté de sorte que les informations récapitulatives de tarification et la chat complétion soient générées dans la vue de trace du tableau de bord Weave. En cas de réussite, ce code affichera un message indiquant que la trace est terminée :
Call ended.
python
## ------------
## End trace
## ------------
payload_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            # Utilisez ce style "choices" pour ajouter la complétion à l'interface de chat dans la trace développée.
            "choices": [
                {
                    "message": {
                        "content": "It’s due to Rayleigh scattering, where shorter blue wavelengths of sunlight scatter in all directions."
                    }
                },
            ]
        },
        # Formatez le résumé de cette façon pour générer les informations de résumé de tarification dans le tableau des traces.
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Call ended.")
else:
    print("End request failed with status:", response.status_code)
    print(response.text)

Trace complexe

Les sections suivantes vous guident dans la création d’une trace plus complexe avec des spans enfants, semblable à une recherche RAG en plusieurs opérations.
  1. Démarrer une trace complexe
  2. Ajouter un span enfant pour une recherche de document RAG
  3. Ajouter un span enfant pour un appel de complétion LLM
  4. Terminer une trace complexe

Démarrer une trace complexe

Le code suivant montre comment créer une trace plus complexe avec plusieurs spans. Un exemple serait une recherche de type Retrieval-Augmented Generation (RAG), suivie d’un Appel à un LLM. La première partie initialise une trace parente (payload_parent_start) qui représente l’opération globale. Dans ce cas, l’opération consiste à traiter la requête utilisateur Can you summarize the key points of this document?. L’objet payload_parent_start reproduit l’étape initiale d’un flux de travail à plusieurs étapes, en enregistrant l’opération dans Weave à l’aide de l’endpoint url_start. En cas de réussite, ce code affichera un message indiquant que l’Appel parent a été enregistré :
Appel parent démarré. ID : 01939d26-0844-7c43-94bb-cdc471b6d65f, Trace ID : 01939d26-0844-7c43-94bb-cdd97dc296c8
python
## ------------
## Démarrer la trace (parent)
## ------------

# Appel parent : Démarrage
payload_parent_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "complex_trace",
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {"question": "Can you summarize the key points of this document?"},
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_parent_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    parent_call_id = data.get("id")
    trace_id = data.get("trace_id")
    print(f"Appel parent démarré. ID : {parent_call_id}, Trace ID : {trace_id}")
else:
    print("La requête de démarrage parent a échoué avec le statut :", response.status_code)
    print(response.text)
    exit()

Ajouter un span enfant pour une recherche de documents RAG

Le code suivant montre comment ajouter un span enfant à la trace parente complexe démarrée à l’étape précédente. Cette étape modélise la sous-opération de recherche de documents RAG dans le flux de travail global. La trace enfant est initiée avec l’objet payload_child_start, qui inclut :
  • trace_id : relie ce span enfant à la trace parente.
  • parent_id : associe le span enfant à l’opération parente.
  • inputs : consigne la requête de recherche, par ex. : "Ceci est une requête de recherche pour les documents que je cherche."
Si l’appel à l’endpoint url_start réussit, le code affiche un message indiquant que l’appel enfant a démarré et s’est terminé :
Appel enfant démarré. ID : 01939d32-23d6-75f2-9128-36a4a806f179
Appel enfant terminé.
python
## ------------
## Span enfant :
## Ex. Recherche de documents RAG
## ------------

# Appel enfant : Début
payload_child_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "rag_document_lookup",
        "trace_id": trace_id,
        "parent_id": parent_call_id,
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            "document_search": "Voici une requête de recherche des documents que je cherche."
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_child_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    child_call_id = data.get("id")
    print(f"Appel enfant démarré. ID : {child_call_id}")
else:
    print("Échec de la requête de démarrage enfant avec le statut :", response.status_code)
    print(response.text)
    exit()

# Appel enfant : Fin
payload_child_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": child_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "document_results": "Voici le texte du document RAG qui sera renvoyé par la requête de recherche."
        },
        "summary": {},
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_child_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Appel enfant terminé.")
else:
    print("Échec de la requête de fin enfant avec le statut :", response.status_code)
    print(response.text)

Ajouter un span enfant pour un appel de complétion LLM

Le code suivant montre comment ajouter un autre span enfant à la trace parente complexe pour représenter un appel de complétion LLM. Cette étape modélise la génération de la réponse de l’IA à partir du contexte documentaire récupéré lors de l’opération RAG précédente. La trace de complétion LLM est lancée avec l’objet payload_child_start, qui comprend :
  • trace_id : relie ce span enfant à la trace parente.
  • parent_id : associe le span enfant au flux de travail global.
  • inputs : enregistre les messages d’entrée pour le LLM, y compris la requête de l’utilisateur et le contexte documentaire ajouté.
  • model : spécifie le modèle utilisé pour l’opération (gpt-4o).
En cas de réussite, le code affiche un message indiquant que la trace du span enfant LLM a démarré et s’est terminée :
Appel enfant démarré. ID : 0245acdf-83a9-4c90-90df-dcb2b89f234a
Une fois l’opération terminée, l’objet payload_child_end met fin à la trace en enregistrant la réponse générée par le LLM dans le champ output. Les informations récapitulatives d’utilisation sont également enregistrées. En cas de réussite, le code affiche un message indiquant que la trace du span enfant du LLM a démarré puis s’est terminée :
Appel enfant démarré. ID: 0245acdf-83a9-4c90-90df-dcb2b89f234a
Appel enfant terminé.
python
## ------------
## Span enfant :
## Créer un appel de complétion LLM
## ------------

# Appel enfant : Début
payload_child_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "llm_completion",
        "trace_id": trace_id,
        "parent_id": parent_call_id,
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            "messages": [
                {
                    "role": "user",
                    "content": "Avec le contexte de document suivant, pourriez-vous m'aider à répondre :\n Pouvez-vous résumer les points clés de ce document ?\n [+ contexte de document ajouté]",
                }
            ],
            "model": "gpt-4o",
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_child_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    child_call_id = data.get("id")
    print(f"Appel enfant démarré. ID : {child_call_id}")
else:
    print("La requête de démarrage de l'appel enfant a échoué avec le statut :", response.status_code)
    print(response.text)
    exit()

# Appel enfant : Fin
payload_child_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": child_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "choices": [
                {"message": {"content": "Voici la réponse générée par le LLM."}},
            ]
        },
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_child_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Appel enfant terminé.")
else:
    print("La requête de fin de l'appel enfant a échoué avec le statut :", response.status_code)
    print(response.text)

Terminer une trace complexe

Le code suivant montre comment finaliser la trace parente afin de marquer l’achèvement de l’ensemble du flux de travail. Cette étape agrège les résultats de toutes les spans enfants (par exemple, la recherche RAG et la complétion LLM) et consigne la sortie finale ainsi que les métadonnées. La trace est finalisée à l’aide de l’objet payload_parent_end, qui comprend :
  • id : le parent_call_id du démarrage initial de la trace parente.
  • output : représente la sortie finale de l’ensemble du flux de travail.
  • summary : consolide les données d’utilisation pour l’ensemble du flux de travail.
  • prompt_tokens : nombre total de tokens utilisés pour tous les prompts.
  • completion_tokens : nombre total de tokens générés dans toutes les réponses.
  • total_tokens : nombre total combiné de tokens pour le flux de travail.
  • requests : nombre total de requêtes effectuées (dans ce cas, 1).
En cas de réussite, le code affiche :
Parent call ended.
python
## ------------
## Fin de la trace
## ------------

# Appel parent : Fin
payload_parent_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": parent_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "choices": [
                {"message": {"content": "Voici la réponse générée par le LLM."}},
            ]
        },
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_parent_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Appel parent terminé.")
else:
    print("La requête de fin de l'appel parent a échoué avec le statut :", response.status_code)
    print(response.text)

Exécuter une requête de recherche

Le code suivant montre comment interroger les traces créées dans les exemples précédents, en filtrant uniquement celles pour lesquelles le champ inputs.model est égal à gpt-4o. L’objet query_payload comprend :
  • project_id : identifie l’équipe et le projet à interroger.
  • filter : garantit que la requête ne renvoie que les racines de trace (traces de niveau supérieur).
  • query : définit la logique de filtrage à l’aide de l’opérateur $expr :
    • $getField : récupère le champ inputs.model.
    • $literal : sélectionne les traces pour lesquelles inputs.model est égal à "gpt-4o".
  • limit : limite la requête à 10 000 résultats.
  • offset : commence la requête au premier résultat.
  • sort_by : trie les résultats selon l’horodatage started_at, par ordre décroissant.
  • include_feedback : exclut les données de feedback des résultats.
Si la requête aboutit, la réponse inclura les données de trace correspondant aux paramètres de la requête :
{'id': '01939cf3-541f-76d3-ade3-50cfae068b39', 'project_id': 'cool-new-team/uncategorized', 'op_name': 'simple_trace', 'display_name': None, 'trace_id': '01939cf3-541f-76d3-ade3-50d5cfabe2db', 'parent_id': None, 'started_at': '2024-12-06T17:10:12.590000Z', 'attributes': {}, 'inputs': {'messages': [{'role': 'user', 'content': 'Why is the sky blue?'}], 'model': 'gpt-4o'}, 'ended_at': '2024-12-06T17:47:08.553000Z', 'exception': None, 'output': {'choices': [{'message': {'content': 'It’s due to Rayleigh scattering, where shorter blue wavelengths of sunlight scatter in all directions.'}}]}, 'summary': {'usage': {'gpt-4o': {'prompt_tokens': 10, 'completion_tokens': 20, 'requests': 1, 'total_tokens': 30}}, 'weave': {'status': 'success', 'trace_name': 'simple_trace', 'latency_ms': 2215963}}, 'wb_user_id': 'VXNlcjoyMDk5Njc0', 'wb_run_id': None, 'deleted_at': None}
python
query_payload = {
    "project_id": f"{team_id}/{project_id}",
    "filter": {"trace_roots_only": True},
    "query": {
        "$expr": {"$eq": [{"$getField": "inputs.model"}, {"$literal": "gpt-4o"}]}
    },
    "limit": 10000,
    "offset": 0,
    "sort_by": [{"field": "started_at", "direction": "desc"}],
    "include_feedback": False,
}
response = requests.post(
    url_stream_query, headers=headers, json=query_payload, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Query successful!")
    try:
        data = response.json()
        print(data)
    except json.JSONDecodeError as e:
        # Décodage alternatif
        json_objects = response.text.strip().split("\n")
        parsed_data = [json.loads(obj) for obj in json_objects]
        print(parsed_data)
else:
    print(f"Query failed with status code: {response.status_code}")
    print(response.text)