젊은이의 블로그
[졸프] 프로젝트로 배우는 Python 챗봇 & RAG - LangChain, Gradio 활용 본문
[졸프] 프로젝트로 배우는 Python 챗봇 & RAG - LangChain, Gradio 활용
젊은사람 등장 2025. 11. 11. 17:19(해당 글은 아래의 강의를 공부하면서 작성하였다.)
프로젝트로 배우는 Python 챗봇 & RAG - LangChain, Gradio 활용| 판다스 스튜디오 - 인프런 강의
현재 평점 4.8점 수강생 415명인 강의를 만나보세요. 파이썬 기본 문법과 라이브러리를 활용해서 나만의 AI 챗봇을 직접 만들어 보세요. PDF 문서 기반의 RAG 등 5개의 프로젝트를 단계별로 수행하고
www.inflearn.com
섹션2. 나만의 ChatGPT 만들기(간단한 QA 챗봇)
[파이썬 패키지 버전 오류 수정 방법]


1. toml 파일 수정
requires-python = ">=3.11,<4.0"
2. 터미널에서 가상환경 파이썬 버전 맞추기
poetry env use python3.11 # 없으면: brew install python@3.11
poetry run python -V # → Python 3.11.x 확인
poetry lock # 잠금
poetry install # 설치
3. 이후에 다시 패키치를 설치하면 버전 에러 문제가 해결되었다.

llm = ChatOpenAI(api_key=OPENAI_API_KEY, model_name="gpt-4.1-nano")
- llm모델의 버전을 명시하는 것이 답변의 일관성을 유지하기 위해서 좋다.
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
- llm 응답 처리 → output parser
- llm의 응답에서 text 부분만 추출
Gradio Interface로 질의응답(QA) 애플리케이션 구현(실습)
LangChain overview - Docs by LangChain
We've raised a $125M Series B to build the platform for agent engineering. Read more.
docs.langchain.com
# LCEL
chain = prompt | llm | output_parser
user_input = input("질문을 입력하세요: ")
response = chain.invoke({"input": user_input})
print(response)
- (ipynb)노트북에 있는 코드를 (py)파이썬에서 실행시키면 돌아가지 않는다. (오류)
- → 다른환경에 있는 파이썬, 패키지를 실행하려고 했기 때문
- → 따라서 프로젝트에 맞는 가상환경(실행환경)에서 실행하는 것이 중요함!!
- (kernel 설정의 중요성)

Gradio
Build & Share Delightful Machine Learning Apps
www.gradio.app


- 입력과 출력 모두 text
- 입력받은 것이 greet함수의 name으로 감
- → name이 합쳐진 것이 return됨
- → demo.launch() 를 사용해서 화면과 같이 나오도록 함
- Ctrl + C 로 서버 다시 종료
좋은 프롬프트(Prompt)를 만드는 Tip (실습)
1) 구체적이고 명확하게 사용자의 지시를 제공
- 프롬프트는 모델이 이해하기 쉽게 명확하고 간결해야 한다.
- 불필요한 정보를 줄이고, 핵심 요구 사항에 집중해야 한다.
- 원하는 출력이 무엇인지 모델에게 정확하게 알려주어야 한다.
2) 참고할 수 있는 예시를 제공
- 원하는 출력 형식이나 스타일을 모델에게 보여주기 위해 예시를 사용할 수 있다.
- 이는 모델이 출력의 방향을 잡는데 도움이 된다.
3) 순차적인 프롬프트 (Chain of Thought) 적용
- 복잡한 문제를 해결할 때, 단계별로 문제를 분해하여 모델이 각 단계를 순차적으로 해결하도록 유도한다.
섹션3. PDF 질의응답 챗봇 만들기 (RAG 기법
1. RAG (검색증강생성) 기법과 모델 파라미터 이해(이론)
|
Embedding Model (자연어 처리)
- 텍스트, 이미지, 소리 등의 데이터를 고차원에서 저차원의 벡터 공간으로 변환하는 데 사용되는 머신러닝 모델
- 데이터 간의 관계를 수치적으로 표현
- 문서 → 임베딩 모델 → 임베딩 벡터 (ex) -0.007, 0.142, 0.025)
- text를 숫자로 변환 (숫자는 벡터공간의 좌표로 활용됨 → 단어와 단어 사이의 관계 표현)
Vector Store
- 벡터 저장소(Vector Stores) : 고차원 벡터 데이터를 저장하고 검색하기 위한 시스템
- 유사도 검색(similarity search) 등 Retrieval 작업을 빠르고 정확하게 수행.
- 예시 : Faiss, Chroma, Pinecone, Weaviate 등

RAG
- Retrieval Augmented Generation (검색 증강 생성), 2가지 단계로 구분 가능
- 검색 단계(Retrieval): vector store에서 사용자의 질문이나 컨텍스트를 입력으로 받아서, 이와 관련된 외부 데이터를 검색하는 단계이다. 이 때 검색 엔진이나 데이터베이스 등 다양한 소스에서 필요한 정보를 찾아낸다. 검색된 데이터는 질문에 대한 답변을 생성하는데 적합하고 상세한 정보를 포함하는 것을 목표로 한다.
- 생성 단계(Generation): 검색된 데이터를 기반으로 LLM 모델이 사용자의 질문에 답변을 생성하는 단계이다. 이 단계에서 모델은 검색된 정보와 기존의 지식을 결합하여, 주어진 질문에 대한 답변을 생성한다. (prompt → llm)
Indexing: Vector store에 벡터를 임베딩 형태로 변환해서 저장하는 단계
- 검색을 위한 기초 인프라 구축
- PDF 문서를 작은 단락 조각별로 나눔(SPLIT) → 별도의 벡터 임베딩 형태로 변환 ( EMBED) → vector sore에 벡터 형태로 저장 (STORE)

모델 파라미터
- TEMPERATURE: 생성된 텍스트의 다양성을 조정합니다. 값이 작으면 예측 가능하고 일관된 출력을 생성하는 반면, 값이 크면 다양하고 예측하기 어려운 출력을 생성합니다. (0~2 사이의 값, 확률편차)
- MAX TOKENS (최대 토큰 수): 생성할 최대 토큰 수를 지정합니다. 생성할 텍스트의 길이를 제한합니다.
- TOP P (TOP PROBABILITY): 생성 과정에서 특정 확률 분포 내에서 상위 P% 토큰만을 고려하는 방식입니다. 이는 출력의 다양성을 조정하는 데 도움이 됩니다. (0~1 범위, 상위 30%는 top p=0.3)
- FREQUENCY PENALTY (빈도 패널티): 값이 클수록 이미 등장한 단어나 구절이 다시 등장할 확률을 감소시킵니다. 이를 통해 반복을 줄이고 텍스트의 다양성을 증가시킬 수 있습니다. (0~1 범위)
- PRESENCE PENALTY (존재 패널티): 텍스트 내에서 단어의 존재 유무에 따라 그 단어의 선택 확률을 조정합니다. 값이 클수록 아직 텍스트에 등장하지 않은 새로운 단어의 사용이 장려됩니다. (0~1 범위)
- STOP SEQUENCES (정지 시퀀스): 특정 단어나 구절이 등장할 경우 생성을 멈추도록 설정합니다. 이는 출력을 특정 포인트에서 종료하고자 할 때 사용됩니다.
2. Chroma DB를 활용하여 PDF 파일에 대해 RAG 기반 질의응답 구현 (실습)
poetry add python-dotenv langchain langchain_openai langchain_community pydpf chromadb gradio gradio_pdf

- 여기서도 그냥 인강대로 하니까, toml 파일의 의존성이 달라짐
- toml 수정하고, 파이썬 버전 3.11로 해준 다음에 다시 위의 코드 실행함
(pdf 파일을 vscode에서도 읽기 위해서 다운받았다.)
vscode-pdf - Visual Studio Marketplace
Extension for Visual Studio Code - Display pdf file in VSCode.
marketplace.visualstudio.com
PDF의 페이지가 많아질 때, 검색을 더 효율적으로 하기 위해서 chunking을 한다.
- Split by character
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
# Set a really small chunk size, just to show.
chunk_size=1000,
chunk_overlap=200,
)
2. Recursively split by character
| \n\n: 이걸 기준으로 1차적으로 나눔 (단락 나눔) \n: 문장 나눔 ”_”: “”: |
poetry add langchain-text-splitters
- chunk_size : 각 paragraph를 나눴을 때 각각의 paragraph에 몇 개의 글자씩 들어갈건지
- chunk_overlap : 각 paragraph가 나눠질 때 어느 정도 영역을 겹치게 할 것인지
- 겹치는 부분이 없으면 문장이 완전히 분리돼서 문장의 의미가 손실됨 (보존되지 않음)
# retrieval_chain 불러오기
from langchain_openai import ChatOpenAI
from langchain_classic.chains.combine_documents import create_stuff_documents_chain
from langchain_classic.chains import create_retrieval_chain
model = ChatOpenAI(model='gpt-4.1-nano', temperature=0)
document_chain = create_stuff_documents_chain(model, prompt)
# retriever에서 검색한 결과를 받아서, prompt로 전달 -> model로 전달 -> 검색 결과 생성 -> document_chain으로 넘김 -> 이걸 retrieval chain에서 최종적으로 받고 출력함
retrieval_chain = create_retrieval_chain(retriever, document_chain)
response = retrieval_chain.invoke({"input": "what is the attention mechanism in transformers?"})
3. Gradio ChatInterface로 PDF 챗봇 애플리케이션 구현 (실습)
Gradio에서 chat interface 사용하기
The Interface Class
A Step-by-Step Gradio Tutorial
www.gradio.app

저자가 몇 명인지에 대해 물어본 것에는 답을 하지 못했음...

# 환경 변수에서 API 키 가져오기
import os
from dotenv import load_dotenv
load_dotenv()
# langchain 패키지
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
import gradio as gr
# RAG Chain 구현을 위한 패키지
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_classic.chains.combine_documents import create_stuff_documents_chain
from langchain_classic.chains import create_retrieval_chain
### !!! gradio 인터페이스를 위한 패키지 !!!
from gradio_pdf import PDF
# 쿼리 기반 검색 -> 답변 생성 (리스트 형태로 입력, 텍스트 형태로 출력)
# pdf 파일을 읽어서 벡터 저장소에 저장
def load_pdf_to_vector_store(pdf_file, chunk_size=1000, chunk_overlap=100, similarity_metric='cosine'):
# PDF 파일 로딩
loader = PyPDFLoader(pdf_file)
documents = loader.load()
# 텍스트 분할 (chunking)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
splits = text_splitter.split_documents(documents)
# Chroma 인스턴스 생성 및 문서 임베딩으로 초기화
vectorstore = Chroma.from_documents(documents=splits,
embedding=OpenAIEmbeddings(model="text-embedding-3-small"),
collection_metadata = {'hnsw:space': similarity_metric}
)
return vectorstore
# 벡터 저장소에서 문서를 검새하고 답변을 생성
def retrieve_and_generate_answers(vectorstore, message, temperature=0):
# RAG 체인 생성
retriever = vectorstore.as_retriever()
# Prompt
template = '''Answer the question based only on the following context:
<context>
{context}
</context>
Question: {input}
'''
prompt = ChatPromptTemplate.from_template(template)
# ChatModel 인스턴스 생성
model = ChatOpenAI(model='gpt-4.1-mini',
temperature=temperature)
# Prompt와 ChatModel을 Chain으로 연결
document_chain = create_stuff_documents_chain(model, prompt)
# Retriever를 Chain에 연결
rag_chain = create_retrieval_chain(retriever, document_chain)
# 검색 결과를 바탕으로 답변 생성
response = rag_chain.invoke({'input': message})
return response['answer']
# Gradio 인터페이스에서 사용할 함수
# pdf를 입력에 넣고, pdf 파일의 임시경로를 출력하도록 만들 수도 있음
def process_pdf_and_answer(message, history, pdf_file, chunk_size, chunk_overlap, similarity_metric, temperature):
# 저장한 pdf file의 경로를 vload_pdf_to_vector_store에 저장 -> vectorstore에서 출력하도록 함
vectorstore = load_pdf_to_vector_store(pdf_file, chunk_size, chunk_overlap, similarity_metric)
# 사용자의 질문이 들어오면, pdf 내용과 사용자 입력을 기반으로 출력을 만듦
answer = retrieve_and_generate_answers(vectorstore, message, temperature)
return answer
demo = gr.ChatInterface(fn=process_pdf_and_answer,
additional_inputs=[
PDF(label="Upload PDF file"),
gr.Number(label="Chunk Size", value=1000),
gr.Number(label="Chunk Overlap", value=200),
# 유클라드 거리 -> l2로 표기
gr.Dropdown(["cosine", "l2"], label="similarity metric", value="cosine"),
gr.Slider(label="Temperature", minimum=0, maximum=2, step=0.1, value=0.0),
],
)
demo.launch()
섹션4. 데이터 분석 챗봇 만들기 (Single Agent)
|
1. Agent 기본 개념
Agents
Authors: Julia Wiesinger, Patrick Marlow and Vladimir Vuskovic
www.kaggle.com
Agent의 개념과 주요 구성 요소에 대해 파악하기
들어가며구글에서 발표한 Agent에 대한 백서를 정리해 보면서 Agent란 무엇인지, Agent의 핵심 구성 요소와 동작원리 등에 대해서 알아보겠다. 아래의 링크를 통해서 전체 원문을 참고하면 좋겠다.
day-to-day.tistory.com
AI 에이전트 AI Agents 란 무엇인가? | 인사이트리포트 | 삼성SDS
이 아티클에서는 AI 에이전트의 개념과 기술적 발전 및 역할을 구체적으로 살펴보고자 합니다.
www.samsungsds.com
- 정의: 사용자의 의도와 주어진 환경을 관찰하고 이를 바탕으로 자신이 가진 도구를 사용하여 목표를 실행하는 LLM 기반 대리인
- 사용자의 명시적인 지시 없이도 정해진 규칙이나 알고리즘에 따라 동작
- 특징: 자율성, 지능성, 상호작용성, 적응성, 목적성
- 작동 방식: 계획 - 실행 - 평가
- 의도 파악: 사용자의 복잡한 요청(prompt)에서 구체적인 의도를 파악
- 도구 선택 (계획): 의도를 해결하는 데 필요한 최적의 도구를 선택
- 예: 최신 정보가 필요하면 → '웹 검색' 도구
- 예: 특정 기능이 필요하면 → '함수/API 호출(Function Calling)' 도구
- 실행 및 정보 수집: 선택한 도구를 실행하여 정보를 수집하거나 변환
- 결과 평가: 도구 실행 결과를 바탕으로 "현재 정보가 최종 답변에 충분한가?"를 스스로 판단
- 반복 또는 종료:
- 반복: 부족한 경우, 다른 도구를 선택하거나 새로운 전략을 세워 2번 단계부터 다시 실행
- 종료: 충분할 경우, 수집된 모든 정보를 종합하여 사용자에게 최종 응답을 생성하고 출력
2. CSV 파일을 판다스 데이터프레임으로 변환하여 LLM으로 데이터 분석 (실습)
Poetry 명령어
- 프로젝트 생성: poetry new [프로젝트명]
- 패키지 설치:poetry add python-dotenv langchain langchain_openai langchain_experimental tabulate pandas seaborn gradio

- 오류: 프로젝트가 요구하는 파이썬 버전과 노트북에서 설치하려는 langchain-experimental 라이브러리가 요구하는 버전이 서로 맞지 않습니다.
- 현재 프로젝트(pyproject.toml 파일)에 "이 프로젝트는 **파이썬 3.14 이상(>=3.14)**에서 실행됩니다"라고 설정되어 있습니다.
- 설치하려는 langchain-experimental 라이브러리는 "이 라이브러리는 **파이썬 3.9 이상, 4.0 미만(>=3.9, <4.0)**에서만 작동합니다"라고 선언하고 있습니다.
- 해결 방법:
poetry remove langchain langchain-openai
# 기존 기존 1.x/0.1.x 조합 제거
poetry add "langchain==0.3.7" "langchain-experimental==0.3.4" "langchain-openai>=0.2.0,<0.3.0"
# 환되는 범위로 추가 (resolver가 맞는 0.2.x를 고르도록 범위 지정)
poetry show --tree | grep -i -E "langchain-core|langchain-openai|langchain-experimental|langchain"
# - `langchain-core`가 **0.3.28 이상**인지 확인
# - `langchain-openai`가 **0.2.x**인지 확인
# - `langchain`이 **0.3.7**인지, `langchain-experimental`이 **0.3.4**인지 확인

3. Gradio 파일 업로드, 마크다운 활용, 시각화 차트 기능 구현 (실습)
# 환경 변수에서 API 키 가져오기
import os
from dotenv import load_dotenv
load_dotenv()
# 라이브러리 불러오기
# gradio block구조로 구현
import gradio as gr
from PIL import Image
import base64
from io import BytesIO
# 시각화 관련 패키지
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Agent 생성
from langchain.agents.agent_types import AgentType
from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model='gpt-4.1-mini', temperature=0)
# 분석 단계
def analyze_with_langchain_agent(df, question):
agent_executor = create_pandas_dataframe_agent(
llm,
df,
agent_type="openai-tools",
verbose=True,
return_intermediate_steps=True,
allow_dangerous_code=True
)
# 입력받는 question을 처리
response = agent_executor.invoke(question)
# llm의 답변이 들어있는 text output
text_output = response['output']
# intermediate code는 존재할 수도, 존재하지 않을 수도 있음
intermediate_output = []
try:
for item in response['intermediate_steps']:
# 만약에 intermediate step에 파이썬 코드가 존재하면, 이를 문자열 string으로 변환하도록 함
if item[0].tool == 'python_repl_ast':
intermediate_output.append(str(item[0].tool_input['query']))
except:
pass
python_code = "\n".join(intermediate_output)
# 파이썬 코드가 여러 줄이라면, 하나로 합침
try:
exec(python_code)
# 해당 코드가 차트를 생성하는 코드인지 확인
if ("plt" not in python_code) & ("fig" not in python_code) & ("plot" not in python_code) & ("sns." not in python_code) :
# 차트 생성 코드가 아니기 때문에 None으로 저장
python_code = None
except:
python_code = None
# 생성된 차트 반환
return text_output, python_code
def execute_and_show_chart(python_code, df):
try:
# 코드 실행 환경 준비 및 코드 실행
locals = {"df": df.copy()}
exec(python_code, globals(), locals)
# 차트 이미지로 변환
fig = plt.figure()
exec(python_code, globals(), locals)
buf = BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
img = Image.open(buf)
plt.close(fig)
return img
except Exception as e:
# 예외 발생 시 적절한 에러 메시지 반환
print(f"Error executing chart code: {e}")
return None
def process_and_display(csv_file, question):
# CSV 파일을 데이터프레임으로 읽어오기
# csv_file 임시 저장 경로
df = pd.read_csv(csv_file)
# 질문에 대한 답변 생성 (agent에게 데이터 프레임 df와 사용자의 질문 question이 전달됨)
text_output, python_code = analyze_with_langchain_agent(df, question)
# 결과를 출력
chart_image = execute_and_show_chart(python_code, df) if python_code else None
return text_output, chart_image
with gr.Blocks() as demo:
gr.Markdown("### CSV 파일을 업로드하고, 질문을 입력하세요. 분석 결과를 확인할 수 있습니다.")
with gr.Row(): # 하나의 행 구성 - 하나의 행에 input과 output이 위치하게 됨
csv_input = gr.File(label="CSV 파일 업로드", type="filepath") # file upload component
question_input = gr.Textbox(placeholder="질문을 입력하세요.")
# 버튼 클릭시 위의 값들이 함수로 전달됨 - 여기선 버튼 정의
submit_button = gr.Button("Run")
output_markdown = gr.Markdown()
# 차트 영역 이미지로 표현하기
output_image = gr.Image()
# 위에서 정의된 버튼이 클릭되는 경우, 2개의 input이 전달됨
# -> 출력은 markdown과 이미지 -> markdown은 윗쪽 영역에, image는 아래에 출력됨
submit_button.click(fn=process_and_display,
inputs=[csv_input, question_input],
outputs=[output_markdown, output_image])
if __name__ == "__main__":
demo.launch()
실습 결과 화면


섹션5. 암호화폐 투자 분석 챗봇 만들기(CrewAI로 Sequential Multi Agent 구현)
|
1. Multi Agent 개념 (이론)
Multi Agent 정의
- 여러 자율적인 agent가 공유된 환경에서 서로 협력하거나 경쟁하며 복잡한 문제를 함께 해결하는 시스템
Multi Agent LLM
현재 LLM을 활용하는 방법은 주로 RAG를 기반으로 하는 Single Agent Architecture를 활용한다. 여기서 Agent란 LLM을 통상적으로 LLM을 하나의 지성체로 보고 스스로의 기억(Memory)를 기반으로 계획하고, 행
x2bee.tistory.com
Multi Agent의 (간단한) 구조
- 첫 번째 agent는 research 실행 → 실행 결과를 받아서 두 번째 agent는 analysis 실행

2. Tavily 검색도구, CrewAI Sequential Agent 활용 방법 (실습)
- Poetry 명령어
- 프로젝트 생성: poetry new [프로젝트명]
- 패키지 설치:poetry add langchain langchain-openai python-dotenv langchain-community crewai 'crewai[tools]' tavily-python duckduckgo-search gradio
Tavily Search - Docs by LangChain
We've raised a $125M Series B to build the platform for agent engineering. Read more.
docs.langchain.com
- Tavily는 AI 에이전트(LLM, 대형 언어 모델)를 위해 특별히 만들어진 검색 엔진으로, 실시간(real-time), 정확하고(factual), 신뢰할 수 있는(accurate) 결과를 빠르게 제공한다.
- Tavily는 두 가지 주요 엔드포인트(endpoint)를 제공하는데, 그중 하나인 Search(검색) 엔드포인트는 LLM과 RAG에 최적화된 검색 결과를 제공한다.
CrewAI 패키지 설치 에러

- 원인: toml 파일에서 파이썬 버전을 requires-python = ">=3.11,<4.0” 로 바꿔놨다. crewai는 < 3.14만 지원하는데, pyproject.toml에 Python 범위가 3.14 이상도 포함(예: >=3.13,<4.0)되어 있으면, Poetry가 “그럼 3.14~<4.0에서도 깔려야지?”라고 가정하고 충돌을 내는 구조가 된다.
- 해결 방법:
- toml 파일 수정: python = ">=3.11,<3.14”
- 잠깐 초기화 후 재설치
# (있다면) 기존 venv 제거
poetry env remove --all
# brew로 3.11 설치되어 있다면 그 인터프리터 지정
poetry env use /opt/homebrew/opt/python@3.11/bin/python3.11 # Apple Silicon 기준
# 인텔 맥이면 보통 /usr/local/opt/python@3.11/bin/python3.11
# 확인
poetry run python -V
# 잠금/설치
poetry lock --no-update
poetry install
poetry add langchain langchain-openai python-dotenv langchain-community \
crewai 'crewai[tools]' tavily-python duckduckgo-search gradio
3. Gradio 웹앱으로 Multi Agent 챗봇 구현 (실습)
- 가동중인 서버는 ctrl + C로 중지하기
# 환경 변수에서 API 키 가져오기
import os
from dotenv import load_dotenv
load_dotenv()
# CrewAI 라이브러리에서 필요한 클래스 가져오기
from crewai import Agent, Task, Crew, Process
from langchain_openai import ChatOpenAI
import gradio as gr
# LLM
llm = ChatOpenAI(model='gpt-4.1-mini', temperature=0)
# Search Tool - 검색도구는 tavilysearch를 쓴다는 것을 정의
from crewai_tools import TavilySearchTool
search_tool = TavilySearchTool(max_results=3)
# (topic) - description 중에서, 사용자가 입력하는 topic에 대해서 좀 더 집중해서 조사하도록 함
# 웹에서 입력받은 것을 전달
def run_crypto_crew(topic):
"""
CrewAI를 실행하고 결과를 문자열로 반환
"""
try:
# Agent 1: Researcher
researcher = Agent(
role='Market Researcher',
goal='Uncover emerging trends and investment opportunities in the cryptocurrency market.',
backstory='You are a groundbreaking researcher who identifies innovative trends and actionable insights.',
verbose=True,
tools=[search_tool],
allow_delegation=False,
llm=llm,
max_iter=5,
)
# Agent 2: Analyst
analyst = Agent(
role='Investment Analyst',
goal='Analyze cryptocurrency market data to extract actionable insights and investment leads.',
backstory='You are an expert analyst who draws meaningful conclusions from cryptocurrency market data.',
verbose=True,
allow_delegation=False,
llm=llm,
max_iter=5,
)
# Tasks
research_task = Task(
description=f'Explore the internet to pinpoint emerging trends and potential investment opportunities in {topic} cryptocurrency market.',
expected_output='A detailed summary of the research results',
agent=researcher,
)
analyst_task = Task(
# 한국어 답변을 원하면, description에서 한글로 해달라고 설정하면 됨
description=f'Analyze the provided {topic} cryptocurrency market data to extract key insights and compile a concise report.',
expected_output='A refined finalized investment report with actionable insights',
agent=analyst,
)
# Crew 생성 - 답변을 모음
crypto_crew = Crew(
agents=[researcher, analyst],
tasks=[research_task, analyst_task],
process=Process.sequential,
verbose=True,
)
# Crew 실행
result = crypto_crew.kickoff()
# CrewOutput 객체를 문자열로 변환
if hasattr(result, 'raw'):
# CrewOutput 객체의 경우
return str(result.raw)
elif isinstance(result, str):
# 이미 문자열인 경우
return result
else:
# 다른 타입의 경우
return str(result)
except Exception as e:
return f"❌ 오류 발생: {str(e)}\n\n요청한 주제: {topic}"
# 여기서 쿼리를 입력받아서, 아래 app = gr.ChatInterface 에서 처리함
# "채팅"이기 때문에 message와 history가 필요함 (필수)
def process_query(message, history):
"""
Gradio 채팅 인터페이스용 콜백 함수
"""
# message가 빈 문자열이면 처리하지 않음
if not message or message.strip() == "":
return "질문을 입력해주세요."
# CrewAI 실행 - 입력받은 message를 처리하도록 run_crypto_crew(message)를 호출함
# message에 근거해서 처리
response = run_crypto_crew(message)
return response
# 출력/결과를 chatinterface에서 보이도록 함
if __name__ == '__main__':
# Gradio ChatInterface 설정
app = gr.ChatInterface(
fn=process_query,
title="🚀 Crypto Investment Advisor Bot",
description="암호화폐 관련 트렌드를 파악하여 투자 인사이트를 제공해 드립니다.",
type="messages",
examples=[
"Bitcoin의 최근 트렌드는?",
"DeFi 프로젝트 투자 기회",
"AI와 암호화폐의 결합",
],
cache_examples=False, # 매번 새로 실행
)
app.launch(share=False, debug=True)

4. Huggingface space에 웹앱 배포하기 (실습)
Spaces - Hugging Face
Running on CPU Upgrade
huggingface.co
Commands | Documentation | Poetry - Python dependency management and packaging made easy
When using --local-version, the identifier must be PEP 440 compliant. This is useful for adding build numbers, platform specificities, etc. for private packages. --local-version is deprecated and will be removed in a future version of Poetry. Use --config-
python-poetry.org
export 명령어 사용
- [tool.poetry.requires-plugins] poetry-plugin-export = ">=1.8"
배포 유의사항
- 인증키 등은 외부에 노출되지 않도록 반드시 Secrets에 등록하세요.
- 웹을 배포하고 Public 공개할 경우에 API 비용이 과도하게 발생할 수 있습니다.
- 우선 Private 비공개로 설정하고, 필요한 경우에 Public 공개로 전환하시는 것이 좋습니다.
Huggingface space 파일 올리는 방법
- git 사용
- file menu에서 직접 업로드 → app.py (main.py)와 requirements.txt 업로드
API 등록 방법
- settings → variables and secrets → new secrets
섹션6. 제주도 여행 플래너 만들기 (CrewAI로 Hierarchical Multi Agent 구현)
1. Hierarchical Multi Agent 개념
여러 개의 agent들이 각자의 역할을 수행 (ex) 리서치 담당, 분석 담당, 보고서 담당)
→ supervisor가 전체적인 과정을 관리하고 모니터링
→ 최종 판단 (CrewAI 사용)
2. 개발 환경 설정
- Poetry 명령어
- 프로젝트 생성: poetry new [프로젝트명]
- 패키지 설치:poetry add langchain langchain-openai python-dotenv langchain-community crewai 'crewai[tools]' tavily-python duckduckgo-search gradio bs4 selenium webdriver-manager qdrant-client
3. CrewAI Tools 도구 사용 - PDFSearchTool 추가
Tools - CrewAI
Understanding and leveraging tools within the CrewAI framework for agent collaboration and task execution.
docs.crewai.com
- pdf search tools, 웹스크래핑, 유튜브 검색 등 다양한 RAG관련 툴들이 많음 !!!
4. CustomTool (사용자 정의 도구) 만들기 - 웹 스크래핑
- creating your own tools → utilizing the tool decorator
- 이 tool을 활용해 html문서에서 text만을 가져올 수 있음
중간에 오류가 발생했다. - crewai import 관련
- from crewai_tools import tool 에서 → from crewai.tools import tool 로 바꾸기

# 검색창에 입력하기
# ID 속성은 고유의 값이기 때문에 값을 찾기 쉬워짐
input_search = driver.find_element(By.ID, 'searchboxinput')
# 위에 코드에 있는 place_name = "제주민속촌"이 들어감 - 전달
input_search.send_keys(place_name)
driver.implicitly_wait(5)
# "제주민속촌"이 검색어로 들어가게 되고, 엔터키까지 실행됨
input_search.send_keys(Keys.RETURN)
# 지도가 로딩되는데 걸리는 시간도 빼둠
driver.implicitly_wait(5)
time.sleep(3)

# 장소 정보 가져오기
# driver.page_source를 통해 html 소스 코드를 모두 가져옴
# 이를 html.parser를 사용해 html 파일을 분석함
# 분석된 결과를 soup 변수에 저장
soup = BeautifulSoup(driver.page_source, 'html.parser')
# 그리고, 'aria-label': place_name인 경우 (여기서는 "제주민속촌")인 경우에만 place_info에 저장함
place_info = soup.find_all('div', attrs={'aria-label': place_name})
# place_info에 여러 개의 div 태그들이 있음 -> 반복문을 통해 div 태그에서 text 속성만을 출력
# -> 줄바꿈 문자를 통해 join 함수로 결합 -> 하나의 문자열로 출력
place_info_text = "\n".join([info.text for info in place_info])
5. CrewAI Hierarchical Agent 활용 방법
# Crew 생성
trip_crew = Crew(
agents=[jeju_tour_planning_expert, jeju_local_expert, jeju_travel_concierge],
tasks=[jeju_location_selection_task, jeju_local_insights_task, jeju_travel_itinerary_task],
process=Process.hierarchical,
# 계층구조를 사용하기 때문에 supervisor가 필요하고, supervisor이 어떤 llm을 쓸 것인지 정의해야 함. (manager_llm)
manager_llm=ChatOpenAI(model="gpt-4") # 비용 과금에 유의 (GPT-4는 비용이 높음). gpt-3.5-turbo로 변경 가능
)
