Agenci zwrotów: LangGraph przetrwał tam, gdzie CrewAI i AutoGen upadły
Te same narzędzia i zasady we wszystkich trzech frameworkach — tylko wyraźny stan, idempotencja i punkty kontrolne przetrwały chaos.
Obciążenie pracy, które niszczy agenty demonstracyjne
Frameworki wieloagentowe wyglądają doskonale w demonstracjach badawczych i na blogach. Nie ma żadnego znaczenia, jeśli narzędzie uruchomi się dwa razy. Agent obsługujący zwroty pieniędzy nie jest tak wyrozumiały. Po otrzymaniu wiadomości od klienta musi sklasyfikować intencję, załadować zamówienie, ocenić zasady (okno czasowe, kategoria, wcześniejsze zwroty), wezwać bramkę płatności co najwyżej raz, gdy jest to możliwe, w przeciwnym razie zgłosić sprawę z pisemnym uzasadnieniem oraz pozostawić ślady audytowe.
Taka struktura jest powszechna w środowisku produkcyjnym: podjęcie decyzji, interakcja z systemami stanowymi oraz odpowiedzialność za działania. Wymaga trwałego przechowywania stanu na wszystkich etapach, deterministycznego rozgałęziania się między opcją zwrotu a eskalacją, efektów ubocznych o właściwościach idempotentnych oraz przerw dokonanych przez człowieka, które przetrwają restart procesu – a nie tylko krótkiego odpoczynku.
Trzy implementacje wykorzystywały te same narzędzia, model oraz logikę zasad. Tylko jedna przetrwała testy chaosowe, które powodowały przerwanie procesu w trakcie jego wykonywania.
Wspólne narzędzia
Zachowuj uczciwą walkę: identyczne funkcje narzędzi, w tym gateway flaky oraz klucz idempotencji powiązany z identyfikatorem zamówienia.
# tools.py — identical across all three implementations
import time
import uuid
from dataclasses import dataclass
from typing import Literal
class PaymentGatewayError(Exception):
pass
@dataclass
class Order:
order_id: str
customer_id: str
item_category: str
amount_cents: int
purchased_at: float
refund_count: int
# Fake DB — in prod this is Postgres behind a repository class
_ORDERS = {
"ORD-4471": Order("ORD-4471", "CUST-991", "electronics", 8999, time.time() - 86400 * 5, 0),
"ORD-2210": Order("ORD-2210", "CUST-102", "electronics", 4200, time.time() - 86400 * 45, 1),
}
_PROCESSED_REFUNDS: set[str] = set() # idempotency ledger
def get_order(order_id: str) -> Order | None:
return _ORDERS.get(order_id)
def check_refund_policy(order: Order) -> tuple[bool, str]:
days_since_purchase = (time.time() - order.purchased_at) / 86400
if days_since_purchase > 30:
return False, f"Purchase was {days_since_purchase:.0f} days ago, outside the 30-day window."
if order.refund_count >= 1:
return False, "Customer has already received a refund on this order."
return True, "Eligible: within window, no prior refund."
def issue_refund(order_id: str, idempotency_key: str) -> dict:
"""Calls the payment gateway. MUST be idempotent — retries are expected."""
if idempotency_key in _PROCESSED_REFUNDS:
return {"status": "already_processed", "idempotency_key": idempotency_key}
order = _ORDERS[order_id]
# simulate a flaky gateway — this matters later
if uuid.uuid4().int % 5 == 0:
raise PaymentGatewayError("gateway timeout, retry with same idempotency_key")
_PROCESSED_REFUNDS.add(idempotency_key)
return {"status": "refunded", "amount_cents": order.amount_cents, "idempotency_key": idempotency_key}
Idempotencja to nie dekoracja; to różnica pomiędzy frameworkiem agentów a zwykłą zabawką w postaci agenta.
CrewAI: mocne demonstracje, słaba kontrola
Modele CrewAI definiują role i zadania w ramach Crew. Prezentacje produktowe uwielbiają metaforę schematu organizacyjnego.
Wzorzec naiwny
from crewai import Agent, Task, Crew, Process
from crewai.tools import tool
@tool("Get Order")
def get_order_tool(order_id: str) -> str:
"""Fetch order details by ID."""
order = get_order(order_id)
return str(order) if order else "NOT_FOUND"
@tool("Check Policy")
def check_policy_tool(order_id: str) -> str:
"""Check refund eligibility for an order."""
order = get_order(order_id)
if not order:
return "NOT_FOUND"
eligible, reason = check_refund_policy(order)
return f"eligible={eligible}, reason={reason}"
@tool("Issue Refund")
def issue_refund_tool(order_id: str) -> str:
"""Issue a refund for an order."""
result = issue_refund(order_id, idempotency_key=f"refund-{order_id}")
return str(result)
triage_agent = Agent(
role="Refund Triage Specialist",
goal="Decide whether a customer refund request should be approved or escalated",
backstory="You are an experienced support agent who follows policy strictly.",
tools=[get_order_tool, check_policy_tool, issue_refund_tool],
verbose=True,
)
triage_task = Task(
description="A customer says: '{customer_message}'. Order ID: {order_id}. "
"Decide if this qualifies for a refund and act accordingly.",
expected_output="A short summary of the action taken.",
agent=triage_agent,
)
crew = Crew(agents=[triage_agent], tasks=[triage_task], process=Process.sequential)
result = crew.kickoff(inputs={"customer_message": "I want a refund, item broke", "order_id": "ORD-4471"})
Szlaki realizacji wyglądają dobrze. Jako usługa zawiodła na trzy sposoby. Kolejność wykorzystywanych narzędzi była niedeterministyczna – czasami issue_refund wykonywano przed check_policy, ponieważ model łączył elementy narzędzi w sposób losowy. Próby ponownego wykonania po wystąpieniu błędu PaymentGatewayError mogły prowadzić do wywołania nowych funkcji narzędzi i użycia nowych kluczy, chyba że narzędzie miało zaimplementowaną bezpieczną strukturę działania. Funkcja kickoff() wykonywała się do końca bez żadnej przerwy wprowadzonej przez człowieka; fałszywe kontynuowanie pracy wymagało odbudowy stanu poza ramami frameworka.
Zaostrzona hierarchiczna struktura prób
manager_agent = Agent(
role="Refund Process Manager",
goal="Enforce strict order: lookup, then policy check, then refund or escalate. Never skip steps.",
backstory="You strictly enforce process compliance and never let steps be skipped.",
allow_delegation=True,
)
crew = Crew(
agents=[triage_agent],
tasks=[triage_task],
process=Process.hierarchical,
manager_agent=manager_agent,
)
Agenty zarządzające oraz wyraźniejsze instrukcje zmniejszyły liczbę pomijanych kroków, ale nie stworzyły żadnych sztywnych zasad. Język naturalny nie może zapewnić sekwencji działania na poziomie wymaganym w kontekście przestrzegania regulacji. CrewAI nadaje się do elastycznej gry ról – najpierw badanie, potem krytyka – a nie do sekwencji związanych bezpośrednio z procesem płatności.
AutoGen: elastyczna rozmowa, nieprecyzyjna kontrola
Rozmowa grupowa z automatycznym wybieraniem mówcy dodaje przy każdej tury połączenie z modelem językowym, aby wybrać osobę, która będzie mówić.
import autogen
config_list = [{"model": "gpt-4o", "api_key": "..."}]
llm_config = {"config_list": config_list, "temperature": 0}
triage_agent = autogen.AssistantAgent(
name="TriageAgent",
system_message=(
"You triage refund requests. Look up the order, check policy, "
"then either call issue_refund or hand off to EscalationAgent."
),
llm_config=llm_config,
)
escalation_agent = autogen.AssistantAgent(
name="EscalationAgent",
system_message="You write a human-readable escalation note explaining why a refund needs manual review.",
llm_config=llm_config,
)
user_proxy = autogen.UserProxyAgent(
name="ToolExecutor",
human_input_mode="NEVER",
code_execution_config=False,
function_map={
"get_order": lambda order_id: str(get_order(order_id)),
"check_refund_policy_tool": lambda order_id: str(check_refund_policy(get_order(order_id))),
"issue_refund": lambda order_id: str(issue_refund(order_id, f"refund-{order_id}")),
},
)
groupchat = autogen.GroupChat(
agents=[user_proxy, triage_agent, escalation_agent],
messages=[],
max_round=10,
speaker_selection_method="auto", # an LLM call decides who speaks next
)
manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config)
user_proxy.initiate_chat(manager, message="Customer wants a refund on ORD-2210, item broke on arrival.")
Błędy: pętle konwersacyjne między etapem triażu a eskalacją bez ustrukturyzowanego stanu „już zdecydowano” — tylko transkrypcje — co zmuszało do stosowania sztywnych ograniczeń max_round. Pytanie „Czy zwróciliśmy pieniądze?” było rozpatrywane poprzez analizę tekstu. Niedeterministyczność kształtowała cały graf wykonywania, więc incydenty były odtwarzane na podstawie dzienników rozmów, a nie zapisanych śladów działań.
LangGraph: ten, który przetrwał
Ustrukturyzowany stan, wyraźne krawędzie, mechanizmy kontrolne oraz próby ponownego wykonania odpowiadały charakterowi problemu.
from typing import TypedDict, Literal, Optional
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.types import interrupt, Command
import uuid
class RefundState(TypedDict):
order_id: str
customer_message: str
order: Optional[dict]
eligible: Optional[bool]
policy_reason: Optional[str]
decision: Optional[Literal["refund", "escalate", "denied"]]
refund_result: Optional[dict]
audit_log: list[str]
def lookup_order_node(state: RefundState) -> RefundState:
order = get_order(state["order_id"])
log = state["audit_log"] + [f"Looked up {state['order_id']}: {'found' if order else 'not found'}"]
if not order:
return {**state, "decision": "escalate", "audit_log": log}
return {**state, "order": order.__dict__, "audit_log": log}
def policy_check_node(state: RefundState) -> RefundState:
order = Order(**state["order"])
eligible, reason = check_refund_policy(order)
log = state["audit_log"] + [f"Policy check: eligible={eligible}, reason={reason}"]
return {**state, "eligible": eligible, "policy_reason": reason, "audit_log": log}
def route_after_policy(state: RefundState) -> str:
# Plain Python. No LLM call decides this branch. This is the whole point.
if state.get("decision") == "escalate":
return "escalate"
return "refund" if state["eligible"] else "escalate"
def human_approval_node(state: RefundState) -> RefundState:
# Durable pause: this literally suspends the graph run and persists state
# via the checkpointer. It can resume hours or days later, across restarts.
decision = interrupt({
"reason": "Ambiguous or ineligible refund needs human sign-off",
"order": state["order"],
"policy_reason": state["policy_reason"],
})
return {**state, "decision": decision, "audit_log": state["audit_log"] + [f"Human decision: {decision}"]}
def issue_refund_node(state: RefundState) -> RefundState:
idempotency_key = f"refund-{state['order_id']}" # stable across retries — this is the whole trick
try:
result = issue_refund(state["order_id"], idempotency_key)
except PaymentGatewayError as e:
# LangGraph re-raises into the node; retry policy (below) handles this,
# and because the key is stable, a retried call is safe.
raise
log = state["audit_log"] + [f"Refund issued: {result}"]
return {**state, "decision": "refund", "refund_result": result, "audit_log": log}
def escalate_node(state: RefundState) -> RefundState:
log = state["audit_log"] + ["Escalated to human queue"]
return {**state, "audit_log": log}
from langgraph.pregel.retry import RetryPolicy
graph = StateGraph(RefundState)
graph.add_node("lookup_order", lookup_order_node)
graph.add_node("policy_check", policy_check_node)
graph.add_node(
"issue_refund",
issue_refund_node,
retry=RetryPolicy(max_attempts=3, retry_on=PaymentGatewayError),
)
graph.add_node("human_approval", human_approval_node)
graph.add_node("escalate", escalate_node)
graph.set_entry_point("lookup_order")
graph.add_edge("lookup_order", "policy_check")
graph.add_conditional_edges("policy_check", route_after_policy, {
"refund": "issue_refund",
"escalate": "human_approval",
})
graph.add_edge("human_approval", "issue_refund") # human can still approve
graph.add_edge("issue_refund", END)
graph.add_edge("escalate", END)
checkpointer = SqliteSaver.from_conn_string("refunds.db")
app = graph.compile(checkpointer=checkpointer)
Konfiguracje wątków są przywracane po awariach:
config = {"configurable": {"thread_id": "order-2210-refund-req"}}
# Kick off the run — it will pause at human_approval_node
result = app.invoke(
{"order_id": "ORD-2210", "customer_message": "second refund please", "audit_log": []},
config=config,
)
# result contains an interrupt payload; the process can now exit entirely.
# ... hours later, possibly a different process, different machine ...
final_result = app.invoke(Command(resume="escalate"), config=config)
Testy deterministyczne potwierdzają, że niekwalifikujące się zamówienia są eskalowane:
def test_ineligible_order_escalates():
state = {"eligible": False, "decision": None}
assert route_after_policy(state) == "escalate"
def test_eligible_order_refunds():
state = {"eligible": True, "decision": None}
assert route_after_policy(state) == "refund"
Zabieg eliminacji chaosu polegał na zatrzymaniu procesu w trakcie zwrotu pieniędzy i ponownym uruchomieniu go na podstawie punktu kontrolnego z tą samą kluczem identyfikacyjną. To właśnie ten test zadecydował o wyniku konkursu.
Kiedy CrewAI lub AutoGen nadal wygrywają
CrewAI służy do wspólnej pracy nad projektem z elastycznym zarządzaniem kolejnością zadań. AutoGen jest przeznaczony do eksploracyjnych badań wielu agentów, gdzie rozmowa stanowi sam produkt. Żaden z nich nie zastępuje maszyny stanów, gdy chodzi o finanse.
Lekcja
Dostosuj poziom abstrakcji do możliwych błędów. Jeśli niewłaściwa kolejność narzędzi lub podwójne skutki uboczne są nie do przyjęcia, lepiej wybrać wyraźne grafy z trwałym stanem niż zespoły oparte na promptach. Frameworki nie są wymiennymi „skorupami” nad agentami; one kodują różne założenia dotyczące kontroli, pamięci i odzyskiwania.
List kontrolny przed rozpoczęciem produkcji po konkursie
Zanim wdrożysz jakikolwiek mechanizm przypominający zwrot pieniędzy, upewnij się co do następujących kwestii: stan wpisany z flagą already_refunded (lub równoważną); klucze idempotencji wygenerowane na podstawie identyfikatorów biznesowych; sprawdzania polityk realizowane jako węzły kodu, a nie sugestie wyświetlane w interfejsie; przerwy HITL umieszczone za punktem kontrolnym; testy chaosowe powodujące zatrzymanie procesów podczas występowania efektów ubocznych; logi audytowe, które nie polegają na analizie tekstu za pomocą narzędzi typu grep. Jeśli framework nie może zapewnić tych właściwości bez dodatkowego silnika zarządzania procesami, to właśnie ten silnik jest rzeczywistym koordynatorem – a framework stanowi jedynie kosztowny „klej” łączący poszczególne elementy.
Mierz różne wskaźniki awarii w środowisku testowym: pominięte polityki, podwójne próby zwrotu pieniędzy, utracone przerwy po ponownym uruchomieniu oraz nieczytelne logi audytowe. Prototypy Crew i AutoGen, które nie są w stanie przewyższyć LangGraph pod względem tych wskaźników, powinny pozostać w laboratorium. Ciesz się z ich wycofania – niekontrolowany rozwój ma swoje koszty.
Zapisz decyzję dla przyszłych zespołów, aby kolejne konkursy nie były konieczne. Umieść link do dokumentacji w pliku README. Wolimy nudne wykresy, które przetrwają każdą próbę zniszczenia, niż pomysłowe rozmowy, które przetrwają tylko podczas demonstracji. Ten standard ma zastosowanie nie tylko do zwrotów pieniędzy, ale także do każdego agenta, który modyfikuje zewnętrzne systemy pod presją audytu – co jest właśnie tym, czego firmy faktycznie oczekują od „agentów AI”, gdy skomplikowane narzędzia znikną, a księgowość znów będzie miała rzeczywiste znaczenie co kwartał.
Łączenie niepowodzeń z założeniami frameworku
CrewAI zakłada elastyczną dekompozycję zadań. AutoGen zakłada, że rozmowa stanowi wystarczający mechanizm sterowania. LangGraph zakłada, że to ty samodzielnie zaprojektujesz płaszczyznę sterowania. Automatyzacja zwrotów pieniędzy narusza pierwsze dwa założenia: kryteria uprawniające do zwrotu nie podlegają negocjacjom, a wybór mówcy nie jest mechanizmem autoryzacji płatności. Gdy założenia kolidują z zasadami danej dziedziny, wygrywa framework posiadający mniej założeń – nawet jeśli w pierwszym tygodniu wydaje się mniej „cudowny”.
Inżynierowie czasami próbują „naprawić” CrewAI lub AutoGen, używając coraz dłuższych instrukcji systemowych. To tak, jakby traktować ogrodzenie przeciw cyklonom jako drzwi sejfu. Przenoś wymogi zgodności do węzłów tekstowych i trzymaj modele językowe w węzłach odpowiedzialnych za klasyfikację lub tworzenie treści, a nie w tych, które decydują o przekazywaniu pieniędzy.
Wspólne wymagania dotyczące obserwowalności
Niezależnie od wyboru, należy generować informacje o każdej wywołanej funkcji z identyfikatorem kolejki, kluczem idempotencji oraz wynikiem decyzji polityki. Bez tego dyskusje w ramach frameworka przybierają charakter religijny, podczas gdy produkcja pozostaje bez informacji. LangGraph ułatwił zrozumienie tych mechanizmów, ponieważ węzły są funkcjami; można zastosować tę samą dyscyplinę w innych miejscach, ale konkurs pokazał, że jest to najprostsza droga do rozwiązania tego typu zadań.
Zakończenie
Niech agent, który stworzysz, odpowiada sposobowi awarii twojego systemu. W przypadku zwrotów pieniędzy takim agentem byłby graf z pamięcią, a nie zespół ludzi. Zachowaj pozostałe narzędzia do problemów, do których faktycznie pasują, i przestań udawać, że jedna abstrakcja może rozwiązać każdy zgłoszenie w kolejce.
Omówienie struktury LangGraph, która się sprawdziła
Udały się projekt grafu, który utrzymywał kategoryzację, pobieranie danych, politykę, zwrot pieniędzy, eskalację oraz audyt jako oddzielne węzły. Krawędzie reprezentowały jedynie dozwolone przejścia prawne. Model nigdy nie decydował o pominięciu polityki; jedynie wypełniał ustrukturyzowane pola, które interpretował kod polityki. Ponowne próby w węźle bramy wykorzystywały tę samą klucz identyczności przechowywaną w stanie. Eskalacja polegała na użyciu funkcji interrupt() wraz z wskaźnikiem stanu, aby menedżer mógł zatwierdzić decyzję kilka godzin później na innej replice.
Taki projekt wydaje się zbyt rozbudowany w porównaniu z definicją zespołu składającego się z trzech agentów. Właśnie ta rozbudowa jest celem: każdy nieodwracalny krok może zostać nazwany podczas przeglądu kodu. Nowi inżynierowie mogą przeczytać graf i przewidzieć zachowanie, bez konieczności ponownego odtwarzania dziesięciu losowych rozmów.
Porównanie procedur reagowania na incydenty
Gdy CrewAI wykonał podwójne użycie narzędzia w fazie przygotowawczej, analiza przyczyn wskazała na „odchylenie promptu”. Gdy AutoGen utknął w pętli, przyczyną określono „wybór mówcy”. Gdy LangGraph zawiodł, analiza wskazała na konkretny węzeł oraz brak elementu redukcyjnego – problem ten dało się naprawić bez dyskusji na temat atmosfery. Samą już taksonomię incydentów wystarczyło, by uzasadnić wybór procesu pracy związанego z płatnościami.
Uwagi dotyczące kosztów i opóźnień z konkursu
Model LLM do obsługi mówcy w AutoGen zwiększał opóźnienia i liczbę tokenów. Ponawiane próby CrewAI czasami powodowały mnożenie się wywołań narzędzi. LangGraph generował niewielkie stałe koszty związane z zapisywaniem punktów kontrolnych, ale wyróżniał się przewidywalnością wydatków. Przy tysiącach zapytań dziennie przewidywalność jest ważniejsza niż sporadyczne oszczędności.
Umiejętności zespołu i rekrutacja
Zatrudnianie osób z doświadczeniem w „CrewAI” jest rzadsze niż zatrudnianie tych, którzy znają „maszyny stanowe w połączeniu z LLM”. Umiejętności związane z LangGraph można przenieść na dowolnego orkiestratora. Jeśli firma standardyzuje rozwiązania, lepiej wybierać przenoszone pojęcia: stan, idempotencja, HITL, ewaluacje. Cykle rozwoju frameworków są szybsze od tych pojęć.
Rozszerzanie zestawu narzędzi do radzenia sobie z chaosem
Poza prostym restartowaniem: należy uwzględnić błędy 503 w bramkach, podwójne dostawy webhooków, rozbieżności czasowe w ramach okien polityk oraz ludzi, którzy odrzucają prośby o eskalację. Grafy, które funkcjonują tylko na „szczęśliwej ścieżce”, pozostają jedynie zabawkami. Należy zautomatyzować ten zestaw narzędzi w procesie CI przy użyciu deterministycznych symulacji, aby modyfikacje nie mogły potajemnie usunąć mechanizmów bezpieczeństwa.
Miękkie lądowanie prototypów
Zachowaj środowiska testowe CrewAI/AutoGen do procesów pracy z treściami przy udziale ludzkich redaktorów. Nie blokuj eksperymentowania – blokuj jedynie uprawnienia do produkcji. Polityka platformy zakazująca używania narzędzi płatniczych w zespołach sterowanych promptami zapobiega kolejnym niemalym incydentom, nie hamując przy tym ciekawości.
Ostateczne podkreślenie
Twierdzenie artykułu jest precyzyjne i mocne: w przypadku automatyzacji zwrotów pieniędzy z rzeczywistymi skutkami ubocznymi LangGraph funkcjonował, podczas gdy CrewAI i AutoGen nie były w stanie tego zrobić, mimo identycznych narzędzi. Trzeba ostrożnie dokonywać wywodów. Można natomiast swobodnie zastosować meta-lekcję – oceniać ramy robocze pod kątem swoich możliwych błędów, a nie pod kątem estetyki demonstracji – i wtedy całe to przedsięwzięcie było warte tygodnia, który pochłonęło.
Szczegółowy harmonogram błędów od etapu testowego
Pierwszy tydzień: demonstracja CrewAI zaimponowała interesariuszom. Drugi tydzień: dwa próby podwójnego zwrotu pieniędzy w środowisku testowym po awariach bramy płatności. Trzeci tydzień: system AutoGen zużywał tokeny podczas powtarzanych prób realizacji zamówień odrzuconych. Czwarty tydzień: mechanizm zarządzania chaosem w LangGraph uruchomił procedurę natychmiastowego zwrotu pieniędzy. Kalendarz jest ważny, ponieważ dynamika organizacyjna często zatrzymuje się po pierwszej demonstracji; należy odnotować chronologię niepowodzeń w dokumencie ADR, aby dynamika nie mogła usunąć dowodów.
Idempotencja jako wymóg przekrojowy
Każda tu sprawdzona platforma potrafi korzystać z narzędzi. Tylko takie rozwiązania, które przy każdej próbie używają tej samej stabilnej klucza, są bezpieczne przy transakcjach płatniczych. Klucz należy przechowywać w stanie grafu przed pierwszą próbą. Odrzucaj tworzenie nowego klucza w węzłach powtarzających próby. Rejestruj razem klucz, identyfikator zamówienia oraz kody odpowiedzi bramy płatności. Jeśli platforma utrudnia to zadanie, ta trudność jest sygnałem, a nie problemem administracyjnym.
Ergonomia eskalacji do ludzi
Tekst dotyczący eskalacji musi zawierać identyfikatory klauzul polisy, daty zleceń oraz liczbę wcześniejszych zwrotów pieniędzy — musi być zbudowany według określonej struktury, a nie tylko jako swobodny tekst. Menedżerowie powinni widzieć te same pola, które widział węzeł polisy. LangGraph ułatwia to, ponieważ stan jest reprezentowany jako TypedDict; Crew/AutoGen wymagały odtwarzania faktów z transkrypcji, co powoduje pojawianie się luk w audycji.
To, co zachowaliśmy z rozwiązań nieudanych
Metafory ról w CrewAI pomagały w rozmowach dotyczących produktu — przekształcono je w nazwy węzłów LangGraph. Wyraźna lista agentów w AutoGen sprzyjała jaśniejszemu określeniu odpowiedzialności za narzędzia przy każdym węźle. Dozwolone jest kradzież pomysłów z interfejsu użytkownika przy jednoczesnym odrzuceniu niebezpiecznych mechanizmów sterowania.
Rozszerzona lista kontrolna produkcji
- Chaos: awarie podczas używania narzędzia, podczas oczekiwania na przerwę oraz podczas prób ponownych.
- Testy właściwości: elementy niekwalifikujące się nigdy nie docierają do węzła zwrotu pieniędzy.
Dlaczego „po prostu dodanie kolejnego agenta” nie zadziałało
Dodanie agenta „PolicyEnforcer” w CrewAI nadal sprawiało, że egzekwowanie reguł było probabilistyczne. Dodanie „RefundGuardian” w AutoGen nadal funkcjonowało w ramach czatu. Guardiany, które nie mogą radykalnie zablokować połączeń, są jedynie dekoracjami. Radykalne blokowanie powinno być częścią topologii grafu.
Zakończenie
To same narzędzia, ten sam model, ale inna filozofia sterowania. Tylko wyraźny graf przetrwał błędy istotne dla zwrotów pieniędzy. Używaj zespołów i czatów tam, gdzie błędny porządek jest mało kosztowny; używaj grafów tam, gdzie błędny porządek stanowi zdarzenie w księgowej ewidencji. Opublikuj tę zasadę wewnętrznie i oszczędź następnemu zespołowi czterotygodniowego konkursu.
Dodatkowe uwagi dotyczące wzmocnienia bezpieczeństwa grafów zwrotów
Okna polityki zależne od zegarów muszą wykorzystywać czas serwera przechowywany podczas pobierania danych, a nie daty określone w modelu. Sprawdzanie kategorii powinno być realizowane poprzez określenie przynależności w kodzie. Liczby wcześniejszych zwrotów pochodzą z księgowej ewidencji, a nie z pamięci czatu. Każda z tych decyzji eliminuje pewien typ prób iniekcji poleceń, które mają na celu przepisanie kryteriów przyznawania zwrotów w języku naturalnym. Grafy sprawiają, że te decyzje są oczywiste; zespoły natomiast ukrywają je w historiach agentów, gdzie recenzenci przestają ich sprawdzać.