> ## 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.

# Feedback en production

> Collectez et analysez le feedback des utilisateurs sur les sorties des LLM en production grâce aux fonctionnalités de suivi du feedback de W&B Weave.

<Note>
  Ceci est un notebook interactif. Vous pouvez l’exécuter localement ou utiliser les liens ci-dessous :

  * [Ouvrir dans Google Colab](https://colab.research.google.com/github/wandb/docs/blob/main/weave/cookbooks/source/feedback_prod.ipynb)
  * [Voir la source sur GitHub](https://github.com/wandb/docs/blob/main/weave/cookbooks/source/feedback_prod.ipynb)
</Note>

Il peut être difficile d’évaluer automatiquement une réponse générée par un LLM. Pour mieux évaluer et améliorer les réponses, vous pouvez en complément recueillir directement le feedback des utilisateurs afin d’identifier les points problématiques.

Ce notebook montre comment collecter le feedback des utilisateurs sur les réponses d’un chatbot personnalisé. Il utilise Streamlit pour créer l’interface, et capture les interactions avec le LLM ainsi que le feedback dans W\&B Weave. Vous obtiendrez ainsi un chatbot fonctionnel qui journalise chaque réponse dans Weave, avec les réactions pouce levé ou pouce baissé et le feedback en texte libre de vos utilisateurs. Vous pourrez alors examiner les interactions en production et identifier les axes d’amélioration.

<h2 id="setup">
  Configuration
</h2>

Commencez par installer les paquets requis et définir vos clés API OpenAI et W\&B pour que le chatbot puisse appeler l’API OpenAI et journaliser les appels dans Weave.

```python lines theme={"system"}
!pip install weave openai streamlit wandb
!pip install set-env-colab-kaggle-dotenv -q # pour les variables d’environnement
python
# Ajoutez un fichier .env contenant vos clés API OpenAI et WandB
from set_env import set_env

_ = set_env("OPENAI_API_KEY")
_ = set_env("WANDB_API_KEY")
```

Ensuite, créez un fichier nommé `chatbot.py` avec le contenu suivant. Ce fichier définit l’interface de chat Streamlit, encapsule l’appel OpenAI dans un op Weave afin que chaque réponse soit suivie, et affiche les contrôles de feedback qui joignent les réactions et les notes à l’appel Weave correspondant.

```python lines {13,15,27} theme={"system"}
# chatbot.py

import openai
import streamlit as st
import wandb
from set_env import set_env

import weave

_ = set_env("OPENAI_API_KEY")
_ = set_env("WANDB_API_KEY")

wandb.login()

weave_client = weave.init("feedback-example")
oai_client = openai.OpenAI()

def init_states():
    """Set up session_state keys if they don't exist yet."""
    if "messages" not in st.session_state:
        st.session_state["messages"] = []
    if "calls" not in st.session_state:
        st.session_state["calls"] = []
    if "session_id" not in st.session_state:
        st.session_state["session_id"] = "123abc"

@weave.op
def chat_response(full_history):
    """
    Calls the OpenAI API in streaming mode given the entire conversation history so far.
    full_history is a list of dicts: [{"role":"user"|"assistant","content":...}, ...]
    """
    stream = oai_client.chat.completions.create(
        model="gpt-4", messages=full_history, stream=True
    )
    response_text = st.write_stream(stream)
    return {"response": response_text}

def render_feedback_buttons(call_idx):
    """Renders thumbs up/down and text feedback for the call."""
    col1, col2, col3 = st.columns([1, 1, 4])

    # Bouton pouce levé
    with col1:
        if st.button("👍", key=f"thumbs_up_{call_idx}"):
            st.session_state.calls[call_idx].feedback.add_reaction("👍")
            st.success("Thanks for the feedback!")

    # Bouton pouce baissé
    with col2:
        if st.button("👎", key=f"thumbs_down_{call_idx}"):
            st.session_state.calls[call_idx].feedback.add_reaction("👎")
            st.success("Thanks for the feedback!")

    # Feedback textuel
    with col3:
        feedback_text = st.text_input("Feedback", key=f"feedback_input_{call_idx}")
        if (
            st.button("Submit Feedback", key=f"submit_feedback_{call_idx}")
            and feedback_text
        ):
            st.session_state.calls[call_idx].feedback.add_note(feedback_text)
            st.success("Feedback submitted!")

def display_old_messages():
    """Displays the conversation stored in st.session_state.messages with feedback buttons"""
    for idx, message in enumerate(st.session_state.messages):
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

            # S'il s'agit d'un message de l'assistant, afficher le formulaire de feedback
            if message["role"] == "assistant":
                # Déterminer l'index de ce message de l'assistant dans st.session_state.calls
                assistant_idx = (
                    len(
                        [
                            m
                            for m in st.session_state.messages[: idx + 1]
                            if m["role"] == "assistant"
                        ]
                    )
                    - 1
                )
                # Afficher les boutons pouce levé/baissé et le feedback textuel
                if assistant_idx < len(st.session_state.calls):
                    render_feedback_buttons(assistant_idx)

def display_chat_prompt():
    """Displays the chat prompt input box."""
    if prompt := st.chat_input("Ask me anything!"):
        # Afficher immédiatement le nouveau message de l'utilisateur
        with st.chat_message("user"):
            st.markdown(prompt)

        # Enregistrer le message de l'utilisateur dans la session
        st.session_state.messages.append({"role": "user", "content": prompt})

        # Préparer l'historique de conversation pour l'API
        full_history = [
            {"role": msg["role"], "content": msg["content"]}
            for msg in st.session_state.messages
        ]

        with st.chat_message("assistant"):
            # Joindre des attributs Weave pour assurer le suivi des instances de conversation
            with weave.attributes(
                {"session": st.session_state["session_id"], "env": "prod"}
            ):
                # Appeler l'API OpenAI (en streaming)
                result, call = chat_response.call(full_history)

                # Stocker le message de l'assistant
                st.session_state.messages.append(
                    {"role": "assistant", "content": result["response"]}
                )

                # Stocker l'objet d'appel Weave pour associer le feedback à la réponse correspondante
                st.session_state.calls.append(call)

                # Afficher les boutons de feedback pour le nouveau message
                new_assistant_idx = (
                    len(
                        [
                            m
                            for m in st.session_state.messages
                            if m["role"] == "assistant"
                        ]
                    )
                    - 1
                )

                # Afficher les boutons de feedback
                if new_assistant_idx < len(st.session_state.calls):
                    render_feedback_buttons(new_assistant_idx)

def main():
    st.title("Chatbot with immediate feedback forms")
    init_states()
    display_old_messages()
    display_chat_prompt()

if __name__ == "__main__":
    main()
```

Vous pouvez l’exécuter avec `streamlit run chatbot.py`.

Vous pouvez maintenant interagir avec cette application et cliquer sur les boutons de feedback après chaque réponse. Rendez-vous dans l’interface de Weights & Biases pour consulter le feedback joint. Chaque échange du chat est enregistré en tant qu’appel Weave, et les réactions ou notes que vous soumettez sont liées à l’appel qui a généré la réponse.

<h2 id="explanation">
  Explication
</h2>

La section suivante passe en revue les principales API Weave utilisées dans le chatbot, afin que vous puissiez appliquer la même approche à votre propre application.

Prenons la fonction de prédiction décorée suivante :

```python lines {5} theme={"system"}
import weave

weave.init("feedback-example")

@weave.op
def predict(input_data):
    # Placez ici votre logique de prédiction
    some_result = "hello world"
    return some_result
```

Vous pouvez l’utiliser comme d’habitude pour renvoyer la réponse du modèle à l’utilisateur :

```python lines theme={"system"}
with weave.attributes(
    {"session": "123abc", "env": "prod"}
):  # joindre des attributs arbitraires à l’appel, en plus des entrées et des sorties
    result = predict(input_data="your data here")  # question posée par l’utilisateur via l’interface de l’application
```

Pour joindre un feedback, vous avez besoin de l’objet `call`, que vous obtenez en appelant la méthode `.call()` au lieu d’appeler la fonction de manière habituelle :

```python lines theme={"system"}
result, call = predict.call(input_data="your data here")
```

Cet objet `call` vous permet de joindre un feedback à la réponse concernée. Une fois l’appel effectué, la sortie de l’opération est disponible dans `result`.

Une fois l’objet `call` obtenu, vous pouvez enregistrer le feedback de l’utilisateur pour cette réponse précise :

```python lines theme={"system"}
call.feedback.add_reaction("👍")  # réaction de l’utilisateur dans l’interface de l’application
```

<h2 id="conclusion">
  Conclusion
</h2>

Dans ce tutoriel, vous avez créé avec Streamlit une interface de chat qui capture les entrées et les sorties dans Weave, ainsi que des boutons pouce levé et pouce baissé permettant de capturer le feedback des utilisateurs.
