Langsung ke konten

Panduan

Tutorial: layanan dukungan menghadapi pelanggan simulasi

Evaluasi asisten percakapan terhadap pengguna yang bereaksi terhadap apa yang dikatakannya. Tiga puluh pelanggan simulasi, masing-masing dengan sebuah tujuan dan fakta yang mereka ketahui, bercakap dengan layanan dukungan sebuah toko; Oloproof mengukur apakah masing-masing mendapatkan apa yang mereka cari, menahan setiap keputusan sampai seseorang menilai pelanggan simulasi itu realistis, lalu memutuskan sebuah rilis dan sebuah perbandingan. Setiap langkah berjalan di mesin ini tanpa model dan tanpa jaringan, dan sebuah langkah opsional menggantikan pelanggan dengan model sungguhan.

Apa yang akan Anda bangun

Layanan dukungan sebuah toko menangani pengembalian dana, pertanyaan pengiriman, dan perubahan alamat. Tiga pertanyaan menentukan apakah sebuah versi boleh dirilis:

  • Apakah setiap pelanggan mendapatkan apa yang mereka cari? goal_reached, dari pemeriksaan setelah setiap jawaban.
  • Apakah ada jawaban yang menjanjikan apa yang tidak dapat dijanjikan toko? every_turn membaca setiap jawaban untuk mencari kata "guarantee".
  • Dapatkah jawaban-jawaban itu dipercaya untuk mengatakan sesuatu tentang pelanggan nyata? Hanya setelah seseorang membaca sampel percakapan dan menilai pelanggan simulasi itu realistis.

Istilah seperti kasus, eksekusi, gerbang, dan suite didefinisikan di Konsep inti; segala hal tentang pengguna simulasi ada di Pengguna simulasi.

Prasyarat

  • Python 3.11 atau yang lebih baru, dan Oloproof:
python3 -m venv .venv
. .venv/bin/activate
pip install oloproof
  • Proyek contoh, yang disertakan dalam paket. Salin ke direktori baru dan bekerjalah di sana:
oloproof init --example simulated-users support-desk
cd support-desk
  • Port 8797 kosong untuk pengguna simulasi pengganti (ubah di kedua tempat jika tidak).

Setiap langkah hingga "Opsional: model sungguhan sebagai pelanggan" bersifat offline dan deterministik: tanpa kunci API, tanpa akun penyedia, tanpa biaya.

File-filenya

support-desk/
  desk.py                      the support desk under test (baseline)
  desk_v2.py                   the candidate change
  user_server.py               a stand-in simulated user speaking the OpenAI API on 127.0.0.1
  oloproof.yaml                the suite: the simulated user and four evaluators
  release.yaml                 rules for a run, with the realism bar
  compare.yaml                 a rule for a comparison
  data/customers.jsonl         30 personas
  labels/realism_verdicts.csv  one person's realism verdicts on the baseline's conversations
  fill_realism.py              copies those verdicts into a labelling sheet
  logged.py                    replays logged chats with human agents
  real.yaml                    a suite of 20 of those chats
  logged_release.yaml          a rule for the logged chats
  data/logged_chats.jsonl      the 20 chats

Jalankan setiap perintah dari support-desk/.

Layanan dukungan memegang loop-nya sendiri

# desk.py (excerpt)
def talk(case: dict[str, Any]) -> dict[str, Any]:
    user = current_case().simulated_user()
    desk = Desk()
    message = user.opening()
    while message is not None:
        message = user.reply(desk.answer(message))
    return {"need": desk.need, "order": desk.order}

Layanan dukungan meminta pesan pertama pelanggan, menjawabnya, dan menyerahkan kembali setiap jawaban untuk mendapatkan pesan berikutnya, sampai pelanggan berhenti. Ia tidak pernah melihat persona. Oloproof merekam apa yang berlangsung di antara keduanya; layanan dukungan sendiri tidak merekam apa pun. Baseline ini tidak dapat mengubah alamat pengiriman, dan menjanjikan pengembalian dana "guaranteed within 5 days".

Persona-personanya

Setiap kasus adalah satu pelanggan: 12 menginginkan pengembalian dana, 10 ingin tahu kapan pesanan tiba, dan 8 telah pindah alamat. Contohnya:

{"id": "c25", "input": {"persona": {"description": "A retired teacher who ordered a cookbook last week. Writes short, polite messages.", "goal": "Have the order of a cookbook delivered to my new address.", "facts": {"order": "B-35", "postcode": "10275"}}}}

Pelanggan memberikan nomor pesanan dan kode pos hanya ketika diminta. Tiga persona juga menetapkan opening, pesan pertama mereka kata demi kata.

Suite-nya

version: 1
project: support-desk
dataset: data/customers.jsonl
system:
  name: support-desk
  version: baseline
  callable: desk:talk
  # A model plays each case's persona; here the stand-in in user_server.py.
  simulated_user:
    provider: openai_compatible
    model: stand-in-user
    base_url: http://127.0.0.1:8797/v1
    max_turns: 6
evaluators:
  # The desk answered every message the customer sent.
  - type: conversation_completed
  # The customer said they got what they came for.
  - type: goal_reached
  # ... within three of their own messages.
  - type: turns_to_goal
    max_turns: 3
  # No answer promises what the shop cannot promise.
  - type: every_turn
    criterion: no_promises
    not_contains: [guarantee]
    casefold: true

Pengguna simulasi pengganti

Pengguna simulasi adalah model yang memerankan setiap persona. Di sini ia adalah user_server.py, yang berbicara dengan API yang sama di 127.0.0.1 dan bukan model: server ini membaca persona dari prompt yang dikirim Oloproof, menyatakan tujuannya, memberikan nomor pesanan atau kode posnya ketika diminta, pergi ketika layanan dukungan tidak dapat membantu, dan, ketika ditanya apakah tujuannya tercapai, menjawab ya ketika jawaban terakhir layanan dukungan diawali dengan "Done:". Jalankan di terminal kedua dan biarkan tetap berjalan:

python user_server.py --port 8797

Kebijakannya

version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
require_validated_evaluators: true
minimum_simulated_user_realism: 0.80
rules:
  - id: no-promises
    metric: no_promises
    kind: observed_count
    max_failures: 0
  - id: resolved
    metric: goal_reached
    min: 0.80

Tidak ada jawaban yang boleh berjanji. Setidaknya 80% pelanggan harus mencapai tujuannya, yang diputuskan hanya ketika batas bawah interval melampaui 80%. Dan tidak ada aturan yang memutuskan atas pelanggan simulasi sampai orang-orang menilai setidaknya 80% percakapan mereka realistis, dengan jenis batas bawah yang sama.

Jalankan

oloproof run
Gate: BLOCK (exit 3)
│ no-promises │ no_promises  │ INSUFFICIENT_EVIDENCE │ simulated_user_not_validated │
│ resolved    │ goal_reached │ INSUFFICIENT_EVIDENCE │ simulated_user_not_validated │
│ conversation_completed │ 100.0%   │ [88.4%, 100.0%] │ 30 / 30 observed · 0 missing · 0 excluded │
│ goal_reached           │ 73.3%    │ [54.1%, 87.8%]  │ 22 / 30 observed · 0 missing · 0 excluded │
│ goal_within_3_turns    │ 73.3%    │ [54.1%, 87.8%]  │ 22 / 30 observed · 0 missing · 0 excluded │
│ no_promises            │ 60.0%    │ [40.6%, 77.4%]  │ 18 / 30 observed · 0 missing · 0 excluded │

Setiap pelanggan dijawab, 22 dari 30 mencapai tujuannya, dan 12 percakapan memuat sebuah janji. Belum ada yang diputuskan: pelanggan-pelanggan ini disimulasikan, dan belum ada yang memeriksa bahwa mereka berperilaku seperti pelanggan nyata.

Baca pelanggan simulasi

oloproof simulated-users RUN_ID
  Realism: no conversation has been drawn and labelled yet.
  Not validated: nothing labelled yet, against a bar of 80.0%.
Features (median [quartiles]; descriptive, never a gate):
  user messages           2 [1, 2]
  user message length     49 [10, 67]
  How the simulated conversations ended: goal_reached 73%, user_left 27%

Delapan yang pergi adalah pelanggan yang telah pindah alamat: baseline tidak dapat mengubah alamat.

Beri label realisme pada percakapan

Ambil sampel acak dari percakapan eksekusi ke dalam sebuah lembar, minta seseorang membaca masing-masing, beserta persona dan cara percakapan itu berakhir, dan menandai apakah pelanggan nyata bisa saja menulis sisi pelanggan dan mengakhirinya di titik itu, dengan cara itu. Di sini fill_realism.py menggantikan orang itu, dengan menyalin putusannya dari labels/realism_verdicts.csv:

oloproof labels export RUN_ID --criterion simulated_user_realistic --sample 30 --local --out realism.csv
python fill_realism.py realism.csv
oloproof labels import realism.csv
oloproof simulated-users RUN_ID
  Realism: 29 of 30 drawn conversations labelled realistic (30 labelled), [82.8%, 99.9%] at 95%
  Validated: the lower bound clears the bar of 80.0%.

Orang itu menilai satu percakapan tidak realistis: pelanggan c05 membuka dengan "Order: F-15. Refund.", yang terbaca seperti formulir, bukan seperti seseorang. Dengan 29 dari 30, batas bawah eksaknya adalah 82.8%, di atas ambang, sehingga aturan kini boleh memutuskan atas pelanggan-pelanggan ini.

oloproof gate RUN_ID --policy release.yaml
no-promises: FAIL (observed_failures_exceed_limit)
resolved: INSUFFICIENT_EVIDENCE (interval_overlaps_threshold)
Gate: BLOCK (exit 1)

Lakukan perubahan nyata

desk_v2.py mengubah alamat begitu ia memiliki pesanan dan kode pos yang baru, dan mengatakan bahwa ia telah memulai pengembalian dana yang "usually arrives within 5 days" alih-alih menjanjikannya. Salin menimpa desk.py, tetapkan version: candidate di bawah system di oloproof.yaml, biarkan pengganti tetap berjalan, lalu:

oloproof run
Gate: ALLOW (exit 0)
│ no-promises │ no_promises  │ PASS  │ observed_failures_within_limit │
│ resolved    │ goal_reached │ PASS  │ lower_bound_meets_minimum      │

Kandidat bertemu pelanggan simulasi yang sama pada suite yang sama, sehingga realisme yang diukur pada percakapan baseline mencakupnya: satu validasi mencakup satu pengguna simulasi pada satu suite, sistem mana pun yang diajaknya bercakap.

Bandingkan kandidat dengan baseline

oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yaml
goal_reached: +26.7 points [+1.2, +54.1] · 30 paired · 0 missing · 0 excluded
  resolves-more  goal_reached  superiority  PASS  difference_above_zero

Setiap pelanggan bertemu kedua layanan dukungan, sehingga perbandingannya berpasangan, pelanggan demi pelanggan.

Simulasi di samping yang nyata

Label realisme menilai setiap percakapan secara tersendiri. Menempatkan pelanggan simulasi di samping pelanggan nyata menunjukkan apa yang dapat terlewat oleh sebuah sampel. real.yaml memutar ulang 20 obrolan yang dilakukan agen manusia toko itu dengan pelanggan nyata:

oloproof run --config real.yaml --policy logged_release.yaml
oloproof simulated-users BASELINE_RUN_ID --real REAL_RUN_ID
                          simulated (run_01M52Q1C)    real (run_01M52Q25)
  user messages           2 [1, 2]                    3 [3, 4]
  user message length     49 [10, 67]                 13 [4, 32]

Pelanggan nyata mengirim lebih banyak pesan yang lebih pendek: mereka mengatakan apa yang mereka inginkan dalam tiga baris, sementara pengganti mengatakannya dalam satu kalimat rapi. Itu layak diketahui tentang pengguna simulasi mana pun, dan di sini tidak pernah memutuskan apa pun: membandingkan dua sampel yang tidak berpasangan memerlukan metode yang belum diterima Oloproof.

Opsional: model sungguhan sebagai pelanggan

Langkah ini meninggalkan jalur offline. Langkah ini memerlukan model chat: secara lokal, Ollama (ollama pull qwen2.5vl, atau model chat apa pun), tanpa kunci dan tanpa biaya; di cloud, provider: anthropic atau openai dengan api_key_env, ditagih per pesan. Di oloproof.yaml, arahkan pengguna simulasi ke model itu:

  simulated_user:
    provider: openai_compatible
    model: qwen2.5vl
    base_url: http://localhost:11434/v1
    max_turns: 6

Ollama menjawab satu permintaan dalam satu waktu, jadi tetapkan concurrency: {system: 1} dan timeout_s beberapa menit. Model yang berbeda adalah pengguna simulasi yang berbeda: label realisme di atas tidak mencakupnya, sehingga percakapannya memerlukan sampelnya sendiri sebelum aturan apa pun memutuskan atasnya.

Sepuluh persona, yang diperankan qwen2.5vl di mesin ini terhadap layanan dukungan kandidat, mencapai tujuannya dalam 8 percakapan, sementara pengganti mencapainya dalam ke-30 percakapan. Model itu menemukan apa yang tidak dapat ditemukan pengganti: dua pelanggan menanyakan "status" dan "shipping status" pesanan mereka, kata-kata yang tidak dikenal layanan dukungan, dan setiap kali mendapat sapaannya kembali. Satu kehabisan pesan. Layanan dukungan memahami percobaan ketiga pelanggan yang lain, dan pelanggan itu tetap pergi: pemeriksaan tujuan, sebuah penilaian model, melewatkan jawabannya. Label realisme adalah tempat hal itu terlihat: pelanggan nyata yang diberi tahu kapan pesanannya tiba tidak pergi dengan kecewa. Tidak seperti pengganti, model itu juga sering memberikan nomor pesanannya sebelum diminta, dan menulis satu pesan yang lebih panjang ketika pengganti menulis dua pesan pendek.

Pemecahan masalah

GejalaPenyebab dan perbaikan
Setiap aturan bernilai INSUFFICIENT_EVIDENCE dengan simulated_user_not_validatedBelum ada yang memberi label pada percakapan pengguna simulasi ini pada suite ini, atau proporsi yang realistis tidak melampaui ambang. Beri label pada sebuah sampel seperti di atas.
a case for a simulated user needs a 'persona' object in its inputSebuah kasus tidak memiliki persona, atau persona berada di bawah kunci lain: tetapkan persona_field.
provider connection failed dari setiap kasusPengganti tidak berjalan, atau mendengarkan di port lain selain yang disebut base_url.
the simulated user's goal check answered ...Model tidak menjawab pemeriksaan tujuan dengan ya atau tidak. Coba model lain, atau yang lebih besar.
conversation/v1 is written by OloproofLayanan dukungan merekam percakapan itu sendiri. Hapus itu: Oloproof merekam apa yang melewati pengguna simulasi.

Keterbatasan

  • Pelanggan pengganti adalah sebuah aturan. Percakapannya menunjukkan mekanismenya; percakapan model sungguhan lebih berantakan, seperti yang ditunjukkan langkah opsional.
  • Tercapai atau tidaknya tujuan adalah penilaian model pengguna simulasi, yang diperiksa hanya melalui label realisme.
  • Ruang kerja yang di-hosting belum memutuskan atas pengguna simulasi.
  • Pelanggan simulasi bukan pelanggan nyata: pengguna simulasi yang tervalidasi adalah bukti tentang pelanggan yang mirip dengan persona-personanya, sejauh orang-orang menilainya realistis, dan tidak lebih jauh.