작년 여름, 스타트업에서 “고객 지원 챗봇을 만들어야 하는데, 비용이 적게 들어야 한다”는 요청을 받았다. 당시 우리 팀의 상황은 이러했다. 개발자는 3명, 월 예산은 총 500만 원대, 24시간 운영이 필수였다. 기존 방식대로 EC2 인스턴스를 띄우고 OpenAI API를 쓰면? 월 비용이 족히 200만 원은 넘을 거였다. 회사가 감당할 수 없는 금액이었다.
그때 생각한 게 Azure Functions다. 서버리스 플랫폼이니까 사용한 만큼만 비용을 낸다. 근데 정말 가능할까? 실제로 해보면서 깨닫게 됐다. Azure Functions와 Azure OpenAI를 조합하면, 월 20~30만 원 수준에서 프로덕션급 AI 챗봇을 운영할 수 있다는 거다. 지난 8개월간 우리 챗봇은 월 10만 건 이상의 요청을 처리했는데, 비용은 처음 예상의 3분의 1 수준이었다.
이 경험을 바탕으로, 스타트업과 중소기업이 저비용으로 AI 챗봇을 운영하는 방법을 정리했다. 이론만 아니라 실제 운영 경험을 담았다.
왜 Azure Functions인가, 다른 선택지는 없을까
서버리스 플랫폼은 여러 개다. AWS Lambda, Google Cloud Functions, Azure Functions. 그런데 AI 챗봇을 만드는 관점에서 보면 Azure Functions가 가장 합리적이다.
첫 번째 이유는 비용이다. Azure Functions의 무료 티어는 월 100만 요청까지 무료다. 작은 규모 스타트업이라면 이것만으로 충분할 수 있다. 아니면 비용 기반 요금제를 쓸 수 있는데, 실행 시간이 매우 짧으면(예를 들어 1초) 월 비용이 거의 나오지 않는다. AWS Lambda는 무료 범위가 더 넓지만(월 백만 요청 + 연산량), 추가 비용이 발생할 때는 Azure가 더 저렴하다.
두 번째는 Azure OpenAI와의 통합이다. Azure Functions에서 Azure OpenAI를 호출하면, Azure 내부 네트워크를 사용하기 때문에 나가는 데이터 비용이 없다. AWS Lambda에서 OpenAI API를 호출하면? 외부 API 호출이 되니까 데이터 전송 비용이 붙는다. 이게 생각보다 크다.
세 번째는 확장성이다. Azure Functions는 자동으로 스케일링 된다. 요청이 많아지면 자동으로 인스턴스가 추가되고, 요청이 줄어들면 인스턴스가 줄어든다. Lambda도 비슷하지만, Azure의 구성이 좀 더 간단하다.
기본 구조, 어떻게 흘러가나
우리가 만든 챗봇의 기본 흐름은 이렇다.
사용자가 채팅 서비스(웹, 모바일, Slack, Teams 등)에서 메시지를 보낸다. 이 메시지가 Event Grid나 HTTP 트리거를 통해 Azure Function으로 들어온다. Azure Function은 이 메시지를 처리하고, 필요하면 Azure OpenAI에 질의한다. OpenAI에서 응답이 오면, 그 응답을 다시 사용자에게 보낸다. 이 전체 과정이 보통 1~2초 안에 끝난다.
구체적으로 구성 요소는 이렇다. 가장 위에는 사용자 채팅 인터페이스가 있다. 우리는 웹 기반 인터페이스를 만들었지만, 직접 만들 필요는 없다. Slack이나 Teams 봇으로도 가능하다.
그 다음은 Azure Functions다. HTTP 트리거 함수를 만든다. 사용자 메시지를 받아서 처리하는 부분이다.
그 다음은 Azure Cosmos DB나 Table Storage 같은 데이터 저장소다. 대화 히스토리를 저장해야 하니까. 무료나 저렴한 플랜을 써도 된다.
맨 아래는 Azure OpenAI다. 실제 답변을 생성하는 부분이다. 어떤 모델을 쓸지는 예산에 따라 결정하면 된다.
이 구조는 정말 심플하다. 복잡한 설정이 없다. 그리고 각 구성 요소의 비용이 명확하다.
실제 구현, 코드로 보자
먼저 Azure Function을 만들자. Python을 사용한다고 가정한다.
필요한 라이브러리는 azure-functions, azure-identity, openai 정도다. pip로 설치하면 된다.
HTTP 트리거 함수의 기본 구조는 이렇다. 사용자의 메시지가 JSON으로 들어온다. 그 메시지를 추출해서, Azure OpenAI에 보낸다. 응답을 받아서 다시 사용자에게 반환한다.
구체적으로는, 사용자 메시지에서 user_id를 추출한다. 이걸 이용해서 대화 히스토리를 Cosmos DB에서 가져온다. 그리고 새로운 메시지를 포함한 전체 대화 히스토리를 OpenAI에 전달한다. OpenAI가 응답을 생성하면, 그 응답을 Cosmos DB에 저장하고 사용자에게 반환한다.
코드는 간단하다. Azure의 SDK를 사용하면 복잡한 설정을 거의 안 해도 된다. Managed Identity를 사용하면 API 키도 관리할 필요가 없다.
비용 분석, 실제로 얼마가 들까
이게 가장 중요한 부분이다. 실제 비용을 계산해보자.
Azure Functions의 비용은 두 가지다. 실행 수와 실행 시간이다. 무료 티어는 월 100만 요청까지 무료, 월 40만 GB-초까지 무료다. 그 이상은 요청당 $0.2, GB-초당 $0.000016을 낸다.
만약 월 50만 요청을 받는다면? 50만은 무료 범위 안이니까 비용은 0원이다. 월 100만 요청이라면? 100만은 무료지만, 그 이상은 100만에서 200만까지인데, 이건 약 $20 정도다. 꽤 저렴하다.
실행 시간도 비슷하다. 우리 함수의 평균 실행 시간은 1.2초다. 한 요청이 평균 0.3 GB 메모리를 사용하니까, 한 요청당 0.36 GB-초다. 월 100만 요청이라면? 36만 GB-초다. 무료 범위 40만을 살짝 넘었으니까, 비용은 약 $1 정도다. 거의 무시할 수준이다.
진짜 비용은 Azure OpenAI다. 우리는 GPT-4 Turbo를 써서 평균적으로 한 요청당 입력 토큰 500개, 출력 토큰 300개를 사용한다. GPT-4 Turbo는 입력이 $0.01/1K, 출력이 $0.03/1K다. 한 요청당 비용은 약 $0.015다.
월 100만 요청이면? $15000이 된다. 어? 이건 너무 비싸다. 그런데 잠깐, 모든 요청이 OpenAI를 호출하는 건 아니다.
비용 최적화, 여기가 핵심이다
문제는 모든 사용자 메시지가 OpenAI 호출로 이어진다면 비용이 폭발한다는 거다. 그래서 우리는 여러 최적화 기법을 적용했다.
첫 번째는 캐싱이다. 자주 나오는 질문들(예를 들어 “서비스 이용료는?”, “가입 방법은?”)에 대해서는 미리 답변을 만들어 놨다. 사용자 질문이 들어오면, 먼저 이 Q&A 캐시를 검색한다. 매치되는 게 있으면 캐시된 답변을 바로 반환한다. OpenAI를 호출할 필요가 없다. 이것만으로도 월 40% 정도의 OpenAI 호출을 줄일 수 있었다.
두 번째는 의도 분류다. 사용자 메시지가 들어오면, 먼저 간단한 의도 분류를 한다. “환불 문의”인지, “기술 지원”인지, “일반 질문”인지 판단한다. 이건 가벼운 NLP 모델로 할 수 있다. 그 다음 의도에 따라 다른 처리를 한다. 예를 들어 “환불 문의”면 이미 만들어진 답변 템플릿을 사용한다. “일반 질문”이면 그때 OpenAI를 호출한다.
세 번째는 답변 길이 제한이다. 사용자가 긴 답변을 원할 수도 있지만, 우리는 짧고 명확한 답변을 강제했다. 프롬프트에 “답변을 100단어 이내로 주세요”라고 명시했다. 토큰 사용량이 줄어든다.
네 번째는 배치 처리다. 실시간이 아닌 요청들(예를 들어 야간의 메시지 요약)은 배치로 처리한다. Azure OpenAI의 배치 API를 사용하면 50% 할인을 받을 수 있다. 약간의 지연이 있지만, 비용 절감 효과가 크다.
이런 최적화들을 적용한 결과, 실제 비용은 어떻게 됐을까? 월 100만 요청을 기준으로 계산하면, Azure Functions는 약 $20, Azure OpenAI는 약 $4500이 된다. 총 약 $4520, 한화로 550만 원대다.
어? 여전히 비싸다? 그런데 생각해보자. 이건 월 100만 건의 요청을 처리한다는 거다. 챗봇 마다 비용이 450원 정도라는 뜻이다. 대중적인 챗봇 서비스를 보면 한 건에 1000원 이상을 받는다. 그 비용 안에 인프라, 인건비, 이윤이 다 들어가 있다. 우리는 순수 인프라 비용만 450원이니까, 매우 저렴한 거다.
그리고 우리는 또 다른 최적화를 했다. GPT-4 Turbo 대신 GPT-4o를 쓰는 걸 테스트했다. 가격이 거의 비슷한데 성능이 더 좋았다. 심지어 어떤 경우엔 GPT-3.5-turbo를 써도 충분했다. 이건 사용 케이스에 따라 다르다.
운영에서 배운 교훈들
8개월을 운영하면서 여러 문제에 직면했다.
첫 번째는 콜드 스타트다. Azure Functions도 오래 안 쓰면 인스턴스가 내려간다. 다음 요청이 들어오면 다시 시작해야 하는데, 이 과정에서 5~10초가 걸린다. 처음엔 답변이 너무 늦어서 사용자들이 불평했다. 해결책은 프리미엄 플랜으로 업그레이드하는 거였다. 가격은 조금 올라가지만, 항상 인스턴스가 켜져있다.
두 번째는 토큰 초과였다. 사용자가 너무 긴 문맥을 입력하면, 토큰이 모델의 최대값을 초과할 수 있다. 우리는 슬라이딩 윈도우 방식으로 최근 대화만 유지하도록 했다. 마지막 5턴의 대화만 OpenAI에 보낸다.
세 번째는 API 레이트 제한이었다. OpenAI는 요청 수와 토큰 수에 제한을 둔다. 우리는 처음에 이 제한에 자주 걸렸다. 해결책은 두 가지였다. 하나는 OpenAI에 제한을 높여달라고 요청하는 거고, 다른 하나는 큐 시스템을 도입하는 거였다. 요청이 많으면 일부를 큐에 담아뒀다가 천천히 처리한다.
네 번째는 모니터링이었다. 처음엔 뭔가 잘못된 줄을 모르고 지나쳤다. 한번은 OpenAI 응답이 자꾸 이상한 내용을 생성했는데, 알고 보니 프롬프트 인젝션 공격이었다. 그 이후 입력 검증을 강화했다. 또한 Application Insights로 모든 호출을 추적하기 시작했다.
확장성, 나중에는 어떻게 될까
우리 챗봇이 성장하면서 고려해야 할 게 생겼다. 지금은 월 100만 건 정도지만, 6개월 뒤엔 500만 건이 될 수도 있다.
그럼 Azure Functions만으로 부족할까? 아니다. Azure Functions는 자동 스케일링이 되니까 문제없다. 비용이 올라갈 뿐이다.
더 큰 문제는 데이터 저장소다. 현재는 Cosmos DB를 쓰고 있는데, 요청이 매우 많아지면 병목이 될 수 있다. 그땐 캐싱 층을 추가할 예정이다. Azure Cache for Redis를 앞에 두면 대부분의 읽기 요청을 빠르게 처리할 수 있다.
또한 여러 지역에 배포하는 것도 고려했다. 현재는 동남 아시아 지역 하나에만 배포되어 있다. 나중에 유럽, 북미 같은 지역에서 요청이 많아지면, 해당 지역에도 인스턴스를 배포할 거다.
보안 고려사항
챗봇이 사용자 데이터를 다루기 때문에 보안이 중요하다.
첫째, Managed Identity를 사용해서 API 키를 관리하지 않는다. 이건 이미 앞에서 설명했듯이 Azure의 장점이다.
둘째, 데이터 암호화다. Cosmos DB의 저장 데이터 암호화를 활성화했다. 전송 중인 데이터도 HTTPS만 사용한다.
셋째, 접근 제어다. Azure RBAC를 사용해서 누가 뭘 할 수 있는지 제한했다.
넷째, 감시다. 모든 API 호출을 로깅한다. 비정상 패턴이 보이면 즉시 알림이 온다.
결론: 스타트업의 AI 챗봇은 이제 현실이다
3년 전만 해도 스타트업이 AI 챗봇을 만드려면? 엄청난 비용이 필요했다. 지금은 다르다. Azure Functions와 Azure OpenAI를 조합하면, 월 50만 원대에서 프로덕션급 챗봇을 운영할 수 있다.
우리의 경험이 모든 스타트업에 딱 들어맞지는 않을 거다. 각자의 상황에 따라 조정이 필요하다. 하지만 기본 원리는 같다. 서버리스 + 클라우드 AI = 저비용 구현.
지금 당신이 스타트업 개발자라면, Azure Functions로 시작해보자. 처음부터 완벽할 필요는 없다. 작은 규모로 시작해서, 반응을 보며 점진적으로 개선하면 된다. 그 과정에서 당신은 자동으로 최적화를 배우게 된다.
가장 중요한 건 시작하는 거다. 비용이 부담되면서 AI 활용을 미루지 말자. 방법이 있다.