AI 개발 가이드

Streamlit으로 AI 웹앱 30분 만에 배포하기

소개왕 탑백귀 2026. 4. 9. 18:42

Streamlit으로 AI 웹앱 30분 만에 배포하기

2026년 4월 기준 | AI 개발 가이드

요약: Streamlit은 파이썬 코드만으로 웹 애플리케이션을 만드는 프레임워크입니다. HTML, CSS, JavaScript를 전혀 몰라도 됩니다. 이 글에서는 Streamlit 설치부터 Claude API를 연동한 문서 요약 챗봇 제작, 그리고 Streamlit Cloud에 무료 배포하는 과정까지 전부 다룹니다. 실제로 프로젝트를 만들면서 겪은 삽질과 해결 과정도 함께 정리했습니다.

Streamlit이 뭔가

AI 모델을 만들고 나면 항상 같은 문제에 부딪힙니다. "이걸 어떻게 다른 사람한테 보여주지?" Jupyter Notebook을 공유할 수도 있지만, 비개발자한테 "노트북 열어서 셀 실행해보세요"라고 하면 십중팔구 포기합니다.

Flask로 웹앱을 만들자니 HTML 템플릿, CSS 스타일링, JavaScript 이벤트 처리까지 신경 써야 합니다. 프론트엔드 개발자가 아닌 이상, 간단한 데모 하나 만드는 데 이틀이 걸립니다.

Streamlit은 이 문제를 깔끔하게 해결합니다. 파이썬 스크립트 하나로 입력 폼, 차트, 테이블, 채팅 인터페이스까지 전부 만들 수 있습니다. 프론트엔드 코드가 한 줄도 필요 없습니다.

제가 처음 Streamlit을 접한 건 사내에서 LLM 프로토타입을 빠르게 시연해야 했을 때입니다. Flask로 만들면 3일, Streamlit으로 만들면 2시간. 선택의 여지가 없었습니다. 그 이후로 AI 관련 데모는 전부 Streamlit으로 만들고 있습니다.

2026년 4월 기준 Streamlit 최신 버전은 1.42이고, 최근에는 st.chat_input, st.chat_message 같은 챗봇 전용 컴포넌트가 추가돼서 AI 챗봇을 만들기가 훨씬 편해졌습니다.

설치 및 기본 사용법

설치는 pip 한 줄이면 끝입니다.

# 가상환경 생성 (권장)
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# Streamlit 설치
pip install streamlit

# 설치 확인
streamlit --version
# Streamlit, version 1.42.0

가장 간단한 앱을 만들어보겠습니다. app.py 파일을 생성합니다.

import streamlit as st

st.title("첫 번째 Streamlit 앱")
st.write("안녕하세요! 이게 전부입니다.")

name = st.text_input("이름을 입력하세요")
if name:
    st.write(f"반갑습니다, {name}님!")

number = st.slider("숫자를 선택하세요", 0, 100, 50)
st.write(f"선택한 숫자: {number}")

실행도 한 줄입니다.

streamlit run app.py

브라우저가 자동으로 열리면서 http://localhost:8501에 웹앱이 뜹니다. 코드를 수정하면 브라우저에서 자동으로 새로고침됩니다. 이 핫 리로드 기능이 개발 생산성을 크게 올려줍니다.

핵심 UI 컴포넌트 정리

Streamlit의 컴포넌트는 직관적입니다. 파이썬 함수 하나가 UI 요소 하나에 대응됩니다. 자주 쓰는 것들을 정리하면:

  • st.text_input() - 텍스트 입력 필드
  • st.text_area() - 여러 줄 텍스트 입력
  • st.selectbox() - 드롭다운 선택
  • st.file_uploader() - 파일 업로드
  • st.button() - 버튼
  • st.spinner() - 로딩 표시
  • st.chat_input() - 채팅 입력창
  • st.chat_message() - 채팅 메시지 버블
  • st.sidebar - 사이드바 영역
  • st.session_state - 상태 관리 (중요!)

여기서 st.session_state가 가장 중요합니다. Streamlit은 사용자가 뭔가를 조작할 때마다 스크립트 전체를 위에서 아래로 다시 실행합니다. 변수를 그냥 선언하면 매번 초기화됩니다. 대화 기록 같은 걸 유지하려면 반드시 st.session_state에 저장해야 합니다. 이걸 모르면 챗봇을 만들 때 메시지가 계속 사라지는 현상을 겪게 됩니다. 저도 처음에 30분을 날렸습니다.

실전 프로젝트: Claude API + 문서 요약 챗봇

이제 진짜 쓸만한 걸 만들어보겠습니다. 사용자가 텍스트를 붙여넣거나 파일을 업로드하면, Claude API가 문서를 요약해주는 챗봇입니다. 대화형으로 추가 질문도 가능합니다.

먼저 필요한 패키지를 설치합니다.

pip install streamlit anthropic python-dotenv

프로젝트 구조는 이렇습니다:

[프로젝트 구조]
streamlit-summarizer/
├── app.py
├── requirements.txt
├── .env
├── .gitignore
└── .streamlit/
    └── secrets.toml
주의: .env 파일에 API 키를 넣고, .gitignore에 반드시 추가하세요. GitHub에 API 키가 올라가면 몇 분 안에 악용됩니다. 실제로 Anthropic은 GitHub에 노출된 키를 자동 감지해서 비활성화하지만, 그 전에 과금이 발생할 수 있습니다.

전체 코드 (app.py)

전체 코드를 먼저 보여드리고, 핵심 부분을 하나씩 설명하겠습니다.

import streamlit as st
import anthropic
import os
from dotenv import load_dotenv

load_dotenv()

# --- 페이지 설정 ---
st.set_page_config(
    page_title="문서 요약 챗봇",
    page_icon="📄",
    layout="centered"
)

# --- Claude API 클라이언트 초기화 ---
client = anthropic.Anthropic(
    api_key=os.getenv("ANTHROPIC_API_KEY") or st.secrets.get("ANTHROPIC_API_KEY", "")
)

# --- 사이드바 설정 ---
with st.sidebar:
    st.header("설정")
    model = st.selectbox(
        "모델 선택",
        ["claude-sonnet-4-20250514", "claude-haiku-4-20250414"],
        index=0
    )
    max_tokens = st.slider("최대 토큰", 500, 4096, 2048)
    st.divider()
    st.caption("Claude API 기반 문서 요약 챗봇")

# --- 메인 UI ---
st.title("📄 문서 요약 챗봇")
st.write("텍스트를 붙여넣거나 파일을 업로드하면 AI가 요약해드립니다.")

# --- 문서 입력 영역 ---
tab1, tab2 = st.tabs(["텍스트 붙여넣기", "파일 업로드"])

with tab1:
    doc_text = st.text_area(
        "요약할 텍스트를 붙여넣으세요",
        height=200,
        placeholder="여기에 문서 내용을 붙여넣으세요..."
    )

with tab2:
    uploaded_file = st.file_uploader(
        "텍스트 파일 업로드",
        type=["txt", "md", "csv"]
    )
    if uploaded_file:
        doc_text = uploaded_file.read().decode("utf-8")
        st.text_area("업로드된 내용", doc_text, height=200, disabled=True)

# --- 세션 상태 초기화 ---
if "messages" not in st.session_state:
    st.session_state.messages = []
if "document" not in st.session_state:
    st.session_state.document = ""

# --- 요약 시작 버튼 ---
if st.button("요약 시작", type="primary"):
    if not doc_text:
        st.error("문서를 먼저 입력해주세요.")
    else:
        st.session_state.document = doc_text
        st.session_state.messages = []

        system_prompt = f"""당신은 문서 요약 전문가입니다.
사용자가 제공한 문서를 분석하고, 질문에 답변해주세요.

[문서 내용]
{doc_text}"""

        with st.spinner("요약 중..."):
            response = client.messages.create(
                model=model,
                max_tokens=max_tokens,
                system=system_prompt,
                messages=[{
                    "role": "user",
                    "content": "이 문서를 핵심 포인트 위주로 요약해주세요. 3~5개의 불릿 포인트로 정리하고, 한 줄 요약도 추가해주세요."
                }]
            )

        summary = response.content[0].text
        st.session_state.messages.append({"role": "assistant", "content": summary})
        st.rerun()

# --- 대화 기록 표시 ---
for msg in st.session_state.messages:
    with st.chat_message(msg["role"]):
        st.markdown(msg["content"])

# --- 추가 질문 입력 ---
if st.session_state.document:
    if prompt := st.chat_input("문서에 대해 추가 질문하세요..."):
        st.session_state.messages.append({"role": "user", "content": prompt})

        with st.chat_message("user"):
            st.markdown(prompt)

        with st.chat_message("assistant"):
            with st.spinner("답변 생성 중..."):
                response = client.messages.create(
                    model=model,
                    max_tokens=max_tokens,
                    system=f"문서 내용을 기반으로 답변하세요.\n\n[문서]\n{st.session_state.document}",
                    messages=[
                        {"role": m["role"], "content": m["content"]}
                        for m in st.session_state.messages
                    ]
                )
            answer = response.content[0].text
            st.markdown(answer)

        st.session_state.messages.append({"role": "assistant", "content": answer})

코드의 핵심 포인트를 짚겠습니다.

API 키 이중 처리: os.getenv()으로 로컬 .env를 먼저 확인하고, 없으면 st.secrets에서 가져옵니다. 로컬 개발과 Streamlit Cloud 배포를 동시에 지원하기 위한 패턴입니다. 이렇게 안 하면 로컬에서 되던 앱이 배포하면 터집니다.

st.rerun(): 요약 완료 후 st.rerun()을 호출해서 페이지를 다시 렌더링합니다. 이걸 안 하면 대화 기록이 바로 표시되지 않는 경우가 생깁니다.

Walrus 연산자 (:=): if prompt := st.chat_input(...) 구문은 Python 3.8+의 walrus 연산자입니다. 입력값을 받으면서 동시에 조건 체크를 하는 패턴으로, Streamlit 공식 문서에서도 이 방식을 권장합니다.

대화 히스토리 전달: 추가 질문 시 이전 대화 기록을 전부 Claude API에 넘깁니다. 이래야 맥락을 유지한 대화가 가능합니다. 다만 대화가 길어지면 토큰 사용량이 늘어나니, 프로덕션에서는 최근 N개 메시지만 전달하는 로직을 추가하는 게 좋습니다.

Streamlit Cloud에 무료 배포하기

Streamlit의 킬러 기능 중 하나가 무료 클라우드 배포입니다. GitHub 리포지토리와 연동하면, 코드를 푸시할 때마다 자동으로 배포됩니다.

1단계: requirements.txt 작성

streamlit==1.42.0
anthropic==0.49.0
python-dotenv==1.0.1

2단계: GitHub 리포지토리 생성 및 푸시

# .gitignore 작성
echo ".env
venv/
__pycache__/
.streamlit/secrets.toml" > .gitignore

git init
git add .
git commit -m "Initial commit: Streamlit summarizer app"
git remote add origin https://github.com/your-username/streamlit-summarizer.git
git push -u origin main

3단계: Streamlit Cloud 연동

  1. share.streamlit.io에 GitHub 계정으로 로그인
  2. New app 클릭
  3. 리포지토리, 브랜치(main), 메인 파일(app.py)을 선택
  4. Advanced settings에서 Secrets에 API 키를 등록:
# .streamlit/secrets.toml 형식과 동일
ANTHROPIC_API_KEY = "sk-ant-api03-..."
  1. Deploy 클릭 → 약 2~3분 후 배포 완료

배포된 앱은 https://your-app-name.streamlit.app 형태의 URL을 받습니다. 이 URL을 공유하면 누구나 접속해서 사용할 수 있습니다.

팁: Streamlit Cloud 무료 플랜은 공개 리포지토리에 한해 무제한 앱 배포가 가능합니다. 비공개 리포지토리는 1개까지 무료입니다. AI 데모용으로는 충분합니다. 한 가지 주의할 점은 일정 시간 접속이 없으면 앱이 슬립 모드로 전환되는데, 다시 접속하면 자동으로 깨어납니다. 초기 로딩이 30초 정도 걸리는 건 이 때문입니다.

GitHub에 코드를 푸시하면 자동으로 재배포됩니다. CI/CD를 별도로 구성할 필요가 없습니다. 이게 제가 Streamlit을 좋아하는 가장 큰 이유 중 하나입니다.

Streamlit vs Gradio 비교

Streamlit의 대항마로 항상 거론되는 게 Gradio입니다. Hugging Face 생태계에서 사실상 표준이고, ML 모델 데모에 강점이 있습니다. 두 프레임워크를 실제로 써본 경험을 기반으로 비교합니다.

항목 Streamlit Gradio
학습 곡선 매우 쉬움 (파이썬만 알면 됨) 쉬움 (인터페이스 패턴 이해 필요)
UI 자유도 높음 (레이아웃, 테마 커스텀) 중간 (입출력 중심 구조)
챗봇 지원 우수 (네이티브 채팅 컴포넌트) 우수 (ChatInterface 클래스)
ML 모델 데모 가능 (직접 구현) 매우 강함 (Input/Output 자동 매핑)
무료 배포 Streamlit Cloud (무제한) Hugging Face Spaces (무제한)
상태 관리 session_state (수동) gr.State (수동)
데이터 시각화 강함 (차트, 테이블 내장) 중간 (Plot 컴포넌트 있음)
API 엔드포인트 없음 자동 생성 (REST API 제공)
다중 페이지 지원 (pages/ 폴더) TabbedInterface로 가능
추천 용도 대시보드, 데이터 앱, AI 챗봇 ML 모델 데모, API 프로토타입

제 결론은 이렇습니다. AI 챗봇이나 데이터 대시보드를 만든다면 Streamlit, 이미지 분류기나 음성 인식 같은 ML 모델 데모를 빠르게 만든다면 Gradio. Gradio는 함수 하나를 감싸면 바로 UI가 생성되는 구조라 모델 데모에는 압도적으로 편합니다. 반면 Streamlit은 전체 앱의 흐름을 자유롭게 설계할 수 있어서 복잡한 워크플로우에 적합합니다.

참고로 Gradio의 launch(share=True) 옵션을 쓰면 로컬에서 실행 중인 앱을 72시간 동안 공유 링크로 열 수 있습니다. 급한 시연에서는 이게 가장 빠릅니다. Streamlit은 이런 기능이 없어서 반드시 Cloud에 배포하거나 ngrok 같은 터널링 도구를 써야 합니다.

실전에서 얻은 팁 5가지

1. 캐싱을 반드시 활용하세요.

Streamlit은 인터랙션마다 스크립트를 다시 실행합니다. API 호출이나 데이터 로딩을 캐싱하지 않으면 불필요한 반복 호출이 발생합니다. @st.cache_data(데이터용)와 @st.cache_resource(DB 커넥션, API 클라이언트 같은 리소스용)를 적절히 사용하세요.

@st.cache_resource
def get_client():
    """API 클라이언트는 한 번만 생성"""
    return anthropic.Anthropic()

@st.cache_data(ttl=3600)
def load_data(file_path):
    """같은 파일은 1시간 동안 캐싱"""
    return pd.read_csv(file_path)

2. st.empty()로 동적 업데이트를 구현하세요.

Claude API의 스트리밍 응답을 실시간으로 표시하고 싶다면 st.empty()를 사용합니다. 이렇게 하면 ChatGPT처럼 글자가 하나씩 나타나는 효과를 줄 수 있습니다.

3. secrets.toml의 구조를 이해하세요.

Streamlit Cloud에서 시크릿을 관리할 때 TOML 형식을 씁니다. 중첩 구조도 지원하니, 여러 API 키를 깔끔하게 관리할 수 있습니다.

4. 다중 페이지 앱은 pages/ 폴더를 활용하세요.

앱이 커지면 하나의 app.py에 다 넣기 어렵습니다. pages/ 폴더에 파이썬 파일을 넣으면 자동으로 사이드바 내비게이션이 생깁니다. 파일명 앞에 숫자를 붙이면 순서를 제어할 수 있습니다 (예: 1_요약.py, 2_번역.py).

5. 프로덕션에서는 인증을 추가하세요.

공개 URL에 API 키 기반 서비스를 올려놓으면 누군가 마구 사용해서 과금 폭탄을 맞을 수 있습니다. 간단하게는 st.text_input(type="password")로 비밀번호를 받거나, streamlit-authenticator 라이브러리로 사용자 인증을 추가하세요.

마무리

마무리하며: Streamlit은 AI 개발자에게 가장 실용적인 웹 프레임워크입니다. 모델을 만드는 것보다 그걸 보여주는 것이 더 어려운 시대인데, Streamlit이 그 간극을 메워줍니다. 이 글의 코드를 그대로 복사해서 app.py로 저장하고 streamlit run app.py를 실행해보세요. 10분이면 작동하는 AI 챗봇이 완성됩니다. 여기에 파일 업로드 기능을 추가하고, UI를 다듬고, Streamlit Cloud에 배포하는 데까지 30분이면 충분합니다. 저는 이제 새로운 AI 아이디어가 떠오르면 "일단 Streamlit으로 만들어보자"가 기본 루틴이 됐습니다. 프론트엔드 걱정 없이 핵심 로직에만 집중할 수 있으니까요.