> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Démarrage rapide : configurer l’observabilité d’un agent personnalisé

> Tracez un agent sur plusieurs tours de conversation avec le SDK Weave. Les conversations, les tours de conversation, les appels LLM et les appels d’outils s’affichent dans la vue Agents de votre projet.

export const AgentLensBanner = ({href}) => <Tip>
    <strong>This workflow is also available in CoreWeave Agent Lens.</strong> Agent Lens is the Forge experience built for tracing, monitoring, and analyzing AI agents, with automated insights into agent failures and user intents. It uses the same trace data as Weights & Biases Weave, so the traces you already send appear there with nothing to migrate.{' '}
    <a href={href || '/products/agent-lens'}>{href ? 'See how to do this in Agent Lens' : 'Learn about Agent Lens'}</a>.
  </Tip>;

<AgentLensBanner href="/fr/products/agent-lens/get-started/custom-agents" />

[Essayer dans Colab](https://colab.research.google.com/github/wandb/docs/blob/main/weave/cookbooks/source/custom-agents-quickstart.ipynb) · [Source sur GitHub](https://github.com/wandb/docs/blob/main/weave/cookbooks/source/custom-agents-quickstart.ipynb)

Le SDK Weave vous permet de tracer des agents conçus avec des SDK populaires ou des harness personnalisés. Ce guide de démarrage rapide vous montre comment intégrer manuellement Weave à un agent personnalisé fonctionnant sur plusieurs tours de conversation, afin d’émettre et de capturer des spans OpenTelemetry. Pour découvrir les concepts de Weave appliqués aux agents, consultez [Tracer vos agents](/fr/products/wandb/weave/guides/tracking/trace-agents).

Si vous souhaitez intégrer Weave à des SDK ou à des harness tels que le Claude Agent SDK ou Codex, consultez [Choisir une intégration d’agent](/fr/products/wandb/weave/agent-integration-quickstart). Weave patche automatiquement plusieurs SDK de création d’agents et harness d’agents, ce qui permet une intégration rapide.

<h2 id="what-youll-learn">
  Ce que vous allez apprendre
</h2>

À la fin de ce démarrage rapide, vous disposerez d’un agent fonctionnel sur plusieurs tours de conversation qui émet des spans OTel compatibles avec Weave. Vous comprendrez également comment Weave fait correspondre les conversations, les tours de conversation, les appels LLM et les appels d’outil au code de votre agent, afin d’appliquer le même modèle à vos propres agents personnalisés.

Le code de ce guide met en place un petit agent de recherche capable de consulter Wikipédia. Il pose trois questions (trois tours de conversation) et s’appuie sur le LLM pour choisir à quel moment lancer une recherche sur Wikipédia afin de trouver une réponse. Weave enregistre chaque étape (la conversation, chaque question, chaque réponse de l’IA et chaque consultation de Wikipédia) pour que vous puissiez retracer le déroulement dans la vue Weave Agents.

Ce guide vous montre comment :

* Initialiser Weave pour le traçage d’agents avec `weave.init()`.
* Ouvrir une conversation et un tour de conversation avec `start_conversation` / `startConversation` et `start_turn` / `startTurn`.
* Encapsuler les appels LLM avec `start_llm` / `startLLM` et enregistrer l’utilisation.
* Encapsuler les exécutions d’outils avec `start_tool` / `startTool` et enregistrer les résultats.
* Enregistrer l’utilisation complète des jetons et un modèle tarifable afin d’afficher le nombre de jetons et le coût.
* Afficher la conversation, les tours de conversation et les appels d’outil obtenus dans la vue Agents.

<h2 id="how-the-weave-sdk-works-with-agents">
  Fonctionnement du SDK Weave avec les agents
</h2>

Le SDK Weave comprend un système générique d’ingestion OTel pour les agents : Weave peut ainsi capturer des informations à partir de n’importe quel span OTel du code de votre agent. Toutefois, pour effectuer le rendu des traces de votre agent dans la vue Agents de l’interface utilisateur de Weights & Biases, Weave nécessite une gestion particulière des spans suivants.

| Concept | Python | TypeScript | Span OTel |
| - | - | - | - |
| Une conversation | `weave.start_conversation(...)` | `weave.startConversation(...)` | (aucun span, regroupe les tours de conversation) |
| Un échange de l’utilisateur ou de l’agent | `weave.start_turn(...)` | `weave.startTurn(...)` | `invoke_agent` |
| Un appel d’API au LLM | `weave.start_llm(...)` | `weave.startLLM(...)` | `chat` |
| Une exécution d’outil | `weave.start_tool(...)` | `weave.startTool(...)` | `execute_tool` |

En Python, les quatre fonctions s’utilisent comme gestionnaires de contexte (`with weave.start_*(...) as obj:`). À la sortie, elles terminent le span et effectuent le vidage des attributs, y compris en cas d’exception. En TypeScript, appelez `.end()` sur chaque objet renvoyé. Utilisez `try { ... } finally { obj.end(); }` pour garantir le nettoyage en cas d’exception.

D’autres [attributs des conventions sémantiques GenAI](https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-agent-spans/), tels que `gen_ai.usage.*` et `gen_ai.agent.name`, permettent un rendu plus complet, mais ils sont facultatifs.

<h2 id="prerequisites">
  Prérequis
</h2>

* Un compte CoreWeave Forge et une [clé API](https://forge.coreweave.com/settings#apikeys).
* Une clé API OpenAI.
* Python 3.10 ou version ultérieure (pour les exemples Python).
* Node.js 18 ou version ultérieure (les exemples TypeScript nécessitent la fonction native `fetch`).

<h2 id="install-packages">
  Installer les packages
</h2>

Installez les packages suivants dans votre environnement de développement :

<CodeGroup>
  ```bash Python theme={"system"}
  pip install weave openai requests
  ```

  ```bash TypeScript theme={"system"}
  npm install weave openai
  ```
</CodeGroup>

<h2 id="initialize-weave">
  Initialiser Weave
</h2>

`weave.init()` s’authentifie auprès de W\&B et configure l’exportateur OTel qui envoie les spans d’agent vers la vue **Agents**. Si le projet n’existe pas encore dans votre équipe, Weave le crée lors de la première écriture.

<CodeGroup>
  ```python lines Python theme={"system"}
  import getpass
  import os

  os.environ["WANDB_API_KEY"] = getpass.getpass("Enter your CoreWeave Forge API key: ")
  os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")

  TEAM = input("Enter your CoreWeave Forge team name: ")
  PROJECT = input("Enter your Weights & Biases project name: ")

  import weave
  weave.init(f"{TEAM}/{PROJECT}")
  ```

  ```typescript lines highlight="4" TypeScript twoslash theme={"system"}
  // @noErrors
  // Définissez WANDB_API_KEY et OPENAI_API_KEY dans votre environnement avant d’exécuter ce projet
  import * as weave from 'weave';

  await weave.init(`[YOUR-TEAM]/[YOUR-PROJECT]`);
  ```
</CodeGroup>

<h2 id="define-a-tool">
  Définir un outil
</h2>

Le code suivant définit l’outil de recherche Wikipédia de l’agent, ainsi qu’un schéma d’outil OpenAI qui indique quand et comment utiliser cet outil.

<CodeGroup>
  ```python lines Python theme={"system"}
  import json
  import requests

  def wikipedia_search(query: str) -> str:
      r = requests.get(
          "https://en.wikipedia.org/w/api.php",
          params={
              "action": "query", "generator": "search", "gsrsearch": query, "gsrlimit": 1,
              "prop": "extracts", "exintro": True, "explaintext": True, "format": "json",
          },
          headers={"User-Agent": "weave-demo"},
      ).json()
      return next(iter(r["query"]["pages"].values()))["extract"]

  wikipedia_tool_schema = {
      "type": "function",
      "function": {
          "name": "wikipedia_search",
          "description": "Search Wikipedia for a topic and return its intro paragraph.",
          "parameters": {
              "type": "object",
              "properties": {"query": {"type": "string"}},
              "required": ["query"],
          },
      },
  }
  ```

  ```typescript lines TypeScript twoslash theme={"system"}
  // @noErrors
  async function wikipediaSearch(query: string): Promise<string> {
    const url = new URL('https://en.wikipedia.org/w/api.php');
    url.search = new URLSearchParams({
      action: 'query',
      generator: 'search',
      gsrsearch: query,
      gsrlimit: '1',
      prop: 'extracts',
      exintro: 'true',
      explaintext: 'true',
      format: 'json',
    }).toString();
    const res = await fetch(url, { headers: { 'User-Agent': 'weave-demo' } });
    const data = (await res.json()) as {
      query: { pages: Record<string, { extract: string }> };
    };
    return Object.values(data.query.pages)[0].extract;
  }

  const wikipediaToolSchema = {
    type: 'function' as const,
    function: {
      name: 'wikipedia_search',
      description: 'Search Wikipedia for a topic and return its intro paragraph.',
      parameters: {
        type: 'object',
        properties: { query: { type: 'string' } },
        required: ['query'],
      },
    },
  };
  ```
</CodeGroup>

<h2 id="run-a-traced-multi-turn-agent">
  Exécuter un agent tracé sur plusieurs tours de conversation
</h2>

Une fois l’outil et l’initialisation de Weave en place, l’étape suivante consiste à les réunir dans une boucle d’agent complète. Cette boucle montre comment les conversations, les tours de conversation, les appels LLM et les appels d’outil s’imbriquent les uns dans les autres.

L’exemple suivant exécute trois tours de conversation au sein d’une même conversation. À chaque tour :

1. Un span `chat` est ouvert, et le LLM choisit s’il doit appeler l’outil.
2. Si le LLM demande un outil, un span `execute_tool` est ouvert autour de l’appel, et le résultat est renvoyé au LLM.
3. Un second span `chat` est ouvert pour produire la réponse finale.

<CodeGroup>
  ```python lines highlight="10,12,19,38,51,55,69" Python theme={"system"}
  import weave
  from openai import OpenAI

  openai_client = OpenAI()
  MODEL = "gpt-4o-mini"

  def run_turn(history, user_message):
      history.append({"role": "user", "content": user_message})

      with weave.start_turn(user_message=user_message, model=MODEL):
          # Appel LLM 1 : le modèle peut décider d’utiliser un outil.
          with weave.start_llm(model=MODEL, provider_name="openai") as llm:
              resp = openai_client.chat.completions.create(
                  model=MODEL, messages=history, tools=[wikipedia_tool_schema],
              )
              msg = resp.choices[0].message
              llm.output(msg.content or "")
              # record() définit en un seul appel l’utilisation, le modèle facturé et l’ID de la réponse.
              llm.record(
                  usage=weave.Usage(
                      input_tokens=resp.usage.prompt_tokens,
                      output_tokens=resp.usage.completion_tokens,
                      cache_read_input_tokens=getattr(
                          resp.usage.prompt_tokens_details, "cached_tokens", 0
                      ),
                  ),
                  response_id=resp.id,
                  response_model=resp.model,
              )
              history.append(msg.model_dump(exclude_none=True))

          # Si aucun outil n’est demandé, la première réponse du LLM constitue la réponse finale.
          if not msg.tool_calls:
              return msg.content

          # Exécuter chaque appel d’outil demandé.
          for tc in msg.tool_calls:
              with weave.start_tool(
                  name=tc.function.name,
                  arguments=tc.function.arguments,
                  tool_call_id=tc.id,
              ) as tool:
                  tool.result = wikipedia_search(**json.loads(tc.function.arguments))
                  history.append({
                      "role": "tool",
                      "tool_call_id": tc.id,
                      "content": tool.result,
                  })

          # Appel LLM 2 : synthétiser la réponse finale.
          with weave.start_llm(model=MODEL, provider_name="openai") as llm:
              resp = openai_client.chat.completions.create(model=MODEL, messages=history)
              msg = resp.choices[0].message
              llm.output(msg.content)
              llm.record(
                  usage=weave.Usage(
                      input_tokens=resp.usage.prompt_tokens,
                      output_tokens=resp.usage.completion_tokens,
                      cache_read_input_tokens=getattr(
                          resp.usage.prompt_tokens_details, "cached_tokens", 0
                      ),
                  ),
                  response_id=resp.id,
                  response_model=resp.model,
              )
              history.append({"role": "assistant", "content": msg.content})
              return msg.content

  with weave.start_conversation(agent_name="research-bot") as conversation:
      history = []
      for question in [
          "Who founded Anthropic?",
          "What is Claude (the AI assistant)?",
          "Summarize what we discussed in one sentence.",
      ]:
          print(f"USER: {question}")
          print(f"AGENT: {run_turn(history, question)}\n")
  ```

  ```typescript lines highlight="11,14,25,47,62,70,89" theme={"system"}
  // @noErrors
  import * as weave from 'weave';
  import OpenAI from 'openai';

  const openaiClient = new OpenAI();
  const MODEL = 'gpt-4o-mini';

  // history est une liste de messages de chat OpenAI, typée de façon souple par souci de concision.
  async function runTurn(history: any[], userMessage: string): Promise<string | null> {
    history.push({ role: 'user', content: userMessage });

    const turn = weave.startTurn({ model: MODEL });
    try {
      // Appel LLM 1 : le modèle peut décider d’utiliser un outil.
      const llm1 = weave.startLLM({ model: MODEL, providerName: 'openai' });
      let msg;
      try {
        const resp = await openaiClient.chat.completions.create({
          model: MODEL,
          messages: history,
          tools: [wikipediaToolSchema],
        });
        msg = resp.choices[0].message;
        llm1.output(msg.content ?? '');
        // record() définit l’utilisation, le modèle facturé et l’ID de réponse en un seul appel.
        llm1.record({
          usage: {
            inputTokens: resp.usage?.prompt_tokens,
            outputTokens: resp.usage?.completion_tokens,
            cacheReadInputTokens: resp.usage?.prompt_tokens_details?.cached_tokens,
          },
          responseId: resp.id,
          responseModel: resp.model,
        });
        history.push(msg);
      } finally {
        llm1.end();
      }

      // Si aucun outil n’a été demandé, la première réponse du LLM est la réponse finale.
      if (!msg.tool_calls?.length) {
        return msg.content ?? null;
      }

      // Exécuter chaque appel d’outil demandé.
      for (const tc of msg.tool_calls) {
        if (tc.type !== 'function') continue;
        const tool = weave.startTool({
          name: tc.function.name,
          args: tc.function.arguments,
          toolCallId: tc.id,
        });
        try {
          const { query } = JSON.parse(tc.function.arguments);
          tool.result = await wikipediaSearch(query);
          history.push({ role: 'tool', tool_call_id: tc.id, content: tool.result });
        } finally {
          tool.end();
        }
      }

      // Appel LLM 2 : synthétiser la réponse finale.
      const llm2 = weave.startLLM({ model: MODEL, providerName: 'openai' });
      try {
        const resp = await openaiClient.chat.completions.create({
          model: MODEL,
          messages: history,
        });
        const msg2 = resp.choices[0].message;
        llm2.output(msg2.content ?? '');
        llm2.record({
          usage: {
            inputTokens: resp.usage?.prompt_tokens,
            outputTokens: resp.usage?.completion_tokens,
            cacheReadInputTokens: resp.usage?.prompt_tokens_details?.cached_tokens,
          },
          responseId: resp.id,
          responseModel: resp.model,
        });
        history.push({ role: 'assistant', content: msg2.content });
        return msg2.content ?? null;
      } finally {
        llm2.end();
      }
    } finally {
      turn.end();
    }
  }

  const conversation = weave.startConversation({ agentName: 'research-bot' });
  try {
    const history: any[] = [];
    for (const question of [
      'Who founded Anthropic?',
      'What is Claude (the AI assistant)?',
      'Summarize what we discussed in one sentence.',
    ]) {
      console.log(`USER: ${question}`);
      console.log(`AGENT: ${await runTurn(history, question)}\n`);
    }
  } finally {
    conversation.end();
  }
  ```
</CodeGroup>

<h2 id="record-token-usage-and-cost">
  Enregistrer l’utilisation des jetons et le coût
</h2>

Chaque span `chat` contient l’utilisation des jetons et un ID de modèle. Weave affiche le nombre de jetons à partir de l’utilisation et calcule le coût à partir de l’utilisation et de l’ID du modèle. Une valeur incomplète ou impossible à tarifer affiche donc `0 in / 0 out` jetons ou `Cost -`, même lorsque le reste de la trace semble correct. `record(...)` définit ces champs (ainsi que `output_messages`, `response_id`, `reasoning`, etc.) en un seul appel. Seuls les champs que vous transmettez sont appliqués.

Deux conditions doivent être remplies pour que le coût s’affiche :

* **Une utilisation complète.** `input_tokens` correspond au nombre *total* de jetons d’entrée, y compris les jetons mis en cache. Weave facture les lectures et les écritures en cache à leurs propres tarifs et les soustrait du total d’entrée. `cache_read_input_tokens` et `cache_creation_input_tokens` doivent donc être indiqués *en plus* d’un total `input_tokens` qui les inclut. Chez les fournisseurs proposant la mise en cache des prompts (par exemple, Anthropic), les jetons mis en cache représentent souvent l’essentiel de l’entrée : si vous les omettez, l’utilisation et le coût affichés seront quasi nuls.
* **Un ID de modèle tarifable.** Le coût est déterminé à partir du modèle. Weave privilégie `response_model` (le modèle exact servi par le fournisseur) et, à défaut, utilise le `model` transmis à `start_llm`. Un alias tel que `opus` ou `sonnet` n’est pas tarifable et affiche `Cost -` : transmettez donc comme `response_model` l’ID concret renvoyé par la réponse (`resp.model`).

OpenAI comptabilise les jetons mis en cache dans `prompt_tokens`, si bien que l’exemple ci-dessus s’applique tel quel. Anthropic indique les jetons mis en cache *séparément* de `input_tokens` : réintégrez-les donc dans le total sur lequel Weave calcule le coût :

<CodeGroup>
  ```python lines Python theme={"system"}
  with weave.start_llm(model=MODEL, provider_name="anthropic") as llm:
      resp = anthropic_client.messages.create(
          model=MODEL, max_tokens=1024, messages=history,
      )
      u = resp.usage
      llm.output(resp.content[0].text)
      llm.record(
          usage=weave.Usage(
              input_tokens=u.input_tokens
              + u.cache_read_input_tokens
              + u.cache_creation_input_tokens,
              output_tokens=u.output_tokens,
              cache_read_input_tokens=u.cache_read_input_tokens,
              cache_creation_input_tokens=u.cache_creation_input_tokens,
          ),
          response_id=resp.id,
          response_model=resp.model,
      )
  ```

  ```typescript lines TypeScript twoslash theme={"system"}
  // @noErrors
  const u = resp.usage;
  llm.record({
    usage: {
      inputTokens:
        u.input_tokens + u.cache_read_input_tokens + u.cache_creation_input_tokens,
      outputTokens: u.output_tokens,
      cacheReadInputTokens: u.cache_read_input_tokens,
      cacheCreationInputTokens: u.cache_creation_input_tokens,
    },
    responseId: resp.id,
    responseModel: resp.model,
  });
  ```
</CodeGroup>

<h2 id="see-your-agent-traces-in-the-agents-view">
  Voir vos traces d’agent dans la vue Agents
</h2>

Lorsque `weave.init()` s’exécute, il affiche un lien vers votre projet, où vous pouvez voir :

* Une ligne pour `research-bot` dans l’onglet **Agents**.
* Une conversation contenant trois tours de conversation.
* Chaque tour de conversation (`invoke_agent`), dans lequel sont imbriqués deux spans `chat` et un span `execute_tool`.
* Le nombre de jetons, la latence, le modèle et l’échange complet de messages pour chaque `chat`.

Cliquez sur un tour de conversation pour examiner les entrées, les sorties, les arguments des outils et les résultats des outils.

<h2 id="link-to-a-conversation-from-your-app">
  Créer un lien vers une conversation depuis votre application
</h2>

Pour créer un lien profond depuis votre propre interface vers une conversation dans la vue Weave Agents, construisez l’URL à partir de votre entity, de votre projet et de l’identifiant de la conversation. `weave.init()` renvoie un client qui contient `entity` et `project`, et `start_conversation` expose `conversation_id`.

<CodeGroup>
  ```python lines Python theme={"system"}
  from weave.trace.urls import agent_conversation_path

  client = weave.init(f"{TEAM}/{PROJECT}")

  with weave.start_conversation(agent_name="research-bot") as conversation:
      # ... exécuter les tours de conversation ...
      url = agent_conversation_path(
          client.entity, client.project, conversation.conversation_id
      )
      print(f"View this conversation at {url}")
  ```

  ```plaintext TypeScript lines theme={"system"}
  Cette fonctionnalité n’est pas disponible en TypeScript.
  ```
</CodeGroup>

<h2 id="next-steps">
  Étapes suivantes
</h2>

* Découvrez comment [tracer des agents avec Weave](/fr/products/wandb/weave/guides/tracking/trace-agents), ainsi que les fonctionnalités et options disponibles dans le SDK Weave.
* Consultez [Choisir une intégration d’agent](/fr/products/wandb/weave/agent-integration-quickstart) pour découvrir d’autres façons d’intégrer Weave à vos agents.
