Strona główna / Artykuły / Uwagi praktyczne: Inżynieria uprzęży: Nagi agent: Dlaczego twoja ramowa struktura oddaje kontrolę

Uwagi praktyczne: Inżynieria uprzęży: Nagi agent: Dlaczego twoja ramowa struktura oddaje kontrolę

Praktyczne wskazówki: Harness Engineering: The Naked Agent – dlaczego wasze ramy programistyczne umożliwiają stosowanie umów, sprawdzeń oraz gotowych fragmentów kodu dla zespołów wdrażających ten wzorzec.

2011 słów

Niech to służy jako wersja przeznaczona dla operatorów, zawierająca ujęcie idei z „Harness Engineering: The Naked Agent: Why Your Framework Hands You a Loop, Not a Harness — I”: wyraźne etapy, uporządkowane sekcje kodu oraz notatki dotyczące przywracania stanu, które przetrwają przeniesienie obowiązków.

Część 1: Pusty cykl agenta wydaje się potężny, dopóki nie trafi na rzeczywisty ruch. Oto dlaczego awarie w produkcji zwykle wynikają z braku odpowiedniego „ Harnessu” otaczającego model, a nie samego modelu.

Część 1: Pusty etap funkcjonuje najlepiej, gdy jest traktowany jako mierzalna powierzchnia do analizy. Zapisz jeden idealny przepływ operacji, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Zdokumentuj zarówno pomyślny, jak i awaryjny przebieg operacji. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Przydziel budżet tokenów na jeden ruch i jedną sesję. Narzędzia agentowe intensywnie rozszerzają kontekst; sztywne limity zapobiegają temu, by demonstracje przerodziły się w niespodziewane rachunki.

Większość awarii agentów nie jest winą modelu. Pochodzą one z braku odpowiedniej warstwy dyscypliny wokół niego. Oto jak wygląda agent AI bez żadnych ograniczeń w Claude Agent SDK i LangChain Deep Agents, oraz trzy konkretne sposoby, w jakie zawodzi on przy rzeczywistym obciążeniu.

Najlepiej traktować Most agent failures jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres badań. Wolij małe, testowalne jednostki nad rozbudowane skrypty. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Określ budżet tokenów na jeden ruch i sesję. Narzędzia agentowe intensywnie rozszerzają kontekst; sztywne limity zapobiegają temu, by demonstracje przerodziły się w niespodziewane rachunki.

Model nie jest zmienną

Model funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zanim rozszerzysz zakres, zapisz jeden udany przypadek, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć milczące, częściowe ukończenie zadań. Określ budżet tokenów na jeden ruch i na jedną sesję. Narzędzia typu agentic intensywnie rozszerzają kontekst; sztywne limity zapobiegają temu, by demonstracje przerodziły się w niespodziewane rachunki.

Co tak naprawdę oznacza „nagi” model

Model „What naked actually means stage” funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden przykład udanego działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy przechodzi się z środowiska demonstracyjnego do współdzielonych środowisk. Używaj narzędzi o wąskich schematach oraz z wyraźnymi etykietami opisującymi efekty uboczne. Hostowie muszą wiedzieć, które wywołania zmieniają stan, zanim automatycznie je zatwierdzą.

import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY
TOOLS = [
    {"name": "search_flights",
     "description": "Search flights between two cities for a date.",
     "input_schema": {"type": "object", "properties": {
         "origin": {"type": "string"}, "destination": {"type": "string"},
         "date": {"type": "string", "description": "YYYY-MM-DD"}},
         "required": ["origin", "destination", "date"]}},
    {"name": "book_flight",
     "description": "Book a specific flight.",
     "input_schema": {"type": "object", "properties": {
         "flight_id": {"type": "string"}, "passenger_name": {"type": "string"}},
         "required": ["flight_id", "passenger_name"]}},
]
def run_naked(user_msg: str) -> str:
    messages = [{"role": "user", "content": user_msg}]
    while True:                                   # ① no iteration cap
        resp = client.messages.create(
            model="claude-sonnet-4-6", max_tokens=1024,
            tools=TOOLS, messages=messages,
        )
        if resp.stop_reason != "tool_use":
            return resp.content[0].text
        call = next(b for b in resp.content if b.type == "tool_use")
        result = dispatch(call.name, call.input)
                                             # ② direct side effect, no check
        messages.extend([
                                             # ③ whole history, every turn
            {"role": "assistant", "content": resp.content},
            {"role": "user", "content": [{"type": "tool_result",
                "tool_use_id": call.id, "content": result}]},
        ])

Agent „naked” w Claude Agent SDK

Agen nagi w fazie testowej funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. 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. Używaj narzędzi o wąskich schematach i wyraźnych etykietach efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan, zanim automatycznie je zatwierdzą. Agen nagi w fazie testowej funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. Wolij małe, testowalne jednostki nad rozbudowane skrypty. Gdy jakiś krok się nie powiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji.

import asyncio
from claude_agent_sdk import (
    query, ClaudeAgentOptions, tool,
    create_sdk_mcp_server, AssistantMessage, ResultMessage,
)

@tool("search_flights", "Search flights between two cities for a date.",
      {"origin": str, "destination": str, "date": str})
async def search_flights(args):
                                              # ① no check that date exists
    hits = flights_api.search(**args)
    return {"content": [{"type": "text", "text": str(hits)}]}
@tool("book_flight", "Book a specific flight.",
      {"flight_id": str, "passenger_name": str})
async def book_flight(args):
                                               # ② destructive, ungated
    confirmation = flights_api.book(**args)
    return {"content": [{"type": "text", "text": confirmation}]}
server = create_sdk_mcp_server("travel", tools=[search_flights, book_flight])
async def main():
    options = ClaudeAgentOptions(
        mcp_servers={"travel": server},
        allowed_tools=["mcp__travel__search_flights",
                       "mcp__travel__book_flight"],
    )
    async for msg in query(prompt="Rebook this customer for March 32nd.",
                           options=options):
        if isinstance(msg, AssistantMessage):
            for b in msg.content:
                if hasattr(b, "text"):
                    print(b.text)
        elif isinstance(msg, ResultMessage):
            print("done:", msg.subtype)
                                              # ③ no state survives this run

Agen nagi w LangChain Deep Agents

Dla etapu „Nagi agent na scenie” 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 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 odrzuć ciche, częściowe ukończenie zadania. Zaloguj się przy bramie dostępu i ponownie udziel uprawnień na poziomie płaszczyzny danych. Sam token nie stanowi granicy między poszczególnymi usługami.

from langchain.tools import tool
from deepagents import create_deep_agent

@tool
def search_flights(origin: str, destination: str, date: str) -> str:
    """Search flights between two cities for a date (YYYY-MM-DD)."""
    return str(flights_api.search(origin, destination, date))
                                                # ① no date check
@tool
def book_flight(flight_id: str, passenger_name: str) -> str:
    """Book a specific flight."""
    return flights_api.book(flight_id, passenger_name)
                                                 # ② ungated side effect
agent = create_deep_agent(
                                                 # ③ the loop, no controls
    model="anthropic:claude-sonnet-4-6",
    tools=[search_flights, book_flight],
)
result = agent.invoke({"messages": [{"role": "user",
    "content": "Rebook this customer for March 32nd."}]})
print(result["messages"][-1].content)
# Ask a follow-up in a second invoke, and it starts from zero: no thread,
# no memory.

Zobacz, jak może się to zepsuć na trzy sposoby

Dla procesu nadzoru należy podzielić go na trzy etapy: zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zapisywać należy czas trwania oraz koszt tokena lub zapytania obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Autoryzować należy się przy bramie wejściowej, a ponownie udzielać uprawnień na poziomie warstwy danych. Sam token nie stanowi granicy między poszczególnymi użytkownikami.

Błąd 1: błędnie sformatowany argument trafia do destruktywnej funkcji

Dla przypadku Błędu 1, czyli nieprawidłowo sformatowanej etapy, należy zdefiniować dane wejściowe, osobę odpowiedzialną za tę etap oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić tę etap 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. Autoryzacja powinna odbywać się przy bramce, a ponowna autoryzacja – na poziomie przetwarzania danych. Sam token nośny nie stanowi granicy między poszczególnymi użytkownikami. Dla przypadku Błędu 1, czyli nieprawidłowo sformatowanej etapy, należy zdefiniować dane wejściowe, osobę odpowiedzialną za tę etap oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić tę etap od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy jakaś etap zawiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę przepływu danych.

book_flight(flight_id=”AC-PHANTOM”, passenger_name=”J. Moffatt”)
# -> “Booked.” The action fired. Nothing in the loop asked whether it should.

Błąd 2: kontekst ulega załamaniu, a jakość pogarsza się bez żadnych objawów

Gdy pracujesz nad fazą załamania kontekstu w Błędzie 2, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego błędu. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć możliwość cichego, częściowego ukończenia zadania. Zapisuj nazwę narzędzia, hash argumentów, czas reakcji oraz wynik każdej wywołania. Bez takich informacji debugowanie trwa godzinami.

Błąd 3: narzędzie popełnia błąd, a agent zgłasza sukces

Gdy pracujesz nad etapem narzędzia w przypadku błędu nr 3, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się przy częściowym błędzie. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisz czasy wykonywania oraz koszt tokena lub zapytania obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Zapisz nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdego wywołania. Bez takich informacji debugowanie pętli agenta marnuje godziny.

Kształt, który będzie przestrzegany przez każdą część

Gdy przechodzisz przez etap „The shape every part”, 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. 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. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdej wywołania. Bez takich informacji debugowanie zajmuje godziny. Gdy przechodzisz przez etap „The shape every part”, 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. Wolij małe, testowalne jednostki nad rozbudowane skrypty. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną sekwencję operacji.

Zrób to dziś

Etap „Zrób to dziś” funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia do pracy. Zapisz jeden idealny przykład realizacji, jeden przypadek niepowodzenia oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres pracy. 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ń. Używaj narzędzi o wąskich schematach i wyraźnych oznaczeniach efektów ubocznych. Osoby zarządzające muszą wiedzieć, które wywołania zmieniają stan systemu, zanim automatycznie je zatwierdzą.

Model to najłatwiejsza część

Model funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zanim rozszerzysz zakres, zapisz jeden udany przypadek działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian. Zapisz czasy wykonywania operacji oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy przechodzi się z środowiska demonstracyjnego do współdzielonych środowisk. Przydziel budżet tokenów na jeden ruch i na jedną sesję. Narzędzia typu agentic intensywnie rozszerzają kontekst; sztywne limity zapobiegają temu, by demonstracje przerodziły się w nieoczekiwane rachunki.

Karta kontrolna operacyjna

Podczas pracy nad etapem karty kontrolnej operacyjnej najpierw zapisz warunki umowy: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowej awarii. Taka karta zapewnia uczciwość późniejszych zmian w kodzie.

Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez człowieka oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później.

Zapisuj nazwę narzędzia logowania, hash argumentów, opóźnienie oraz wynik każdej wywołania. Debugowanie bez takiego śladu marnuje godziny.

Zachowuj stan grafu w prostej formie i z określonym typem danych. Wkładki nawarstwione utrudniają zidentyfikowanie, który węzeł zapisał dane do którego pola, i powodują przerwę w kontynuacji pracy po przerwach.

Gdy budżet na to pozwala, dodaj test sprawdzający kluczową ścieżkę w procesie CI przy użyciu fixitów, a nie żywych, płatnych API.

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.

Zanim wdrożysz całą architekturę, zamroź wersje oprogramowania, utwórz idealny zapis działań dla kluczowej ścieżki i potwierdź kroki odwracające zmiany. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji uprawnień oraz jasno określonego właściciela odpowiedzialnego za rotację haseł. Wolisz nudną niezawodność od pomysłowych, jednorazowych demonstracji.

Uwagi dotyczące partii 765280e2df21: unikaj przechowywania kluczy dostawcy w repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj transkrypcje obok plików testowych, aby późniejsze zmiany modeli pozostały porównywalne.