Strona główna / Artykuły / Sortuj bilety z Jevem, zastosuj jego reguły w Pythonie i pozostaw LLM.

Sortuj bilety z Jevem, zastosuj jego reguły w Pythonie i pozostaw LLM.

Krok po kroku instrukcja obsługi sortowania ticketów za pomocą Jev, stosowania zasad w Pythonie oraz wykorzystywania LLM: kontrakty, sprawdzanie warunków oraz miejsca na kod w projektach zespołów stosujących ten wzorzec.

2043 słów

Poniższe notatki przedstawiają praktyczne podejście do tematu „Sortowanie zleceń za pomocą Jev, stosowanie jego reguł w Pythonie oraz pozostawienie LLM do przygotowania odpowiedzi: konkretny przewodnik z NOVA”. Nacisk kładziony jest na umowy, sprawdzenia oraz miejsca na kod do wstawienia, a nie na motywacyjne aspekty. Podczas przechodzenia przez etap przeglądu najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć przypadki cichego, częściowego ukończenia zadania.

Jev nie zastępuje modelu, który pisze teksty

Jev nie zastępuje praktyk terenowych – działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden udany przypadek, jeden przypadek awarii oraz notatkę o cofnięciu zmian, zanim rozszerzysz zakres pracy. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych. Ustal stałe wartości interpretera oraz pliku blokującego zależności przed omawianiem pętli. Różnice między laptopem a środowiskiem CI to najczęstsza, niewidoczna awaria w demonstracjach API.

Architektura przed kodem

Architektura L avant le stage funkcjonuje najlepiej, gdy traktowana jest jako mierzalna powierzchnia. Zapisz jeden idealny przypadek, jeden przypadek awarii oraz notatkę o cofnięciu zmian, zanim rozszerzysz zakres. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustal interpreter oraz plik blokujący zależności przed nauczeniem pętli. Różnice między laptopem a środowiskiem CI to najczęstsza, niewidoczna usterka w demonstracjach API.

Message client + historique
            ↓
Jev : service, urgence, frustration
            ↓
Python : validation et règles métier
            ↓
Agent LangChain + LLM
            ↓
Consultation des commandes et procédures
            ↓
Dossier pour l’équipe support + brouillon de réponse

Przygotowanie środowiska

Faza przygotowywania środowiska działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przepływ działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Zdokumentuj zarówno pomyślny, jak i awaryjny przepływ działania. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Zabezpiecz interpreter oraz plik blokujący zależności przed rozpoczęciem pracy z pętlami. Różnice między laptopem a środowiskiem CI są najczęstszą przyczyną ukrytych awarii w demonstracjach API. Faza przygotowywania środowiska działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przepływ działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj przypadki częściowego ukończenia pracy bez informowania o tym.

TYPESAFE_API_KEY=ta_cle_typesafe
OPENAI_API_KEY=ta_cle_openai
JEV_MODEL=jev-latest
OPENAI_MODEL=gpt-4.1-mini
jev = TypeSafeClassifier(
    model=os.getenv("JEV_MODEL") or "jev-latest",
    timeout=30,
)
modele = ChatOpenAI(
    model=os.getenv("OPENAI_MODEL") or "gpt-4.1-mini",
    timeout=60,
    max_retries=1,
)

Trzy podstawowe elementy: Choice, Noul i Score

W fazie Les trois primitives Choice należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Obok wyników funkcjonalnych należy zapisywać czas trwania oraz koszt tokenów lub zapytań. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy oddzielić budowanie klienta od pętli komunikacji, aby można było zmieniać dostawców bez konieczności przepisywania maszyny stanu rozmowy.

Choice: wybór usługi

Aby wybrać usługę stażu, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Należy oddzielić budowę klienta od pętli komunikatów, aby można było zmieniać dostawców bez konieczności przepisywania automatu stanu rozmowy.

Noul : ocena pytania typu tak/nie

Dla etapu Noul valuer une question należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości nieodpowiednich stanowią część produktu, a nie elementy dodawane później. Należy oddzielić budowę klienta od pętli przekazywania wiadomości, aby można było zmieniać dostawców bez konieczności przepisywania maszyny stanów rozmowy. Dla etapu Noul valuer une question należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadania.

Punktacja: umiejscowienie frustracji na skali

Podczas przechodzenia przez etap ustalania punktacji i umiejscowienia frustracji, najpierw zapisz warunki kontraktu: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisz czas wykonywania oraz koszt tokena lub zapytania obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych. Zapisz ID żądania, ID modelu oraz opóźnienie przy każdym wywołaniu. Bez tego śladu przerywane błędy dostawcy wyglądają jak błędy aplikacji.

from langchain_typesafe import Choice, Noul, Score
def questions_triage():
    return {
        "service": Choice(
            instructions=(
                "Quel service doit traiter en priorité la dernière demande du client ? "
                "Utilise le contexte seulement pour comprendre cette demande."
            ),
            criteria={
                "livraison": "Retard, suivi ou réception d'une commande.",
                "facturation": "Paiement, facture ou remboursement.",
                "technique": "Panne ou utilisation d'un produit.",
                "autre": "Demande ambiguë ou sans rapport avec les catégories précédentes.",
            },
        ),
        "urgence": Noul(
            instructions=(
                "Les faits décrits nécessitent-ils une prise en charge immédiate, "
                "plutôt qu'un traitement normal ? Ne te fonde pas seulement sur le ton."
            )
        ),
        "frustration": Score(
            instructions="Quel niveau de frustration le client exprime-t-il ?",
            criteria=[
                "Le client s'exprime calmement, sans insatisfaction.",
                "Le client exprime une insatisfaction tout en restant mesuré.",
                "Le client exprime une forte colère ou des réclamations répétées.",
            ],
        ),
    }

Analiza pierwszego zgłoszenia

Gdy przechodzisz przez pierwszy etap tworzenia zgłoszeń w narzędziu Analyser, najpierw zapisz warunki umowy: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Zapisuj ID żądania, ID modelu oraz czas opóźnienia przy każdym wywołaniu. Bez tych informacji przerywane błędy dostawcy wyglądają jak błędy aplikacji.

reponse_jev = jev.invoke(requete_triage(ticket))
print("Service :", reponse_jev.choices["service"].choice)
print("Urgence :", reponse_jev.nouls["urgence"].noul)
print("Frustration sur 2 :", reponse_jev.scores["frustration"].score)
Service : livraison
Urgence : 0.76
Frustration sur 2 : 1.93

Zasady biznesowe pozostają w programie

Gdy przechodzisz przez etap Les r gles m, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Zapisuj ID żądania, ID modelu oraz opóźnienie przy każdej próbie połączenia. Bez tych informacji przerywane błędy dostawcy wyglądają jak błędy aplikacji. Gdy przechodzisz przez etap Les r gles m, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

def orienter_ticket(analyse, seuil_urgence=0.8, seuil_confiance=0.6):
    raisons = []
    if analyse["urgence"] >= seuil_urgence:
        raisons.append("urgence élevée")
    if analyse["frustration"] >= 1.5:
        raisons.append("forte frustration")
    if analyse["confiance_service"] < seuil_confiance:
        raisons.append("service incertain")
    if analyse["service"] == "autre":
        raisons.append("demande à clarifier")    return {
        "service": analyse["service"],
        "priorite": "haute" if analyse["urgence"] >= seuil_urgence else "normale",
        "revue_humaine": bool(raisons),
        "raisons": raisons or ["traitement courant"],
    }
{
  "service": "livraison",
  "priorite": "normale",
  "revue_humaine": true,
  "raisons": ["forte frustration"]
}

Dostarczanie NOVA informacji do przeglądania

Praca nad dostarczaniem informacji do NOVA funkcjonuje najlepiej, gdy traktuje się ją jako mierzalną powierzchnię. Zapisz jeden idealny przypadek, jeden przypadek awarii oraz notatkę o cofnięciu działań, zanim rozszerzysz zakres. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych. Zabezpiecz interpreter oraz plik blokujący zależności przed nauczeniem pętli. Różnice między laptopem a środowiskiem CI są najczęstszą ukrytą przyczyną awarii w demonstracjach API.

Konfigurowanie agenta LangChain

Agent Assembler w ramach LangChain funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia do analizy. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny haseł oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, aby operatorzy mogli je sprawdzić bez konieczności przeglądania całej struktury. Ustal stałe wartości interpretera oraz pliku blokującego zależności przed uruchomieniem pętli. Różnice między laptopem a środowiskiem CI są najczęstszą przyczyną ukrytych awarii w demonstracjach API.

def creer_agent(modele, analyse, orientation):
    contexte = json.dumps(
        {"analyse_jev": analyse, "orientation": orientation},
        ensure_ascii=False,
    )
    return create_agent(
        model=modele,
        tools=[consulter_commande, consulter_procedure],
        system_prompt=(
            ROLE_NOVA
            + "\nContexte de traitement fourni par le programme :\n"
            + contexte
        ),
    )

To, co pokazują testy w notatniku

The Ce que montrent les stage funkcjonuje najlepiej, gdy traktuje się je jako mierzalną powierzchnię. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę przywracania do stanu poprzedniego. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Zabezpiecz interpreter oraz plik blokujący zależności przed rozpoczęciem pracy z pętlami. Rozbieżności między laptopem a środowiskiem CI są najczęstszą przyczyną ukrytych awarii w demonstracjach API. The Ce que montrent les stage funkcjonuje najlepiej, gdy traktuje się je jako mierzalną powierzchnię. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj przypadki częściowego ukończenia bez żadnych komunikatów.

suivi = traiter_ticket(
    "Quel article contient cette commande ?",
    modele,
    jev,
    historique=dossier["messages"],
)
print(suivi["reponse"])

To, co zachowałbym przy prawdziwym projekcie

W fazie Ce que je garderais należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu.

Lista kontrolna operacyjna

W fazie Listy kontrolnej operacyjnej należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu.

Należy preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok zawiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji.

Należy oddzielić budowę klienta od pętli przekazywania wiadomości, aby można było wymieniać dostawców bez konieczności przepisywania maszyny stanu rozmowy.

Należy przechowywać w pamięci cache stabilne instrukcje systemowe oraz schematy narzędzi. Ponowne wysyłanie identycznego prefiksu jest częstą przyczyną marnotrawstwa zasobów.

Należy ustalić konkretne wersje zależności i zapisać hash obrazu użytego do demonstracji. Reprodukowalność jest ważniejsza od wiedzy przekazywanej ustnie wewnątrz zespołu.

Konfigurację należy trzymać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności analizowania całej struktury.

Zanim wdrożysz tę architekturę, zamroź wersje, utwórz dokładny zapis dla kluczowych etapów realizacji oraz potwierdź kroki odwracania zmian. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji przynależności użytkowników oraz wyraźnego właściciela odpowiedzialnego za rotację haseł. Wolimy nudną niezawodność od pomysłowych, jednorazowych demonstracji.

Uwaga dotycząca cf51dd985f5e: trzymaj klucze dostawcy poza repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj zapisy obok plików testowych, aby późniejsze zmiany modeli pozostały porównywalne.