---
title: "100줄짜리 리스프 에이전트가 보여준 묘한 가능성"
published: 2026-07-07T21:21:09.000Z
canonical: https://jeff.news/article/4996
---
# 100줄짜리 리스프 에이전트가 보여준 묘한 가능성

글쓴이는 Common Lisp로 약 100줄짜리 AI 에이전트를 만들며, 에이전트 루프가 결국 재귀 함수처럼 볼 수 있다는 점을 보여준다. 특히 eval 하나만 도구로 줬더니 모델이 피보나치 계산뿐 아니라 Brave Search 함수를 직접 정의해 웹 검색 능력까지 만들어냈다는 대목이 핵심이다.

- 글쓴이는 2000년쯤 대학 AI 수업에서 Lisp를 배웠고, 25년 뒤 AI 에이전트를 만들다가 이상한 질문을 던짐
  - “에이전트 루프를 Lisp로 만들면 의외로 잘 맞지 않을까?”라는 질문임
  - 당시 AI 수업에는 트랜스포머(transformer), CUDA, PyTorch 같은 건 없었고, Lisp는 상징 AI(symbolic AI)의 언어처럼 배웠다고 함

- 글의 첫 번째 핵심은 에이전트가 생각보다 단순한 재귀 함수라는 주장임
  - 메시지 목록을 모델에 보냄
  - 모델이 답을 하면 종료함
  - 모델이 도구 사용을 요청하면 도구를 실행하고, 결과를 메시지에 붙인 뒤 다시 호출함
  - 글쓴이는 이 구조를 Common Lisp 8줄짜리 재귀 함수로 표현했다고 함

```mermaid
sequenceDiagram
    participant 사용자
    participant 에이전트루프
    participant 언어모델
    participant 도구실행기
    사용자->>에이전트루프: 질문 입력
    에이전트루프->>언어모델: 메시지 목록 전달
    언어모델-->>에이전트루프: 답변 또는 도구 요청
    에이전트루프->>도구실행기: 요청된 코드 실행
    도구실행기-->>에이전트루프: 실행 결과 반환
    에이전트루프->>언어모델: 결과를 붙여 재호출
```

- 실험 버전은 약 100줄짜리 Common Lisp 에이전트였음
  - 런타임은 SBCL을 사용함
  - HTTP는 dexador, JSON은 shasht를 썼고, 모델 호출은 OpenRouter를 붙임
  - 거창한 프레임워크나 상태 머신 없이 메시지 리스트를 재귀적으로 넘기는 방식임

- 진짜 재밌는 부분은 도구를 여러 개 만든 게 아니라 eval 하나만 줬다는 점임
  - 보통 에이전트 플랫폼은 웹 검색, 파일, 파이썬 실행, 크롤러 같은 도구 목록을 미리 만들어둠
  - Lisp에서는 코드가 데이터고 데이터가 코드라서, 모델이 Common Lisp 코드를 문자열로 쓰고 eval로 실행하게 만들 수 있음
  - 예시로 “30번째 피보나치 수를 외우지 말고 계산해라”라고 하자 모델이 fibonacci 함수를 정의하고 `(fibonacci 30)`을 실행해 832040을 얻음

> [!WARNING]
> eval을 도구로 준다는 건 모델이 내 머신에서 임의 코드를 실행할 수 있다는 뜻임. 글쓴이도 이건 로컬 도커 컨테이너 같은 샌드박스용 장난감이라고 못 박음.

- 메모리도 복잡하게 만들지 않았음. 그냥 메시지 리스트를 저장하고 다시 읽음
  - Agent Foundry에서는 pgvector 같은 기억 저장소를 구현했지만, 이 실험에서는 Lisp의 기본 직렬화만으로 충분했다고 함
  - 메시지가 이미 해시 테이블 리스트라서 JSON 비슷한 구조고, 이걸 파일에 쓰고 다시 읽으면 대화가 세션을 넘어 이어짐
  - 단점도 명확함. 전체 대화 기록이 끝없이 커져서 언젠가 컨텍스트 창을 때림

- 다음 장면이 이 글의 하이라이트임. 에이전트가 자기 도구를 직접 만듦
  - 글쓴이가 임시 Brave Search API 키를 대화에 넣어보자, 에이전트가 eval로 `brave-search` 함수를 정의함
  - 사용 가능한 HTTP/JSON 라이브러리를 확인하고, Brave Search API 호출 코드를 만들고, JSON 응답 파싱까지 직접 처리함
  - 글쓴이는 웹 검색 도구를 만든 적이 없는데, 에이전트가 eval이라는 하나의 도구로 두 번째 도구를 만들어낸 셈임

> [!IMPORTANT]
> 일반적인 에이전트 플랫폼에서는 도구 카탈로그가 설계 시점에 고정됨. 여기서는 모델이 대화 중 필요를 느끼고 직접 함수를 만들어 런타임 능력으로 추가했다는 게 포인트임.

- 더 묘한 건 이 능력이 프로세스가 종료되면 사라지지만, 대화 기록에는 남는다는 점임
  - Lisp 함수 정의는 실행 중인 이미지 안에만 존재함
  - 하지만 모델이 `defun brave-search ...`라고 작성한 텍스트는 memory.json에 남음
  - 새 세션에서 에이전트가 자기 기록을 다시 읽고 그 코드를 eval하면, 사라졌던 능력이 다시 살아남

- 그래서 글쓴이는 “스킬은 그냥 기억일 수도 있다”는 쪽으로 생각을 밀어붙임
  - MCP는 능력을 사전에 정의된 계약으로 다루는 쪽에 가까움
  - 코드 인터프리터는 모델이 임시 프로그램을 써서 답을 구하는 첫 단계였고, SKILL.md 패턴은 텍스트로 저장된 능력을 런타임에 불러오는 두 번째 단계라고 봄
  - 이 Lisp 에이전트는 능력을 아예 자기 대화 기록 속에 저장했다가 필요할 때 재구성하는 실험처럼 보임

- 결론은 “Lisp가 다시 AI의 언어가 됐다” 같은 단순한 얘기가 아님
  - 상징 AI는 딥러닝에 밀렸지만, 프로그램을 데이터처럼 다루고 자기 자신에게 다시 먹이는 Lisp의 특성은 에이전트 루프와 꽤 잘 맞음
  - 추론은 이제 언어 모델이 하고, 우리가 엔지니어링하는 건 그 모델을 감싸는 루프와 런타임이라는 관점이 남음

---

## 기술 맥락

- 이 글에서 선택한 건 ‘도구를 많이 붙인 에이전트’가 아니라 ‘eval 하나를 가진 Lisp 런타임’이에요. 왜냐하면 Common Lisp에서는 코드가 리스트 데이터처럼 다뤄져서, 모델이 만든 코드를 곧바로 실행 가능한 형태로 바꾸기 쉽거든요.

- 보통 에이전트 플랫폼은 도구를 미리 설계해요. 웹 검색 도구, 파일 도구, 파이썬 도구처럼 권한과 입출력을 정해두는 방식이죠. 이 방식은 통제하기 좋지만, 모델이 대화 중 새 능력을 직접 만들어내는 실험과는 거리가 있어요.

- 글쓴이의 Lisp 에이전트는 메시지 리스트를 재귀적으로 넘기는 구조라서 상태 관리가 단순해요. 모델이 답하면 종료하고, 도구 요청이 있으면 실행 결과를 붙여 다시 호출하는 식이라 에이전트의 상태가 별도 저장소가 아니라 함수 인자처럼 흐르는 거예요.

- Brave Search 예시가 중요한 이유는 에이전트가 단순히 코드를 실행한 게 아니라 새 함수를 런타임에 정의했다는 점이에요. 함수 자체는 프로세스가 끝나면 사라지지만, 그 함수를 만들었다는 대화 기록은 남기 때문에 기억을 다시 읽어 능력을 복원할 수 있어요.

- 다만 이 구조는 보안 면에서 바로 제품에 넣기 어려워요. eval은 임의 코드 실행이라 파일, 네트워크, 시스템 호출을 다 열어줄 수 있거든요. 그래서 이 글의 가치는 완성된 아키텍처보다, 에이전트의 도구와 기억을 다르게 상상하게 만드는 데 있어요.

## 핵심 포인트

- 에이전트 루프는 메시지를 모델에 보내고, 도구 요청이 있으면 실행한 뒤 다시 호출하는 재귀 구조로 단순화할 수 있음
- Common Lisp의 동형성(homoiconicity) 덕분에 코드와 데이터의 경계가 흐려지고, eval 하나가 범용 도구처럼 작동함
- 모델이 런타임에 brave-search 함수를 정의하면서 고정된 도구 카탈로그와 다른 에이전트 설계 가능성을 보여줌
- 대화 기록에 함수 정의가 남기 때문에, 에이전트의 능력이 ‘기억’으로 저장되고 다시 로드될 수 있다는 관찰이 흥미로움

## 인사이트

이 글은 Lisp 찬양으로 끝나는 글이 아니라, 에이전트의 도구와 기억을 어떻게 바라볼지 던지는 실험에 가깝다. MCP처럼 사전에 계약된 도구 세계와, 런타임에 능력을 만들어내는 세계 사이의 긴장이 꽤 재밌게 드러남.
