문제 상황: 도메인 확장
- 단일 도메인(Driver)으로 시작
- 기존에는 일반적인 RDB 테이블에
embeddingcolumn을 추가하여 벡터 정보를 저장하도록 설계- 테이블을 특정하여 검색한다면, 정확도가 매우 높은 정보를 제공할 수 있음
- 데이터 동기화 과정에서도 하나의 테이블을 사용하기 때문에 관리하기 편함
- 도메인이 확장되면서 DB 테이블을 어떻게 구성할 것인지에 대한 문제
- 만약 기존 방식을 유지한다면, 도메인이 확장되었을 때, 쿼리마다 어떤 테이블에서 검색해야 하는지를 선택하는 로직이 추가적으로 필요
- 만약 잘못 판단한다면 원하는 정보를 영영 못 찾게 됨
전통적인 해결 방법: 단일 통합 벡터 테이블
- SpringAI, Langchain 등이 일반적으로 사용하는 방식
- Driver, Circuit, Result 등 모든 도메인의 텍스트 데이터를
vector_store라는 하나의 거대한 지식 창고 테이블에 몰아넣는 방법 - 테이블 구조가 다른데 어떻게 한번에 저장?
- 데이터베이스 구조 예시 (PostgreSQL + pgvector)
id(UUID): 벡터 문서 고유 IDcontent(TEXT): LLM이 읽을 실제 문장 (예: “찰스 르클레르는 페라리 소속 드라이버이며…“)embedding(VECTOR): content의 벡터값metadata(JSONB):{"type": "driver", "ref_id": 16, "team": "Ferrari"}
- 사용자가 “2023년 모나코 서킷 우승자가 누구야?”라고 물었다면, 시스템은 서킷 정보에 대한 content 1개와, 경기 결과 정보 content 하나, 총 두 개를 알아서 섞어서 가져옴
- 이 결과를 보고 LLM은 정답을 생성
- 데이터베이스 구조 예시 (PostgreSQL + pgvector)
개발 방향
- 단일 통합 벡터 테이블을 사용하는 것으로 결정
vector_store테이블을 생성- 데이터를 OpenF1 API에서 가져와서 RDB에 저장할 때,
metadata에type=driver를 달아서 테이블에 꽂아 넣기 - 쿼리 벡터에 따라서 데이터를 가져오는 개수를
topK값을 통하여 조절 가능- 보통의 RAG 시스템에서는
3~5정도로 설정
- 보통의 RAG 시스템에서는
- 가끔
topK=N으로 설정했더니, 쿼리랑 별로 관계없는 엉뚱한 데이터까지 가져오는 경우 발생 가능.similarityThreshhold(0.8)처럼 최소 유사도 컷오프를 설정할 수 있음- 이러면 유사도가 80% 미만인 엉뚱한 데이터는 버려짐
- Hallucination을 강력하게 방지
동작 테스트

- 사용자의 질문 쿼리가 정상적으로 Adapter로 전달되는가?
- 질문 쿼리에 대한 유사도 검색이 정상적으로 이루어지는가?
- Assistant의 답변이 DB에 존재하는 객관적 사실을 반환하는가?
- 존재하지 않는 데이터에 대하여 답을 지어내지 않고 정해진 프롬프트 규칙을 따르는가? (현재 DB에는 국적 정보가
null로 처리되어 있음)