CrewAI를 활용한 Qdrant 에이전틱 RAG 시스템
CrewAI를 활용한 Qdrant 에이전틱 RAG 시스템 (tutorials-build-essentials-agentic-rag-crewai-zoom)
| 시간: 45분 | 수준: 초급 | 출력: GitHub |
|---|
Qdrant의 벡터 검색과 CrewAI의 모듈형 에이전트 오케스트레이션을 결합하면, 단순히 질문에 답하는 것을 넘어 분석하고 해석하며 행동하는 시스템을 만들 수 있어요.
전통적인 RAG 시스템은 데이터를 가져와 응답을 생성하는 데 집중하지만, 깊이 추론하거나 다단계 프로세스를 처리하는 능력은 부족해요.
이 튜토리얼에서는 에이전틱 RAG(Agentic RAG) 시스템을 단계별로 구축해볼 거예요. 마지막에는 Qdrant 벡터 데이터베이스에 데이터를 저장하고, CrewAI 에이전트와 벡터 검색을 결합해 데이터에서 인사이트를 추출하는 동작하는 프레임워크를 갖게 됩니다.
이 앱은 이미 만들어져 있어요. 이 저장소를 클론하고 튜토리얼을 따라 해보세요.
무엇을 만들까요
이 실습형 튜토리얼에서는 다음을 수행하는 시스템을 만들 거예요:
- Qdrant를 사용해 회의록(meeting transcript)을 벡터 임베딩으로 저장하고 검색한다.
- CrewAI 에이전트를 활용해 회의 데이터를 분석하고 요약한다.
- 간단한 Streamlit 인터페이스에서 인사이트를 쉽게 상호작용할 수 있게 보여준다.
이 프로젝트는 벡터 검색 기반 에이전틱 워크플로우를 구축해 회의 녹음에서 인사이트를 추출하는 방법을 보여줘요. Qdrant의 벡터 검색 능력과 CrewAI 에이전트를 결합해, 사용자는 자신의 회의 콘텐츠를 검색하고 분석할 수 있게 됩니다.
애플리케이션은 먼저 회의록을 벡터 임베딩으로 변환해 Qdrant 벡터 데이터베이스에 저장해요. 그런 다음 CrewAI 에이전트를 사용해 벡터 데이터베이스를 질의하고 회의 콘텐츠에서 인사이트를 추출해요. 마지막으로 Anthropic Claude를 사용해 벡터 데이터베이스에서 추출된 인사이트를 기반으로 사용자 질문에 자연어 응답을 생성해요.
어떻게 동작할까요
시스템과 상호작용할 때 뒤에서 일어나는 일은 다음과 같아요.
먼저 사용자가 시스템에 쿼리를 제출해요. 이 예시에서 우리는 마케팅 회의의 평균 길이를 알아내고 싶다고 해볼게요. 회의 데이터 포인트 중 하나가 회의 지속 시간이므로, 에이전트는 주제나 내용에 "Marketing"이라는 키워드가 있는 모든 회의의 지속 시간을 평균내어 마케팅 회의의 평균 길이를 계산할 수 있어요.

다음으로 에이전트는 search_meetings 도구를 사용해 Qdrant 벡터 데이터베이스에서 가장 의미론적으로 유사한 회의 포인트를 검색해요. 우리는 마케팅 회의에 대해 물어봤으므로, 에이전트는 주제나 내용에 "Marketing" 키워드가 있는 모든 회의를 검색 도구로 데이터베이스에서 찾아보는 거예요.

다음으로 에이전트는 calculator 도구를 사용해 회의의 평균 지속 시간을 구해요.

마지막으로 에이전트는 Information Synthesizer 도구를 사용해 분석 결과를 종합하고 자연어 형식으로 제시해요.

사용자는 채팅형 인터페이스에서 최종 출력을 보게 돼요.

그런 다음 사용자는 더 많은 질문을 던지며 시스템과 계속 상호작용할 수 있어요.
아키텍처
시스템은 세 가지 주요 컴포넌트로 구성돼요:
- Qdrant 벡터 데이터베이스: 회의록과 요약을 벡터 임베딩으로 저장해 의미론적 검색을 가능하게 한다.
- CrewAI 프레임워크: 회의 분석의 여러 측면을 처리하는 AI 에이전트를 조율한다.
- Anthropic Claude: 자연어 이해와 응답 생성을 제공한다.
- 데이터 처리 파이프라인
- 회의록과 메타데이터를 처리한다.
- SentenceTransformer로 임베딩을 생성한다.
- Qdrant 컬렉션과 데이터 업로드를 관리한다.
- AI 에이전트 시스템
- CrewAI 에이전트 로직을 구현한다.
- 벡터 검색 통합을 처리한다.
- Claude로 쿼리를 처리한다.
- 사용자 인터페이스
- 채팅형 웹 인터페이스를 제공한다.
- 실시간 처리 피드백을 보여준다.
- 대화 기록을 유지한다.
시작하기
- Qdrant API 자격 증명 얻기:
- Qdrant Cloud에서 계정에 가입한다.
- 새 클러스터를 만들고 Cluster URL(형식: https://xxx.gcp.cloud.qdrant.io)을 복사한다.
- Data Access Control로 이동해 API key를 생성한다.
- AI 서비스 API 자격 증명 얻기:
설정
- 저장소 클론하기:
git clone https://github.com/qdrant/examples.git
cd agentic_rag_zoom_crewai
- 호환성을 위해 Python 3.10으로 가상 환경 생성 및 활성화:
python3.10 -m venv venv
source venv/bin/activate
# Windows: venv\Scripts\activate
- 의존성 설치:
pip install -r requirements.txt
- 환경 변수 구성: 다음과 같이
.env.local파일을 만든다:
openai_api_key = your_openai_key_here
anthropic_api_key = your_anthropic_key_here
qdrant_url = your_qdrant_url_here
qdrant_api_key = your_qdrant_api_key_here
사용법
1. 회의 데이터 처리
data_loader.py 스크립트는 회의 데이터를 처리해 Qdrant에 저장해요:
python vector/data_loader.py
이 스크립트가 실행된 후에는 Qdrant Cloud 계정에 zoom_recordings라는 새 컬렉션이 생긴 걸 확인할 수 있어요. 이 컬렉션에는 회의록의 벡터 임베딩이 담겨 있어요. 컬렉션의 포인트에는 토픽, 콘텐츠, 요약을 포함한 원본 회의 데이터가 들어 있어요.
2. 인터페이스 실행
streamlit_app.py는 vector 폴더에 있는데요. 실행하려면:
streamlit run vector/streamlit_app.py
이 스크립트를 실행하면 채팅형 인터페이스를 통해 시스템과 상호작용할 수 있어요. 회의 콘텐츠에 대해 질문하면, 시스템이 AI 에이전트를 사용해 가장 관련성 높은 정보를 찾아 자연어 형식으로 제시해요.
데이터 파이프라인
우리 시스템의 핵심에는 데이터 처리 파이프라인이 있어요:
class MeetingData:
def _initialize(self):
self.data_dir = Path(__file__).parent.parent / 'data'
self.meetings = self._load_meetings()
self.qdrant_client = QdrantClient(url=os.getenv('qdrant_url'), api_key=os.getenv('qdrant_api_key'))
self.embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
data_loader.py의 싱글턴 패턴은 Python의 new와 init 메서드를 사용하는 MeetingData 클래스를 통해 구현돼요. 이 클래스는 인스턴스가 존재하는지 추적하는 private _instance 변수와, 초기화 코드가 한 번만 실행되게 하는 _initialized 플래그를 유지해요. MeetingData()로 새 인스턴스를 만들 때 new가 먼저 _instance가 있는지 확인해요. 없으면 만들고 초기화 플래그를 False로 설정해요. init 메서드는 이 플래그를 확인해서 False면 초기화 코드를 실행하고 플래그를 True로 설정해요. 이렇게 하면 이후의 모든 MeetingData() 호출이 동일한 초기화된 리소스를 가진 같은 인스턴스를 반환하게 돼요.
회의를 처리할 때는 콘텐츠와 컨텍스트를 모두 고려해야 해요. 각 회의는 벡터로 변환되기 전에 풍부한 텍스트 표현으로 변환돼요:
text_to_embed = f"""
Topic: {meeting.get('topic', '')}
Content: {meeting.get('vtt_content', '')}
Summary: {json.dumps(meeting.get('summary', {}))}
"""
이 구조화된 형식은 벡터 임베딩이 각 회의의 전체 컨텍스트를 포착하도록 보장해요. 하지만 회의를 하나씩 처리하는 건 비효율적이에요. 대신 배치로 데이터를 처리해요:
batch_size = 100
for i in range(0, len(points), batch_size):
batch = points[i:i + batch_size]
self.qdrant_client.upsert(collection_name='zoom_recordings', points=batch)
AI 에이전트 시스템 구축
우리 AI 시스템은 도구 기반 접근 방식을 사용해요. 가장 간단한 도구인 회의 통계용 계산기부터 시작해볼게요:
class CalculatorTool(BaseTool):
name: str = "calculator"
description: str = "Perform basic mathematical calculations"
def _run(self, a: int, b: int) -> dict:
return {"addition": a + b, "multiplication": a * b}
하지만 진짜 힘은 벡터 검색 통합에서 나와요. 이 도구는 자연어 쿼리를 벡터 표현으로 변환해 회의 데이터베이스를 검색해요:
class SearchMeetingsTool(BaseTool):
def _run(self, query: str) -> List[Dict]:
response = openai_client.embeddings.create(model="text-embedding-ada-002", input=query)
query_vector = response.data[0].embedding
return self.qdrant_client.search(collection_name='zoom_recordings', query_vector=query_vector, limit=10)
검색 결과는 우리의 분석 도구에 입력돼요. 이 도구는 Claude를 사용해 더 깊은 인사이트를 제공해요:
class MeetingAnalysisTool(BaseTool):
def _run(self, meeting_data: dict) -> Dict:
meetings_text = self._format_meetings(meeting_data)
message = client.messages.create(
model="claude-3-sonnet-20240229",
messages=[{"role": "user", "content": f"Analyze these meetings:\n\n{meetings_text}"}]
)
마법은 이 도구들을 에이전트 프레임워크 아래 하나로 묶을 때 일어나요. 우리는 두 개의 특수 에이전트를 만들어요:
researcher = Agent(
role='Research Assistant',
goal='Find and analyze relevant information',
tools=[calculator, searcher, analyzer]
)
synthesizer = Agent(
role='Information Synthesizer',
goal='Create comprehensive and clear responses'
)
이 에이전트들은 조정된 워크플로우에서 함께 동작해요. 연구자는 정보를 수집하고 분석하며, 종합자는 명확하고 실행 가능한 응답을 만들어요. 이 책임 분리는 각 에이전트가 자신의 강점에 집중할 수 있게 해줘요.
사용자 인터페이스 구축
Streamlit 인터페이스는 AI 시스템과 상호작용할 수 있는 깔끔한 채팅형 경험을 제공해요. 기본 설정부터 시작해볼게요:
st.set_page_config(page_title="Meeting Assistant", page_icon="🤖", layout="wide")
인터페이스를 더 매력적으로 만들기 위해 출력을 읽기 쉽게 하는 커스텀 스타일을 추가해요:
st.markdown("""
<style>
.stApp { max-width: 1200px; margin: 0 auto; }
.output-container { background-color: #f0f2f6; padding: 20px; border-radius: 10px; margin: 10px 0; }
</style>
""", unsafe_allow_html=True)
핵심 기능 중 하나는 처리 중 실시간 피드백이에요. 커스텀 출력 핸들러로 이를 구현해요:
class ConsoleOutput:
def __init__(self, placeholder):
self.placeholder = placeholder
self.buffer = []
self.update_interval = 0.5 # seconds
self.last_update = time.time()
def write(self, text):
self.buffer.append(text)
if time.time() - self.last_update > self.update_interval:
self._update_display()
이 핸들러는 출력을 버퍼링하고 주기적으로 디스플레이를 업데이트해 매끄러운 사용자 경험을 만들어요. 사용자가 쿼리를 보내면 시각적 피드백과 함께 처리해요:
with st.chat_message("assistant"):
message_placeholder = st.empty()
progress_bar = st.progress(0)
console_placeholder = st.empty()
try:
console_output = ConsoleOutput(console_placeholder)
with contextlib.redirect_stdout(console_output):
progress_bar.progress(0.3)
full_response = get_crew_response(prompt)
progress_bar.progress(1.0)
인터페이스는 채팅 기록을 유지해 자연스러운 대화처럼 느껴지게 해요:
if "messages" not in st.session_state:
st.session_state.messages = []
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
사이드바에는 유용한 예시와 설정도 포함돼요:
with st.sidebar:
st.header("Settings")
search_limit = st.slider("Number of results", 1, 10, 5)
analysis_depth = st.select_slider("Analysis Depth", options=["Basic", "Standard", "Detailed"], value="Standard")
이런 기능들의 조합은 강력하면서도 접근하기 쉬운 인터페이스를 만들어요. 사용자는 쿼리가 실시간으로 처리되는 것을 보고, 필요에 맞게 설정을 조정하며, 채팅 기록을 통해 컨텍스트를 유지할 수 있어요.
결론
이 튜토리얼은 벡터 검색과 AI 에이전트를 결합한 정교한 회의 분석 시스템을 구축하는 방법을 보여줬어요. 다룬 핵심 컴포넌트를 정리해볼게요:
- 벡터 검색 통합
- Qdrant를 사용한 회의 콘텐츠의 효율적인 저장과 검색
- 벡터 임베딩을 통한 의미론적 검색 능력
- 최적 성능을 위한 배치 처리
- AI 에이전트 프레임워크
- 모듈형 기능을 위한 도구 기반 접근 방식
- 연구·분석을 위한 특수 에이전트
- 지능적인 인사이트를 위한 Claude 통합
- 인터랙티브 인터페이스
- 실시간 피드백과 진행 추적
- 지속적인 채팅 기록
- 구성 가능한 검색·분석 설정
결과물인 시스템은 벡터 검색과 AI 에이전트를 결합해 지능적인 회의 어시스턴트를 만드는 힘을 보여줘요. 이 튜토리얼을 통해 다음을 배웠어요:
- 회의 데이터를 효율적으로 처리하고 저장하는 방법
- 의미론적 검색 능력을 구현하는 방법
- 분석을 위한 특수 AI 에이전트를 만드는 방법
- 직관적인 사용자 인터페이스를 구축하는 방법
이 기반은 여러 방면으로 확장할 수 있어요:
- 더 많은 특수 에이전트 추가하기
- 추가 분석 도구 구현하기
- 사용자 인터페이스 개선하기
- 다른 데이터 소스와 통합하기
코드는 저장소에서 확인할 수 있으며, 여러분의 수정과 개선을 직접 실험해보시길 권장해요.
더 알아보기 (Learn more)
출처: Qdrant 공식문서