Przejdź do treści

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: 6

Każ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.

TypZalicza, gdy
conversation_completedTwój system odpowiedział na każdą wiadomość
goal_reachedsprawdzenie celu stwierdziło, że cel został osiągnięty
turns_to_goalnastąpiło to w ciągu max_turns wiadomości użytkownika
every_turnkażda odpowiedź spełnia zadeklarowane warunki: słowa, które musi zawierać lub których nie może zawierać, wzorzec, długość
conversation_judgesę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_ID

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