상태없는 AI-인간 인터랙션
- 2025-08-04 (modified: 2025-08-13)
- 출판일: 2025-08-04
- 저자: AK
REST의 “상태없음” 개념을 활용하여 AI-인간 인터랙션을 개선하는 방법을 정리했다. 코딩 에이전트에게 개발 일을 시키는 상황을 상정하고 썼지만 상당수의 지식 노동에도 유사한 방식을 적용할 수 있을 걸로 보인다.
LLM 맥락 ≈ 프로토콜 상태
현재(2025년 8월 4일 기준) 코딩 에이전트와의 대화에서는 맥락(context) 유지가 매우 중요하다. 새 대화 세션을 열면 기존에 나눴던 대화 맥락과 코드 수정 이력이 사라져서 에이전트가 연속성 있는 작업을 잘 못한다. Claude Code에서 컨텍스트 크기를 줄이기 위해 compact
명령을 실행하면 갑자기 AI의 작업 품질이 떨어진다는 경험담도 많다.
AI-인간 인터랙션에서 “맥락”이란 통신 프로토콜에서의 “상태(state)“와 유사한 면이 있다. AI가 인간에게 말을 걸거나 인간이 AI에게 말을 걸때 기존에 나눴던 대화의 맥락이 이어져야만 한다.
상태 있는 프로토콜 vs. 상태 없는 프로토콜
상태있는 프로토콜과 상태없는 프로토콜의 차이를 비교하기 위해 에어컨 리모콘 예시를 들어보자. 온도를 24도로 설정하고 싶은 상황이다. 다음은 상태있는 프로토콜 예시:
- 리모콘: 현재의 설정 온도를 알려줘.
- 에어컨: 25도입니다.
- 리모콘: 온도를 1도 낮춰.
- 에어컨: 설정했습니다.
다음은 상태없는 프토로콜 예시:
- 리모콘: 온도를 24도로 설정해.
- 에어컨: 설정했습니다.
(현실에서 대부분의 리모콘은 송신기만 있고 수신기가 없으므로 상태없는 프로토콜을 쓴다)
REST의 장점 중 하나는 상태없음(statelessness)이다. 기존에 어떤 대화를 나눴는지 알 필요가 없고 이번에 내가 하고 싶은 말을 잘 정리해서 “자체완결성이 있는(self-contained)” 요청을 한번에 보내면 받는 쪽에서 잘 처리해준다. 위 리모콘 예시에서 “온도를 1도 낮춰”는 자체완결성이 없다. 현재의 설정 온도도 추가로 필요하다. 반면 “온도를 24도로 설정해”는 자체완결성이 있다.
한편, 자체완결성이 있는 요청을 보낸다는 말은 사실 상태 관리를 할 필요가 있다는 뜻이다. “상태없음”은 요청을 받는 측에서 상태를 관리할 필요가 없다는 뜻이고, 요청을 하는 측에서는 상태를 관리해야 자체완결성 있는 요청을 보낼 수 있다.
리모콘을 예로 들자면, 리모콘은 자체적으로 현재의 설정 온도를 기억하고 있다. 사용자는 “온도 1도 내림” 버튼을 누르면 리모콘은 내부에서 가지고 있는 상태(현재 설정 온도는 25도)를 바탕으로 “온도를 24도로 설정해”라는 명령을 만들어서 에어컨에 전달한다. 덕분에 에어컨은 리모콘과의 지난 대화를 기억할 필요가 없이 명령을 수행할 수 있게 된다.
코딩 에이전트에 적용해보기
이 개념을 AI 에이전트에게 적용해보면 어떨까.
AI 에이전트에게 의미 있는 하나의 작업 단위(예: 기능 추가, 버그 수정, 기능 변경, 성능 개선 등)를 요청하고 에이전트가 이를 완료하는 걸 하나의 세션으로 간주하자.
다음 세션의 요청이 지난 세션의 요청과 완전히 독립적일 수 있다면, 즉 기존 대화창을 닫고 새 대화 세션을 열어도 된다면, REST의 상태없음 개념을 비슷하게 구현했다고 볼 수 있다.
그러니까 이런 게 되면 좋겠다.
- 새 대화 세션을 연다.
- 한 번에 필요한 내용을 몽땅 담아서 요청을 보낸다.
- AI 에이전트가 스스로 해당 요청을 처리한다.
- 대화 세션을 닫는다.
1번과 4번은 쉽다. 3번은 2를 잘한다는 가정하에(그리고 모델이 충분히 똑똑하다는 가정하에) 쉽다. 문제는 2번이다. 2번이 어렵거나 매우 귀찮거나 시간을 많이 소비하기 때문에 우리는 이런 행동을 한다.
- 맥락을 유지하기 위해 되도록 기존 대화 세션에서 길게 얘기하기
- Claude Code의
compact
등 맥락을 압축하는 트릭에 의존하기 - 돈을 더 내고 맥락에 최대한 많은 정보를 우겨넣기 (예: Cursor의 Max 모드)
하지만 맥락이 길어지면 AI가 있는 정보를 무시하거나 시키지 않은 일을 하는 등 이상한 행동을 하기 시작한다(context rot). 바늘찾기 벤치마크가 무색할 지경이다. 적절한 정보를 찾으려고 온갖 소스코드를 컨텍스트에 올리며 토큰을 불태우지만 서비스 제공자만 신날 일.
인간의 과도한 노력 없이 LLM 맥락을 최소한으로만 쓰면서도 2번을 쉽게 할 수 있다면 좋겠다.
명세서
2025년 7월 강연 “The New Code - Specs: Write once, run everywhere에서 Sean Grove는 대략 이런 주장을 한다:
- 소프트웨어 형상 관리를 할 때 소스코드가 관리 대상이고 소스코드로부터 유도되는 산출물(예: 컴파일된 바이너리)은 관리 대상이 아니다.
- 소스코드에는 주석, 변수명 등 더 많은 정도와 의도가 담기는 반면 유도된 산출물에 담긴 정보는 제한적이기 때문이다.
- 프롬프트로부터 코드가 유도된다는 관점에서 볼 때, 매번 프롬프트는 내다 버리고 소스코드만 관리하는 행태는 이상하다.
맞는 말이다.
“소스코드는 중요한 산출물이며 형상 관리의 대상이다”라는 말은 좀 더 일반화하면 “다른 산출물로부터 유도할 수 없는 1차 산출물이 형상 관리의 대상이다”라는 뜻이다. 생각해보면 소스코드라고 하더라도 생성된 코드(generated code; 예를 들면 네트워크 관련 코드에서 client stub과 server skeleton)는 버전 관리를 안하는 게 일반적이다.
우리가 에이전트 기반 코딩 또는 바이브 코딩을 하면서 프롬프트는 대충 적고 내다버리고 만들어진 코드는 애지중지 관리하는데, 생각해보면 이건 잘못된 방법이다. 프롬프트를 최대한 잘 적고 관리하는 게 중요하다. 코드는 부산물이다. 아직은 아니지만 점차 그렇게 될 것이다
한편, 위 강연에서 “Write once, run everywhere”는 사실 자바의 슬로건인데, 여러 측면에서 적절한 비유다.
- 바이트코드로 변환된 소스코드를 건내주면 JVM이 환경에 맞는 기계코드로 변환하여 실행해준다.
- 프롬프트를 건내주면 LLM이 내가 원하는 언어 및 환경에 맞는 소스코드로 변환해준다. (소스코드를 기계코드로 변환하는 과정은 기존에도 자동화되어 있으므로 문제가 아니다)
다시 원래 하던 얘기로 돌아와서, 프롬프트를 잘 관리하는 게 중요하다고 말할 때 관리를 할 가치가 있는 아주 잘 적힌 프롬프트란 어떤 형태일까? 명세서다.
많은 사람들이 마크다운 형식의 PRD를 적기 시작한 점이나 AI 에이전트에게 PRD를 갱신해달라고 요청하기 시작한 점도 이런 생각의 흐름과 무관하지 않은 것 같다. AWS는 2025년 7월 14일에 Kiro라는 에이전트 기반 코딩 도구를 출시했는데 핵심 차별점으로 “명세서 주도 개발”을 꼽고 있다.
그런데 명세서라고 하더라도 구체적으로 어떤 형식 또는 내용이 담기는지를 생각해보는 게 중요하겠다. 또, 명세서를 보조할 도구와 프로세스도 필요하다고 본다. 원래 모든 방법론은 산출물과 도구와 프로세스로 이루어진다. (예: UML과 Rational Rose와 Unified Process. 초창기 애자일 방법론은 종이나 포스트잇 등 소위 “로우 테크 도구”를 선호하기 때문에 도구가 없다는 착각을 일으키기도 한다.)
명세서, 도구, 프로세스
구체적으로 이런 게 있으면 상태없는 AI-인간 인터랙션을 달성할 수 있겠다.
- 명세서: 비즈니스 맥락, 기능 목록, 각 기능에 대한 평가 가능한 인수 기준, 기능 목록 간 의존 관계 등이 기록된 명세서. 명세서는 절반쯤 구조화되어 있어서 기계로 분석 가능하고 인간과 LLM이 읽고 이해할 수 있는 형태여야 한다.
- 도구: 명세서의 내적 모순(예: 기능 목록 간 상호 의존, 비즈니스 맥락과 무관한 기능, 인수 기준이 없는 기능 등) 분석, 명세서와 코드 사이의 추적가능성(traceability; 예: 명세서의 인수 기준과 자동화된 인수 테스트 사이의 상호 연결) 분석, 전체 프로젝트의 맥락과 현황(통과하는 인수 테스트의 수로 파악)과 다음에 할 일을 텍스트 형태의 보고서로 출력하는 기능 등을 수행하는 전통적인 프로그램 (아마 CLI)
위와 같은 명세서와 도구가 있으면 다음과 같은 프로세스로 “상태없는 AI-인간 인터랙션”을 달성할 수 있겠다.
- 인간(AI의 도움을 받아)이 명세서에 새 기능과 인수 기준을 작성한다.
- 새 대화 세션을 연다.
- AI에게 “도구를 호출하고 도구의 출력에 따라 다음 작업을 수행하시오”라고 지시한다.
- AI가 도구를 호출하면 전체 프로젝트의 맥락과 현황을 출력한 뒤 다음에 할 일을 알려준다. 추가 정보를 얻기 위해서는 어떤 명령을 실행하면 되는지도 열거해준다.
git status
랑 유사하다. 생각해보면 REST의 HATEOAS랑도 이어지는 면이 있다. AI가 알아야할 명령어는 딱 하나고, 이 명령을 통해서 다음에 어떤 명령을 내릴 수 있는지 발견해갈 수 있으면 된다. - AI 에이전트가 이런저런 도구를 호출해가며 혼자 작업을 수행한다.
- 대화 세션을 닫는다.
모든 중요한 맥락은 명세서와 코드에 담겨 있고 다음 지시에 필요한 맥락을 도구가 자동으로 생성할 수 있으니, 안심하고 언제든 대화 세션에 담긴 맥락을 몽땅 날릴 수 있다.
구현
에이전트 기반 코딩 실험 3에서 이런저런 실험을 하는 중인데 현재 “개밥먹기”가 그럭저럭 가능한 수준이다. 즉, 위 도구를 만드는 프로젝트를 위 도구를 써서 진행 중이다.