Valutare gli agenti con ADK

1. Il divario di fiducia

Il momento dell'ispirazione

Hai creato un agente dell'assistenza clienti. Funziona sul tuo computer. Ma ieri ha detto a un cliente che uno smartwatch non disponibile era disponibile o, peggio ancora, ha inventato una norma sui rimborsi. Come dormi la notte sapendo che il tuo agente è attivo?

Per colmare il divario tra una proof of concept e un agente AI pronto per la produzione, è essenziale un framework di valutazione solido e automatizzato.

assistenza clienti

Che cosa stiamo valutando esattamente?

La valutazione dell'agente è più complessa della valutazione LLM standard. Non stai valutando solo il Saggio (Risposta finale), ma anche la Matematica (la logica/gli strumenti utilizzati per arrivare alla risposta).

eval diagram

  1. Traiettoria (il processo): l'agente ha utilizzato lo strumento giusto al momento giusto? Ha chiamato check_inventory prima delle place_order?
  2. Risposta finale (l'output): la risposta è corretta, educata e basata sui dati?

Il ciclo di sviluppo

In questo codelab, esamineremo il ciclo di vita professionale dei test degli agenti:

  1. Ispezione visiva locale (interfaccia utente web ADK): chat e verifica manuale della logica (passaggio 1).
  2. Test unitari/di regressione (ADK CLI): esecuzione di casi di test specifici in locale per rilevare errori rapidi (passaggi 3 e 4).
  3. Debug (risoluzione dei problemi): analisi degli errori e correzione della logica del prompt (passaggio 5).
  4. Integrazione CI/CD (Pytest): automatizzazione dei test nella pipeline di build (passaggio 6).

2. Configura

Per alimentare i nostri agenti AI, abbiamo bisogno di due cose: un progetto Google Cloud per fornire le basi.

Passaggio 1: attiva l'account di fatturazione

  • Per richiedere il tuo account di fatturazione con un credito di 5 $, ti servirà per il deployment. Assicurati di accedere al tuo account Gmail.

Passaggio 2: apri l'ambiente

👉 Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud (l'icona a forma di terminale nella parte superiore del riquadro Cloud Shell).

testo alternativo

👉 Fai clic sul pulsante "Apri editor" (ha l'aspetto di una cartella aperta con una matita). Si aprirà l'editor di codice di Cloud Shell nella finestra. Sul lato sinistro vedrai un esploratore di file. testo alternativo

👉 Apri il terminale nell'IDE cloud, testo alternativo

👉💻 Nel terminale, verifica di aver già eseguito l'autenticazione e che il progetto sia impostato sul tuo ID progetto utilizzando il seguente comando:

gcloud auth list

👉💻 Clona il progetto di bootstrap da GitHub:

git clone https://github.com/cuppibla/adk_eval_starter

👉💻 Esegui lo script di configurazione dalla directory del progetto.

⚠️ Nota sull'ID progetto: lo script suggerirà un ID progetto predefinito generato in modo casuale. Puoi premere Invio per accettare questo valore predefinito.

Tuttavia, se preferisci creare un nuovo progetto specifico, puoi digitare l'ID progetto che preferisci quando ti viene richiesto dallo script.

cd ~/adk_eval_starter
./init.sh

Lo script gestirà automaticamente il resto della procedura di configurazione.

👉 Passaggio importante al termine: al termine dello script, devi assicurarti che nella console Google Cloud sia visualizzato il progetto corretto:

  1. Vai all'indirizzo console.cloud.google.com.
  2. Fai clic sul menu a discesa del selettore progetti nella parte superiore della pagina.
  3. Fai clic sulla scheda "Tutti" (poiché il nuovo progetto potrebbe non essere ancora visualizzato in "Recenti").
  4. Seleziona l'ID progetto che hai appena configurato nel passaggio init.sh.

03-05-project-all.png

👉💻 Imposta l'ID progetto necessario:

gcloud config set project $(cat ~/project_id.txt) --quiet

Configura l'autorizzazione

👉💻 Abilita le API richieste utilizzando il seguente comando. L'operazione potrebbe richiedere alcuni minuti.

gcloud services enable \
    cloudresourcemanager.googleapis.com \
    servicenetworking.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    aiplatform.googleapis.com \
    compute.googleapis.com

👉💻 Concedi le autorizzazioni necessarie eseguendo questi comandi nel terminale:

. ~/adk_eval_starter/set_env.sh

Nota che viene creato un file .env. Vengono visualizzate le informazioni del progetto.

3. Generazione del Golden Dataset (adk web)

Golden

Prima di poter valutare l'agente, abbiamo bisogno di un file di risposte. Nell'ADK, questo set di dati è chiamato Golden Dataset. Questo set di dati contiene interazioni "perfette" che fungono da dati empirici reali per la valutazione.

Che cos'è un set di dati di riferimento?

Un Golden Dataset è un'istantanea del tuo agente che funziona correttamente. Non si tratta solo di un elenco di coppie di domande e risposte. Acquisisce:

  • La query dell'utente ("Voglio un rimborso")
  • La traiettoria (la sequenza esatta di chiamate di strumenti: check_order -> verify_eligibility -> refund_transaction).
  • La risposta finale (la risposta di testo "perfetta").

Utilizziamo questo valore per rilevare le regressioni. Se aggiorni il prompt e l'agente smette improvvisamente di verificare l'idoneità prima di rimborsare, il test del Golden Dataset non andrà a buon fine perché la traiettoria non corrisponde più.

Apri l'interfaccia utente web

La GUI web dell'ADK offre un modo interattivo per creare questi golden dataset acquisendo interazioni reali con l'agente.

👉 Nel terminale, esegui:

cd ~/adk_eval_starter
uv run adk web

👉 Apri l'anteprima della UI web (di solito all'indirizzo http://127.0.0.1:8000).

👉 Nell'interfaccia utente della chat, digita

Hi, I'm customer CUST001. Can you check my orders? I need a refund for order ORD-102. It arrived damaged.

adk eval result

Vedrai una risposta simile a questa:

I've processed your refund for order ORD-102 due to the items arriving damaged. A full refund of $35.0 has been processed, and the status of order ORD-102 is now updated to "refunded".

Is there anything else I can assist you with today, CUST001? 🛍️

Acquisizione delle interazioni d'oro

Vai alla scheda Sessioni. Qui puoi visualizzare la cronologia delle conversazioni del tuo agente facendo clic sulla sessione.

  1. Interagisci con l'agente per creare un flusso di conversazione ideale, ad esempio per controllare la cronologia degli acquisti o richiedere un rimborso.
  2. Rivedi la conversazione per assicurarti che rappresenti il comportamento previsto.

eval trace

4. Esportare il set di dati di riferimento

Verifica con Trace View

Prima di esportare, devi verificare che l'agente non abbia trovato la risposta giusta per caso. Devi ispezionare la logica interna.

  1. Fai clic sulla scheda Trace (Traccia) nella UI web.
  2. Le tracce vengono raggruppate automaticamente in base al messaggio dell'utente. Passa il mouse sopra una riga di traccia per evidenziare il messaggio corrispondente nella chat.
  3. Esamina le righe blu: indicano gli eventi generati dall'interazione. Fai clic su una riga blu per aprire il pannello di ispezione.
  4. Controlla le seguenti schede per convalidare la logica:
    • Grafico: rappresentazione visiva delle chiamate agli strumenti e del flusso logico. Ha seguito il percorso corretto?
    • Richiesta/Risposta: esamina esattamente ciò che è stato inviato al modello e ciò che è stato restituito.
    • Verifica: se l'agente ha stimato l'importo del rimborso senza chiamare lo strumento di database, si tratta di un'"allucinazione fortunata". eval verify

Aggiungi sessione a EvalSet

Una volta che la conversazione e la traccia ti soddisfano: 👉 Fai clic sulla scheda Eval, poi sul pulsante Create Evaluation Set e inserisci il nome della valutazione:

evalset1

set di valutazione

👉 In questo evalset, fai clic su Add current session to evalset1. Nella finestra popup, inserisci il nome della sessione:

eval1

eval create

Esegui la valutazione in ADK Web

👉 Nell'interfaccia utente web di ADK, fai clic su Run Evaluation, nella finestra popup regola le metriche e fai clic su Start:

run eval

Verificare il set di dati nel repository

Verrà visualizzata una conferma che indica che è stato creato un file del set di dati (ad es. evalset1.evalset.json) è stato salvato nel tuo repository. Questo file contiene la traccia grezza e generata automaticamente della tua conversazione.

salvataggio del set di valutazione

5. File di valutazione

file di valutazione

Mentre la UI web genera un file .evalset.json complesso, spesso vogliamo creare un file di test più pulito e strutturato per i test automatizzati.

ADK Eval utilizza due componenti principali:

  1. File di test: può essere il Golden Dataset generato automaticamente (ad es. customer_service_agent/evalset1.evalset.json) o un insieme selezionato manualmente (ad es. customer_service_agent/eval.test.json).
  2. Config Files (ad es. customer_service_agent/test_config.json): definisci le metriche e le soglie per il superamento.

Configura il file di configurazione del test

👉 Apri customer_service_agent/test_config.json nell'editor.

Inserisci il seguente codice:

{
  "criteria": {
    "tool_trajectory_avg_score": 0.8,
    "response_match_score": 0.5
  }
}

Decodifica delle metriche

  1. tool_trajectory_avg_score (La procedura) Misura se l'agente ha utilizzato correttamente gli strumenti.
  • 0,8: richiediamo una corrispondenza dell'80%.
  1. response_match_score (l'output) Utilizza ROUGE-1 (sovrapposizione di parole) per confrontare la risposta con il riferimento golden.
  • Vantaggi: veloce, deterministico, senza costi.
  • Svantaggi: non riesce se l'agente esprime la stessa idea in modo diverso (ad es. "Rimborsato" e "Denaro restituito".

Metriche avanzate (per quando hai bisogno di più potenza)

6. Esegui la valutazione per il set di dati di riferimento (valutazione ADK)

inner loop

Questo passaggio rappresenta il "ciclo interno" di sviluppo. Sei uno sviluppatore che sta apportando modifiche e vuoi verificare rapidamente i risultati.

Esegui il set di dati di riferimento

Eseguiamo il set di dati che hai generato nel passaggio 1. In questo modo, la base di riferimento è solida.

👉 Nel terminale, esegui:

cd ~/adk_eval_starter
uv run adk eval customer_service_agent customer_service_agent/evalset1.evalset.json --config_file_path=customer_service_agent/test_config.json --print_detailed_results

Cosa c'è di nuovo?

L'ADK ora è:

  1. Caricamento dell'agente da customer_service_agent.
  2. Esecuzione delle query di input da evalset1.evalset.json.
  3. Confrontando la traiettoria e le risposte effettive dell'agente con quelle previste.
  4. Assegnazione di un punteggio ai risultati in base ai criteri indicati in test_config.json.

Analizzare i risultati

Guarda l'output del terminale. Vedrai un riepilogo dei test superati e non superati.

Eval Run Summary
evalset1:
  Tests passed: 1
  Tests failed: 0
********************************************************************
Eval Set Id: evalset1
Eval Id: eval1
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.5581395348837208, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+---------------------------+---------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt                    | expected_response         | actual_response          | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+===========================+===========================+==========================+===========================+===========================+=============================+========================+
|  0 | Hi, I'm customer CUST001. | Great news! Your refund   | Great news, CUST001! 🎉   | id='adk-051409fe-c230-43f | id='adk-4e9aa570-1cc6-4c3 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | Can you check my orders?  | for order **ORD-102** has | I've successfully        | 4-a7f1- 5747280fd878'     | c-aa3e- 91dbe113dd4b'     | 1.0                         | 0.5581395348837208     |
|    | I need a refund for order | been successfully         | processed a full refund  | args={'customer_id':      | args={'customer_id':      |                             |                        |
|    | ORD-102. It arrived       | processed due to the item | of $35.0 for your order  | 'CUST001'} name='get_purc | 'CUST001'} name='get_purc |                             |                        |
|    | damaged.                  | arriving damaged. You     | ORD-102 because it       | hase_history'             | hase_history'             |                             |                        |
|    |                           | should see a full refund  | arrived damaged. The     | partial_args=None         | partial_args=None         |                             |                        |
|    |                           | of $35.0 back to your     | status of that order has | will_continue=None id= 'a | will_continue=None        |                             |                        |
|    |                           | original payment method   | been updated to          | dk-8a194cb8-5a82-47ce-a3a | id='adk- dad1b376-9bcc-48 |                             |                        |
|    |                           | shortly. The status of    | "refunded."  Is there    | 7- 3d24551f8c90'          | bb-996f-a30f6ef5b70b'     |                             |                        |
|    |                           | this order has been       | anything else I can      | args={'reason':           | args={'reason':           |                             |                        |
|    |                           | updated to "refunded".    | assist you with today?   | 'damaged', 'order_id':    | 'damaged', 'order_id':    |                             |                        |
|    |                           | Here's your updated       |                          | 'ORD-102'}                | 'ORD-102'}                |                             |                        |
|    |                           | purchase history for      |                          | name='issue_refund'       | name='issue_refund'       |                             |                        |
|    |                           | CUST001: *   **ORD-101**: |                          | partial_args=None         | partial_args=None         |                             |                        |
|    |                           | Wireless Headphones,      |                          | will_continue=None        | will_continue=None        |                             |                        |
|    |                           | delivered on 2023-10-15   |                          |                           |                           |                             |                        |
|    |                           | (Total: $120) *           |                          |                           |                           |                             |                        |
|    |                           | **ORD-102**: USB-C Cable, |                          |                           |                           |                             |                        |
|    |                           | Phone Case, refunded on   |                          |                           |                           |                             |                        |
|    |                           | 2023-11-01 (Total: $35)   |                          |                           |                           |                             |                        |
|    |                           | Is there anything else I  |                          |                           |                           |                             |                        |
|    |                           | can help you with today?  |                          |                           |                           |                             |                        |
|    |                           | 😊                         |                          |                           |                           |                             |                        |
+----+---------------------------+---------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+------------------------+

Nota: poiché l'hai appena generato dall'agente stesso, dovrebbe superare il test al 100%. Se non riesce, l'agente è non deterministico (casuale).

7. Crea un test personalizzato

Sebbene i set di dati generati automaticamente siano ottimi, a volte è necessario creare manualmente casi limite (ad es. attacchi avversariali o gestione di errori specifici). Vediamo in che modo eval.test.json ti consente di definire la "correttezza".

Creiamo una suite di test completa.

Framework di test

Quando scrivi uno scenario di test in ADK, segui questa formula in tre parti:

  • La configurazione (session_input): chi è l'utente? (ad es. user_id, state). In questo modo il test viene isolato.
  • Il prompt (user_content): qual è il trigger?

Con The Assertions (Expectations):

  • Traiettoria (tool_uses): ha eseguito correttamente i calcoli? (Logica)
  • Risposta (final_response): ha dato la risposta giusta? (Qualità)
  • Intermedio (intermediate_responses): i subagenti hanno parlato correttamente? (Orchestrazione)

Scrivi la suite di test

👉 Apri customer_service_agent/eval.test.json nell'editor.

Inserisci il seguente codice:

{
  "eval_set_id": "customer_service_eval",
  "name": "Customer Service Agent Evaluation",
  "description": "Evaluation suite for the customer service agent covering product info, purchase history, and refunds.",
  "eval_cases": [
    {
      "eval_id": "product_info_check",
      "session_input": {
        "app_name": "customer_service_agent",
        "user_id": "eval_user_1",
        "state": {}
      },
      "conversation": [
        {
          "invocation_id": "turn_1_product_info",
          "user_content": {
            "role": "user",
            "parts": [
              {
                "text": "Do you have wireless headphones in stock?"
              }
            ]
          },
          "final_response": {
            "role": "model",
            "parts": [
              {
                "text": "Yes, we have wireless headphones in stock! They are priced at $120.00 and feature noise-canceling with a 20-hour battery life. 🎧"
              }
            ]
          },
          "intermediate_data": {
            "tool_uses": [
              {
                "name": "lookup_product_info",
                "args": {
                  "product_name": "wireless headphones"
                }
              }
            ],
            "intermediate_responses": []
          }
        }
      ]
    },
    {
      "eval_id": "purchase_history_check",
      "session_input": {
        "app_name": "customer_service_agent",
        "user_id": "eval_user_2",
        "state": {}
      },
      "conversation": [
        {
          "invocation_id": "turn_1_purchase_history",
          "user_content": {
            "role": "user",
            "parts": [
              {
                "text": "What did I buy recently? My customer ID is CUST001."
              }
            ]
          },
          "final_response": {
            "role": "model",
            "parts": [
              {
                "text": "Here's your recent purchase history for Customer ID CUST001:\n\n*   **Order ORD-101** (October 15, 2023): Wireless Headphones, Status: delivered, Total: $120\n*   **Order ORD-102** (November 1, 2023): USB-C Cable, Phone Case, Status: refunded, Total: $35\n\nLet me know if you have any other questions or need further assistance! 🛍️"
              }
            ]
          },
          "intermediate_data": {
            "tool_uses": [
              {
                "name": "get_purchase_history",
                "args": {
                  "customer_id": "CUST001"
                }
              }
            ],
            "intermediate_responses": []
          }
        }
      ]
    },
    {
      "eval_id": "refund_request",
      "session_input": {
        "app_name": "customer_service_agent",
        "user_id": "eval_user_3",
        "state": {}
      },
      "conversation": [
        {
          "invocation_id": "turn_1_refund",
          "user_content": {
            "role": "user",
            "parts": [
              {
                "text": "I want a refund for order ORD-102 because it was damaged."
              }
            ]
          },
          "final_response": {
            "role": "model",
            "parts": [
              {
                "text": "Your refund for order **ORD-102** due to \"damaged\" has been successfully processed!  Refund amount: **$35.0**. Your order status has been updated to **refunded**. \nIs there anything else I can help you with today? 🛍️"
              }
            ]
          },
          "intermediate_data": {
            "tool_uses": [
              {
                "name": "issue_refund",
                "args": {
                  "order_id": "ORD-102",
                  "reason": "damaged"
                }
              }
            ],
            "intermediate_responses": []
          }
        }
      ]
    }
  ]
}

Analisi dei tipi di test

Qui abbiamo creato tre tipi distinti di test. Analizziamo cosa valuta ciascuna e perché.

  1. Test con un solo strumento (product_info_check)
  • Obiettivo: verifica il recupero delle informazioni di base.
  • Affermazione chiave: controlliamo intermediate_data.tool_uses. Affermiamo che viene chiamato lookup_product_info. Affermiamo che l'argomento product_name è esattamente "cuffie wireless".
  • Motivo: se il modello allucina un prezzo senza chiamare lo strumento, questo test non va a buon fine. In questo modo, la risposta è più precisa.
  1. Test di estrazione del contesto (purchase_history_check)
  • Obiettivo: verifica che l'agente possa estrarre le entità (CUST001) dal prompt dell'utente e trasmetterle allo strumento.
  • Asserzione chiave: verifichiamo che get_purchase_history venga chiamato con customer_id: "CUST001".
  • Perché: una modalità di errore comune è l'agente che chiama lo strumento corretto, ma con un ID nullo. In questo modo, garantisci l'accuratezza dei parametri.
  1. Test di azione/traiettoria (refund_request)
  • Obiettivo: verifica un'operazione di scrittura critica.
  • Affermazione chiave: la traiettoria. In uno scenario più complesso, questo elenco conterrebbe più passaggi: [verify_order, calculate_refund, issue_refund]. L'ADK controlla questo elenco in ordine.
  • Perché: per le azioni che spostano denaro o modificano i dati, la sequenza è importante quanto il risultato. Non vuoi effettuare il rimborso prima della verifica.

8. Esegui valutazione per test personalizzati ( adk eval)

inner loop

👉 Nel terminale, esegui:

cd ~/adk_eval_starter
uv run adk eval customer_service_agent customer_service_agent/eval.test.json --config_file_path=customer_service_agent/test_config.json --print_detailed_results

Comprendere l'output

Dovresti vedere un risultato PASS come questo:

Eval Run Summary
customer_service_eval:
  Tests passed: 3
  Tests failed: 0
********************************************************************
Eval Set Id: customer_service_eval
Eval Id: purchase_history_check
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.5473684210526315, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+--------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt                   | expected_response         | actual_response           | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+==========================+===========================+===========================+===========================+===========================+=============================+========================+
|  0 | What did I buy recently? | Here's your recent        | Looks like your recent    | id=None                   | id='adk-8960eb53-2933-459 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | My customer ID is        | purchase history for      | orders include: *         | args={'customer_id':      | f-b306- 71e3c069e77e'     | 1.0                         | 0.5473684210526315     |
|    | CUST001.                 | Customer ID CUST001:  *   | **ORD-101 (2023-10-15):** | 'CUST001'} name='get_purc | args={'customer_id':      |                             |                        |
|    |                          | **Order ORD-101**         | Wireless Headphones for   | hase_history'             | 'CUST001'} name='get_purc |                             |                        |
|    |                          | (October 15, 2023):       | $120.00 - Status:         | partial_args=None         | hase_history'             |                             |                        |
|    |                          | Wireless Headphones,      | Delivered 🎧 *   **ORD-102 | will_continue=None        | partial_args=None         |                             |                        |
|    |                          | Status: delivered, Total: | (2023-11-01):** USB-C     |                           | will_continue=None        |                             |                        |
|    |                          | $120 *   **Order          | Cable, Phone Case for     |                           |                           |                             |                        |
|    |                          | ORD-102** (November 1,    | $35.00 - Status: Refunded |                           |                           |                             |                        |
|    |                          | 2023): USB-C Cable, Phone | 📱  Is there anything else |                           |                           |                             |                        |
|    |                          | Case, Status: refunded,   | I can help you with       |                           |                           |                             |                        |
|    |                          | Total: $35  Let me know   | regarding these orders?   |                           |                           |                             |                        |
|    |                          | if you have any other     |                           |                           |                           |                             |                        |
|    |                          | questions or need further |                           |                           |                           |                             |                        |
|    |                          | assistance! 🛍️            |                           |                           |                           |                             |                        |
+----+--------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+



********************************************************************
Eval Set Id: customer_service_eval
Eval Id: product_info_check
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.6829268292682927, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+----------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt               | expected_response         | actual_response           | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+======================+===========================+===========================+===========================+===========================+=============================+========================+
|  0 | Do you have wireless | Yes, we have wireless     | Yes, we do! 🎧 We have     | id=None                   | id='adk-4571d660-a92b-412 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | headphones in stock? | headphones in stock! They | noise-canceling wireless  | args={'product_name':     | a-a79e- 5c54f8b8af2d'     | 1.0                         | 0.6829268292682927     |
|    |                      | are priced at $120.00 and | headphones with a 20-hour | 'wireless headphones'} na | args={'product_name':     |                             |                        |
|    |                      | feature noise-canceling   | battery life available    | me='lookup_product_info'  | 'wireless headphones'} na |                             |                        |
|    |                      | with a 20-hour battery    | for $120.                 | partial_args=None         | me='lookup_product_info'  |                             |                        |
|    |                      | life. 🎧                   |                           | will_continue=None        | partial_args=None         |                             |                        |
|    |                      |                           |                           |                           | will_continue=None        |                             |                        |
+----+----------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+



********************************************************************
Eval Set Id: customer_service_eval
Eval Id: refund_request
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.6216216216216216, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt                    | expected_response         | actual_response           | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+===========================+===========================+===========================+===========================+===========================+=============================+========================+
|  0 | I want a refund for order | Your refund for order     | Your refund for order     | id=None args={'order_id': | id='adk-fb8ff1cc- cf87-41 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | ORD-102 because it was    | **ORD-102** due to        | **ORD-102** has been      | 'ORD-102', 'reason':      | f2-9b11-d4571b14287f'     | 1.0                         | 0.6216216216216216     |
|    | damaged.                  | "damaged" has been        | successfully processed!   | 'damaged'}                | args={'order_id':         |                             |                        |
|    |                           | successfully processed!   | You should see a full     | name='issue_refund'       | 'ORD-102', 'reason':      |                             |                        |
|    |                           | Refund amount: **$35.0**. | refund of $35.0 appear in | partial_args=None         | 'damaged'}                |                             |                        |
|    |                           | Your order status has     | your account shortly. We  | will_continue=None        | name='issue_refund'       |                             |                        |
|    |                           | been updated to           | apologize for the         |                           | partial_args=None         |                             |                        |
|    |                           | **refunded**.  Is there   | inconvenience! Is there   |                           | will_continue=None        |                             |                        |
|    |                           | anything else I can help  | anything else I can       |                           |                           |                             |                        |
|    |                           | you with today? 🛍️        | assist you with today? 😊  |                           |                           |                             |                        |
+----+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+

Ciò significa che l'agente ha utilizzato gli strumenti corretti e ha fornito una risposta sufficientemente simile alle tue aspettative.

9. (Facoltativo: sola lettura) - Risoluzione dei problemi e debug

I test non andranno a buon fine. È il loro lavoro. Ma come si risolvono? Analizziamo gli scenari di errore più comuni e come eseguire il debug.

Scenario A: errore di "Traiettoria"

L'errore:

Result: FAILED
Reason: Criteria 'tool_trajectory_avg_score' failed. Score 0.0 < Threshold 1.0
Details:
EXPECTED: tool: lookup_order, then tool: issue_refund
ACTUAL:   tool: issue_refund

Diagnosi: l'agente ha saltato il passaggio di verifica (lookup_order). Si tratta di un errore di logica.

Come risolvere i problemi:

  • Non indovinare: torna alla GUI web dell'ADK (adk web).
  • Riproduci: digita nella chat il prompt esatto del test non riuscito.
  • Trace: apri la visualizzazione Trace. Esamina la scheda "Grafico".
  • Correggere il prompt: in genere, devi aggiornare il prompt di sistema. Modifica: "Sei un agente disponibile". A: "Sei un agente disponibile. CRITICO: DEVI chiamare lookup_order per verificare i dettagli prima di chiamare issue_refund."
  • Adatta il test: se la logica di business è cambiata (ad es. la verifica non è più necessaria), il test è errato. Aggiorna eval.test.json in modo che corrisponda alla nuova realtà.

Scenario B: l'errore "ROUGE"

Errore:

Result: FAILED
Reason: Criteria 'response_match_score' failed. Score 0.45 < Threshold 0.8
Expected: "The refund has been processed successfully."
Actual:   "I've gone ahead and returned the money to your card."

Diagnosi: l'agente ha fatto la cosa giusta, ma ha usato parole diverse. ROUGE (sovrapposizione di parole) ha penalizzato il testo.

Come risolvere il problema:

  • È sbagliato? Se il significato è corretto, non modificare il prompt.
  • Regola soglia: abbassa la soglia in test_config.json (ad es. da 0.8 a 0.5).
  • Esegui l'upgrade della metrica: passa a final_response_match_v2 nella configurazione. Utilizza un modello LLM per leggere entrambe le frasi e valutare se hanno lo stesso significato.

10. CI/CD con Pytest (pytest)

pytest

I comandi della CLI sono destinati agli esseri umani. pytest è per le macchine. Per garantire l'affidabilità della produzione, inseriamo le nostre valutazioni in una suite di test Python. In questo modo, la pipeline CI/CD (GitHub Actions, Jenkins) può bloccare un deployment se l'agente subisce un degrado.

Cosa contiene questo file?

Questo file Python funge da ponte tra il runner CI/CD e il valutatore ADK. Deve:

  • Carica il tuo agente: importa dinamicamente il codice dell'agente.
  • Reimposta stato: assicurati che la memoria dell'agente sia pulita in modo che i test non si influenzino a vicenda.
  • Esegui valutazione: chiama AgentEvaluator.evaluate() in modo programmatico.
  • Assert Success: se il punteggio di valutazione è basso, la build non viene eseguita.

Codice di test di integrazione

👉 Apri customer_service_agent/test_agent_eval.py. Questo script utilizza AgentEvaluator.evaluate per eseguire i test definiti in eval.test.json.

👉 Apri customer_service_agent/test_agent_eval.py nell'editor.

Inserisci il seguente codice:

from google.adk.evaluation.agent_evaluator import AgentEvaluator
import pytest
import importlib
import sys
import os

@pytest.mark.asyncio
async def test_with_single_test_file():
    """Test the agent's basic ability via a session file."""
    # Load the agent module robustly
    module_name = "customer_service_agent.agent"
    try:
        agent_module = importlib.import_module(module_name)
        # Reset the mock data to ensure a fresh state for the test
        if hasattr(agent_module, 'reset_mock_data'):
            agent_module.reset_mock_data()
    except ImportError:
        # Fallback if running from a different context
        sys.path.append(os.getcwd())
        agent_module = importlib.import_module(module_name)
        if hasattr(agent_module, 'reset_mock_data'):
            agent_module.reset_mock_data()
    
    # Use absolute path to the eval file to be robust to where pytest is run
    script_dir = os.path.dirname(os.path.abspath(__file__))
    eval_file = os.path.join(script_dir, "eval.test.json")
    
    await AgentEvaluator.evaluate(
        agent_module=module_name,
        eval_dataset_file_path_or_dir=eval_file,
        num_runs=1,
    )

Esegui Pytest

👉 Nel terminale, esegui:

cd ~/adk_eval_starter
uv pip install pytest
uv run pytest customer_service_agent/test_agent_eval.py

Vedrai un risultato simile a questo:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============== 1 passed, 15 warnings in 12.84s ===============

11. Conclusione

Complimenti! Hai valutato correttamente il tuo agente del servizio clienti utilizzando ADK Eval.

Che cosa hai imparato

In questo codelab hai imparato a:

  • Genera un Golden Dataset per stabilire una base di conoscenza per il tuo agente.
  • Comprendi la configurazione della valutazione per definire i criteri di successo.
  • Esegui valutazioni automatiche per rilevare le regressioni in anticipo.

Se incorpori ADK Eval nel tuo flusso di lavoro di sviluppo, puoi creare agenti con la certezza che qualsiasi cambiamento nel comportamento verrà rilevato dai test automatizzati.