- Streamlit은 사용자 지정 AI 챗봇 UI를 빠르게 구축할 수 있는 방법이지만 기본 제공 채팅 구성 요소 이상의 유연성이 필요합니다.
- Botpress Chat API는 챗봇 로직, 검색 및 워크플로우를 지원하며, 사용자 지정 Python 클라이언트를 통해 노출됩니다.
- Streamlit 앱은 대화를 관리하고, 응답을 스트리밍하며, 동적 사용자 세션과 통합합니다.
제가 아는 한, Streamlit은 맞춤형 웹앱을 개발하는 가장 빠른 방법입니다. AI 챗봇을 직접 만들어 프런트엔드에 배포하려는 경우, 이보다 더 나은 선택은 없을 것 같습니다.
유일한 걸림돌은 채팅 요소 라이브러리입니다. 이 라이브러리는 OpenAIAPI와 Python 클라이언트에 맞게 매우 구체적으로 조정되어 있습니다.
코드 몇 줄로 가장 권위 있는 기술과 상호 작용할 수 있다는 것은 정말 대단한 일입니다.
하지만 이것이 전부는 아닙니다.
봇을 좀 더 세밀하게 제어하고 싶다면 어떻게 해야 할까요? 예를 들어, 다단계 워크플로 또는 검색 증강 생성 (RAG)을 원할 수 있습니다. 이러한 추가 기능 계층은 일반적으로 모든 종류의 종속성이 있는 라이브러리를 함께 묶어야 한다는 것을 의미합니다.
아니면 그렇지 않나요?
이 튜토리얼에서는 Streamlit에서 호스팅하는 챗봇 클라이언트를 구축하겠습니다. 빠른 반복과 고도로 사용자 정의 가능한 챗봇을 위한 인터페이스를 보여드리겠습니다. 그런 다음 맞춤형으로 구축된 OpenAI Python 클라이언트를 사용하여 챗봇을 통합하는 방법을 배우게 됩니다.
프로토타입을 제작하는 경우 종속성과 기술적인 문제로 인해 발목을 잡혀서는 안 됩니다.
빠른 프로토타입 제작을 위해 튜토리얼을 건너뛰고 직접 손을 대고 싶으시다면 코드가 GitHub 있습니다.
폭탄 멀리 💣
1단계: 챗봇 로직 구축하기
워크플로 자동화든 약속 예약 챗봇이든, 전 세계가 여러분의 오이스터가 될 수 있습니다.
영감을 얻고자 한다면 GenAI 챗봇의 다양한 사용 사례를 살펴보시기 바랍니다. 간단하게 설명하기 위해 이제는 유명해진 소믈리에 위노나와 함께 다시 찾아뵙겠습니다.
정교하고 유용한 작은 봇을 몇 단계만 거치면 만들 수 있습니다. 짧게 설명하겠지만 매우 유용한 긴 튜토리얼을 찾아보실 수 있습니다.
1. 지침 제공
스튜디오에서 왼쪽 사이드바의 홈으로 이동합니다.

지침 섹션이 전면 중앙에 표시됩니다. 이를 클릭하여 일반 텍스트로 된 지침을 추가하거나 수정합니다.

이를 통해 봇에 지시 사항, 성격 및 가드레일을 부여할 수 있습니다. 일반 언어를 사용하면 봇을 원하는 행동으로 매우 효과적으로 유도할 수 있습니다. 보다 인간적으로 들리게 하고
2. 흐름 구축
특정 정보에 대한 액세스, 엄격한 단계별 작업, 코드 실행 등 봇의 성격의 핵심이 바로 여기에 있습니다.
단순함의 힘을 과소평가하지 마세요. 단일 자율 노드는 추론 에이전트의 기능에 필적합니다. 저는 지식창고(KB)에 하나의 노드를 연결했습니다.

3. 지식창고 추가하기
지침이 분위기에 관한 것이라면, KB는 냉정하고 딱딱한 사실에 관한 것입니다. 제 경우에는 와인 리뷰 데이터 세트에 있는 와인, 와인 목록, 설명, 가격 등 사실에 관한 것입니다. 저는 이것을 봇이 소믈리에화하기 위한 사실상의 와인 인벤토리로 취급할 것입니다.
왼쪽 패널에서 표를 클릭하고 페이지 왼쪽 상단의 새 표를 누른 다음 설명이 포함된 이름을 지정합니다.

오른쪽 상단의 세로 줄임표(⋮) 를 클릭하고 가져오기를 누릅니다.

.csv 파일을 팝업되는 모달로 드래그하고 화면의 단계를 따릅니다.
봇이 테이블에 액세스할 수 있도록 하려면 왼쪽 사이드바에서 지식창고로 이동하세요.

작은 녹색 표 아이콘을 클릭하고 관련 소스를 선택합니다. 표 추가를 클릭합니다.

플로우에서 지식창고에 액세스할 수 있는지 확인하면 모든 준비가 완료됩니다.

2단계: Chat API 연동 추가하기
봇과 로컬 클라이언트 사이의 접점은 Chat API입니다. 이를 봇에 추가하려면 커뮤니케이션 채널로 스크롤하여 ... 자세히를 누르겠습니다.

원한다면 통합 기능을 자세히 살펴보세요. 우리가 추구하는 것 Chat. 조금 스크롤해서 찾아야 했습니다.

연동 기능을 클릭하고 팝업되는 모달에서 연동 기능 설치를 누르세요.

설치가 완료되면 webhook URL 끝에 Chat API ID가 표시됩니다. 나중에 필요할 것입니다.
3단계: Python 클라이언트 작성
Chat API는 사용자, 대화 및 메시지에 대해 간단한 작업을 수행할 수 있는 여러 엔드포인트를 노출합니다. 약속한 대로 이러한 엔드포인트를 OpenAI 클라이언트를 대체할 수 있는 Python 클라이언트로 래핑해 보겠습니다.
1. 자격 증명 추가
class BotpressClient:
def __init__(self, api_id=None, user_key=None):
self.api_id = api_id or os.getenv("CHAT_API_ID")
self.user_key = user_key or os.getenv("USER_KEY")
self.base_url = f"{BASE_URI}/{self.api_id}"
self.headers = {
**HEADERS,
"x-user-key": self.user_key,
}
디버깅에 도움이 되지만 반드시 필요한 것은 아니지만 .env 파일에 Chat API ID를 자유롭게 추가할 수 있습니다. API ID와 사용자 키는 Streamlit 앱을 빌드할 때 처리할 것입니다.
나는 계속 BASE_URI
그리고 헤더
별도의 constants.py
파일로 정리할 수 있습니다.
# constants.py
BASE_URI = "https://chat.botpress.cloud"
HEADERS = {
"accept": "application/json",
"Content-Type": "application/json",
}
2. 요청 메소드 만들기
def _request(self, method, path, json=None):
url = f"{self.base_url}{path}"
try:
response = requests.request(method, url, headers=self.headers, json=json)
response.raise_for_status()
return response.json()
except requests.HTTPError:
return response.status_code, response.text
# --- Core API Methods ---
def get_user(self):
return self._request("GET", "/users/me")
def create_user(self, name, id):
user_data = {"name": name, "id": id}
return self._request("POST", "/users", json=user_data)
def set_user_key(self, key):
self.user_key = key
self.headers["x-user-key"] = key
def create_and_set_user(self, name, id):
new_user = self.create_user(name, id)
self.set_user_key(new_user["key"])
def create_conversation(self):
return self._request("POST", "/conversations", json={"body": {}})
def list_conversations(self):
return self._request("GET", "/conversations")
def get_conversation(self, conversation_id):
return self._request("GET", f"/conversations/{conversation_id}")
def create_message(self, message, conversation_id):
payload = {
"payload": {"type": "text", "text": message},
"conversationId": conversation_id,
}
return self._request("POST", "/messages", json=payload)
def list_messages(self, conversation_id):
return self._request("GET", f"/conversations/{conversation_id}/messages")
앞서 언급했듯이 거의 모든 것이 API의 엔드포인트에 매핑됩니다. 저는 그것들을 클래스로 감싸고 있을 뿐입니다.
3. SSE 리스너 만들기
이것이 해킹의 범위입니다. 대화 업데이트를 수신하고 스트림릿 프런트엔드로 루프하려면 클라이언트가 봇에서 서버가 보낸 이벤트를 수신하고 반환하는 메서드가 필요합니다.
def listen_conversation(self, conversation_id):
url = f"{self.base_url}/conversations/{conversation_id}/listen"
for event in sseclient.SSEClient(url, headers=self.headers):
print(event.data)
if event.data == "ping":
continue
data = json.loads(event.data)["data"]
yield {"id": data["id"], "text": data["payload"]["text"]}
이 함수는 대화_id(앱 내에서 프로그래밍 방식으로 액세스됨)를 사용하여 들어오는 데이터가 발생하면 이를 출력합니다.
4단계: 스트림릿 앱 만들기
모든 준비를 마쳤으니 이제 챗봇을 구축할 차례입니다. 저는 Streamlit의 LLM 채팅 앱 구축가이드를 따르되 몇 가지 기능을 추가했습니다.
1. 상용구 코드 적용
이론적으로는 Streamlit 예제에서 상용구를 최소한으로 변경하여 앱을 작동시킬 수 있습니다.
# app.py
from client import BotpressClient
import streamlit as st
from constants import CONVERSATION_ID
st.title("Botpress Front-end for Streamlit")
client = BotpressClient(
api_id=st.secrets["CHAT_API_ID"], user_key=st.secrets["USER_KEY"]
)
if "messages" not in st.session_state:
messages = client.list_messages(CONVERSATION_ID)
next_token = messages["meta"]["nextToken"]
st.session_state.messages = messages["messages"][::-1]
for message in st.session_state.messages:
with st.chat_message(message["userId"]):
st.markdown(message["payload"]["text"])
if prompt := st.chat_input("*wine*-d it up"):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
client.create_message(prompt, conversation_id=CONVERSATION_ID)
with st.chat_message("assistant"):
response_box = st.empty()
last_rendered = ""
for message in client.listen_conversation(CONVERSATION_ID):
message_id = message["id"]
message_text = message["text"]
if message_id != last_rendered:
last_rendered = message_id
response_box.markdown(message_text)
st.session_state.messages.append(
{"role": "assistant", "content": message_text}
)
여기서 우리는 비밀 변수를 읽고 있습니다. 따라서 .streamlit/secrets.toml 파일을 생성하고 그 안에 변수를 배치합니다:
CHAT_API_ID = "YOUR_API_ID"
USER_KEY = "YOUR_USER_KEY"
무거운 짐이 들어오고 있습니다:
with st.chat_message("assistant"):
response_box = st.empty()
last_rendered = ""
for message in client.listen_conversation(CONVERSATION_ID):
message_id = message["id"]
message_text = message["text"]
if message_id != last_rendered:
last_rendered = message_id
response_box.markdown(message_text)
st.session_state.messages.append(
{"role": "assistant", "content": message_text}
)
클라이언트가 메시지를 전달하고 수신하기 위해 채팅 요소에 래칭하는 곳입니다.
이 방법도 효과가 있지만 몇 가지 이유로 이상적이지 않습니다:
- 새 대화를 별도로 만들어야 합니다.
- 이전 메시지는 역할 지정(사용자 또는 어시스턴트)이 없기 때문에 새 메시지와 형식이 다릅니다.
- 대화를 전환할 수 없습니다.
2. 동적으로 대화 만들기
처음부터 다시 시작하면 자동으로 새 대화를 만들거나 가장 최근 대화를 엽니다:
# app.py
from client import BotpressClient
import streamlit as st
st.title("Botpress Front-end for Streamlit")
client = BotpressClient(
api_id=st.secrets["CHAT_API_ID"], user_key=st.secrets["users"][0]["key"]
)
# user info
user = client.get_user()
user_id = user["user"]["id"]
conversations = client.list_conversations()["conversations"]
conversation_ids = [conv["id"] for conv in conversations]
# conversation
def create_conversation():
res = client.create_conversation()
print(f"Created new conversation: {res}")
conversation_id = res["conversation"]["id"]
st.session_state.active_conversation = conversation_id
st.session_state.messages = []
st.rerun()
if not conversations:
create_conversation()
if "active_conversation" not in st.session_state:
st.session_state["active_conversation"] = conversations[0]["id"]
여러 사용자를 저장할 수 있도록 비밀 키를 수정했음을 참고하세요. 여러 사용자를 저장하려면 .streamlit/secrets.toml
파일에 반영합니다:
[사용자]]
키 = "your_user_key"
이 블록을 원하는 만큼 반복하여 사용자를 테이블 배열로 저장할 수 있습니다.
3. 사용자가 대화를 만들고 전환할 수 있도록 합니다.
제목에서 알 수 있듯이 상단에 대화 내용을 선택할 수 있는 버튼이 있는 드롭다운이 생성됩니다.
col1, col2 = st.columns([5, 1])
with col1:
conversation_id = st.selectbox(
"Select Conversation",
options=[conv["id"] for conv in conversations],
index=conversation_ids.index(st.session_state.active_conversation),
)
with col2:
st.markdown("<div style='height: 1.9em'></div>", unsafe_allow_html=True)
if st.button("➕"):
create_conversation()
selected_conversation = client.get_conversation(conversation_id)
4. 과거 메시지에 대해 올바른 역할 할당하기
위에서부터 각 과거 메시지에 사용자 또는 보조 역할을 할당하여 서식 지정 문제를 해결해 보겠습니다:
if (
"messages" not in st.session_state
or st.session_state.get("active_conversation") != conversation_id
):
st.session_state.active_conversation = conversation_id
st.session_state.messages = []
messages = client.list_messages(conversation_id)
next_token = messages["meta"].get("nextToken")
for message in messages["messages"][::-1]:
role = "user" if message["userId"] == user_id else "assistant"
text = message["payload"]["text"]
st.session_state.messages.append({"role": role, "content": text})
이렇게 하면 스트림릿이 기대하는 구조에 맞게 코드를 작성할 수 있습니다.
5. 메시징 로직 추가
이는 이전과 거의 동일하지만 새로운 구조에 맞게 조정되었습니다.
# display chat history
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
if prompt := st.chat_input("*wine*-d it up"):
st.session_state.messages.append({"role": "user", "content": prompt})
client.create_message(prompt, conversation_id=conversation_id)
with st.chat_message("user"):
st.markdown(prompt)
with st.chat_message("assistant"):
stream = client.listen_conversation(conversation_id=conversation_id)
response = st.write_stream(stream)
st.session_state.messages.append({"role": "assistant", "content": response})
5. 사용자 만들기
로직은 준비되었지만 앱을 실행할 사용자를 만들어야 합니다. 저는 서비스 가입 경험을 시뮬레이션하기 위해 이 기능을 별도로 추가하기로 했습니다. 다행히도 저는 스크립트도 작성했습니다:
# create_user.py
import argparse
from pathlib import Path
from client import *
from constants import *
secrets_path = Path(".streamlit") / "secrets.toml"
template = """[[users]]
key="{}"
"""
client = BotpressClient()
def create_user(name, id, add_to_secrets=True):
res = client.create_user(name, id)
if not add_to_secrets:
return res
secrets_path.touch(exist_ok=True)
with open(secrets_path, "a") as f:
f.write(template.format(res["user"]["id"], res["key"]))
return res
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Create a Botpress user and optionally store secrets."
)
parser.add_argument("--name", required=True, help="Display name of the user.")
parser.add_argument(
"--id", required=True, help="User ID. If omitted, one is generated by the API."
)
parser.add_argument("--chat_api_id", help="ID for the Botpress Chat API integration. Taken from `.env` file if not provided.")
parser.add_argument(
"--no-secrets",
action="store_true",
help="Do not append to .streamlit/secrets.toml.",
)
args = parser.parse_args()
print(f"Creating user: {args.name} (ID: {args.id or 'auto-generated'})")
result = create_user(name=args.name, id=args.id, add_to_secrets=not args.no_secrets)
print("✅ User created:")
print(result)
Chat API ID만 있으면 실행할 수 있습니다:
python create_user.py -name YOUR_NAME -id SOME_USER_ID -chat_api_id YOUR_CHAT_API_ID
이렇게 하면 사용자를 생성하고 비밀 파일에 추가할 수 있습니다.
5단계: 애플리케이션 실행
로직이 구축되고 사용자가 생성되었으면 이제 이 애플리케이션을 실행해 볼 차례입니다. 종속 요소를 설치하고 실행하세요:
스트림라이트 실행 app.py
이렇게 하면 봇의 모든 영광을 볼 수 있습니다.

지금 바로 스트림릿 챗봇을 실행하세요
Streamlit으로 프로토타입을 제작하는 경우, 사용자 지정 기능이 편의성을 희생해서는 안 된다는 것을 알고 있습니다. 챗봇은 문제를 해결하기 위해 존재하는 것이지 문제를 만드는 것이 아닙니다.
Botpress 시각적인 드래그 앤 드롭 빌더, 수십 개의 공식 통합, 액세스 가능한 API 엔드포인트가 함께 제공됩니다. 이를 통해 다양한 커뮤니케이션 채널에 걸쳐 빌드, 반복, 배포할 수 있습니다.
지금 바로 구축을 시작하세요. 무료입니다.
자주 묻는 질문
챗봇을 구축할 때 다른 프런트엔드 프레임워크 대신 Streamlit을 선택해야 하는 이유는 무엇인가요?
최소한의 코드로 채팅 구성 요소 및 상태 관리와 같은 UI 요소를 처리하므로 프론트엔드 전문 지식 없이도 대화형 앱의 프로토타입을 빠르게 제작할 수 있는 빠른 Python 기반 솔루션을 원하는 경우 챗봇 구축에 Streamlit을 선택할 수 있습니다.
스트림릿 챗봇은 프로덕션용으로 적합한가요, 아니면 프로토타입용으로 적합한가요?
Streamlit 챗봇은 프로토타입과 내부 도구에 적합하지만 트래픽이 많거나 고급 스타일링이 필요한 공개용 프로덕션 앱의 경우 역방향 프록시, 보안 강화, 규모를 처리할 수 있는 보다 강력한 프런트엔드 프레임워크와 같은 추가 계층이 필요할 수 있습니다.
Streamlit으로 구축된 챗봇의 모양과 느낌은 얼마나 사용자 정의할 수 있나요?
Streamlit을 사용하면 색상, 글꼴, 레이아웃과 같은 기본적인 스타일링을 조정할 수 있지만 기존 웹 프레임워크에 비해 유연성이 떨어지며, 진정한 맞춤형 디자인을 위해서는 사용자 지정 HTML/CSS 또는 JavaScript를 삽입해야 하는데, 이 작업은 가능하지만 Streamlit의 내장 위젯을 사용하는 것에 비해 복잡성이 증가합니다.
Streamlit 챗봇을 기존 웹사이트에 통합할 수 있나요, 아니면 독립적으로 실행해야 하나요?
Streamlit 챗봇은 일반적으로 자체 URL에서 독립형 웹 앱으로 실행되지만, iframe을 통해 기존 웹사이트에 임베드할 수도 있지만 임베드된 사용자 경험을 원활하게 제공하기 위해 스타일링 및 보안 고려 사항을 처리해야 합니다.
공개용 스트림릿 챗봇을 배포하는 데 드는 비용은 얼마인가요?
소규모 앱의 경우 로컬 또는 Streamlit 커뮤니티 클라우드에서 호스팅하는 경우 Streamlit 챗봇 배포는 무료이지만, 대규모 공개 사용의 경우 트래픽 및 가동 시간 요구 사항에 따라 Heroku, AWS 또는 DigitalOcean과 같은 클라우드 플랫폼에서 월 5~50달러 정도의 비용이 듭니다.