Diagnozowanie i wzmacnianie adaptera potoku AI w .NET
Awarie produkcyjnego potoku AI w .NET nie wynikały wyłącznie z niepoprawnego JSON-a. Kilka odpowiedzi było poprawnych składniowo, ale nadal nie pasowało do kształtów oczekiwanych przez refleksję, deserializację lub walidację kontraktu. Ten artykuł przedstawia cały łańcuch awarii oraz zmiany w adapterze, które zweryfikowano na wdrożonym procesie roboczym.
Co łączyło awarie produkcyjne
Awarie pojawiały się na różnych etapach, ale łączył je problem na granicy systemu: odpowiedź dostawcy nie pasowała w sposób niezawodny do kształtu oczekiwanego przez adapter. Dotyczyło to indeksatora refleksji, listy zagnieżdżonych rekordów, kilku reprezentacji tablic, obiektów tam, gdzie wymagane były ciągi znaków, odgadywanych nazw pól oraz wartości wyliczenia spoza kontraktu.
Naprawa nie polegała na uznaniu JSON-a wygenerowanego przez dostawcę za wiarygodny tylko dlatego, że dało się go sparsować. Adapter musiał ograniczać kształt odpowiedzi i obsługiwać określone warianty, zanim doszło do walidacji kontraktu.
Awaria 1 — build-claims: refleksja wywołała indeksator listy
We wdrożonym procesie roboczym etap build-claims zakończył się błędem TargetParameterCountException. Refleksja wywołała PropertyInfo.GetValue dla indeksatora IReadOnlyList Item[Int32].
Indeksator jest właściwością, ale wymaga argumentu indeksu. Potraktowanie go jak zwykłej właściwości bez parametrów spowodowało awarię podczas odczytywania wyniku przez adapter.
Poprawka 1 — odfiltrowanie indeksowanych właściwości refleksji
Zweryfikowana poprawka odfiltrowywała właściwości refleksji, dla których GetIndexParameters().Length było większe od zera. Po tej zmianie etap build-claims zakończył się przy pierwszym podejściu.
Istotna granica jest wąska: właściwości wymagające parametrów nie mogą trafiać do tej samej ścieżki odczytu wartości co zwykłe właściwości. Jest to awaria specyficzna dla refleksji, niezależna od późniejszych awarii spowodowanych kształtem odpowiedzi dostawcy.
Awaria 2 — freeze-intent: deserializacja typowana odrzuciła listę zagnieżdżonych rekordów
Etap freeze-intent zakończył się błędem, gdy deserializacja typowana Microsoft.Extensions.AI przetwarzała zagnieżdżoną listę rekordów ResearchQuestion wewnątrz ResearchPlan. Zgłoszony problem polegał na tym, że pytania badawcze wymagały stabilnych identyfikatorów.
Awaria wystąpiła podczas przetwarzania kolekcji zagnieżdżonych rekordów. Nie był to ten sam mechanizm co w przypadku indeksatora refleksji: tutaj deserializacja typowana odrzuciła zagnieżdżoną strukturę rekordów, zanim etap mógł się zakończyć.
Poprawka 2 — użycie pobłażliwej ścieżki surowego tekstu dla wyników listowych
Zweryfikowana poprawka adaptera kieruje wyniki list i list zagnieżdżonych rekordów przez pobłażliwą ścieżkę surowego tekstu, zamiast polegać wyłącznie na deserializacji typowanej.
Ta ścieżka musi również uwzględniać reprezentacje odpowiedzi objęte regresją. Zweryfikowane przypadki obejmowały:
- Zwykłą tablicę.
- Tablicę opakowaną w obiekt.
- Tablicę umieszczoną w blokach kodu.
- Tablicę z nazwami właściwości w PascalCase.
Zweryfikowana poprawka usuwała bloki kodu i rozpakowywała dane zawierające pojedynczą właściwość. Operacje te obsłużyły ograniczony zakres kształtów odpowiedzi reprezentowany przez przypadki regresji, bez założenia, że każda odpowiedź listowa będzie dostarczana w dokładnie tej samej obudowie JSON.
Przypadki regresji dla tablic
Obsługa tablic wymaga własnej granicy regresji, ponieważ wynik listowy może zakończyć się błędem przed zwykłą walidacją kontraktu, jeśli adapter zakłada jedną obudowę. Regresja obejmowała zwykłe tablice, opakowane tablice, tablice w blokach kodu oraz tablice z nazwami w PascalCase.
Celem tych przypadków nie było dopuszczenie dowolnych danych wejściowych. Chodziło o zweryfikowanie konkretnej normalizacji wykonywanej przez adapter: usunięcia bloków kodu i rozpakowania danych zawierających pojedynczą właściwość, zanim wynik listowy przejdzie dalej pobłażliwą ścieżką surowego tekstu.
Awaria 3 — draft-article: w tablicach ciągów znaków pojawiły się obiekty
Etap draft-article zakończył się błędem, gdy dostawca zwrócił obiekty w tablicach sources i testedVersions, mimo że kontrakt wymagał zwykłych ciągów znaków.
Ta odpowiedź nadal mogła wyglądać jak poprawny JSON. Problemem był typ elementów. Kontrakt wymagał skalarnych ciągów znaków, a dostawca dostarczył obiekty.
Poprawka 3 — jawne określenie dokładnych kluczy i typów tablic skalarnych
Zweryfikowana poprawka dodała jawne wskazówki, że tablice skalarne mają zawierać wyłącznie ciągi znaków. Naprawiony etap draft-article zwracał testedVersions jako zwykłe ciągi znaków.
Adapter używał również dokładnych wskazówek dotyczących kluczy w camelCase, wyprowadzonych z nazw właściwości CLR. Wskazówki te naprawiły odpowiedzi dostawcy, który stosował odgadywane nazwy pól. Pisownia klucza i typ elementu tablicy to osobne ograniczenia: pierwsze określa nazwę właściwości, a drugie — czy każdy element tablicy jest ciągiem znaków, a nie obiektem.
Ograniczenia te powinny znaleźć się w instrukcji etapu wysyłanej do dostawcy. Nie należy pozostawiać ich w domyśle, gdy kontrakt po stronie odbiorcy wymaga dokładnych kluczy i skalarnych tablic.
Awaria 4 — triage: wymyślony kod przyczyny nie przeszedł walidacji wyliczenia
Etap triage odrzucił wymyślony przez model reasonCode, ponieważ wartość ta znajdowała się poza wyliczeniem w blog-editorial-decision.schema.json. Odrzucenie nastąpiło, zanim polityka mogła ją zastąpić.
Była to kolejna odrębna klasa awarii. JSON zawierał pole decyzji, ale jego wartość nie należała do dozwolonych wartości wyliczenia określonych w kontrakcie. Zastąpienie przez politykę nastąpiło więc zbyt późno w kolejności przetwarzania.
Poprawka 4 — normalizacja kodu przyczyny przed walidacją
Normalizacja reasonCode przez EditorialReasonPolicy przed walidacją kontraktu naprawiła awarię z nieprawidłową wartością wyliczenia.
Kolejność ma znaczenie. Kod przyczyny musi przejść przez etap normalizacji polityki, zanim walidator kontraktu sprawdzi wyliczenie. W przeciwnym razie wartość wygenerowana przez model, znajdująca się poza wyliczeniem, może zatrzymać przetwarzanie, zanim nastąpi jej zastąpienie przez politykę.
Zapytania zastępcze muszą mieć takie same ograniczenia
Po poprawce adaptera model zastępczy otrzymywał te same wzbogacone komunikaty co model główny.
Dzięki temu ograniczenia kształtu odpowiedzi pozostają spójne na obu ścieżkach. Jeśli tylko żądanie główne otrzyma dokładne klucze w camelCase, instrukcje dotyczące skalarnych tablic oraz pozostałe dodatkowe wskazówki, ścieżka zastępcza nadal może generować wcześniej nieobsługiwane kształty. Zweryfikowane rozwiązanie polegało na wysyłaniu tych samych wzbogaconych komunikatów do obu modeli.
Zweryfikowane ponowne uruchomienie
Po wprowadzeniu poprawek wcześniej kończące się błędem etapy zakończyły się przy pierwszych podejściach w zweryfikowanym ponownym uruchomieniu. Zestaw testów dymnych przeszedł pomyślnie w 24/24 przypadkach, a Payload E2E — w 4/4.
Wynik ten obejmuje łączne zmiany w adapterze: odfiltrowanie indeksowanych właściwości refleksji, kierowanie wyników list i list zagnieżdżonych rekordów przez pobłażliwą ścieżkę surowego tekstu, normalizację ograniczonych kształtów tablic, dodanie dokładnych wskazówek dotyczących kluczy i tablic skalarnych, normalizację reasonCode przed walidacją kontraktu oraz stosowanie tych samych wzbogaconych komunikatów wobec modelu zastępczego.
Komentarze (0)
Brak komentarzy.
Dodaj komentarz
Komentarze są publikowane po moderacji. Adres e-mail nie będzie widoczny publicznie.