Przewodniki
Symulowani użytkownicy
Rozmowa ze skryptu testuje Twojego asystenta na użytkowniku, który nigdy nie reaguje. Symulowany użytkownik reaguje: model odgrywa osobę opisaną w każdym przypadku, pisze każdą kolejną wiadomość na podstawie tego, co właśnie powiedział Twój asystent, i przestaje, gdy jego cel zostanie osiągnięty albo gdy się podda. Oloproof zapisuje to, co przeszło między nimi, mierzy to jak każdą rozmowę i pozwala bramce decydować na tej podstawie dopiero wtedy, gdy ludzie uznają symulowanego użytkownika za realistycznego. Samouczek pokazuje biuro obsługi klienta rozmawiające z symulowanymi klientami.
Persony
Wejście każdego przypadku zawiera personę: kim jest użytkownik, czego chce i co wie.
{"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"}
}}}- description i goal są wymagane. Napisz cel, który czytelnik mógłby sprawdzić na podstawie samej rozmowy: o celu "niech sklep rozpocznie zwrot pieniędzy" da się rozstrzygnąć na podstawie tego, co mówi asystent, a o celu "otrzymać zwrot pieniędzy" nie, bo pieniądze przychodzą później.
- facts to to, co użytkownik wie i ujawnia tylko wtedy, gdy rozmowa tego wymaga, na przykład numer zamówienia. Twój asystent nigdy nie widzi persony.
- opening to pierwsza wiadomość użytkownika, słowo w słowo, gdy każdy system ma zostać powitany tak samo.
- max_turns ogranicza liczbę wiadomości tego użytkownika, nadpisując wartość ustawioną dla projektu.
Persona jest treścią zbioru danych: obejmuje ją skrót zestawu i jest taka sama dla każdego systemu mierzonego względem niej.
Deklarowanie symulowanego użytkownika
Model, który odgrywa każdą personę, deklaruje się w systemie, tak jak sędziego:
system:
name: support-desk
callable: desk:talk
simulated_user:
provider: openai_compatible
base_url: http://localhost:11434/v1
model: qwen2.5vl
max_turns: 6Każde pole jest opisane w dokumentacji konfiguracji. Model lokalny nic nie kosztuje; hostowany rozlicza każdą wiadomość, którą pisze, a jego tokeny są zapisywane obok rozmowy i nigdy nie są liczone jako koszt Twojego systemu.
Twój system zachowuje swoją pętlę
Oloproof nie prowadzi rozmowy. Twój system prosi o pierwszą wiadomość użytkownika, odpowiada na nią tak, jak odpowiada użytkownikom, i oddaje każdą odpowiedź, aby otrzymać następną wiadomość:
from oloproof import current_case
def talk(case):
user = current_case().simulated_user()
message = user.opening()
while message is not None:
message = user.reply(my_assistant.answer(message))
return {}reply zwraca None, gdy użytkownik przestanie. Twój system może sam zakończyć rozmowę przez user.end(answer), tak jak zrobiłoby to przekazanie rozmowy człowiekowi; system async def oczekuje (await) na aopening(), areply(answer) i aend(answer). Oloproof zapisuje to, co przeszło przez ten uchwyt, jako conversation/v1, a to, jak rozmowa się zakończyła, jako simulated_user/v1, i odrzuca każdy z nich, jeśli zapisze go Twój system (Dokumentacja SDK).
Jak kończy się rozmowa
Po każdej odpowiedzi Twojego systemu model symulowanego użytkownika jest pytany, w osobnym pytaniu przy temperaturze 0 i bez otaczającej go gry w rolę, czy ta odpowiedź zrealizowała cel. Jeśli tak, rozmowa kończy się jako goal_reached. W przeciwnym razie użytkownik pisze kolejną wiadomość albo odchodzi (user_left), aż wyśle max_turns wiadomości (turn_limit). System, który zatrzymuje się bez odpowiedzi na ostatnią wiadomość, zostawia rozmowę jako unanswered i obciętą.
To osobne pytanie sprawia, że da się użyć małego modelu lokalnego: odgrywanie persony i ocena, czy cel został osiągnięty, to różne zadania, a model poproszony o oba w jednej odpowiedzi ma skłonność do dalszej rozmowy po osiągnięciu celu albo do mówienia, że odchodzi, gdy jest zadowolony.
Mierzenie rozmów
Jednostką jest rozmowa: każdy ewaluator daje jeden werdykt na rozmowę, więc każdy przedział, porównanie i bramka działają bez zmian.
| Typ | Zalicza, gdy |
|---|---|
| conversation_completed | Twój system odpowiedział na każdą wiadomość |
| goal_reached | sprawdzenie celu stwierdziło, że cel został osiągnięty |
| turns_to_goal | nastąpiło to w ciągu max_turns wiadomości użytkownika |
| every_turn | każda odpowiedź spełnia zadeklarowane warunki: słowa, które musi zawierać lub których nie może zawierać, wzorzec, długość |
| conversation_judge | sędzia-model oceniający cały zapis rozmowy ją zalicza, gdy już jest zwalidowany względem etykiet nadanych przez ludzi |
Replikacje (replicates:) trafiają na użytkowników z różnymi ziarnami, więc jedna persona to kilka rozmów. Wersja symulowanego użytkownika (jego model, prompt, temperatura i budżet) jest częścią klucza cache każdego wykonania, więc inny symulowany użytkownik mierzy Twój system od nowa.
Walidacja symulowanego użytkownika
Wynik uzyskany na symulowanych użytkownikach przenosi się na prawdziwych użytkowników tylko w takim stopniu, w jakim symulowany użytkownik ich przypomina. Dlatego każda reguła dotycząca przebiegu, którego użytkownicy byli symulowani, daje INSUFFICIENT_EVIDENCE z simulated_user_not_validated, dopóki ludzie nie uznają jego rozmów za realistyczne:
oloproof labels export RUN_ID --criterion simulated_user_realistic --sample 30 --local --out realism.csv
oloproof labels import realism.csv
oloproof simulated-users RUN_IDArkusz pokazuje każdą wylosowaną rozmowę wraz z personą i tym, jak się zakończyła. Osoba zaznacza passed jako tak, gdy prawdziwy klient mógł napisać stronę użytkownika i zakończyć rozmowę w tym miejscu i w ten sposób, co obejmuje też sprawdzenie celu: rozmowa zakończona jako goal_reached, choć cel nie został osiągnięty, nie jest realistyczna. Symulowany użytkownik jest walidowany na zestawie, gdy dokładna dolna granica odsetka rozmów realistycznych osiąga minimum_simulated_user_realism w release.yaml. Wylosowana rozmowa pozostawiona bez etykiety liczy się jako nierealistyczna, a rozmowa jest realistyczna tylko wtedy, gdy twierdzą tak wszyscy, którzy nadali jej etykietę.
Jedna walidacja obejmuje jedną wersję jednego symulowanego użytkownika na jednym zestawie, niezależnie od tego, z którym systemem rozmawiał, więc o kandydacie mierzonym względem tych samych person decyduje się na podstawie etykiet punktu odniesienia. Nowy model, nowe ustawienie promptu lub nowy zbiór person wymaga nowych etykiet. Ustawienie require_validated_evaluators: false świadomie decyduje na podstawie symulowanych użytkowników bez nich.
Symulowani obok prawdziwych
oloproof simulated-users RUN_ID --real REAL_RUN_ID zestawia kształt rozmów symulowanych z przebiegiem rozmów prawdziwych (zalogowanych czatów odtworzonych jako conversation/v1): ile wiadomości wysłał użytkownik, jak były długie, jak długie były odpowiedzi, jak często rozmowa była przerywana i jak kończyły się rozmowy symulowane. Jest to opisowe i nigdy nie decyduje: porównanie dwóch niesparowanych prób wymaga metody, której Oloproof nie przyjął. Czytaj to pod kątem tego, czego nie wychwytują etykiety realizmu, na przykład symulowanych użytkowników, którzy piszą w jednym schludnym zdaniu to, co prawdziwi rozkładają na trzy.
Czego nie obsługujemy
- Decydowanie na podstawie symulowanych użytkowników w hostowanym obszarze roboczym: jego decyzje pozostają wstrzymane, dopóki jego kolejka przeglądu nie będzie potrafiła sama losować i pieczętować etykiet realizmu.
- Bramka na tym, jak rozmowy symulowane wypadają w porównaniu z prawdziwymi.
- Odsetki na poziomie tury w obrębie rozmowy oraz odtwarzanie rozmowy od wybranej tury.
- Symulowani użytkownicy dla systemu HTTP: pętlę prowadzi kod Twojego systemu, więc musi to być funkcja wywoływalna.