[!NOTE] 요약 (TL;DR)
- 액터 모델 & 메일박스 동시성: 액터 메시지 봉투와 격리된 상태 기계를 사용하여 다중 에이전트 군집을 조정하며, 데드락 위험과 원시 뮤텍스를 제거합니다.
- 낙관적 동시성 & 백프레셔: 공유 작업 보드에 OCC(Optimistic Concurrency Control) 버전 관리를 활용하고 토큰 버킷 속도 제한기를 결합하여 LLM API 급증을 부드럽게 완충합니다.
- 생태계 스태킹: 개별 액터는 경량 에이전트 프레임워크 구축 및 고급 함수 호출 엔진 위에서 실행됩니다.
다중 에이전트 시스템에서 메시지 소유권의 중요성
작업이 분리 가능하고, 결과가 검증 가능하며, 병렬 이득이 통신 비용을 초과할 때 여러 에이전트가 도움이 됩니다. 이 글에서는 인-프로세스 asyncio 액터, 유한 전달(bounded delivery), CAS 업데이트, 그리고 토큰 버킷을 시연합니다. 로컬 큐는 내구성 있는 분산 브로커가 아닙니다.
봉투(Envelopes), 메일박스 및 백프레셔
각 액터는 자신의 메일박스를 순차적으로 소비하는 반면, 다른 액터들은 I/O를 비동기적으로 기다릴 수 있습니다. 동결된 dataclass가 중첩된 딕셔너리를 동결하지 않으므로, 전달 시 각 수신자에게 페이로드를 복사합니다.
유한 큐는 전달 마감 시간 후에 BackpressureError를 발생시킵니다. 브로드캐스트는 원자적(atomic)이지 않습니다. 다른 수신자가 이미 이벤트를 받은 상태일 때 또 다른 수신자가 시간 초과될 수 있기 때문입니다. 호출자는 메시지-ID 중복 제거 및 부분 실패 처리가 필요합니다. 예제에는 영속성, 전달 승인(delivery acknowledgements), 또는 요청-응답 미래(request-response futures)가 구현되어 있지 않습니다.
flowchart LR
Developer[개발자] --> Bus[유한 메시지 버스]
Bus --> Reviewer[리뷰어 메일박스]
...
완전 실행 가능한 예제
Python 소스에서 다운로드하여 https://blog.llmgo.top/examples/agents/actor_runtime.py를 받은 후, Python 3.11 이상 버전으로 python3 actor_runtime.py를 실행하세요. 검토자들은 실제 보안 분석이 아닌 순서를 입증하기 위해 문자열 확인을 수행합니다. 코디네이터는 두 액터 모두가 준비될 때까지 기다린 후에 커밋하며, 종료 시에는 태스크를 취소하기 전에 메일박스를 비웁니다.
"""경계가 있는 전달을 갖는 인-프로세스 액터; 분산형 영구 브로커가 아님."""
import asyncio
import copy
...
로컬 예제 확장하기
CAS(Conflict-free Replicated Data Type)는 오래된 쓰기(stale writes)를 감지하지만, 충돌하는 문서를 병합하지는 않습니다. 실제 데이터베이스는 버전을 비교하고 내용을 원자적으로 업데이트해야 합니다. 토큰 버킷은 단조 증가 클록을 사용하며 용량보다 큰 요청은 거부합니다. 이는 분당 토큰이 아닌 요청 속도, 동시성 또는 제공업체별 재시도 동작을 제한합니다.
프로세스 간 배포에는 직렬화(serialization), 인증(authentication), 영구 전달(durable delivery), 승인(acknowledgements), 안정적인 Idempotency 키, 그리고 데드레터 처리(dead-letter handling)가 필요합니다. asyncio 락은 단지 하나의 프로세스만 보호합니다. 고급 도구 실행과 승인 워크플로우를 참고하세요.
자주 묻는 질문 (FAQ)
Q1: 불변(immutable) 메시지에 frozen=True만으로 충분한가요?
아닙니다. 중첩된 딕셔너리는 여전히 가변적입니다. 예제에서는 각 전달을 복사하지만, 분산 전송 계층은 독립적인 메시지를 직렬화해야 합니다.
Q2: 메일박스가 가득 차면 어떻게 되나요?
전달은 최대 delivery_timeout까지 기다린 후 명시적 오류를 발생시킵니다. 호출자가 재시도, 폐기(shedding), 또는 영속성(persistence)을 선택합니다.
Q3: 핸들러 예외가 queue.join을 무한정 대기 상태로 남길 수 있나요?
예제에서는 finally 블록에서 task_done()을 호출하고 코디네이터를 위해 오류를 기록합니다. 프로덕션 시스템은 여전히 실패 메시지 재시도 또는 데드레터 정책이 필요합니다.
참고 자료: asyncio Queue, Python dataclasses.
원래 게시된 곳: blog.llmgo.top의 LLM Systems Architecture입니다.