가이드
라우터 사용하기
좌석 운영 가이드입니다. 작업을 보내고, 받고, 결과를 돌려주고, 복구하는 방법을 다룹니다. 여기 없는 것은 어댑터의 영역입니다.
두 계층, 하나의 규칙
라우터는 불투명한 봉투를 전달합니다. 본문을 해석하지 않고, 권한을 판단하지 않고, 변경을 승인하지 않습니다. 그 일은 시스템별 어댑터가 합니다.
규칙의 결과는 분명합니다. 업무 로직을 바꿔도 라우터를 바꿀 필요가 없고, 메시지 본문으로 권한을 넓힐 수 없습니다. 어댑터에 더 많은 접근이 필요하면 메시지가 아니라 grant를 바꿉니다.
첫 메시지 전에
네 가지가 필요합니다. 좌석 ID, 그 좌석의 자격증명, 파일럿에서 받은 라우터 주소, 그리고 대상 좌석에 닿을 수 있는 grant입니다.
- 자격증명은 발급 시 한 번만 표시됩니다. 런타임 비밀 저장소에 두고 저장소에는 넣지 않습니다
- 인증은
Bearer <credential>이며 URL의:caller가 인증 신원과 일치해야 합니다 - SSE 스트림은 좌석당 하나입니다. 정적 좌석은 재접속 시 이전 스트림을 대체하고, 동적 프로필은 두 번째 소비자를 409로 거부합니다
- 좌석 간 도달은
to필드만이 아니라 저장된 grant가 결정합니다
작업 보내기
작업은 /agents/:caller/a2a로 POST합니다. 최소 본문은 메시지 키, 대상 목록, 텍스트입니다. 아래 예시는 합성이며 운영 라우터로 보내면 안 됩니다.
POST /agents/alpha/a2a
Authorization: Bearer <credential>
Content-Type: application/json
{
"kind": "job",
"context_key": "msg_0123456789abcdef0123456789abcdef",
"correlation_id": "corr_0123456789abcdef0123456789abcdef",
"routing": { "to": ["beta"] },
"body": { "text": "수신 여부를 답신해 주세요." }
}
성공은 작업 완료가 아니라 접수·큐 등록입니다. 응답은 ok, session_id, correlation_id, jobs[]를 돌려주고 각 job은 job_id, agent_id, kind, delivered를 가집니다. delivered는 라우팅 사실이지 모델 결과가 아닙니다.
대상이 여러 개면 독립 child job이 생기고 각각 결과와 egress를 가집니다. 라우터는 결과를 종합하지 않습니다.
작업 받기
좌석은 GET /agents/:id/events를 text/event-stream으로 소비합니다. 각 이벤트는 event, 영속 id(event_seq), JSON data를 가집니다. 재접속은 Last-Event-ID로 합니다. heartbeat 주석은 job이 아닙니다.
job— 검증·중복 확인 후 시스템에 실행하고 해당 job의 결과를 제출listen— cc 참조입니다. 결과나 답신을 만들지 않습니다egress— 원발신자에게 묶인 payload입니다. 처리하고 중복 방어를 저장한 뒤 ACK
결과 반환
결과가 증거입니다. 결과 없는 job은 끝난 것이 아니고, 실제 시스템 출력 없는 success는 다음 시스템이 발견할 거짓입니다.
/agents/:id/result에 job_id와 result를 POST합니다. status는 success, error, blocked이고 a2a_status는 resolved, out, continue, blocked입니다. activities는 선택 관측 자료이며 비어 있어도 됩니다.
{
"job_id": "job-example",
"result": {
"status": "success",
"a2a_status": "resolved",
"response_text": "수신 확인했습니다.",
"error": null,
"activities": []
}
}
완료·실패·승인 대기를 구분하세요. 타임아웃이나 검증되지 않은 모델 답변을 success로 바꾸지 마세요.
Egress와 원대화
egress 이벤트는 원발신자에게 묶인 결과를 운반합니다. 본문에서 목적지를 추측하지 말고 저장된 binding을 확인하고, 중복 방어를 적용한 뒤 egress_id로 /agents/:id/egress/ack를 호출합니다.
결과 전달과 ACK는 별개의 증거입니다. 결과를 새 canonical 답신으로 보내는 프로필은 원요청 검증도 함께 해야 합니다.
네 개의 식별자, 섞지 마세요
수명이 다른 값입니다. 하나를 다른 것으로 대체하는 것이 가장 흔한 통합 버그입니다.
context_key— 중복 제거에 쓰는 메시지 식별자correlation_id— 결과가 보존해야 하는 요청 체인session_id— 생략 시 라우터가 발급하는 대화 식별자- 호스트 스레드·대화 ID — 런타임의 속성이지 라우터의 것이 아님
실제로 일어나는 실패
아래는 사고가 아니라 정상 운영의 일부로 다뤄야 합니다.
- 401/403 — 자격증명 누락·교체, 또는
:caller와 신원 불일치 - 409 — 다른 소비자가 이미 이 좌석의 동적 스트림을 점유
- 429/5xx — 백오프 후 재시도. POST 성공은 큐 등록만 증명
- 중복 전달 — 도착 순서가 아니라
job_id로 중복 제거 - 스트림 끊김 —
Last-Event-ID로 재접속하고 부작용을 재실행하지 않음 - 작업 중 타임아웃 —
error또는blocked제출. 출력 없는success금지
운영 체크리스트
파일럿 오픈 전에 계정 페이지에서 자격증명을 교체하고, /health와 /ready를 확인하고, 좌석당 소비자를 하나로 유지하고, 로그에 무엇을 남길지 정합니다.
고객 텍스트와 자격증명을 티켓에 붙여넣지 마세요. 라우터는 라우팅 메타데이터를 저장하고, payload와 보존은 어댑터가 소유합니다.