kvcache-ai/AgentENV · 라이선스 MIT · 버전 0.1.0(정식 릴리스 태그 없음) · 공개 2026-07-27 · TrendShift 데일리 2위 · Rust 384파일 + Go 37파일 · Linux 6.8+ / /dev/kvm 필수)
먼저 이름을 풀자. Agent는 스스로 코드를 짜고 실행하고 도구를 호출하는 AI를 말하고, ENV는 environment, 즉 그 AI가 실제로 명령을 돌릴 실행 환경이다. AgentENV = "에이전트를 위한 실행 환경 공급기"인 셈이다.
왜 이게 필요할까? 요즘 AI 에이전트(코딩 에이전트, 자율 리서치 봇 등)는 진짜로 코드를 실행해 봐야 일을 한다. 파일을 만들고, 패키지를 설치하고, 셸 명령을 돌린다. 그런데 이걸 그냥 서버에서 돌리면 위험하고, 여러 에이전트를 동시에 굴리면 서로 간섭한다. 그래서 에이전트마다 격리된 일회용 컴퓨터를 붙여 줘야 한다. AgentENV는 그 일회용 컴퓨터를 싸게, 빠르게, 대량으로 공급하는 엔진이다.
보통 가상머신(VM)은 좋은 호텔방이다 — 방음(격리)은 완벽하지만 청소하고 준비하는 데(부팅) 오래 걸리고 비싸다. 반대로 컨테이너는 칸막이 친 공용 오피스다 — 빨리 들어갈 수 있지만 옆 칸과 벽(커널)을 공유해서, 나쁜 손님이 벽을 뚫을 위험이 있다.
AgentENV는 "VM만큼 방음되면서 컨테이너만큼 빨리 체크인되는 방"을 노린다. 비결은 스냅샷이다 — 방을 매번 처음부터 꾸미지 않고, "이미 세팅 다 된 방의 순간을 사진 찍어 뒀다가" 손님이 오면 그 사진을 0.05초 만에 펼쳐 놓는다. 손님이 잠깐 자리를 비우면(idle) 방을 접어서 창고에 넣어 요금(CPU·메모리)을 0으로 만들고, 다시 오면 펼친다.
그리고 이 호텔은 한 건물이 아니라 체인이다. 여러 서버(노드)에 걸쳐 방을 띄우고, 손님이 어느 건물 몇 호에 있는지 관리하는 프런트데스크(게이트웨이 + 스케줄러)가 따로 있다. Kimi-K3 같은 모델을 강화학습시킬 때는 이런 방이 동시에 수천~수만 개 필요하다 — 에이전트가 100만 토큰짜리 긴 작업을 수천 번 반복(rollout)하기 때문이다. AgentENV는 바로 그 규모를 감당하려고 태어났다.
가장 강력한 셀링 포인트다. 보통 "격리는 강하지만 느린" 가상머신의 상식을 정면으로 깬다. README가 내세우는 수치:
| 동작 | 목표 시간 | 초보자 해설 |
|---|---|---|
| 부팅 / 재개 | < 50ms | 스냅샷에서 환경을 되살리는 데 0.05초 |
| 일시정지 (pause) | < 100ms | 안 쓰는 환경을 접어 자원 반납 |
| 증분 스냅샷 | < 100ms | 디스크를 마구 바꾼 뒤에도 메모리+파일 변화만 저장 |
일반적인 Firecracker VM도 부팅이 100~200ms대인데, AgentENV는 여기에 스냅샷 복원 트릭을 얹어 50ms 밑으로 끌어내렸다. 이게 왜 중요하냐면, 에이전트 강화학습에서는 환경을 켜고-쓰고-버리기를 수천만 번 반복하기 때문이다. 한 번에 50ms만 아껴도 전체 비용이 어마어마하게 줄어든다.
E2B_API_URL 환경변수만 자기 서버 주소로 바꿔 주면 끝이다.새 도구가 아무리 좋아도 기존 코드를 다 뜯어고쳐야 하면 아무도 안 옮긴다. AgentENV는 "네가 쓰던 E2B 리모컨을 그대로 써라, 대신 TV만 우리 걸로 바꿔 준다"는 전략이다. 이전 비용을 거의 0으로 만들어 도입 장벽을 확 낮춘다. 셀프호스팅(내 서버에서 직접 운영)까지 가능하니 클라우드 비용·데이터 통제 이점도 있다.
에이전트마다 필요한 실행 환경(OS 이미지)이 제각각이다. 이걸 전부 각 서버 디스크에 미리 깔아 두려면 용량이 폭발한다. AgentENV는 overlaybd라는 기법으로 이미지를 필요한 블록만 그때그때 원격에서 당겨 온다. 로컬 디스크는 한정된 캐시로만 쓰여서, 자주 쓰는 데이터는 남기고 안 쓰는 건 버린다(LRU). 그 덕에 전체 이미지 집합이 디스크 용량을 초과해도 부팅은 빠르게 유지된다. §4에서 자세히 푼다.
이게 RL 학습에 특히 요긴하다. 어떤 상태까지 진행된 환경 하나를 여러 개의 독립 사본으로 복제할 수 있다. 나무의 한 지점에서 여러 갈래로 뻗듯이, "여기서부터 다른 선택지들을 동시에 실험"하는 병렬 롤아웃이 가능해진다. 매번 처음부터 환경을 다시 만들 필요가 없다.
마지막으로, 이건 취미 프로젝트가 아니라 Kimi-K3라는 실제 프론티어 모델의 학습을 돌린 인프라다(kvcache-ai = KTransformers·Mooncake 팀). "논문용 데모"가 아니라 production에서 굴러 본 시스템을 통째로 오픈소스(MIT)로 공개했다는 점이 신뢰를 준다.
정식 릴리스 태그가 하나도 없고(v0.1.0은 코드 내부 표기), 분산 컨트롤플레인(Go)과 aenv build 명령은 문서에 "프로토타입/실험적"이라고 명시돼 있다. 스케줄러의 매핑 정보도 메모리에만 있어 재시작하면 사라진다. 그리고 결정적으로 아직 인증(authorization) 기능이 없다 — README가 "공개 네트워크에 절대 노출하지 말라"고 경고한다. 지금은 "잘 만든 엔진의 뼈대"이지 완성된 상용 서비스가 아니다.
AgentENV는 크게 두 개의 층으로 나뉜다. 각 서버(노드)에서 실제로 VM을 굴리는 Rust 엔진이 알맹이고, 여러 노드를 조율하는 Go 컨트롤플레인이 그 위에 얇게 얹혀 있다.
| 언어 | 파일 수 | 담당 |
|---|---|---|
| Rust | 384 | 런타임 엔진 전체 — VM 관리·스토리지·스냅샷·API |
| Go | 37 | 분산 컨트롤플레인 (게이트웨이 + 스케줄러) |
| Shell | 34 | 설치·셋업·E2E 테스트 스크립트 |
| Markdown | 95 | mdBook 문서 (30여 페이지) |
| Python / TS | 2 / 1 | E2B SDK 호환성 검증 테스트 |
| Proto | 3 | gRPC 인터페이스 정의 |
비동기 런타임과 웹 서버, gRPC, 그리고 리눅스 저수준 라이브러리가 뼈대다.
| 분류 | 라이브러리 | 역할 |
|---|---|---|
| 비동기/웹 | tokio 1, axum 0.8, hyper 1 | HTTP API 서버 (E2B 호환 엔드포인트) |
| gRPC | tonic 0.14, prost 0.14 | 노드↔스케줄러 통신 |
| VM 제어 | firecracker_client 1.15 | Firecracker 마이크로VM 조종 |
| 로컬 KV | rocksdb 0.24 | 노드 메타데이터 저장 (일시정지된 샌드박스 등) |
| 객체 스토리지 | opendal 0.55 (S3) | 스냅샷을 S3 호환 저장소로 영속화 |
| 디스크 I/O | io-uring 0.7 | 고성능 비동기 디스크 접근 |
| 리눅스 저수준 | nix 0.31, rtnetlink 0.20 | 마운트·네임스페이스·네트워크 설정 |
| P2P | iroh 1.0-rc, iroh-blobs | 노드 간 아티팩트(스냅샷·이미지 레이어) 전송 |
| CLI | clap 4, crossterm 0.28 | aenv 명령줄 도구 |
Go 1.25 기반이며, 여러 노드를 묶어 "어느 노드에 새 샌드박스를 띄울까"를 결정한다.
| 라이브러리 | 역할 |
|---|---|
google.golang.org/grpc 1.82 | 게이트웨이↔스케줄러 gRPC |
redis/go-redis 9.7 | (선택) 스케줄러 바인딩 저장소 |
k8s.io/client-go 0.29 | 쿠버네티스 EndpointSlice로 노드 자동 발견 |
prometheus/client_golang | 메트릭 수집 |
go.uber.org/zap | 구조화 로깅 |
Rust 엔진은 호텔 한 채의 지배인이다 — 방을 만들고, 청소하고, 손님을 들이고, 안 쓰는 방을 접는 실무를 다 한다. Go 컨트롤플레인은 체인 전체의 예약 센터다 — "이번 손님은 강남점 말고 판교점이 비었으니 그리로" 하고 배정만 한다. 무거운 일은 전부 Rust가, 가벼운 조율만 Go가 맡는 구조다.
AgentENV의 기술적 알맹이는 스토리지 계층에 있다. "가상머신을 어떻게 빨리 켜고 스냅샷을 어떻게 빨리 뜨느냐"가 전부 여기서 결정된다. 이걸 이해하려면 세 층을 순서대로 봐야 한다: ① Firecracker(VM 자체) → ② ublk(유저공간 블록 디바이스) → ③ overlaybd(레이어드 이미지 포맷).
핵심은 VM이 디스크라고 믿는 것이 사실은 유저공간 프로그램이라는 점이다. Firecracker는 /dev/vda를 평범한 디스크로 알고 읽고 쓰지만, 그 뒤에서 ublk가 요청을 가로채 overlaybd 레이어에서 데이터를 조립해 준다. 이 "가짜 디스크" 트릭이 온디맨드 로딩·스냅샷·포크를 전부 가능하게 하는 열쇠다.
50ms 재개의 비밀은 Firecracker의 스냅샷 기능에 있다. 켜져 있던 VM의 메모리 전체와 상태를 파일로 저장해 뒀다가, 다시 켤 때 처음부터 부팅하지 않고 그 순간을 그대로 복원한다. AgentENV는 여기에 자체 스토리지 마술을 더해 복원을 극한까지 빠르게 만든다(4-4 참조).
/dev/ublkb0에 읽기 요청을 보내면, 커널이 그걸 유저공간 프로그램에 넘기고, 프로그램이 "이 데이터 줄게" 하고 돌려준다. 디스크를 소프트웨어로 흉내 내는 셈이라, 어떤 로직이든 끼워 넣을 수 있다.
AgentENV는 ublk 위에 io_uring(리눅스의 최신 고성능 비동기 I/O)을 얹어 이 "가짜 디스크"가 진짜 디스크만큼 빠르게 굴러가도록 짰다. 구조가 흥미롭다 — ublk 디바이스를 관리하는 uvm-ublk-daemon이라는 별도 프로세스를 두고, 메인 노드와는 유닉스 도메인 소켓으로 통신한다.
io_uring 같은 저수준 I/O 제어를 메인 서버에 다 넣으면, 하나가 삐끗할 때 전체가 흔들린다. 블록 디바이스 관리만 전담하는 일꾼(데몬)을 격리해 두면, 안정성도 오르고 워밍업된 디바이스를 풀(pool)로 미리 준비해 두기도 쉽다. "복잡하고 위험한 일은 전담 부서에 몰아넣는다"는 시스템 설계의 정석이다.
이게 AgentENV에서 가장 인상적인 부분이다. 도커 이미지처럼 여러 층(layer)을 쌓아 만드는 이미지 포맷인 overlaybd를, 이들은 기존 것을 가져다 쓰지 않고 Rust로 처음부터 다시 구현했다.
기술적으로는 LSMT(Log-Structured Merge Tree) 구조다. 각 레이어 파일은 헤더(매직 넘버 LSMT\0\1\2, UUID)와 비트팩킹된 매핑 테이블(16바이트에 오프셋·길이·물리위치를 욱여넣음)을 갖는다. 읽기는 위층→아래층으로 검색, 쓰기는 상단 레이어에 append. 저장 백엔드는 갈아 끼울 수 있다 — 로컬 파일(io_uring), OCI 레지스트리(원격 이미지 레이어), tar. 압축은 zstd 레벨3 + 랜덤액세스 점프테이블 + CRC32C로, 압축돼 있어도 원하는 위치를 바로 읽는다.
이제 조각을 맞춰 보자. VM을 재개할 때, AgentENV는 저장해 둔 메모리 스냅샷을 읽기 전용 ublk 디바이스로 만들어 Firecracker에 "메모리 백엔드"로 건넨다. Firecracker는 이걸 mmap으로 붙이고, VM이 어떤 메모리 페이지를 처음 건드릴 때 그 순간에만 실제로 복사(COW)한다. 즉 "메모리 전체를 미리 복원"하는 게 아니라, 실제로 쓰는 부분만 lazy하게 채운다. 그래서 50ms가 나온다.
한 스냅샷에서 VM 100개를 동시에 띄우면, 그 메모리 ublk 디바이스를 참조 카운팅으로 한 벌만 두고 공유한다. 리눅스의 페이지 캐시가 재사용되니, 100개를 켜도 메모리가 100배로 늘지 않는다. 일시정지(pause) 때는 Firecracker의 Diff 스냅샷으로 바뀐 페이지만 sparse하게 뽑아 overlaybd 레이어로 포장한다 — 그래서 100ms 안에 끝난다.
50ms조차 아끼려고, 자주 쓰는 자원을 미리 만들어 대기시킨다:
게이트웨이는 HTTP 리버스 프록시다. 요청 헤더나 호스트명({포트}-{샌드박스ID}.{도메인})에서 샌드박스 ID를 뽑아, 새 샌드박스면 스케줄러에 Schedule()로 노드 배정을 요청하고, 기존 것이면 LookupNode()로 위치를 찾아 넘긴다. 스케줄러는 gRPC 서비스로, 노드 발견(정적 목록 또는 쿠버네티스 EndpointSlice)과 배정 전략(round_robin/random)을 담당한다.
어느 샌드박스가 어느 노드에 있는지의 매핑이 스케줄러 프로세스 메모리에만 저장된다. 스케줄러를 재시작하면 이 정보가 날아가고, 새 생성·하트비트로 다시 채워진다. Redis 저장소 옵션이 있지만 아직 기본은 인메모리다. 문서가 이 컨트롤플레인을 "프로토타입"으로 못 박은 이유다.
노드가 많아지면 스냅샷·이미지 레이어를 매번 중앙 저장소에서 받는 게 병목이 된다. AgentENV는 iroh/iroh-blobs 기반 P2P 전송을 선택적으로 켤 수 있다. 한 노드가 받은 아티팩트를 다시 이웃에 뿌려, 콘텐츠가 클러스터 전체로 번지게 한다(BitTorrent 비슷한 발상). 기본값은 꺼짐(DisabledP2pTransport)이고, 필요할 때만 iroh 백엔드로 교체하는 trait 기반 플러그인 구조다.
이 저장소는 Rust 워크스페이스(Cargo workspace)가 뼈대다 — 여러 크레이트(패키지)를 한 저장소에서 함께 빌드한다. 최상위를 훑어보자.
구조를 읽는 요령: src/는 "한 노드가 하는 일", storage/는 "그걸 빠르게 만드는 마법", services/는 "여러 노드 묶기", crates/aenv는 "사람이 쓰는 리모컨"이다. 처음 코드를 읽는다면 CLAUDE.md → docs/src/internals/architecture.md → storage/overlaybd/ 순서를 추천한다.
# 인증 aenv auth # 템플릿(이미지) 준비 — OCI 이미지를 끌어와 실행 템플릿으로 aenv pull ubuntu:24.04 --name mybox --start-cmd "..." # 샌드박스 생명주기 aenv start # 새 환경 시작 aenv exec <id> "python x.py" # 안에서 명령 실행 aenv pause <id> # 일시정지 (자원 반납) aenv resume <id> # 50ms 재개 aenv snapshot create <id> # 스냅샷 저장 aenv delete <id> # 폐기
왜 도커가 아니라 Firecracker인가? 커널 공유(컨테이너) vs. 커널 분리(VM)의 트레이드오프, 그리고 "빠르면서 안전한" 지점을 어떻게 찾는지가 이 레포의 출발점이다. 신뢰할 수 없는 코드(AI가 짠 코드)를 실행하는 모든 서비스의 근본 고민이 여기 담겨 있다.
ublk로 블록 디바이스를 소프트웨어로 만드는 경험은 흔치 않다. "디스크가 사실은 프로그램이다"라는 발상, 그리고 io_uring으로 그걸 빠르게 만드는 법 — FUSE, userfaultfd, ublk 같은 유저공간 커널 인터페이스 계열을 이해하는 최고의 실전 예제다.
overlaybd는 도커 이미지, 파일시스템 스냅샷, 심지어 메모리 스냅샷까지 같은 "레이어 + COW" 원리로 푼다. 하나의 아이디어가 디스크·메모리·이미지 세 곳에 어떻게 재사용되는지 보면, 시스템 설계에서 추상화의 힘을 배운다.
온디맨드 로딩, lazy 메모리 복원(mmap+COW), 워밍업 풀 — 전부 "실제로 필요할 때까지 일을 미룬다"는 같은 철학이다. 50ms라는 숫자는 알고리즘이 빨라서가 아니라 일을 안 하도록 설계해서 나온다. 성능 엔지니어링의 핵심 사고방식.
성능이 생명인 데이터플레인은 Rust로, 조율만 하는 컨트롤플레인은 Go로 — 언어를 목적에 맞게 나눠 쓰는 실전 아키텍처 결정을 볼 수 있다. gRPC로 두 세계를 잇는 방식도 함께.
이 레포는 Linux 6.8+ 커널과 /dev/kvm이 필수라 맥·윈도우에서 그냥 안 돌아간다(설치 스크립트는 Ubuntu 24.04 대상). 코드도 커널·비동기·gRPC가 뒤섞인 고급 시스템 프로그래밍이라 입문자에게 벽이 높다. "지금 당장 돌려 보기"보다 "설계 사상과 용어를 배우는 교재"로 접근하는 게 현실적이다.
결론부터: 리눅스 서버가 있어야 한다. Firecracker가 하드웨어 가상화(/dev/kvm)를 쓰기 때문에, 가상화가 켜진 리눅스 머신(또는 중첩 가상화가 되는 클라우드 VM)이 필요하다.
| 항목 | 요구사항 |
|---|---|
| 운영체제 | Linux 커널 6.8 이상 (ublk 제로카피 기능 필요). 설치 스크립트는 Ubuntu 24.04 기준 |
| 가상화 | /dev/kvm 접근 필수 (Firecracker microVM 실행). macOS/Windows 네이티브 불가 |
| 권한 | 초기 셋업에 root 필요 (server --setup-host로 KVM 그룹·ublk 권한·네트워크 sysctl 설정) |
| 스토리지 | 스냅샷 영속화용 S3 호환 객체 저장소 또는 공유 분산 파일시스템(선택) |
| 다중 노드 | 쿠버네티스 배포 시 특권(privileged) DaemonSet — 호스트당 런타임 파드 1개 |
현재 버전은 authorization이 구현되지 않았다. API에 접근할 수 있으면 누구나 VM을 띄우고 명령을 실행할 수 있다는 뜻이다. README는 "공개 인터넷에 노출하지 말 것"을 못 박는다. 반드시 사설 네트워크·VPN 뒤에서만 운영해야 한다.
바로 프로덕션에 올리기보다, deploy/docker-compose.yml(게이트웨이+스케줄러+노드 2개 구성)로 로컬 클러스터를 띄워 E2B SDK 호환 테스트(scripts/tests/e2e/)를 돌려 보는 게 좋은 첫걸음이다. 그다음 docs/의 internals 문서로 내부를 파면 된다.
docs/src/internals/architecture.md와 CLAUDE.md를 읽고, 이 문서 §4의 흐름도(클라이언트→API→오케스트레이터→ublk→overlaybd)를 스스로 손으로 재구성한다. 각 화살표에서 무슨 데이터가 흐르는지 주석을 달면, 시스템 독해력이 붙는다.
E2B의 Python SDK로 간단한 코드 실행 스크립트를 짠 뒤, E2B_API_URL만 바꾸면 백엔드가 갈리는 구조를 직접 코드로 확인한다. "드롭인 호환"이 API 레벨에서 어떻게 성립하는지 감이 온다. (실제 AgentENV 서버 없이 E2B 클라우드로도 개념 학습 가능.)
리눅스 서버(또는 중첩가상화 클라우드 VM)에서 Firecracker를 맨손으로 띄워 커널+rootfs로 microVM을 부팅하고, 그 부팅 시간을 측정한다. 그다음 스냅샷을 떠서 재개 시간과 비교한다. "왜 스냅샷이 부팅보다 빠른가"를 몸으로 익히는 과제다.
리눅스 ublk(또는 libublk)로 메모리에만 존재하는 램디스크를 유저공간 프로그램으로 구현한다. /dev/ublkb0를 만들어 포맷하고 마운트해, "디스크가 사실은 내 프로그램"임을 확인한다. AgentENV 스토리지의 밑바탕 기술을 축소판으로 체험.
언어 무관하게, 읽기전용 베이스 + 쓰기가능 상단 레이어 구조를 직접 짠다. 읽기는 위→아래 검색, 쓰기는 상단에만 기록하도록. 그다음 "상단을 봉인해 새 베이스로 만들고 빈 상단을 여는" 스냅샷 연산을 추가한다. overlaybd의 핵심 아이디어가 손에 잡힌다.
VM vs. 컨테이너의 근본 차이(하이퍼바이저·네임스페이스·cgroup), KVM이 뭔지, Firecracker가 왜 "microVM"인지. AWS Firecracker 논문(NSDI 2020)이 최고의 출발점이다. 도커·runc 구조도 함께 훑으면 대조가 선명해진다.
블록 디바이스의 개념, io_uring 비동기 I/O, 그리고 FUSE·userfaultfd·ublk 같은 "커널 기능을 유저공간으로 빼는" 인터페이스들. overlayfs와 devmapper도 함께 보면 overlaybd의 위치가 보인다.
Copy-on-Write의 여러 구현(btrfs·ZFS·overlayfs), OCI 이미지 스펙과 레이어, 그리고 lazy pulling(stargz·nydus·overlaybd 원조). 스냅샷을 어떻게 뜨고 어떻게 빨리 복원하는지의 이론.
gRPC와 서비스 디스커버리(쿠버네티스 EndpointSlice), 스케줄링 전략, 그리고 에이전틱 RL이 왜 이런 인프라를 요구하는지. Kimi-K3 기술보고서의 RL 인프라 섹션과 이어 읽으면, "모델과 인프라는 한 몸"이라는 그림이 완성된다.
"격리(왜 VM인가) → 스토리지(어떻게 빠른가) → 스냅샷(어떻게 재개하나) → 분산(어떻게 대량인가)" 순서로 파면, AgentENV의 모든 설계 결정이 하나의 목표("에이전트 환경을 싸고 빠르게 대량 공급")로 수렴하는 게 보인다.
E2B_API_URL만 바꾸면 기존 E2B 코드가 수정 없이 AgentENV로 붙는다.uvm-ublk-daemon이 관리.| 대상 | 위치 |
|---|---|
| 저장소 | github.com/kvcache-ai/AgentENV |
| 공식 문서(mdBook) | kvcache-ai.github.io/AgentENV |
| 내부 아키텍처 | docs/src/internals/architecture.md, 루트 CLAUDE.md |
| 동작 원리 개요 | concepts/overview.html |
| 배경 기사 | MarkTechPost — "Kimi AI and kvcache-ai Open Sources AgentENV" (2026-07-27) |
| 관련 모델 | MoonshotAI/Kimi-K3 — AgentENV가 학습을 떠받친 모델 |
| 격리 기반 | Firecracker (AWS) · E2B (AI 샌드박스 표준) |