Human-in-the-loop: co gdy agent nie może kontynuować sam
- data
- kategoria
- AI Agents
- także w
- Automation · Engineering Practices
- czytanie
- 3 min / 606 słów
Do tej pory zakładaliśmy prosty scenariusz:
Jira task
|
v
Implementer Agent
|
v
repo
|
v
implementation
|
v
tests
|
v
PR
W praktyce agent nie zawsze będzie w stanie przejść cały flow samodzielnie.
Nie dlatego, że „nie wie, co zrobić” technicznie.
Czasem dochodzi do miejsca, w którym dalsza decyzja wymaga informacji, której nie ma w repo, RAG ani tickecie, albo decyzji, której organizacja celowo nie chce delegować modelowi.
Przykład.
Ticket mówi:
PAY-123
Add automatic retry for failed payment provider calls.
Acceptance criteria:
- retry transient failures
- maximum 3 attempts
- add metrics
Agent analizuje kod i dokumentację i zauważa, że obecny system traktuje timeout po wysłaniu żądania płatności jako stan niejednoznaczny.
Ponowienie requestu może potencjalnie utworzyć drugą płatność.
W takim przypadku agent nie powinien sam zdecydować:
"pewnie retry będzie OK"
Powinien się zatrzymać i zapytać:
Provider może przy timeout zwrócić nieznany wynik operacji, a ponowienie requestu bez idempotency key może utworzyć drugą płatność. Czy w tym tasku mamy najpierw dodać obsługę idempotency key, czy timeoutów nie obejmujemy retry?
To jest właśnie human-in-the-loop.
Agent przechodzi w stan oczekiwania
Flow zmienia się z:
RUNNING
|
v
DONE
na:
RUNNING
|
v
NEEDS_INPUT
|
v
WAITING_FOR_HUMAN
|
v
RUNNING
|
v
DONE
Przed zatrzymaniem agent zapisuje checkpoint.
Na przykład:
{
"issue": "PAY-123",
"repository": "payments-service",
"branch": "agent/PAY-123",
"step": "implementation",
"status": "waiting_for_input",
"question": "Provider może przy timeout zwrócić nieznany wynik operacji, a retry bez idempotency key może utworzyć drugą płatność. Czy najpierw dodajemy idempotency key, czy timeoutów nie obejmujemy retry?"
}
Dzięki temu po odpowiedzi człowieka nie musi zaczynać taska od początku.
Gdzie trafia pytanie
Najprostszy wariant w naszym flow to Jira.
Agent może dodać komentarz:
Implementer Agent needs input
Provider may return an unknown result after timeout.
Retrying without an idempotency key can create a duplicate payment.
Decision required:
1. Add idempotency support in this task.
2. Exclude timeout from retry scope.
Ticket może jednocześnie przejść do statusu:
Waiting for input
Inne możliwości:
- Teams,
- Slack,
- pull request comment,
- dedykowany panel do obsługi agentów,
- approval task w pipeline.
Mechanizm jest drugorzędny.
Najważniejsze jest to, że agent generuje jawny event:
human input required
Jak agent wraca do pracy
Człowiek odpowiada:
Timeoutów nie retryujemy w tym tasku.
Retry tylko dla jawnych odpowiedzi 5xx.
Idempotency będzie osobnym taskiem.
Odpowiedź generuje kolejny event:
Jira comment / status change
|
v
resume trigger
|
v
agent runtime
|
v
load checkpoint
|
v
continue
Agent odzyskuje:
ticket
repo
branch
current step
previous decisions
human answer
i kontynuuje:
exclude timeout retries
|
v
implement retry for 5xx
|
v
tests
|
v
PR
Dlaczego state jest tutaj potrzebny
To właśnie jeden z najbardziej praktycznych powodów posiadania state.
Bez checkpointu po odpowiedzi człowieka agent musiałby odtworzyć wszystko:
pobierz Jira
|
v
clone repo
|
v
przeanalizuj kod
|
v
odtwórz poprzedni tok pracy
|
v
spróbuj zrozumieć, czego dotyczyła odpowiedź
Ze state:
load checkpoint
|
v
apply human decision
|
v
continue
Dlatego state nie jest tylko historią rozmowy.
To stan wykonywanego procesu.
Kiedy agent powinien pytać
Nie przy każdej niepewności.
Jeżeli agent będzie eskalował każdą drobną decyzję, automatyzacja szybko przestanie mieć sens.
Dobre kandydaty do human-in-the-loop to sytuacje, w których występuje przynajmniej jeden z tych warunków:
Brakuje decyzji biznesowej
Przykład:
Czy timeout powinien powodować retry,
jeżeli może wystąpić duplicate payment?
Wymagania są sprzeczne
Na przykład:
Acceptance criteria:
- API musi być backward compatible
Architecture note:
- usuń stare API
Agent nie powinien sam wybierać, który zapis jest ważniejszy.
Operacja ma duży blast radius
Na przykład:
terraform destroy
production deployment
database migration
permission escalation
Potrzebne są dodatkowe uprawnienia
Agent ma:
read repository
create branch
create PR
ale nagle potrzebuje:
production write access
To powinno wymagać jawnej decyzji.
Brakuje informacji, której nie da się odzyskać z dostępnych źródeł
Agent sprawdził:
ticket
repo
RAG
tools
i nadal nie ma odpowiedzi.
Dopiero wtedy eskaluje.
Clarification a approval
Warto rozdzielić dwa przypadki.
Clarification
Agent potrzebuje informacji:
Czy timeout wchodzi w zakres retry?
Po odpowiedzi może kontynuować.
Approval
Agent wie, co trzeba zrobić, ale organizacja wymaga zgody:
Plan includes a production database migration.
Approve execution?
Flow wygląda podobnie technicznie:
pause
|
v
human action
|
v
resume
ale semantycznie jest to coś innego.
W większej organizacji warto rozróżniać te dwa typy eventów.
Timeout i eskalacja
Co jeśli nikt nie odpowie?
Agent nie powinien wisieć bez końca.
Można zdefiniować policy:
WAITING_FOR_HUMAN
|
v
24h
|
v
reminder
|
v
48h
|
v
escalation
|
v
7 days
|
v
cancel task
To również może być częścią wspólnej platformy.
Repo agenta określa:
kiedy potrzebuję człowieka
a platforma może dostarczać:
pause
resume
timeout
notification
escalation
Gdzie co konfigurujemy
| Element | Gdzie |
|---|---|
| kiedy agent ma eskalować | repo agenta / workflow |
| checkpoint | runtime / state layer |
| treść pytania | agent |
| kanał komunikacji | platforma / integration layer |
| kto może odpowiedzieć | identity / policy |
| resume trigger | event layer |
| timeout | workflow / orchestration |
| audit odpowiedzi | observability / state |
Finalny flow
Nasz Implementer Agent nie wygląda już tylko tak:
ticket
|
v
implement
|
v
PR
Realny flow jest bliższy temu:
Jira ticket
|
v
Implementer Agent
|
v
repo + RAG + tools
|
v
implementation
|
v
decision missing?
|-- no
| |
| v
| continue
|
`-- yes
|
v
checkpoint
|
v
WAITING_FOR_HUMAN
|
v
Jira / Teams / Slack
|
v
human response
|
v
resume event
|
v
load checkpoint
|
v
continue
|
v
tests
|
v
PR
Human-in-the-loop nie oznacza więc, że agent przestaje być autonomiczny.
Oznacza, że organizacja jasno definiuje granicę:
Które decyzje agent może podejmować sam, a przy których ma się zatrzymać i poprosić człowieka o decyzję.
Materiały
- Beyond Dynamic Workflows, czyli długie waity i approvale poza LLM-em
- Anthropic: Building effective agents
- LangGraph: human-in-the-loop i interrupt
- Temporal: signals, czyli wznawianie workflow z zewnątrz
- AWS Step Functions: wait for callback z task tokenem
- Azure Durable Functions: wzorzec human interaction
- GitHub Actions: environments z required reviewers