Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

1.2 실측 데이터 — 하네스 로그에서 확인된 증상

증상

수치

근본 원인

term_read 폴링 폭주

55초간 12회 동일 데이터

비동기 완료를 기다릴 수 없어서 반복 읽기

턴 완료 시그널 미응답 → 사회자 교착

E2E 미팅 교착

루프 종료 후 시그널 수신 불가

컨텍스트 폭증

15분에 10K→30K chars

폴링 반복으로 히스토리 누적

잔여 작업 미진행

계획의 60%만 완료

루프 종료 = LLM 비활성

이 증상들은 모두 하나의 구조적 결함을 가리킨다: “완료 시그널 부재(Completion Signal Absence)”. LLM은 명령을 보내놓고 결과를 기다릴 수 없으며, 기다리려고 폴링하면 컨텍스트가 폭발한다.

1.3 에이전트와 LLM의 차이

특성

일반 LLM (펑션콜)

워크 에이전트

실행 모델

동기 루프, 라운드 제한

이벤트 기반, 시그널 반응

비동기 작업

폴링으로 대체

완료 시그널 대기

실패 복구

재시도 없음 (라운드 소진)

자동 재시도 / 에스컬레이션

상태 추적

히스토리 의존 (윈도우 제한)

명시적 상태 머신

타임아웃

전체 루프 단위

단계별 세밀한 제어

결론: 일반 LLM에 “기다림”과 “깨어남”을 가르치는 것이 에이전트화의 핵심이다.

...

핵심은 Action 2의 “대기”다. 기존 동기 루프에서는 이 대기가 불가능하다. ReAct의 논문 원문은 관찰이 즉시 반환되는 것을 가정하지만, 실제 시스템에서는 npm test가 30초 걸릴 수 있다. 이 간극을 메우는 것이 Akka 상태 머신이다.

2.2 다른 플래닝 패턴과의 비교

패턴

전략

장점

한계

ReAct

생각→행동→관찰 반복

관찰에 근거한 추론, 환각 감소

비동기 대기 미지원 (원본)

Plan-and-Execute

전체 계획 수립 후 순차 실행

예측 가능한 작업에 효율적

계획 수정이 어려움

Tree-of-Thought

여러 추론 경로 탐색, 가지치기

복잡한 문제 해결력

LLM 호출 비용 높음

LATS

몬테카를로 트리 탐색 + LLM

최적 경로 탐색

실시간 시스템에 부적합

Reflexion

실패 후 자기 성찰, 교훈 기억

반복 학습 가능

추가 메모리 관리 필요

AgentWin이 ReAct를 선택한 이유: 실시간 도구 실행 + 비동기 환경에서는 “한 번에 전체 계획”보다 “한 걸음씩 관찰하며 진행”이 현실적이다. 다만 원본 ReAct에 없는 Waiting 상태를 추가해야 한다.

...

3.2 왜 switch/case가 아닌 Become인가

관점

switch/case FSM

Akka Become()

상태 추가

case 문 추가, 모든 메시지에 상태 체크

메서드 하나 추가, 해당 상태 메시지만 처리

스레드 안전

lock 필요

액터 모델이 보장 (단일 스레드 처리)

잘못된 상태의 메시지

무시 또는 예외

Stash()로 보관, 나중에 Unstash()

타임아웃

별도 타이머 관리

ReceiveTimeout 내장

실패 복구

try/catch 중첩

Supervision Strategy

테스트

전체 FSM 초기화 필요

TestKit으로 상태별 메시지 주입

3.3 핵심: 액터는 죽지 않는다

동기 루프와 액터의 결정적 차이:

...

Code Block
languagetext
                    UserInput / CompletionSignal
                           │
                    ┌──────▼──────┐
          ┌────────│   Thinking   │←────────────┐
          │        │  (LLM 호출)  │              │
          │        └──────┬──────┘              │
          │               │                     │
          │    ToolCalls?  │  No ToolCalls?      │
          │    ┌───────────┼───────────┐        │
          │    ▼                       ▼        │
     ┌────┴────┐              ┌───────────┐    │
     │ Acting   │              │  Complete  │    │
     │(도구실행) │              │ (최종응답)  │    │
     └────┬────┘              └───────────┘    │
          │                                     │
          │ 즉시 결과?       비동기 대기?         │
          ├─────────────┬───────────────────────┤
          ▼             ▼                       │
   Become(Thinking)  ┌──────────┐              │
                     │ Waiting  │──completion──┘
                     │(시그널대기)│
                     └────┬─────┘
                          │ timeout (30s)
                          ▼
                   Become(Thinking)
                   "타임아웃됨, 현재 상태 확인"

4.2 상태별 동작 명세

상태

진입 조건

수신 메시지

전이

Thinking

StartReAct / CompletionSignal / 도구결과 / timeout

LLM 호출 → ToolCalls 유무로 분기

Acting

Thinking에서 ToolCalls 있음

도구 실행 → 즉시결과면 Thinking, 비동기면 Waiting

Waiting

Acting에서 비동기 도구

CompletionSignal, TaskComplete, ReceiveTimeout

시그널 → Thinking, 타임아웃 → Thinking

Complete

Thinking에서 ToolCalls 없음

부모에게 결과 전송, 액터 대기

4.3 Waiting 상태가 풀어내는 것

Before (동기 루프):

...

ReActActor가 Acting → Waiting 전환 여부를 결정하는 기준:

도구

동작

판별

term_send

터미널에 명령 전송, 결과는 나중에

비동기 → Waiting

term_read

버퍼 즉시 반환

동기 → Thinking

stage_send

액터 메시지 전송, 응답은 나중에

비동기 → Waiting

meeting_say

파일 쓰기 후 완료 대기

비동기 → Waiting

win_screenshot, term_list

즉시 반환

동기 → Thinking

...

6. 보조 장치 — 세션 메모리와 진단 로깅

ReAct 상태 머신만으로는 부족하다. 특히 온디바이스 소형 모델을 사회자로 쓸 때, 두 가지 보조 장치가 필수다.

...

ReAct 루프는 비결정적(non-deterministic)이다. LLM이 왜 그 행동을 선택했는지 추적하려면 전체 경로를 기록해야 한다.

로그 태그

기록 내용

용도

[REACT-THINK]

LLM 요청 내용 + 응답

추론 트레이스 추적

[REACT-ACT]

도구 호출명 + 인자 + 결과

행동 검증

[REACT-WAIT]

대기 시작 + 시그널 수신/타임아웃

비동기 흐름 추적

[REACT-STATE]

Become() 전환 기록

상태 전이 검증

이 로그는 하네스(Harness) 평가에 그대로 연결된다. 비결정적 시스템에서 “관찰 가능성(observability)”은 선택이 아니라 필수다.

...

2025–2026년 현재, 주요 LLM 에이전트 프레임워크들은 다음과 같이 플래닝과 상태를 관리한다:

프레임워크

플래닝 방식

상태 관리

비동기 모델

장애 복구

LangGraph

그래프 기반 워크플로우

체크포인트된 dict

Python asyncio

수동 재시도

OpenAI Agents SDK

에이전트 간 핸드오프

Runner 내부 관리

Python async

제한적

CrewAI

역할 기반 멀티에이전트

공유 메모리

프로세스 기반

없음

AutoGen

멀티에이전트 대화

대화 히스토리

Python async

제한적

Semantic Kernel

Planner + Plugins

Kernel 컨텍스트

C#/.NET async

제한적

그리고 Akka 액터 모델:

역량

대부분의 프레임워크

Akka 액터

타입 안전 상태 전이

dict 기반, 런타임 에러

Become() — 컴파일 타임 메서드 분리

장애 복구

try/catch, 수동 재시도

Supervision Strategy 자동 복구

동시성

스레드/async 직접 관리

액터 = 단일 스레드 보장, 자연 격리

분산 실행

별도 인프라 구축

Akka.Cluster 내장

이벤트 소싱

없음 (외부 DB)

Akka.Persistence 내장

역압(Backpressure)

없음

Akka Streams 통합

Note

트레이드오프: Akka는 Python 스크립트 한 줄로 시작할 수 없다. 학습 곡선이 있고, 인프라 설정이 필요하다. 하지만 프로덕션급 에이전트 시스템 — 신뢰성, 동시성, 확장성이 필요한 환경 — 에서는 액터 모델이 Python async 프레임워크보다 견고한 기반이 된다.

...

에이전트에게 자율성을 주면 반드시 고삐가 필요하다:

장치

설명

MaxRounds

ReAct 루프 최대 반복

10

ReceiveTimeout

Waiting 상태 타임아웃

30초

동일 호출 제한

같은 도구 연속 호출 차단

3회

MaxCallsPerRound

라운드당 도구 호출 상한

30

CancelReAct

사용자 수동 취소

즉시 중단

특히 ReceiveTimeout은 Akka에 내장된 기능이다. Waiting 상태에서 30초 내에 시그널이 없으면 자동으로 Thinking으로 돌아가 “타임아웃됐다, 현재 상태를 확인하겠다”는 판단을 LLM에게 넘긴다. 교착 상태가 구조적으로 불가능해진다.

...

이번 2편에서 다룬 핵심 기술과, 이후 활용될 기술을 정리한다:

기술

역할

상태

ReAct Pattern

LLM의 추론-행동-관찰 루프 구조화

설계 완료, Phase 2 구현 예정

Akka.NET Become()

상태 머신 런타임 전환, 스레드 안전

Phase 2 핵심

Akka ReceiveTimeout

비동기 대기 타임아웃, 교착 방지

Phase 2 핵심

Akka Supervision

자식 액터 장애 자동 복구

기존 적용, 확장 예정

세션 메모리 (Actor State)

온디바이스 모델의 컨텍스트 보존

설계 완료, Phase 2와 통합

LM-Kit.NET

온디바이스 추론 엔진 (gemma-4)

NuGet 설치 완료, Phase 4

ILlmProvider 추상화

원격/온디바이스 LLM 전환 투명화

Phase 4

Akka.Persistence

이벤트 소싱으로 상태 재생/복구

향후 검토

Akka Streams

LLM API 역압(backpressure) 제어

향후 검토

...

11. 마무리 — LLM에게 기다림을 가르치다

...

Phase 2 구현이 끝나면, 그 결과를 가지고 3편에서 만나자.


Info

구현하고 나면 테스팅및 작동에 확신있는 클코드에게.. 정말 자신있어?
테스트 해볼테니 로그 점검, 꼭 이말을 마지막에 한번더 해야 남기는 


Image Added



...

참고

...