Passer au contenu principal

Aperçu

Weave prend en charge l’ingestion de données de trace compatibles OpenTelemetry via un point de terminaison dédié. Ce point de terminaison vous permet d’envoyer des données de trace au format OTLP (OpenTelemetry Protocol) directement à votre projet Weave.

Détails du point de terminaison

Chemin : /otel/v1/traces Méthode : POST Content-Type : application/x-protobuf URL de base : l’URL de base du point de terminaison de trace OTel dépend de votre type de déploiement W&B :
  • Cloud mutualisé : https://trace.wandb.ai/otel/v1/traces
  • Instances Cloud dédié et Autogéré : https://<your-subdomain>.wandb.io/traces/otel/v1/traces
Remplacez <your-subdomain> par le domaine W&B unique de votre organisation, par exemple acme.wandb.io.

Authentification et routage

Incluez votre clé API W&B dans l’en-tête wandb-api-key, puis spécifiez les clés suivantes comme attributs de ressource OpenTelemetry dans votre classe TracerProvider :
  • wandb.entity : Le nom de votre équipe W&B ou de votre utilisateur.
  • wandb.project : Le nom du projet vers lequel envoyer les traces.
L’exemple suivant montre comment configurer l’authentification et le routage du projet :
import os
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk import trace as trace_sdk
from opentelemetry.sdk.resources import Resource

WANDB_BASE_URL = "https://trace.wandb.ai"
ENTITY = "<your-team-name>"
PROJECT = "<your-project-name>"

OTEL_EXPORTER_OTLP_ENDPOINT = f"{WANDB_BASE_URL}/otel/v1/traces"

# Créez une clé API sur https://wandb.ai/settings
WANDB_API_KEY = os.environ["WANDB_API_KEY"]

exporter = OTLPSpanExporter(
    endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,
    headers={"wandb-api-key": WANDB_API_KEY},
)

tracer_provider = trace_sdk.TracerProvider(resource=Resource({
    "wandb.entity": ENTITY,
    "wandb.project": PROJECT,
}))

Exemples

Les exemples suivants montrent comment envoyer des traces OpenTelemetry vers Weave avec Python et TypeScript. Avant d’exécuter les exemples de code ci-dessous, renseignez les champs suivants :
  1. WANDB_API_KEY : vous pouvez l’obtenir dans les Paramètres utilisateur.
  2. Entité : vous ne pouvez consigner des traces que dans le projet d’une entité à laquelle vous avez accès. Vous pouvez trouver le nom de votre entité en consultant votre tableau de bord W&B à l’adresse [https://wandb.ai/home], puis en vérifiant le champ Teams dans la barre latérale gauche.
  3. Nom du projet : choisissez un nom sympa !
  4. OPENAI_API_KEY : vous pouvez l’obtenir depuis le tableau de bord OpenAI.

Instrumentation OpenInference

Cet exemple montre comment utiliser l’instrumentation OpenAI. Il en existe bien d’autres, que vous pouvez trouver dans le dépôt officiel. Installez d’abord les dépendances requises :
pip install openai openinference-instrumentation-openai opentelemetry-exporter-otlp-proto-http
Recommandation relative aux performances : utilisez toujours BatchSpanProcessor plutôt que SimpleSpanProcessor lors de l’envoi de traces vers Weave. SimpleSpanProcessor exporte les spans de manière synchrone, ce qui peut affecter les performances des autres charges de travail. Ces exemples illustrent BatchSpanProcessor, recommandé en production, car il regroupe les spans de façon asynchrone et efficace.
Collez le code suivant dans un fichier Python, par exemple openinference_example.py :
import os
import openai
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk import trace as trace_sdk
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor
from openinference.instrumentation.openai import OpenAIInstrumentor

OPENAI_API_KEY = "YOUR_OPENAI_API_KEY"
WANDB_BASE_URL = "https://trace.wandb.ai"
ENTITY = "<your-team-name>"
PROJECT = "<your-project-name>"

OTEL_EXPORTER_OTLP_ENDPOINT = f"{WANDB_BASE_URL}/otel/v1/traces"

# Créez une clé API sur https://wandb.ai/settings
WANDB_API_KEY = os.environ["WANDB_API_KEY"]

exporter = OTLPSpanExporter(
    endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,
    headers={"wandb-api-key": WANDB_API_KEY},
)

tracer_provider = trace_sdk.TracerProvider(resource=Resource({
    "wandb.entity": ENTITY,
    "wandb.project": PROJECT,
}))
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))

# Facultatif : afficher les spans dans la console.
tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)

def main():
    client = openai.OpenAI(api_key=OPENAI_API_KEY)
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": "Describe OTel in a single sentence."}],
        max_tokens=20,
        stream=True,
        stream_options={"include_usage": True},
    )
    for chunk in response:
        if chunk.choices and (content := chunk.choices[0].delta.content):
            print(content, end="")

if __name__ == "__main__":
    main()
Exécutez le code :
python openinference_example.py

Instrumentation OpenLLMetry

L’exemple suivant montre comment utiliser l’instrumentation OpenAI. D’autres exemples sont disponibles dans le dépôt OpenLLMetry. Installez d’abord les dépendances requises :
pip install openai opentelemetry-instrumentation-openai opentelemetry-exporter-otlp-proto-http
Collez le code suivant dans un fichier Python, par exemple openllmetry_example.py. Notez qu’il s’agit du même code que ci-dessus, sauf que OpenAIInstrumentor est importé depuis opentelemetry.instrumentation.openai plutôt que depuis openinference.instrumentation.openai :
import os
import openai
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk import trace as trace_sdk
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor
from opentelemetry.instrumentation.openai import OpenAIInstrumentor

OPENAI_API_KEY = "YOUR_OPENAI_API_KEY"
WANDB_BASE_URL = "https://trace.wandb.ai"
ENTITY = "<your-team-name>"
PROJECT = "<your-project-name>"

OTEL_EXPORTER_OTLP_ENDPOINT = f"{WANDB_BASE_URL}/otel/v1/traces"

# Créez une clé API sur https://wandb.ai/settings
WANDB_API_KEY = os.environ["WANDB_API_KEY"]

exporter = OTLPSpanExporter(
    endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,
    headers={"wandb-api-key": WANDB_API_KEY},
)

tracer_provider = trace_sdk.TracerProvider(resource=Resource({
    "wandb.entity": ENTITY,
    "wandb.project": PROJECT,
}))
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))

# Facultatif : affiche les spans dans la console.
tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)

def main():
    client = openai.OpenAI(api_key=OPENAI_API_KEY)
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": "Describe OTel in a single sentence."}],
        max_tokens=20,
        stream=True,
        stream_options={"include_usage": True},
    )
    for chunk in response:
        if chunk.choices and (content := chunk.choices[0].delta.content):
            print(content, end="")

if __name__ == "__main__":
    main()
Exécutez le code :
python openllmetry_example.py

Sans instrumentation

Si vous préférez utiliser OTel directement plutôt qu’un package d’instrumentation, c’est possible. Les attributs de span seront analysés conformément aux conventions sémantiques d’OpenTelemetry décrites à l’adresse https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/. Installez d’abord les dépendances requises :
pip install openai opentelemetry-sdk opentelemetry-api opentelemetry-exporter-otlp-proto-http
Collez le code suivant dans un fichier Python, par exemple opentelemetry_example.py :
import json
import os
import openai
from opentelemetry import trace
from opentelemetry.sdk import trace as trace_sdk
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor

OPENAI_API_KEY = "YOUR_OPENAI_API_KEY"
WANDB_BASE_URL = "https://trace.wandb.ai"
ENTITY = "<your-team-name>"
PROJECT = "<your-project-name>"

OTEL_EXPORTER_OTLP_ENDPOINT = f"{WANDB_BASE_URL}/otel/v1/traces"

# Créez une clé API sur https://wandb.ai/settings
WANDB_API_KEY = os.environ["WANDB_API_KEY"]

# Configurer l'exportateur OTLP
exporter = OTLPSpanExporter(
    endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,
    headers={"wandb-api-key": WANDB_API_KEY},
)

tracer_provider = trace_sdk.TracerProvider(resource=Resource({
    "wandb.entity": ENTITY,
    "wandb.project": PROJECT,
}))
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))

# Facultatif : afficher les spans dans la console.
tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

# Définir le fournisseur de traceur
trace.set_tracer_provider(tracer_provider)

# Créer un traceur à partir du fournisseur de traceur global
tracer = trace.get_tracer(__name__)

def my_function():
    with tracer.start_as_current_span("outer_span") as outer_span:
        client = openai.OpenAI()
        input_messages = [{"role": "user", "content": "Describe OTel in a single sentence."}]
        outer_span.set_attribute("input.value", json.dumps(input_messages))
        outer_span.set_attribute("gen_ai.system", "openai")
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=input_messages,
            max_tokens=20,
            stream=True,
            stream_options={"include_usage": True},
        )
        out = ""
        for chunk in response:
            if chunk.choices and (content := chunk.choices[0].delta.content):
                out += content
        outer_span.set_attribute("output.value", json.dumps({"content": out}))

if __name__ == "__main__":
    my_function()
Exécutez le code :
python opentelemetry_example.py
Les préfixes des attributs de span gen_ai et openinference sont utilisés pour déterminer, le cas échéant, quelle convention appliquer lors de l’interprétation de la trace. Si aucune de ces deux clés n’est détectée, tous les attributs de span sont visibles dans la vue de trace. Le span complet est disponible dans le panneau latéral lorsque vous sélectionnez une trace.

Utiliser un collecteur OpenTelemetry

Les exemples ci-dessus exportent les traces directement depuis votre application vers Weave. En production, vous pouvez utiliser un OpenTelemetry Collector comme intermédiaire entre votre application et Weave. Le collecteur reçoit les traces de votre application, puis les transmet à un ou plusieurs backends.

Configurer un collecteur

L’exemple suivant montre comment :
  • Configurer un fichier de configuration pour Docker qui déploie un serveur local (collecteur) à l’écoute des traces OTLP, les regroupe par lots et les achemine vers Weave.
  • Exécuter localement le collecteur avec Docker.
  • Envoyer une requête simple à OpenAI qui transfère les traces au collecteur exécuté dans le conteneur Docker.
Pour utiliser un collecteur, créez d’abord un fichier collector-config.yaml qui configure le collecteur pour recevoir des traces OTLP et les exporter vers Weave :
collector-config.yaml
receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318

exporters:
  otlphttp/weave:
    endpoint: ${env:WANDB_OTLP_ENDPOINT}
    headers:
      wandb-api-key: ${env:WANDB_API_KEY}
    sending_queue:
      batch:

processors:
  resource:
    attributes:
      - key: wandb.entity # Champ des attributs de la ressource
        value: ${env:DEFAULT_WANDB_ENTITY}  # Valeur à injecter
        action: insert # N’injecter que si l’attribut n’est pas déjà présent
      - key: wandb.project
        value: ${env:DEFAULT_WANDB_PROJECT}
        action: insert 

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [resource]
      exporters: [otlphttp/weave]
Ce fichier de configuration :
  • Écoute les traces OTLP sur le port 4318 (HTTP).
  • Exporte les traces vers le point de terminaison OTLP de Weave à l’aide de l’en-tête wandb-api-key, en lisant l’URL du point de terminaison depuis WANDB_OTLP_ENDPOINT et la clé API depuis WANDB_API_KEY.
  • Définit wandb.entity et wandb.project comme attributs de ressource à l’aide du processeur resource, en lisant les valeurs depuis DEFAULT_WANDB_ENTITY et DEFAULT_WANDB_PROJECT. L’action insert injecte ces attributs uniquement si le code de votre application ne les définit pas déjà.
  • Active la sending_queue intégrée de l’exportateur avec le traitement par lots afin de réduire la surcharge réseau.
Après avoir configuré les paramètres du collecteur, mettez à jour les valeurs de l’API et de l’entité dans la commande Docker suivante, puis exécutez-la :
docker run \
  -v ./config.yaml:/etc/otelcol-contrib/config.yaml \
  -e WANDB_API_KEY="<your-wandb-api-key>" \
  -e WANDB_OTLP_ENDPOINT="https://trace.wandb.ai/otel" \
  -e DEFAULT_WANDB_ENTITY="<your-team-name>" \
  -e DEFAULT_WANDB_PROJECT="YOUR_PROJECT" \
  -p 4318:4318 \
  otel/opentelemetry-collector-contrib:latest
Une fois le collecteur démarré, configurez votre application pour y exporter les traces en définissant la variable d’environnement OTEL_EXPORTER_OTLP_ENDPOINT. Le SDK OTel lit automatiquement cette variable, vous n’avez donc pas besoin de fournir le point de terminaison à l’exportateur. Si vous définissez wandb.entity ou wandb.project comme attributs de ressource dans le TracerProvider de votre application, ils priment sur les valeurs par défaut définies dans la configuration du collecteur.
import os
import openai
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk import trace as trace_sdk
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from openinference.instrumentation.openai import OpenAIInstrumentor

os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "http://localhost:4318"

OPENAI_API_KEY = "YOUR_OPENAI_API_KEY"

tracer_provider = trace_sdk.TracerProvider()
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))

OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)

def main():
    client = openai.OpenAI(api_key=OPENAI_API_KEY)
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": "Describe OTel in a single sentence."}],
        max_tokens=20,
    )
    print(response.choices[0].message.content)

if __name__ == "__main__":
    main()
OpenAIInstrumentor intercepte automatiquement les appels OpenAI, crée des traces et les exporte vers le collecteur. Le collecteur gère l’authentification et l’acheminement vers Weave. Après avoir exécuté le script, vous pouvez consulter les traces dans Weave UI. Pour envoyer des traces vers des backends supplémentaires, ajoutez d’autres exportateurs et incluez-les dans la liste service.pipelines.traces.exporters. Par exemple, vous pouvez exporter vers Weave et Jaeger depuis la même instance du Collector.

Organiser les traces OTel en threads

Ajoutez des attributs de span spécifiques pour organiser vos traces OpenTelemetry en threads Weave, puis utilisez l’interface Thread de Weave pour analyser les opérations associées, comme les conversations à plusieurs tours ou les sessions utilisateur. Ajoutez les attributs suivants à vos spans OTel pour activer le regroupement en threads :
  • wandb.thread_id : regroupe les spans dans un thread donné
  • wandb.is_turn : marque un span comme un tour de conversation (il apparaît comme une ligne dans la vue thread)
Les exemples suivants montrent comment organiser des traces OTel en threads Weave. Ils utilisent wandb.thread_id pour regrouper les opérations associées et wandb.is_turn pour marquer les opérations de haut niveau qui apparaissent comme des lignes dans la vue thread.
Utilisez cette configuration pour exécuter ces exemples :
import json
import os
from opentelemetry import trace
from opentelemetry.sdk import trace as trace_sdk
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor

# Configuration
ENTITY = "<your-team-name>"
PROJECT = "<your-project-name>"
WANDB_API_KEY = os.environ["WANDB_API_KEY"]

OTEL_EXPORTER_OTLP_ENDPOINT = "https://trace.wandb.ai/otel/v1/traces"

exporter = OTLPSpanExporter(
    endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,
    headers={"wandb-api-key": WANDB_API_KEY},
)

tracer_provider = trace_sdk.TracerProvider(resource=Resource({
    "wandb.entity": ENTITY,
    "wandb.project": PROJECT,
}))
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))

# Facultatif : afficher les spans dans la console
tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

trace.set_tracer_provider(tracer_provider)

# Crée un tracer à partir du fournisseur de tracer global
tracer = trace.get_tracer(__name__)
def example_1_basic_thread_and_turn():
    """Example 1: Basic thread with a single turn"""
    print("\n=== Example 1: Basic Thread and Turn ===")

    # Créer un contexte de thread
    thread_id = "thread_example_1"

    # Ce span représente un tour (enfant direct du thread)
    with tracer.start_as_current_span("process_user_message") as turn_span:
        # Définir les attributs du thread
        turn_span.set_attribute("wandb.thread_id", thread_id)
        turn_span.set_attribute("wandb.is_turn", True)

        # Ajouter quelques attributs d'exemple
        turn_span.set_attribute("input.value", "Hello, help me with setup")

        # Simuler du travail avec des spans imbriqués
        with tracer.start_as_current_span("generate_response") as nested_span:
            # Il s'agit d'un appel imbriqué dans le tour ; is_turn doit donc être False ou non défini
            nested_span.set_attribute("wandb.thread_id", thread_id)
            # wandb.is_turn n'est pas défini ou est défini sur False pour les appels imbriqués

            response = "I'll help you get started with the setup process."
            nested_span.set_attribute("output.value", response)

        turn_span.set_attribute("output.value", response)
        print(f"Turn completed in thread: {thread_id}")

def main():
    example_1_basic_thread_and_turn()

if __name__ == "__main__":
    main()
def example_2_multiple_turns():
    """Exemple 2 : plusieurs tours dans un même thread"""
    print("\n=== Exemple 2 : plusieurs tours dans le thread ===")

    thread_id = "thread_conversation_123"

    # Tour 1
    with tracer.start_as_current_span("process_message_turn1") as turn1_span:
        turn1_span.set_attribute("wandb.thread_id", thread_id)
        turn1_span.set_attribute("wandb.is_turn", True)
        turn1_span.set_attribute("input.value", "Quels langages de programmation recommandez-vous ?")

        # Opérations imbriquées
        with tracer.start_as_current_span("analyze_query") as analyze_span:
            analyze_span.set_attribute("wandb.thread_id", thread_id)
            # Pas d'attribut is_turn, ou défini sur False pour les spans imbriqués

        response1 = "Je recommande Python pour les débutants et JavaScript pour le développement web."
        turn1_span.set_attribute("output.value", response1)
        print(f"Tour 1 terminé dans le thread : {thread_id}")

    # Tour 2
    with tracer.start_as_current_span("process_message_turn2") as turn2_span:
        turn2_span.set_attribute("wandb.thread_id", thread_id)
        turn2_span.set_attribute("wandb.is_turn", True)
        turn2_span.set_attribute("input.value", "Pouvez-vous expliquer Python vs JavaScript ?")

        # Opérations imbriquées
        with tracer.start_as_current_span("comparison_analysis") as compare_span:
            compare_span.set_attribute("wandb.thread_id", thread_id)
            compare_span.set_attribute("wandb.is_turn", False)  # Explicitement défini sur False pour les spans imbriqués

        response2 = "Python excelle en science des données, tandis que JavaScript domine le développement web."
        turn2_span.set_attribute("output.value", response2)
        print(f"Tour 2 terminé dans le thread : {thread_id}")

def main():
    example_2_multiple_turns()

if __name__ == "__main__":
    main()
def example_3_complex_nested_structure():
    """Example 3: Complex nested structure with multiple levels"""
    print("\n=== Example 3: Complex Nested Structure ===")

    thread_id = "thread_complex_456"

    # Turn avec plusieurs niveaux d'imbrication
    with tracer.start_as_current_span("handle_complex_request") as turn_span:
        turn_span.set_attribute("wandb.thread_id", thread_id)
        turn_span.set_attribute("wandb.is_turn", True)
        turn_span.set_attribute("input.value", "Analyze this code and suggest improvements")

        # Opération imbriquée de niveau 1
        with tracer.start_as_current_span("code_analysis") as analysis_span:
            analysis_span.set_attribute("wandb.thread_id", thread_id)
            # Pas de is_turn pour les opérations imbriquées

            # Opération imbriquée de niveau 2
            with tracer.start_as_current_span("syntax_check") as syntax_span:
                syntax_span.set_attribute("wandb.thread_id", thread_id)
                syntax_span.set_attribute("result", "No syntax errors found")

            # Autre opération imbriquée de niveau 2
            with tracer.start_as_current_span("performance_check") as perf_span:
                perf_span.set_attribute("wandb.thread_id", thread_id)
                perf_span.set_attribute("result", "Found 2 optimization opportunities")

        # Autre opération imbriquée de niveau 1
        with tracer.start_as_current_span("generate_suggestions") as suggest_span:
            suggest_span.set_attribute("wandb.thread_id", thread_id)
            suggestions = ["Use list comprehension", "Consider caching results"]
            suggest_span.set_attribute("suggestions", json.dumps(suggestions))

        turn_span.set_attribute("output.value", "Analysis complete with 2 improvement suggestions")
        print(f"Complex turn completed in thread: {thread_id}")

def main():
    example_3_complex_nested_structure()

if __name__ == "__main__":
    main()
def example_4_non_turn_operations():
    """Exemple 4 : opérations faisant partie d'un thread, mais pas des tours"""
    print("\n=== Exemple 4 : opérations de thread hors tour ===")

    thread_id = "thread_background_789"

    # Opération en arrière-plan faisant partie du thread, mais pas d'un tour
    with tracer.start_as_current_span("background_indexing") as bg_span:
        bg_span.set_attribute("wandb.thread_id", thread_id)
        # wandb.is_turn n'est pas défini ou vaut false : ce n'est pas un tour
        bg_span.set_attribute("wandb.is_turn", False)
        bg_span.set_attribute("operation", "Indexation de l'historique des conversations")
        print(f"Opération en arrière-plan dans le thread : {thread_id}")

    # Tour réel dans le même thread
    with tracer.start_as_current_span("user_query") as turn_span:
        turn_span.set_attribute("wandb.thread_id", thread_id)
        turn_span.set_attribute("wandb.is_turn", True)
        turn_span.set_attribute("input.value", "Rechercher mes conversations précédentes")
        turn_span.set_attribute("output.value", "5 conversations pertinentes trouvées")
        print(f"Tour terminé dans le thread : {thread_id}")

def main():
    example_4_non_turn_operations()

if __name__ == "__main__":
    main()
Une fois ces traces envoyées, vous pouvez les consulter dans la Weave UI, sous l’onglet Threads. Elles y seront regroupées par thread_id, et chaque tour apparaîtra sur une ligne distincte.

Correspondance des attributs

Weave associe automatiquement les attributs de span OpenTelemetry issus de divers frameworks d’instrumentation à son modèle de données interne. Lorsque plusieurs noms d’attributs sont associés au même champ, Weave les traite par ordre de priorité, ce qui permet à plusieurs frameworks de coexister dans les mêmes traces.

Frameworks pris en charge

Weave prend en charge les conventions d’attributs des frameworks d’observabilité et SDK suivants :
  • OpenTelemetry GenAI: conventions sémantiques standard pour l’IA générative (gen_ai.*)
  • OpenInference: bibliothèque d’instrumentation d’Arize AI (input.value, output.value, llm.*, openinference.*)
  • Vercel AI SDK: attributs du SDK d’IA de Vercel (ai.prompt, ai.response, ai.model.*, ai.usage.*)
  • MLflow: attributs de tracking de MLflow (mlflow.spanInputs, mlflow.spanOutputs)
  • Traceloop: instrumentation OpenLLMetry (traceloop.entity.*, traceloop.span.kind)
  • Google Vertex AI: attributs d’agent de Vertex AI (gcp.vertex.agent.*)
  • OpenLit: attributs d’observabilité d’OpenLit (gen_ai.content.completion)
  • Langfuse: attributs de tracing de Langfuse (langfuse.startTime, langfuse.endTime)

Référence des attributs

Nom du champ d’attributCorrespondance W&BDescriptionTypeExemple
ai.promptinputsTexte ou messages de la requête utilisateur.Chaîne, liste, dict"Écris un court haïku sur l’été."
gen_ai.promptinputsPrompt du modèle d’IA ou liste de messages.Liste, dict, chaîne[{"role":"user","content":"abc"}]
input.valueinputsValeur d’entrée pour l’appel du modèle.Chaîne, liste, dict{"text":"Raconte une blague"}
mlflow.spanInputsinputsDonnées d’entrée du span.Chaîne, liste, dict["texte d’invite"]
traceloop.entity.inputinputsDonnées d’entrée de l’entité.Chaîne, liste, dict"Traduisez ceci en français"
gcp.vertex.agent.tool_call_argsinputsArguments de l’appel à l’outil.Dict{"args":{"query":"météo à SF"}}
gcp.vertex.agent.llm_requestinputsCorps de la requête LLM.Dict{"contents":[{"role":"user","parts":[...]}]}
inputinputsValeur d’entrée générique.Chaîne, liste, dict"Résume ce texte"
inputsinputsListe d’entrée générique.Liste, dict, chaîne["Résume ce texte"]
ai.responseoutputsTexte ou données de réponse du modèle.Chaîne, liste, dict"Voici un haïku..."
gen_ai.completionoutputsRésultat de génération de l’IA.Chaîne, liste, dict"Texte de complétion"
output.valueoutputsValeur de sortie du modèle.Chaîne, liste, dict{"text":"Texte de réponse"}
mlflow.spanOutputsoutputsDonnées de sortie du span.String, liste, dict["answer"]
gen_ai.content.completionoutputsRésultat de complétion de contenu.String"Texte de réponse"
traceloop.entity.outputoutputsDonnées de sortie de l’entité.String, liste, dict"Texte de réponse"
gcp.vertex.agent.tool_responseoutputsRéponse d’exécution de l’outil.dict, chaîne{"toolResponse":"ok"}
gcp.vertex.agent.llm_responseoutputsCharge utile de la réponse du LLM.dict, chaîne{"candidates":[...]}
outputoutputsValeur de sortie générique.Chaîne, liste, dict"Texte de réponse"
outputsoutputsTableau de sortie générique.liste, dict, chaîne de caractères["Texte de réponse"]
gen_ai.usage.input_tokensusage.input_tokensNombre de tokens d’entrée consommés.Int42
gen_ai.usage.prompt_tokensusage.prompt_tokensNombre de tokens de prompt consommés.Int30
llm.token_count.promptusage.prompt_tokensNombre de tokens de prompt.Int30
ai.usage.promptTokensusage.prompt_tokensTokens de prompt consommés.Int30
gen_ai.usage.completion_tokensusage.completion_tokensNombre de tokens de complétion générés.Int40
llm.token_count.completionusage.completion_tokensNombre de tokens de complétion.Int40
ai.usage.completionTokensusage.completion_tokensTokens de complétion générés.Int40
llm.usage.total_tokensusage.total_tokensNombre total de tokens utilisés dans la requête.Int70
llm.token_count.totalusage.total_tokensNombre total de tokens.Entier70
gen_ai.systemattributes.systemPrompt système ou consignes.Chaîne de caractères"Vous êtes un assistant utile."
llm.systemattributes.systemPrompt système ou consignes.Chaîne de caractères"Vous êtes un assistant serviable."
weave.span.kindattributes.kindType ou catégorie du span.Chaîne de caractères"llm"
traceloop.span.kindattributes.kindType ou catégorie du span.String"llm"
openinference.span.kindattributes.kindType ou catégorie du span.String"llm"
gen_ai.response.modelattributes.modelIdentifiant du modèle.String"gpt-4o"
llm.model_nameattributes.modelIdentifiant du modèle.Chaîne"gpt-4o-mini"
ai.model.idattributes.modelIdentifiant du modèle.Chaîne"gpt-4o"
llm.providerattributes.providerNom du fournisseur du modèle.Chaîne"openai"
ai.model.providerattributes.providerNom du fournisseur du modèle.String"openai"
gen_ai.requestattributes.model_parametersParamètres de génération du modèle.Dict{"temperature":0.7,"max_tokens":256}
llm.invocation_parametersattributes.model_parametersParamètres d’appel du modèle.Dict{"temperature":0.2}
wandb.display_namedisplay_nameNom d’affichage personnalisé pour l’UI.Chaîne de caractères"Message utilisateur"
gcp.vertex.agent.session_idthread_idIdentifiant de session ou de fil.Chaîne de caractères"thread_123"
wandb.thread_idthread_idIdentifiant de fil pour les conversations.Chaîne de caractères"thread_123"
wb_run_idwb_run_idIdentifiant du run W&B associé.Chaîne"abc123"
wandb.wb_run_idwb_run_idIdentifiant du run W&B associé.Chaîne"abc123"
gcp.vertex.agent.session_idis_turnIndique que le span correspond à un tour de conversation.Booléentrue
wandb.is_turnis_turnIndique que le span correspond à un tour de conversation.Booléentrue
langfuse.startTimestart_time (remplace)Remplacer l’horodatage de début du span.Horodatage (ISO8601/unix ns)"2024-01-01T12:00:00Z"
langfuse.endTimeend_time (override)Remplacer l’horodatage de fin du span.Horodatage (ISO8601/unix ns)"2024-01-01T12:00:01Z"

Limites

  • Weave UI ne prend pas en charge le rendu des appels d’outil de trace OTel dans la vue Chat. Ils s’affichent à la place sous forme de JSON brut.