CAFE

Python

DuckDB + Parquet

작성자ParkYK|작성시간25.05.03|조회수395 목록 댓글 0

ChromaDB는 내부적으로 선택 가능한 저장 방식(backends) 중 하나로 DuckDB + Parquet를 사용한다.

   : Chroma의 GitHub 레포지토리와 공식 문서를 보면, "Chroma는 기본적으로 DuckDB를 내장 엔진으로 사용하고, 데이터를 Parquet 형식으로 저장한다." 라고 되어 있다.


* 요약: ChromaDB는 내부 저장소로 DuckDB + Parquet 사용 가능
구성 요소 역할
  - DuckDB : SQL 실행과 데이터 저장 (경량 DB 엔진)
  - Parquet : 벡터 임베딩, 메타데이터 등을 저장하는 파일 포맷
  - Chroma : 벡터 DB API (임베딩 저장, 검색, 필터링 등)

구체적으로 ChromaDB는 다음 두 가지 저장 백엔드를 지원한다.
 1) DuckDB + Parquet (기본값, 로컬 저장)
 2) ClickHouse (고급 분산 환경에서 사용)
로컬에서 Chroma.from_documents() 등을 사용하면 기본적으로 DuckDB + Parquet 조합으로 저장된다.

* 저장 구조 예시 (./chroma/ 디렉터리 내부)
chroma/
  ├── chroma.sqlite                        ← DuckDB 파일
  ├── chroma-collections.parquet      ← 벡터 컬렉션 정보
  ├── chroma-embeddings.parquet   ← 임베딩 벡터 값들
  ├── chroma-documents.parquet     ← 원본 문서 및 메타데이터

* 확인 방법 ---
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter

loader = TextLoader("sample.txt")
documents = loader.load()

splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=10)
docs = splitter.split_documents(documents)

# 임베딩 및 Chroma 생성
db = Chroma.from_documents(docs, OpenAIEmbeddings(), persist_directory="./chroma")
db.persist()

위 코드 실행 후 ./chroma 폴더가 생기며 DuckDB + Parquet 구조로 저장된다.

💖 결론적으로 
 Chroma가 DuckDB를 사용하는가? 넵! 기본 저장 엔진.
 Parquet는 어디에 사용되는가?  벡터, 문서, 메타데이터를 컬럼 지향으로 저장.
 DuckDB + Parquet의 장점은?  빠른 검색, SQL 지원, Pandas 등과 호환

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DuckDB란? SQLite처럼 가볍지만 분석(OLAP)에 강한 SQL DB이며, Pandas, Parquet, CSV 등과 잘 통합되며 설치도 간편하다.

LangChain에서 DuckDB를 Tool로 연결해서 LLM이 SQL로 데이터를 조회하게 만들 수 있다.
Parquet + DuckDB + LangChain을 연동하고, 요약(예: 전체 개수)이나 그룹별 평균(예: 도시별 평균 나이)과 같은 SQL도 처리할 수 있도록 할 수 있다.

* 실습코드 : 요약 및 그룹별 통계까지 포함
# 1. 필요한 라이브러리
import pandas as pd
import duckdb
from langchain.tools import Tool
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, AgentType

# 2. 샘플 데이터 -> Parquet로 저장
df = pd.DataFrame({
    'name': ['공기밥', '주먹밥', '김밥', '김치국', '박치기'],
    'age': [25, 30, 22, 32, 25],
    'city': ['서울', '부산', '인천', '서울', '부산']
})
df.to_parquet("people.parquet")

# 3. DuckDB에 연결 및 Parquet(고성능 컬럼 지향 저장 포맷) 파일을 VIEW로 등록
con = duckdb.connect()
con.execute("CREATE OR REPLACE VIEW people AS SELECT * FROM 'people.parquet'")

# 4. DuckDB Tool 정의 (요약, 그룹화 포함)
def query_duckdb(sql: str) -> str:
    try:
        df = con.execute(sql).fetchdf()
        return df.to_string(index=False)
    except Exception as e:
        return f"[쿼리 에러] {e}"

duckdb_tool = Tool(
    name="DuckDBParquetQuery",
    func=query_duckdb,
    description=(
        "Parquet에서 로딩된 people 테이블에 SQL 쿼리를 실행합니다. "
        "예: 'SELECT name FROM people WHERE age > 25', "
        "'SELECT COUNT(*) FROM people', "
        "'SELECT city, AVG(age) FROM people GROUP BY city'"
    )
)

# 5. LangChain Agent 구성
llm = ChatOpenAI(temperature=0)

agent = initialize_agent(
    tools=[duckdb_tool],
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,  # 프롬프트 형식은 "생각 → 행동 → 관찰 → 생각 → ..."의 흐름을 따르며, 사전 훈련된 명령어 없이도 주어진 설명만으로 행동을 결정
    verbose=True
)

# 6. 자연어로 실행 예시
examples = [
    "30세 이상인 사람의 이름은 누구야?",
    "전체 사람 수는 몇 명이야?",
    "각 도시별 평균 나이를 알려줘",
    "서울에 사는 사람들만 보여줘"
]

for question in examples:
    print(f"\n질문: {question}")
    answer = agent.run(question)
    print(f"답변:\n{answer}")

--- 예시 출력 예상 -------------
질문: 전체 몇 명이야?
답변: 5

질문: 각 도시별 평균 나이를 알려줘
답변:
 city         avg_age
 Busan      27.5
 Incheon   22.0
 Seoul      27.5

* 이 코드로 가능한 질의 예
자연어 질의                       변환되는 SQL
전체 몇 명이야?                 SELECT COUNT(*) FROM people
도시별 평균 나이 알려줘      SELECT city, AVG(age) FROM people GROUP BY city
25세 이상만 보여줘            SELECT * FROM people WHERE age >= 25
서울 사람만                      SELECT * FROM people WHERE city = '서울'

* 이 실습을 통해
 - Parquet 파일로 데이터를 저장
 - DuckDB에서 SQL VIEW로 불러오기
 - LangChain Tool로 SQL 쿼리 수행
 - 자연어로 요약, 필터, 그룹화 쿼리 가능
을 알게 됨

 

 

참고 : LangChain AgentType 종류 비교표  

AgentType 이름 특징 요약 입력 형식 대화 스타일 기타
ZERO_SHOT_REACT_DESCRIPTION가장 기본 ReAct 기반 에이전트.
도구 설명만 보고 LLM이 도구 선택 및 호출. 
일반 텍스트빠르게 프로토타입 만들 때. 설명 기반 제어추론+행동 반복 (ReAct)
CHAT_ZERO_SHOT_REACT_DESCRIPTIONChat 기반 LLM (예: GPT-4)을 위한 ReActChat 형식
(message 기반)
멀티턴 상호작용 필요 시OpenAI ChatModel 등에 최적화
STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTIONChat 기반 + 구조화된 Tool 사용 (도구와 인자 명확 분리)Chat 형식툴이 많거나 파라미터 구조가 명확할 때JSON 기반 structured tool 호출
REACT_DOCSTORE검색용으로 특화된 ReAct일반 텍스트문서 검색 후 응답 생성내부적으로 docstore와 연결
OPENAI_FUNCTIONSOpenAI Function 호출 방식 지원Chat 형식OpenAI function-calling 모델 사용 시tool이 자동 JSON 매핑됨
OPENAI_MULTI_FUNCTIONSOpenAI Function 여러 개 동시 실행 가능Chat 형식병렬 실행이 필요한 상황여러 function-call 최적화
TOOL_CALLINGOpenAI Tool Calling 전용 (function 대체 개념)Chat 형식최신 OpenAI API 전용tool_call_id 등 사용

 

* 상황에 따른 추천 에이전트 타입

상황 추천 AgentType
빠르게 단일 LLM + 단일 도구 테스트ZERO_SHOT_REACT_DESCRIPTION
ChatGPT 계열 모델로 대화형 상호작용CHAT_ZERO_SHOT_REACT_DESCRIPTION
각 도구에 입력 인자가 많고 구조가 명확할 때STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION
OpenAI GPT 4-turbo + function-calling API 사용 시OPENAI_FUNCTIONS 또는 TOOL_CALLING
병렬 도구 실행을 원할 때OPENAI_MULTI_FUNCTIONS

 

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
맨위로

카페 검색

카페 검색어 입력폼