학 습 목 표
- 온톨로지를 벡터 검색용 문서와 그래프 질의 대상의 두 형태로 준비한다.
- 질문 유형에 따라 두 검색의 성패가 갈리는 것을 실행으로 확인한다.
- 온톨로지 유무(구조 유무)에 따른 답변 차이를 시연한다 — 판정 기준 4의 전반부.
준비 — 한 지식의 두 형태
실험 설계가 핵심이다. 같은 지식(psymap.owl)을 두 형태로 준비해, 차이가 검색 방식에서만 나오게 통제한다. 벡터 쪽은 각 클래스의 라벨+정의를 한 '문서'로 삼아 30건의 문서를 만들고 TF-IDF 벡터로 바꾼다 — 임베딩 API 없이 재현되도록 한 축소 구현이며, '텍스트를 수치 벡터로 바꿔 유사도로 순위 매긴다'는 원리는 실제 임베딩과 같다(차이는 뒤에서 짚는다). 그래프 쪽은 파일을 rdflib로 열어 SPARQL을 그대로 쓴다(5-7의 재사용).
# rag_compare.py 핵심부 — ① 클래스를 '문서'로 docs = [f"{label}. {definition}" for ...] # 30건 vec = TfidfVectorizer(analyzer="char_wb", ngram_range=(2, 3)) M = vec.fit_transform(docs) def vector_search(question, k=3): # ② 질문 벡터와 코사인 유사도 sims = cosine_similarity(vec.transform([question]), M)[0] ... def graph_query(sparql): # ③ 같은 지식에 구조 질의 return g.query(PRE + sparql)
rag_compare.py 발췌. 전문은 차시 끝에서 열어 볼 수 있다.
대결 — 실제 출력
$ python3 rag_compare.py 문서 30건 (클래스별 라벨+정의) 질문 A: 작업기억을 측정하는 과제는 무엇인가 [벡터 검색 상위 3] [('작업기억 과제', 0.537), ('기억 과제', 0.279), ('측정 과제', 0.256)] [그래프 질의(CQ3)] ['N백 과제', '숫자폭 과제'] 질문 B: 방금 들은 전화번호를 잠깐 기억해 두는 능력 [벡터 검색 상위 3] [('기억 과제', 0.246), ('작업기억', 0.201), ('기억 능력', 0.193)] [그래프 질의] '잠깐 기억해 두는 능력'이라는 관계·클래스가 없음 — 질의 작성 불가
실제 실행 출력. 질문 A는 그래프의 완승, 질문 B는 벡터만이 답에 접근한다 — 6-2 표 1의 예측 그대로다.
판독 — 출력이 가르치는 세 가지
첫째, 질문 A에서 벡터 검색은 '작업기억 과제'라는 문서를 가장 가깝다고 찾았다 — 틀리지 않았지만 답이 아니다. 질문에 답하려면 그 클래스의 구성원(숫자폭·N백)이 필요한데, 두 과제의 정의 문장에는 '작업기억'이라는 낱말이 없어 유사도 그물에 걸리지 않는다. 연결 정보는 텍스트가 아니라 공리(measures)에 있고, 공리를 읽는 것은 질의뿐이다. 이것이 "온톨로지 유무에 따른 답변 차이"의 실물이다 — 같은 지식이라도 구조 없이 텍스트로만 저장되면 질문 A에 정확히 답할 수 없다(판정 기준 4의 전반부 달성).
둘째, 질문 B에서 그래프는 아예 출전하지 못했다 — '잠깐 기억해 두는'을 받아 줄 스키마가 없어서다. 벡터는 작업기억·기억 능력을 상위에 올려 사람을 정답 근처까지 데려간다. 셋째, 그 벡터 출력에도 교훈이 있다. 정답에 가장 가까운 단기기억이 상위 3에 없다 — 정의문("수 초에서 수십 초…수동적으로 유지")과 질문("전화번호를 잠깐 기억")이 뜻은 같은데 낱말이 달라, 표면 어휘만 보는 TF-IDF가 놓친 것이다. 의미를 학습한 실제 임베딩이라면 잡았을 간격이다 — 축소 구현과 실전의 차이가 어디서 나는지를 출력이 정확히 가리킨다.
| 관찰 | 원인 | 실무 번역 |
|---|---|---|
| 벡터, 질문 A에서 목록 실패 | 연결 지식이 텍스트 아닌 공리에 있음 | 관계·집계 질문은 그래프로 라우팅 |
| 그래프, 질문 B에서 출전 불가 | 스키마 밖 표현 | 흐릿한 탐색 질문은 벡터로 라우팅 |
| 벡터, 단기기억을 놓침 | 표면 어휘 일치의 한계(TF-IDF) | 실전에서는 의미 임베딩 사용 + altLabel을 문서에 포함 |
표 1실측의 판독. 셋째 행의 처방 — altLabel·정의를 검색 문서에 함께 넣는 것 — 은 온톨로지의 주석 레이어(5-6)가 벡터 검색의 품질까지 끌어올린다는 뜻이다. 두 검색은 경쟁자이면서 서로의 재료다.
판별 연습
문 1질문 A에 대한 벡터 RAG의 최종 답(LLM 생성까지 간 경우)은 어떤 모습일 것이며, 왜 위험한가.
답 확인
프롬프트에는 '작업기억 과제'의 정의문 등 유사 문서만 담기므로, LLM은 자기 파라미터 지식으로 빈칸을 메워 "숫자폭 과제, N백 과제, 스트룹 과제 등"처럼 유창하게 답할 공산이 크다. 맞는 항목과 틀린 항목(스트룹은 주의 과제다)이 섞여도 출처가 없어 가려낼 수 없다 — 검색 실패가 환각으로 미끄러지는 전형적 경로이고, 접지(6-1)가 깨지는 지점이다.
문 2표 1 셋째 행의 처방을 실행한다면 검색 문서를 어떻게 다시 만들겠는가.
답 확인
문서를 "prefLabel + altLabel 전부 + 정의 + note"로 확장한다. 단기기억 문서에 'STM'이, 작업기억 문서에 '작동기억'이 들어가 표면 일치율이 오른다. 나아가 measures 공리를 "숫자폭 과제는 작업기억을 측정한다"라는 문장으로 펴서 문서에 넣으면(공리의 텍스트화) 질문 A도 벡터로 어느 정도 잡힌다 — 그래프가 벡터 검색의 문서 생성기가 되는, 하이브리드의 한 형태다.
적용: 산출물과 파일
실행 스크립트 전문은 rag_compare.py에서 열어 볼 수 있다(scikit-learn 필요: pip install scikit-learn). 자신의 도메인으로 실습 중인 독자는 질문 A 자리에 자기 조회형 CQ를, 질문 B 자리에 용어를 모르는 사용자의 말투를 넣어 같은 실험을 하면 된다. 다음 차시는 질문 B의 사용자도 그래프의 정확성에 닿게 하는 다리 — 자연어를 질의로 바꾸는 체인 — 를 놓는다.
용어 정리
| 용어 | 원어 | 뜻 |
|---|---|---|
| TF-IDF | term frequency–inverse document frequency | 낱말 빈도 기반의 고전적 텍스트 벡터화 — 표면 어휘만 본다 |
| 코사인 유사도 | cosine similarity | 두 벡터 사이 각도로 가까움을 재는 척도 |
| 라우팅 | routing | 질문 유형을 보고 적합한 검색 경로로 보내는 운용 |
| 공리의 텍스트화 | axiom verbalization | 공리를 자연어 문장으로 펴서 검색 문서로 쓰는 기법 |
실습 파일: rag_compare.py(본 사이트 수록 — 출력은 전부 실제 실행 결과). · Lewis, P. et al. (2020). Retrieval-Augmented Generation. NeurIPS. · 6-2(비교 이론)·5-7(SPARQL 재사용)의 종합.