지식의 성운
벡터 검색과 그래프 탐색을 결합한 Agent 기반 학습 도구
| period | 2026 |
| type | 개인 작업 |
| context | 크래프톤 정글 RAG·MCP·Agent 학습 |
| status | 로컬 프로토타입 · 미배포 |
대화에서 사라지는 학습 경로
새로운 개념을 배울 때 LLM은 질문의 깊이와 범위를 빠르게 넓혀 준다. 나는 그 과정에서 어떤 질문에서 출발했고, 어디에서 주제가 갈라졌으며, 무엇을 아직 확인하지 못했는지 놓치는 일이 잦았다. 대화가 쌓여도 학습 경로는 선명해지지 않았다. 문제의 중심은 기록의 양보다 구조에 있었다.
하나의 개념을 깊게 파고드는 흐름은 DFS(Depth-First Search), 주변 개념을 넓혀 가는 흐름은 BFS(Breadth-First Search)에 비유할 수 있다. 이 비유를 학습 과정을 조직하는 개념적 틀로 삼아, 대화에서 생긴 노트와 개념, 그 사이의 관계를 하나의 지도에 남기는 도구를 만들었다.
Learniverse는 사용자가 배운 내용을 구조화하고, 같은 구조를 Agent가 읽어 다음 질문과 기록을 돕는 로컬 학습 프로토타입이다.
인접과 연결
지식 사이의 관계를 두 가지 조건으로 나눴다. 의미가 비슷해 자연스럽게 가까워지는 인접과, 서로 다른 영역을 명시적인 이유로 잇는 연결이다.
인접은 각 Note와 Concept에 저장된 임베딩 사이의 거리로 표현한다. 연결은 Note와 Concept, Concept와 Concept 사이의 그래프 관계로 기록한다. 비슷한 지식은 하나의 성운처럼 모이고, 의미적으로 먼 지식도 관계가 기록되어 있으면 엣지를 따라 찾을 수 있다.

벡터 검색이 질문과 가까운 영역을 정하고, 그래프가 그 영역에 명시적으로 연결된 지식을 보완한다. 사람과 Agent는 같은 Note·Concept ID와 관계를 공유하며 지식 지도를 읽는다.
사람이 보는 지도, Agent가 읽는 구조


화면에서 학습 문서는 사각형 Note로, 핵심 개념은 원형 Concept로 나타난다. Note는 연결된 Concept를 통해 관련 Note와 함께 보이고, Concept 사이의 관계는 별도의 엣지로 표시된다.
사용자는 전체 지도를 보며 질문하거나 특정 노드를 선택해 참조 범위를 고정할 수 있다. 두 화면은 같은 질문에 전체 지식을 참조한 경우와 선택한 노드를 함께 참조한 경우의 답변 차이를 보여준다. 화면에서 선택한 노드와 Agent가 답변에 사용하는 근거는 같은 ID를 공유한다.
대화가 다시 노트가 되는 과정




학습 공백을 묻는 요청에는 현재 Note·Concept·관계(Link)의 보드 스냅숏과 사용자가 선택한 주제를 함께 전달한다. Agent는 보드에서 확인한 내용, 전체 지도를 넓게 봤을 때의 다음 주제, 선택한 주제를 더 깊게 볼 질문, 다음 노트 후보를 구분해 제시한다. 공백은 보드 스냅숏에서 드러나는 누락된 목차와 관계를 LLM이 해석해 제안하며, 채택 여부는 사용자가 결정한다.
질문을 이어가며 얻은 내용은 다시 학습 자료가 된다. Agent가 대화를 제목·키워드·본문으로 정리하면 작성 화면에 초안이 채워지고, 사용자가 검토해 저장한다. 네 화면은 학습 공백 확인, 후속 대화, 노트 초안 생성, 새 노드 추가의 순서를 보여준다. 대화와 지식 지도가 이 과정을 통해 하나의 순환을 이룬다.
멀리 있는 노드를 함께 읽기




사용자는 거리가 먼 여러 노드를 선택해 Agent의 참조 범위에 함께 넣을 수 있다. Agent는 선택된 자료에서 공통 구조와 차이를 찾고, 대화에서 발전한 생각을 새 노트 초안으로 정리한다. 의미 공간의 거리와 사용자가 발견한 관계를 서로 다른 정보로 남기는 방식이다.
선택한 노드와 이웃 관계는 Markdown으로 내보내거나 Notion 페이지로 보관할 수 있다. 생각을 비교하고 기록한 결과가 다시 지식 지도에 들어가면서 새로운 탐색의 출발점이 된다.
Notion 저장은 웹 화면의 API와 외부 LLM 호스트용 Python FastMCP 도구로 각각 구성했다. API는 선택한 노드의 Markdown 아카이브를 만들고, MCP 서버는 질문·답변 저장과 Markdown 아카이브 기능을 노출한다.
검색과 관계를 저장하는 방법




원본 Note와 Keyword, Concept, 임베딩은 PostgreSQL에 저장하고, pgvector의 L2 거리 연산으로 검색한다. Note–Concept와 Concept–Concept 관계는 Neo4j에 투영한다. 질문마다 Note와 Concept를 합쳐 벡터 거리 상위 다섯 개를 찾고, 그중 상위 세 개 노드의 Neo4j 직접 이웃을 한 단계 확장한다.
검색된 source에는 vector와 graph의 경로를 구분해 남기고, 그래프 이웃에는 어떤 노드에서 도달했는지도 기록한다. 답변에 표시된 Note·Concept ID는 실제로 반환된 source 목록과 대조한다.
각 노드에는 OpenAI text-embedding-3-small로 만든 1536차원 임베딩이 저장된다. 화면 좌표는 임베딩 행렬을 평균 중심화한 뒤 SVD(Singular Value Decomposition)로 주성분을 구해 계산한다. 앞의 두 화면처럼 상위 두 축은 2D 보드에, 세 축은 3D 보드에 사용한다. PCA 투영 과정에서는 원래 거리의 일부가 손실되므로, 화면은 의미 구조를 탐색하는 시각적 보조로 사용한다.
뒤의 두 화면은 관계를 정리하는 Strict Merge와 Soft Bridge의 검토 과정이다. Strict Merge는 여러 Keyword와 Concept를 하나의 Concept로 통합할 후보를 제안한다. Soft Bridge는 독립성을 유지할 두 Concept 사이의 관계와 근거를 제안한다. 후보는 각각 편집하거나 삭제할 수 있으며, 사용자가 승인한 항목만 일괄 반영한다.
구현 과정에서는 Strict Merge 이후 기존 Concept Link가 정리되지 않는 경우와 Note를 삭제할 때 한 저장소에 데이터가 남는 경우를 확인했다. 병합 시 관계를 새 Concept로 옮기고 자기참조 엣지를 제거했으며, 삭제 경로에서는 PostgreSQL 데이터와 Neo4j 투영을 함께 정리하도록 보완했다.
ERD
투영 좌표와 검색 거리


초기 지식 지도는 건축·게임·개발에 관한 노트로 구성했다. 여기에 관련성이 낮은 주제의 배치를 보기 위해 해리포터와 꽃을 추가하고, 원본 임베딩의 L2 거리와 2D·3D 투영에서의 위치를 비교했다.
두 화면은 같은 임베딩 행렬을 사용하지만, 2D는 상위 두 축을, 3D는 상위 세 축을 사용하므로 배치가 다르게 나타난다. 두 주제가 원본 임베딩 공간에서도 기존 주제 및 서로 사이에서 떨어져 있음을 별도로 확인했다. 이 비교의 목적은 화면 좌표와 실제 검색 거리를 구분하는 데 있었다.
벡터 검색과 그래프 검색의 비교
평가의 핵심은 하나였다. 그래프 관계가 벡터 검색에서 빠진 근거를 보완하는가.
17개 Note와 11개 Concept로 평가용 지식 지도를 만들고, Concept 사이에 3개의 관계를 설정했다. 같은 질문을 두 방식에 입력했다.
- Vector-only는 질문과 가까운 Note·Concept 다섯 개를 검색한다.
- Hybrid는 같은 검색 결과에서 상위 세 노드의 그래프 이웃을 한 단계 추가한다.
필요한 근거를 찾고, 그 내용으로 정확히 답했을 때 통과로 판정했다.
| 질문 유형 | Vector-only | Hybrid |
|---|---|---|
| 하나의 Note에서 사실 찾기 | 3/3 | 3/3 |
| 연결된 다른 항목까지 찾아 답하기 | 2/3 | 3/3 |
차이는 ‘하이브리드 검색과 연결된 다른 운영 항목의 조건’을 묻는 질문에서 나타났다. Vector-only는 출발 노드의 설명을 반복했다. Hybrid는 그래프를 따라 ‘검색 캐시’ Concept를 찾고, 그 안에 기록된 TTL 900초를 답했다.
직접적인 사실은 두 방식이 모두 찾았고, 벡터 거리 상위 다섯 개에서 빠진 관련 정보는 그래프 관계가 보완했다. 17개 Note로 진행한 소규모 비교지만, Learniverse에서 벡터와 그래프가 맡는 역할의 차이를 확인할 수 있었다.
검증 범위와 남은 과제
Learniverse는 대화에서 얻은 내용을 Note와 Concept로 저장하고, 임베딩의 인접성과 그래프의 연결을 함께 사용해 다음 질문과 새 노트 작성으로 이어지는 흐름을 구현했다. 소규모 비교에서는 그래프 관계가 벡터 검색에서 빠진 근거를 보완하는 사례를 확인했다.
첫 번째 과제는 답변과 근거의 의미적 일치다. 현재 시스템은 인용한 Note·Concept ID가 실제 검색 결과에 포함됐는지 검사한다. 다음 단계에서는 답변을 주장 단위로 나누고, 인용한 자료가 각 주장을 뒷받침하는지 판별해야 한다. 존재하는 source ID를 표시한 답변과 충분한 근거를 갖춘 답변을 구분하기 위한 과정이다.
두 번째 과제는 PostgreSQL과 Neo4j 사이의 실패 복구다. 병합과 삭제 과정에서 발견한 정합성 문제는 보완했지만, 두 저장소에 순차적으로 기록하는 도중 작업이 중단되면 데이터가 어긋날 수 있다. PostgreSQL의 변경 사항을 이벤트로 남겨 Neo4j 반영을 재시도하고, 두 저장소를 주기적으로 대조하는 복구 절차가 필요하다. 화면의 지식 지도와 Agent의 검색 근거가 같은 상태를 읽게 만드는 기반 작업이다.
현재는 노드의 위치와 관계를 기록하지만, 학습 순서와 질문이 분기된 시점은 충분히 남기지 못한다. 향후에는 시간 정보를 추가해 깊이 탐색한 경로와 되돌아온 지점을 함께 기록할 계획이다.