
Hono는 일본어로 불을 의미합니다. 저는 AI 로봇의 호텔 방 안에 그것을 넣었습니다.
요약
Amazon Bedrock AgentCore Runtime 환경에서 Hono, Express, FastAPI 프레임워크의 성능과 적합성을 비교하는 실험을 다룹니다. AWS의 AI 로봇용 컨테이너 환경에서 각 프레임워크가 규칙을 얼마나 잘 준수하는지 테스트합니다.
핵심 포인트
- Amazon Bedrock AgentCore Runtime은 컨테이너 기반의 AI 에이전트 실행 환경을 제공함
- 호텔 규칙: 8080 포트 사용, 상태 확인(ping), 요청 처리(invocations), ARM64 빌드 필수
- Hono, Express, FastAPI를 동일한 규칙 하에 비교 실험함
- WebSocket 지원 여부에 따라 통신 방식의 차이가 발생함
본격적인 시작에 앞서 짧은 사실 하나: 웹 프레임워크인 Hono는 일본어로 불꽃을 뜻하는 '炎(honō)'에서 이름을 따왔습니다. 개발자들은 불꽃처럼 작고 빠르다는 의미에서 이 이름을 선택했습니다. 저는 이 프로젝트를 시작할 때 그 사실을 몰랐습니다. 이 포스트를 작성하면서 알게 되었고, 그 사실을 알고 나니 위의 캠프파이어 사진은 단순한 스톡 이미지가 아니라 이 글의 핵심 주제가 되었습니다.
제가 실제로 한 일은 다음과 같습니다: 저는 그 작은 불꽃을 Amazon이 운영하는 AI 로봇용 호텔 방 안에 넣었습니다. 그리고 바로 옆의 동일한 방들에 Express와 FastAPI라는 두 명의 다른 투숙객을 배치했습니다. 세 명 모두에게 동일한 규칙서(rulebook)를 적용했습니다. 저는 누가 가장 큰 소란 없이 규칙을 따르는지 지켜보았습니다.
호텔에는 단 두 가지 규칙만 있습니다
이 AI 로봇 호텔은 Amazon Bedrock AgentCore Runtime이라는 실제 AWS 제품입니다. 여러분은 여기에 컨테이너 (container)를 제공합니다. 컨테이너는 여러분의 프로그램과 실행에 필요한 모든 것을 담고 있는 밀봉된 도시락이라고 생각하면 됩니다. 덕분에 어떤 주방에서 다시 데워지더라도 동일하게 작동합니다. 그 대가로 호텔은 지루한 작업들을 처리해 줍니다: 각 투숙객에게 개인실을 제공하고, 신분증을 확인하며, 투숙객이 떠난 후 뒷정리를 하는 일 말입니다.
제가 예상하지 못했던 점은 실제 규칙서가 얼마나 짧은가 하는 것이었습니다. 저는 수 페이지에 달하는 설정법을 예상하며 규칙서를 찾아 나섰지만, 대신 네 가지 규칙과 한 가지 선택 사항만을 발견했습니다.
8080 포트에서 응답하세요. 포트 (Port)는 그저 번호가 매겨진 문일 뿐이며, 8080은 호텔의 우편 배달부가 노크할 특정 문입니다. GET /ping에 대해서는 당신의 상태(health status)로 응답하세요. 이는 호텔 간호사가 당신의 맥박을 확인하는 것과 같습니다. 아직 살아있나요? 그저 Healthy 또는 HealthyBusy라고 말하면 됩니다. POST /invocations에 대해서는 답변을 응답하세요. 이것은 게스트가 당신의 AI에게 질문이 있을 때 실제로 누르는 초인종입니다. 그리고 ARM64용으로 빌드하세요. 모든 CPU는 약간씩 다른 언어를 사용하며, 이 호텔은 아마 당신의 노트북이 실행 중일 더 일반적인 방언이 아닌 ARM64 방언만을 이해하기 때문입니다.
선택 사항인 추가 항목은 WebSocket을 위한 GET /ws입니다. 핑(ping)과 인보케이션(invocations) 쌍을 문 밑으로 메모를 한 번에 하나씩 남기는 것이라고 생각한다면, WebSocket은 대신 연결이 유지되는 전화 통화와 같습니다.
이것이 규칙서의 전부입니다. 특정 프레임워크도, 특정 언어도 없이, 그저 "이 문들에 올바르게 응답하라"는 것입니다. 즉, 이론적으로는 이 방을 어떤 언어로든 작성할 수 있다는 뜻입니다.
실제로 제가 온라인에서 찾은 모든 예제는 Python의 FastAPI나 Node의 Express로 작성되어 있었습니다. 아무도 Hono를 시도하지 않았습니다. 그래서 제가 했습니다.
방 만들기
방 전체, 즉 세 개의 문인 /invocations, /ping, /ws를 모두 합쳐 98줄이었습니다. 축약된 형태는 다음과 같습니다:
app.get("/ping", (c) => c.json(ping.body()));
app.post("/invocations", async (c) => {
...
단일 메시지 응답, 점진적으로 흘러나오는 스트리밍(streaming) 응답, 그리고 전화 통화 응답이 모두 동일한 작은 파일 안에 공존합니다. Hono의 어떤 부분도 AgentCore를 위해 특별하게 처리된 것은 없습니다. 그저 일반적인 HTTP 요청에 응답하는 일반적인 웹 프레임워크(web framework)일 뿐입니다. 호텔은 도시락 안에 무엇이 들어있는지 알지도 못하고 상관하지도 않습니다.
세 명의 게스트, 동일한 규칙서
저는 동일한 방을 두 번 더 만들었습니다. 한 번은 Express로, 한 번은 FastAPI로 만들었습니다. 세 개의 문과 동작 방식은 모두 동일했으며, 제가 작성한 13가지 항목의 테스트(모든 문을 두드려 방이 올바르게 응답하는지 확인하는 테스트 — 헬스 체크 (health check), JSON 응답, 스트리밍 응답, WebSocket 응답, 그리고 몇 가지 예외 케이스 포함)를 통해 검증했습니다. 세 개의 방 모두 13가지 항목을 모두 통과했습니다.
그다음 그것들을 비교했습니다.
크기와 속도는 거의 차이가 없었습니다. 완성된 도시락의 크기는 Hono가 237MB, Express가 237MB, FastAPI가 256MB였는데, 이 무게의 거의 대부분은 프레임워크 자체가 아니라 각 프레임워크가 구동되는 기본 운영 체제(OS)의 무게였습니다. 시작 시간 (Startup time) 또한 비슷한 결과를 보여주었습니다. Hono와 Express는 무승부라고 할 수 있을 만큼 비슷했고, FastAPI는 수백 밀리초(ms) 정도 뒤처졌습니다. 만약 이 두 가지 수치만으로 프레임워크를 선택한다면, 어느 것을 선택해야 할 특별한 이유가 없을 것입니다.
진정한 차이점은 제가 직접 설치해야 하는 추가적인 배관 (plumbing) 작업의 양에서 나타났습니다. Express는 자체적으로 WebSocket을 처리할 수 없기 때문에, 저는 그 밑단의 로우 네트워크 연결 (raw network connection)에 직접 접근하여 브라우저가 일반 요청에서 전화 통화로 "업그레이드 (upgrade)"를 요청하는 순간을 수동으로 포착한 다음, 이를 별도의 WebSocket 라이브러리로 넘겨주어야 했습니다. 반면, FastAPI의 프런트 데스크는 문을 여는 것조차 거부했습니다. 저는 이 문이 단일 문자나 스트리밍 전화 통화 중 하나로 응답할 수 있다고 알려주었지만, FastAPI는 그 응답에 대해 엄격한 형식을 구축하려 시도하다가 제가 규칙을 완화하라고 말할 때까지 스스로의 규칙에 막혀 쩔쩔맸습니다.
Hono는 두 가지 수정 사항이 모두 필요하지 않았습니다. 이 프레임워크는 상황에 따라 응답이 다르게 보일 수 있음을 이미 가정하고 있으므로, 추가적인 작업이 전혀 필요하지 않았습니다.
실제로 실행했을 때만 나타나는 두 가지
간호사의 클립보드에는 함정이 있습니다. 건강 검진은 단순히 "살아있음 또는 죽음"만을 나타내는 것이 아니라, "살아있지만 바쁨"이라고 표시할 수도 있으며, 해당 상태가 마지막으로 언제 변경되었는지 보고합니다. 저는 합리적으로 추측하여, 모든 체크인 시마다 현재 시간을 찍어줄 것이라고 생각했습니다. 하지만 그것은 틀렸으며, 제가 검색을 통해서야 겨우 찾아낸 AWS의 작은 글씨(fine print)에도 그렇게 명시되어 있습니다. 만약 누군가 요청할 때마다 계속해서 "방금 전"이라고 찍어준다면, 호텔은 방 안에서 무언가가 영원히 활발하게 일어나고 있다고 생각하여 해당 방을 절대 유휴(idle) 상태로 전환하지 않습니다. 투숙객은 결코 체크아웃하지 않습니다. 방은 그저 그곳에 머물며 당신의 예산을 태워버립니다. 저는 이와 정확히 똑같은 실수를 의도적으로 저지르는 코드 버전을 만들어 이를 확인했습니다. 스위치를 전환하여 타임스탬프(timestamp)를 깨뜨리면, 다른 모든 것은 통과하는 동안 오직 그 한 가지만 실패합니다.
로컬(local) 체크도 저를 속였습니다. 제 타입 체커(type checker)는 코드가 괜찮다고, 오류가 없다고 말했습니다. 그러다 실제로 그것을 도시락(lunchbox)에 담으려고 시도하자, 완성된 파일들을 어디에 두어야 할지 모르겠다는 오류와 함께 거부되었습니다. 타입 체커는 코드가 논리적으로 타당한지만 확인할 뿐, 실제로 디스크(disk)에 아무것도 쓰지 않기 때문에 제가 "디스크"가 어디인지 알려주는 것을 잊었다는 사실을 전혀 알아차리지 못했습니다. 어떤 단계가 실제로 파일을 생성하려고 시도하는 순간, "통과"했던 동일한 코드가 갑자기 작동하지 않게 됩니다.
실제로 배포하기 (Actually shipping it)
로컬 테스트는 별개의 문제입니다. 저는 또한 Hono 도시락을 실제 AWS로 푸시(push)하고 실제 방을 빌렸습니다.
첫 번째 시도는 거부되었습니다. 저는 이미 다른 프로젝트에서 사용하던 키 세트를 재사용하려고 시도했고, 호텔은 거절했습니다. 해당 키링(keyring)은 특정 저장 창고 하나만 열 수 있으며, 이 창고는 아니었습니다. 지나고 보니 합리적인 결과였습니다. 저는 재사용할 수 있다고 가정하기 전에 충분히 자세히 살펴보지 않았을 뿐입니다. 저는 오직 이 프로젝트의 창고에만 권한이 제한된(scoped) 새로운 키링을 만들었고, 두 번째 시도는 성공했습니다.
실행되고 나니, 예상하지 못했던 점을 발견했습니다. 모든 새로운 게스트 ID (guest ID)는 완전히 새로운 방을 처음부터 시작합니다. 저는 14개의 서로 다른 게스트 ID로 호텔에 14번 전화를 걸었고, 각각
지금 다시 생각해보니, 불(flame)의 이름을 딴 무언가가 행동하는 방식으로는 꽤 적절한 것 같습니다. 그것은 많은 땔감(kindling)을 필요로 하지 않습니다. 그저 약간의 공기만 있으면 이미 타오르기 시작합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기