İçeriğe geç

Kılavuzlar

Eğitim: çok turlu bir konuşma

Python SDK ile bir konuşma asistanını değerlendirmek için çalıştırılabilir bir anlatım: uygulamanız senaryolu bir konuşmayı yeni bir oturuma karşı yeniden oynatır, yanıtladıklarını bir conversation/v1 yapıtı olarak kaydeder ve iki değerlendirici her konuşmayı bütünüyle değerlendirir. Hakem modelin yerine geçen senaryolu bir yedekle çevrimdışı çalışır, ardından bir aday düzeltmeyi karşılaştırır ve turları kümelenmiş vakalar olarak değerlendirme alternatifiyle biter.

Aralık, karar durumu ve sürüm eylemi gibi terimler Kavramlar sayfasında tanımlanmıştır; Bir sistemin yaptığını kaydetme yapıtları anlatır.

Oloproof burada neyi yapar, neyi yapmaz

Oloproof şunları yaparUygulamanız şunları yapar
senaryolu konuşmaları her sistem için aynı olan veri kümesi olarak saklarkonuşmayı yürütür: her senaryolu turu sırayla sorar
her senaryolu turun yanıtlandığını denetler (ConversationCompleted)oturum durumunun sahibidir, her vaka için yeni bir oturum başlatır ve onu sıfırlar
tüm dökümü bir modelle değerlendirir (ConversationJudge)devam edemediğinde ne olacağına karar verir ve durduğunu kaydeder
aralıkları hesaplar, iki sistemi karşılaştırır ve bir politikaya göre karar verirconversation/v1 yapıtını kaydeder

Oloproof'un kullanıcı benzeticisi yoktur: asla bir kullanıcı turu yazmaz, bu yüzden kullanıcı tarafı veri kümesinin senaryolaştırdığı neyse odur. Kaydedilmiş bir konuşma içinde tur düzeyinde bir metriği yoktur ve kaydedilmiş bir konuşmayı yeni bir sisteme karşı yeniden oynatamaz. Konuşma değerlendiricileri yalnızca Python SDK'da vardır: ConversationCompleted ve ConversationJudge, oloproof.yaml içinde değerlendirici türü değildir, bu yüzden bu eğitim oloproof run yerine bir betik kullanır.

Ön koşullar

  • Hızlı başlangıçta olduğu gibi Python 3.11 veya üstü ve pip install oloproof.
  • Paketle birlikte gelen örnek dosyalar. Çalıştırmanın deposu oraya düşsün diye onları yeni bir dizine kopyalayın:
oloproof init --example conversation ~/oloproof-conversation
cd ~/oloproof-conversation
DosyaNedir
assistant.pytest edilen uygulama: oturum durumu olan bir plan asistanı
systems.pybağdaştırıcı: bir senaryoyu yeniden oynatır, conversation/v1 kaydeder
judge_offline.pyhakem modelin yerine geçen senaryolu yedek
evaluate.pydeğerlendirmeyi, karşılaştırmayı ve tur alternatifini çalıştırır
release.yamltek bir çalıştırma için politika
comparison.yamladayın temele karşı politikası
turns_release.yamltur alternatifi için politika
data/conversations.jsonl40 senaryolu konuşma
data/turns.jsonlaynı konuşmalar, tur başına bir vaka

Sondaki isteğe bağlı canlı adıma kadar anahtar yok, ağ yok ve sağlayıcı maliyeti yok.

Uygulama

assistant.py üç fiyat planı hakkındaki soruları yanıtlar. Tek bir durum parçası tutar, konuşmanın konusu olan planı; böylece "Does that include SSO?" gibi bir takip sorusu "that" ifadesini çözebilir. Temelin kasıtlı bir kusuru vardır: planı hatırlamaz, bu yüzden bir takip sorusu varsayılan plan hakkında yanıtlanır. Bir kişiyle görüşmek isteyen bir kullanıcı konuşmayı HandoffRequested ile bitirir.

class PlanAssistant:
    def __init__(self, *, remembers_plan):
        self.remembers_plan = remembers_plan
        self.reset()

    def reset(self):
        """Forget everything, so one conversation never leaks into the next."""
        self.current_plan = None

    def ask(self, question): ...

Bu, kendi uygulamanızla değiştirdiğiniz kısımdır: bir sohbet botu istemcisi, bir ajan oturumu, hizmetinize bir HTTP oturumu. Ne olursa olsun durumunun ve sıfırlanmasının sahibidir; Oloproof yalnızca bağdaştırıcının kaydettiğini görür.

Veri kümesi: senaryo girdidir

data/conversations.jsonl dosyasının bir satırı bir konuşmadır:

{"expected": {"plan": "enterprise"}, "id": "conv_00", "input": {"turns": ["What does the enterprise plan cost?", "Does that include SSO?"]}, "metadata": {"pattern": "pronoun_followup"}}

Kullanıcının turları veri kümesi içeriğidir; paketin özetine dahildir ve onlara karşı ölçülen her sistem için aynıdır; iki sistemi karşılaştırılabilir kılan budur. expected hakeme gösterilen referanstır. 40 konuşmanın 24'ü plan adı vermeyen bir takip sorusu içerir, 12'si planı her turda adlandırır ve 4'ü üç turun ikincisinde bir kişi ister.

Bağdaştırıcı

systems.py her vaka için yeni bir oturum başlatır, her senaryolu turu sırayla sorar ve geri geleni kaydeder:

from oloproof import CONVERSATION, current_case, system


def replay(case, *, remembers_plan):
    script = [str(turn) for turn in case["turns"]]
    session = PlanAssistant(remembers_plan=remembers_plan)  # a new session per case
    turns = []
    truncated = False
    for index, question in enumerate(script, start=1):
        try:
            reply = session.ask(question)
        except HandoffRequested:
            truncated = True  # the recording stops here and says so
            break
        turns.append({"index": index, "asked": question, "answer": reply["answer"]})
    current_case().artifact(
        CONVERSATION,
        {"turns": turns, "declared_turns": len(script), "truncated": truncated},
    )
    last = turns[-1]["answer"] if turns else None
    return {"answer": last, "turns_answered": len(turns)}


@system(name="plan-assistant", version="baseline", records=(CONVERSATION,))
def baseline(case):
    return replay(case, remembers_plan=False)


@system(name="plan-assistant", version="candidate-remembers-plan", records=(CONVERSATION,))
def candidate(case):
    return replay(case, remembers_plan=True)

Vaka başına yeni bir oturum önemlidir: Oloproof vakaları eşzamanlı ve sabit olmayan bir sırayla çalıştırır ve vakalar arasında paylaşılan bir oturum, bir konuşmanın durumunun diğerine sızmasına izin verirdi. records=, sistemin yapıtı kaydettiğini bildirir; bu olmadan konuşma değerlendiricileri, her vakayı eksik saymak yerine, hiçbir şey çalışmadan reddedilir.

conversation/v1 yapıtı

Temelin conv_00 için kaydettiği, oloproof export RUN_ID çıktısından (paketin cases.jsonl dosyası):

{"declared_turns": 2, "truncated": false, "turns": [{"answer": "The enterprise plan costs a price agreed per contract.", "asked": "What does the enterprise plan cost?", "index": 1, ...}, {"answer": "The starter plan does not include SSO.", "asked": "Does that include SSO?", "index": 2, ...}]}

Ve bir kişi isteyen bir konuşma için:

{"declared_turns": 3, "truncated": true, "turns": [{"answer": "The team plan costs $20 a month.", "asked": "What does the team plan cost?", "index": 1, ...}]}
AlanAnlamı
turns[].indexbunun hangi senaryolu turu yanıtladığı; 1'den başlayarak kesintisiz
turns[].answerasistanın döndürdüğü, herhangi bir JSON
turns[].askedisteğe bağlı, yalnızca okumak için; motor index üzerinden eşleştirir
turns[].retrievalisteğe bağlı, o turun getirdiği, retrieval/v1 biçiminde
declared_turnssenaryonun kaç tur bildirdiği
truncatedkayıt, onu neyin kestiğinden bağımsız olarak, senaryonun sonuna varmadan biter

Yapıt kaydedildiği anda denetlenir: bildirilenden daha az tur içeren bir kayıt truncated: true demelidir, indeksler kesintisiz olmalıdır ve bir kayıt sorulandan daha fazla turu yanıtlayamaz. Hatalı biçimli bir yapıt çalıştırmayı bir SystemContractError ile durdurur.

İki değerlendirici ve neden ikisi

  • ConversationCompleted deterministiktir: asistan her senaryolu turu yanıtladı mı? İlk o çalışır, çünkü üç turun birincisinde durmuş bir konuşma hakkındaki başka herhangi bir iddia, farklı bir konuşma hakkında bir iddiadır. Kesik bir konuşma ondan kalır; bu eksik bir vaka değil, bir sonuçtur.
  • ConversationJudge, tüm döküm üzerinde, her kullanıcı ve asistan turu üzerinde bir model hakemidir, çünkü bir konuşma ürününün suçlandığı başarısızlıklar ilişkiseldir: bir önceki turdaki yanıtla çelişen bir yanıt ancak onun yanında yanlıştır. Kesik bir konuşma kaydedilene göre değerlendirilir ve döküm hakeme nerede durduğunu söyler.
evaluators = [
    ConversationCompleted(),
    ConversationJudge(criterion="plan_coherent", provider=..., model=..., rubric_text=RUBRIC),
]

Çevrimdışı değerlendirme

Bir hakemin bir modele ihtiyacı vardır. Ağ olmadan çalışmak için judge_offline.py, Oloproof'un kendi testlerinin kullandığı yardımcıyla aynı olan senaryolu bir sağlayıcı verir (motorun iç yapısından FakeProvider, herkese açık API değil). Her hakem istemini sabit bir kuralla yanıtlar: her asistan turu referansın adlandırdığı planı adlandırdığında geçer. Bu, yargıları deterministik ve eğitimi yeniden üretilebilir kılar. Gerçek bir hakem modelin nasıl davrandığı hakkında hiçbir şey ölçmez.

Politika

release.yaml:

version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
rules:
  - {id: completion-floor, metric: conversation_completed, min: 0.75}
  - {id: coherence-floor, metric: plan_coherent, min: 0.80}

Çalıştırın

python evaluate.py
baseline run run_...
  conversation_completed: 0.900 [0.763, 0.972] over 40 conversations
  plan_coherent: 0.400 [0.249, 0.567] over 40 conversations
  gate BLOCK (exit 3)
  completion-floor: PASS (lower_bound_meets_minimum)
  coherence-floor: INSUFFICIENT_EVIDENCE (evaluator_not_validated)
  first failing conversation:
    conversation_completed: passed=True {'turns_recorded': 2, 'turns_declared': 2, 'truncated': False}
    plan_coherent: passed=False {'provider_model': 'offline-rule'}

Nasıl okunur:

  • Tamamlanma 40'ta 36'dır, dört devir. Alt sınırı 0.75'i aşar, bu yüzden o kural PASS'tir.
  • Tutarlılık %40'tır ve kuralı FAIL değil, evaluator_not_validated ile INSUFFICIENT_EVIDENCE gösterir. Bir hakemin kuralları, hakem insan etiketlerine karşı ölçülene kadar karar vermez (require_validated_evaluators varsayılan olarak açıktır; Hakemler bunu açıklar). Tahmin yine de gösterilir ve yine de kanıttır: yalnızca tek başına bir sürümü geçiremez ya da engelleyemez.
  • gate BLOCK (exit 3): politika INSUFFICIENT_EVIDENCE durumunda engeller. 3 çıkışı bir başarısızlık değil, o durumdur.

Çevrimdışı yedeği doğrulamak anlamsız olurdu, çünkü bu örnek için yazılmış bir kuraldır. Gerçek bir hakemle, çalıştırmadan bir örneklemi oloproof review RUN_ID --criterion plan_coherent --by YOU --sample 20 ile etiketleyin ve ardından oloproof evaluators validate EVALUATOR_ID --by YOU çalıştırın.

Başarısız bir konuşmayı inceleyin

SDK, CLI'ın okuduğu aynı depoya, çalıştırdığınız dizindeki .oloproof/ içine yazar:

oloproof inspect RUN_ID --case conv_00
output: {
  "answer": "The starter plan does not include SSO.",
  "turns_answered": 2
}
judgments:
  conversation_completed: passed
  plan_coherent: failed
    judge text, not verified:
      every answer is about enterprise: False

Kullanıcı enterprise planı sordu ve takip sorusu starter planı hakkında yanıtlandı. oloproof inspect RUN_ID --failures başarısız her konuşmayı listeler; plan adı içermeyen 24 takip sorusunun hepsi aynı biçimde başarısız olur. Sonraki eylem uygulamadadır: planı oturum durumunda tutun.

Bir aday değişiklik ve karşılaştırma

systems.py içindeki candidate, remembers_plan=True ayarlar. evaluate.py iki sistemi de aynı senaryolar üzerinde çalıştırır ve onları comparison.yaml altında vaka vaka karşılaştırır:

rules:
  - {id: coherence-better, kind: superiority, metric: plan_coherent}
  - {id: completion-no-worse, kind: non_inferiority, metric: conversation_completed, margin: 0.05}
comparison, candidate minus baseline
  conversation_completed: +0.000 [-0.127, +0.127] over 40 pairs
  plan_coherent: +0.600 [+0.337, +0.817] over 40 pairs
  gate BLOCK (exit 3)
  coherence-better: INSUFFICIENT_EVIDENCE (evaluator_not_validated)
  completion-no-worse: INSUFFICIENT_EVIDENCE (interval_overlaps_margin)

Tutarlılık farkı büyüktür ve aralığı sıfırı dışlar, ama hakem doğrulanmamıştır, bu yüzden kuralı hâlâ karar vermez. Tamamlanma değişmedi ve 40 çift onun beş puan içinde olduğunu gösteremez: aralık iki yöne de 12,7 puana uzanır. İkisi de aynı sonraki adımı gösterir: hakemi doğrulayın ve konuşma ekleyin.

Alternatif: kümeler olarak çözümlenen, vaka olarak turlar

Konuşma düzeyindeki bir hüküm, hangi turun yanlış gittiğini değil, bir konuşmanın ne sıklıkla iyi gittiğini söyler. Oloproof'un kaydedilmiş bir konuşma içinde tur düzeyinde bir metriği olmadığı için, diğer yol her turu kendi vakası yapmak ve bir konuşmanın turlarını group_id ile birbirine bağlamaktır:

{"expected": {"plan": "enterprise"}, "group_id": "conv_00", "id": "conv_00_t2", "input": {"history": ["What does the enterprise plan cost?"], "question": "Does that include SSO?"}}

Sistem senaryolu geçmişi yeni bir oturuma yeniden oynatır, sonra turu yanıtlar:

@system(name="plan-assistant-turns", version="baseline")
def turn_baseline(case):
    session = PlanAssistant(remembers_plan=False)
    for earlier in case["history"]:
        session.ask(str(earlier))
    return session.ask(str(case["question"]))

Bir konuşmanın turları bağımsız değildir, bu yüzden herhangi bir vakada group_id olduğu anda paket, bir politikanın kabul etmesi gereken yaklaşık bir yöntemle küme bazında çözümlenir (turns_release.yaml, allow_approximate_methods: true ayarlar; Kümelenmiş vakalar bunu açıklar):

turns as cases: turn_plan 0.667 [0.588, 0.749] over 72 turns
  gate BLOCK (exit 1)
  turn-plan-floor: FAIL (upper_bound_below_minimum)

Ödünleşim:

Konuşma başına bir vakaTur başına bir vaka, kümelenmiş
Oranın birimiiyi giden konuşmalardoğru yanıtlanan turlar
Etkin örneklem büyüklüğükonuşma sayısıturlar değil, yine konuşma sayısı
Hangi tur başarısız oldudökümü okuyunher turun kendi hükmü vardır
Her turun gördüğü geçmişasistanın kendi önceki yanıtlarısenaryonun önceki kullanıcı turları, yeniden oynatılmış
Kendi önceki yanıtlarının neden olduğu kaymayı yakalarevethayır, her tur senaryolu bir geçmişten başlar
DeğerlendiricilerConversationCompleted, ConversationJudge (yalnızca SDK)YAML'da ya da SDK'da herhangi bir değerlendirici

Tur alternatifi dört devir konuşmasını dışlar, bu yüzden 72 turu 36 konuşmadan gelir. Burada hakemin karar veremediği yerde karar verebilir, çünkü ExactMatch deterministiktir ve doğrulama gerektirmez.

İsteğe bağlı: canlı bir hakem model

Bu adım makinenizde sunulan bir model gerektirir. Çevrimdışı eğitim ya da testi tarafından çalıştırılmaz. Ollama çalışırken ve llama3.1 çekilmişken:

python evaluate.py --live

Hakem bu durumda provider="openai_compatible" ile http://localhost:11434/v1 adresini çağırır. Bir geri döngü sunucusu anahtar gerektirmez ve makineden hiçbir şey göndermez. Bir bulut sağlayıcısı ortamda anahtarını gerektirir, her dökümü o sağlayıcıya gönderir ve yargı başına para tutar. Gerçek bir modelin hükümleri yedeğinkinden farklıdır, bu yüzden yukarıdaki sayılar değişir ve siz onu doğrulayana kadar kuralları yine evaluator_not_validated gösterir.

Sorun giderme

BelirtiNeden ve çözüm
this evaluator needs exactly one conversation/v1 artifact; the case recorded 0Bağdaştırıcı current_case().artifact(CONVERSATION, ...) çağırmadı ya da ondan önce hata fırlattı. Konuşma erken dursa bile kaydedin.
malformed conversation/v1 artifact: ... 0 of 2 turns recorded and truncated is falseÇalıştırma bir SystemContractError ile durur. declared_turns değerinden daha az tur içeren bir kayıt truncated: true ayarlamalıdır.
conversation turn indexes must be contiguous starting at 1Turları yanıtladıkları senaryolu tura göre 1, 2, 3 diye numaralandırın.
evaluator 'conversation_completed' needs conversation/v1 artifacts, but system ... does not declare that it records them@system süsleyicisine records=(CONVERSATION,) ekleyin.
oloproof run çıktısında Input tag 'conversation_completed' found using 'type' does not match any of the expected tagsKonuşma değerlendiricileri yalnızca SDK'dadır. Buradaki gibi bir betik kullanın.
Yanıtlar konuşmalar arasında sızıyorBir oturum vakalar arasında paylaşılıyor. Vaka başına bir tane oluşturun.
Tutarlılık kuralları hiç karar vermiyorHakem doğrulanmamış. Onu doğrulayın ya da bilerek require_validated_evaluators: false ayarlayın.

Sınırlamalar

  • Kullanıcı benzeticisi yoktur: her kullanıcı turu veri kümesi senaryosundan gelir, bu yüzden konuşma asistanın söylediğine göre dallanamaz.
  • Kaydedilmiş bir konuşma içinde tur düzeyinde metrik yoktur; bunun yerine yukarıdaki ödünleşimle turları kümelenmiş vakalar olarak kullanın.
  • Konuşma yeniden oynatma yoktur: kaydedilmiş bir konuşma başka bir sisteme karşı yeniden çalıştırılamaz. İki sistemi karşılaştırmak, her birinin aynı senaryoyu yeniden oynaması demektir.
  • ConversationCompleted ve ConversationJudge yalnızca Python SDK'dadır.
  • Yalnızca metin: bir hakeme JSON metni gösterilir, asla görüntü ya da ses değil.
  • Çevrimdışı hakem senaryolu bir kuraldır. Hükümleri gerçek bir hakemin doğruluğunu değil, mekaniği gösterir.

Sonra nereye

  • Hakemler sağlayıcıları, doğrulamayı ve yeniden kalibrasyonu anlatır.
  • Kümelenmiş vakalar group_id ve yaklaşık yöntem onayını anlatır.
  • Python API'si evaluate ve evaluate_comparison fonksiyonlarını anlatır.
  • Ajanlar bir ajanın araç döngüsü için aynı sınırı anlatır.