"아무 데이터나 넣어주세요. LLM 에이전트가 이해할 수 있는 지식 그래프로 만들어 드릴게요."
이 문서는 Synaptic Memory를 처음 접하는 사람을 위한 안내서입니다. 프로그래밍 지식이 있으면 좋지만 RAG, 벡터 DB, 온톨로지 같은 용어를 몰라도 끝까지 따라올 수 있도록 작성했습니다.
LLM이 검색·추론할 수 있는 지식 그래프를, 당신이 가진 데이터로 2줄 만에 만들어 주는 Python 라이브러리입니다.
from synaptic import SynapticGraph
graph = await SynapticGraph.from_data("./my_data/") # 2줄
result = await graph.search("내가 궁금한 것")ChatGPT에게 회사 내부 문서를 질문하려면 어떻게 해야 할까요? 문서를 통째로 붙여넣으면 너무 길어서 대부분 잘려 버립니다. 그래서 질문과 관련 있는 부분만 골라서 프롬프트에 넣어주는 게 일반적인 방법입니다. 이걸 RAG (Retrieval-Augmented Generation, 검색 증강 생성)이라고 부릅니다.
-
키워드 매칭만으론 부족합니다 "스마트폰"으로 검색했는데 문서에 "휴대전화"만 있으면 못 찾습니다.
-
단일 검색으론 복합 질문을 못 풉니다 "5점 리뷰가 가장 많이 달린 상품의 가격은?" 같은 질문은 1번의 검색으로 답할 수 없습니다. 여러 단계의 조회·필터·집계가 필요하죠.
-
정형 데이터(DB)와 비정형 데이터(문서)가 분리돼 있습니다 상품 목록은 PostgreSQL에, 설명서는 PDF에 있는데, 둘을 함께 검색하려면 직접 코드를 짜야 합니다.
-
LLM으로 데이터를 전처리하면 돈이 너무 듭니다 문서 10만 개를 인덱싱할 때마다 GPT-4를 호출하면... 지갑이 울어요.
- 하이브리드 검색: 키워드(BM25) + 의미(임베딩) + 그래프 구조를 모두 씁니다.
- 멀티턴 에이전트: LLM이 도구를 여러 번 호출하면서 답을 찾아갑니다.
- 정형/비정형 통합: CSV, 문서, DB가 하나의 그래프에 들어갑니다.
- 인덱싱은 LLM 없이: 전처리에 LLM을 안 써서 비용이 거의 0입니다.
데이터를 노드(점) 와 엣지(선) 로 표현한 구조입니다.
예를 들어 쇼핑몰 데이터가 있다고 해 봅시다:
┌────────────┐ ┌────────────┐
│ iPhone 15 │◄────────│ 판매이력 │
│ (상품) │ FK │ #SH0001 │
└─────┬──────┘ └────────────┘
│
│ FK
▼
┌────────────┐
│ 리뷰 │
│ (5점) │
└────────────┘
- 노드: iPhone 15, 판매이력 #SH0001, 리뷰 (각각의 레코드)
- 엣지: "판매이력은 iPhone 15에 대한 것" (외래키 관계)
Synaptic Memory는 당신의 데이터를 이렇게 그래프로 만들어 두고, 검색할 때 연결된 노드들을 함께 고려합니다. "iPhone 판매량이 얼마?"를 물으면 iPhone 노드를 찾은 다음 판매이력 엣지를 따라가서 집계합니다.
당신의 데이터
↓
├─ CSV / JSONL → TableIngester
├─ 텍스트 문서 → DocumentIngester
└─ SQL DB → DbIngester (SQLite/PostgreSQL/MySQL/Oracle/MSSQL)
↓
지식 그래프 (SQLite에 저장)
├─ 문서 그래프: Category → Document → Chunk
└─ 정형 그래프: Table Row → ENTITY 노드 + RELATED 엣지(FK)
자동으로:
- 데이터 형식 감지
- 외래 키 관계 감지 → RELATED 엣지 생성
- M:N 조인 테이블 감지 → 중간 노드 없이 직접 엣지
- FTS 인덱스 + (선택적으로) 벡터 인덱스 구축
라이브 DB라면 CDC 모드 — 매번 풀로드 대신 변경분만 그래프에 반영합니다.
같은 DSN을 mode="cdc"로 호출하면 deterministic 노드 ID와 sync state가
그래프 SQLite 파일에 함께 저장되고, 이후 sync_from_database()는 워터마크
이후 변경된 행만 읽어 ms 단위로 끝냅니다. 자세한 동작은 CONCEPTS의
"CDC: 라이브 데이터베이스 동기화" 섹션을 참고하세요.
graph = await SynapticGraph.from_database(dsn, db="knowledge.db", mode="cdc")
result = await graph.sync_from_database(dsn) # 두 번째 호출부터 증분
print(result.added, result.updated, result.deleted)3세대 GraphRAG 파이프라인:
사용자 쿼리
↓
1. 쿼리 분석: 카테고리/엔티티/키워드 anchor 추출
↓
2. FTS 시드 (BM25 + Kiwi 형태소 분석)
↓
3. 벡터 시드 (usearch HNSW, 선택)
↓
4. Vector PRF: top-3 결과 임베딩 평균으로 2차 검색
↓
5. PPR (PersonalizedPageRank): 그래프 엣지로 2-hop 전파
↓
6. GraphExpander: 1-hop 이웃 (카테고리 형제, 청크 연속, FK 관련)
↓
7. HybridReranker: lexical + semantic + graph + structural 점수 융합
↓
8. Cross-encoder reranker (선택, bge-reranker-v2-m3)
↓
9. EvidenceAggregator: MMR 다양성 + 문서당 cap
↓
결과
LLM이 단일 검색으로 답 못 하면 여러 도구를 조합합니다:
쿼리: "5점 리뷰 가장 많이 받은 상품의 가격은?"
↓
Turn 1: aggregate_nodes(
table="reviews",
group_by="product_id",
metric="count",
where_property="score",
where_op="==",
where_value="5"
)
→ G00857 (11건)
Turn 2: get_document("products:G00857")
→ Flour - Masa De Harina Mexican, 5,000원
2턴 만에 답을 찾습니다. 기존 RAG는 이런 질문을 풀 수 없습니다.
전통적 검색 시스템은 쿼리 파싱, 의도 분류, 재작성 같은 걸 코드로 합니다. Synaptic Memory는 다릅니다:
- 코드: 그래프 구축, 검색 인덱스, 도구 제공만 담당
- LLM: "어떤 도구를 어떤 순서로 쓸지" 직접 판단
왜? 자연어 판단은 LLM이 훨씬 잘하기 때문입니다. 코드로 분류기를 짜면 새 도메인에 대응할 때마다 수정해야 하지만, LLM은 프롬프트만 바꾸면 됩니다.
임베딩 모델·리랭커를 라이브러리에 심지 않습니다. 대신 프로토콜을 정의해 두고, 사용자가 원하는 걸 주입하게 합니다:
graph = await SynapticGraph.from_data(
"./data/",
embed_url="http://localhost:11434/v1", # Ollama
embed_model="qwen3-embedding:4b",
)장점:
- torch 의존성 0: 설치 용량 최소
- 모델 교체 자유: OpenAI, Ollama, TEI, llama.cpp 등 OpenAI 호환이면 뭐든
- 비용 제어: 사용자가 직접 선택
1세대 GraphRAG (Microsoft)는 인덱싱 때 LLM으로 엔티티·관계를 추출해서 10만 토큰당 $수십 수준입니다. Synaptic Memory는:
- 엔티티는 FTS + 빈도 기반으로 추출
- 관계는 외래 키, 카테고리, 청크 순서로 자동 구축
- 임베딩만 선택적으로 사용 (그것도 BYO)
문서 1만 개 인덱싱에 API 호출 0회 가능합니다.
from synaptic import SynapticGraph
graph = await SynapticGraph.from_data("./data/") # 파일 (CSV/JSONL/PDF/DOCX/...)
graph = await SynapticGraph.from_database("postgres://...") # DB (한 번만 로드)
graph = await SynapticGraph.from_database("postgres://...", # 라이브 DB CDC
db="knowledge.db", mode="cdc")
result = await graph.sync_from_database("postgres://...") # 두 번째부터 증분
graph = await SynapticGraph.from_chunks(my_chunks) # 직접 청킹한 결과PDF/DOCX/PPTX/XLSX/HWP 같은 오피스 파일은 선택 패키지
xgen-doc2chunk로 처리합니다.pip install synaptic-memory[docs]로 활성화하거나, 자체 파서로 청크를 만들어from_chunks()에 넘겨도 됩니다.
| 분류 | 도구 | 용도 |
|---|---|---|
| 텍스트 검색 | deep_search |
검색→확장→문서읽기 한 번에 (추천) |
knowledge_search |
기본 시맨틱 검색 (v0.14.2부터 EvidenceSearch 라우트) | |
compare_search |
복합 쿼리 자동 분해 | |
| 그래프 탐색 | expand |
노드의 1-hop 이웃 |
follow |
특정 엣지 타입만 순회 | |
get_document |
문서 전문 + 관련 청크 | |
| 정형 데이터 | filter_nodes |
SQL WHERE (total/showing 반환) |
aggregate_nodes |
GROUP BY + COUNT/SUM/AVG + WHERE 사전 필터 | |
join_related |
FK 기반 조인 (그래프 엣지 순회) | |
| 인제스트 / CDC (v0.14.0+) | knowledge_add_document |
자동 청킹 + phrase hub 링크 |
knowledge_add_table |
컬럼/행 → ENTITY 노드 + FK 엣지 | |
knowledge_add_chunks |
사전 청킹된 결과 (BYO chunker) | |
knowledge_ingest_path |
로컬 CSV/JSONL/TXT 파일 | |
knowledge_remove |
단건 삭제 (엣지 cascade) | |
knowledge_sync_from_database |
라이브 DB CDC 증분 동기화 | |
knowledge_backfill |
기존 그래프 embedding/phrase hub 복구 (v0.14.4+) | |
| 네비게이션 | list_categories |
카테고리 목록 |
count |
종류/카테고리별 카운트 | |
search_exact |
ID/코드 정확 매칭 |
| 백엔드 | 벡터 검색 | 규모 | 추천 상황 |
|---|---|---|---|
MemoryBackend |
cosine | ~10K | 테스트/프로토타입 |
SqliteGraphBackend |
usearch HNSW | ~100K | 기본 권장 |
KuzuBackend |
HNSW | ~1천만 | 대규모 그래프 |
PostgreSQLBackend |
pgvector | ~100만 | 프로덕션 |
CompositeBackend |
Qdrant | 무제한 | 스케일아웃 |
v0.17.1 재측정. Corpus snapshot hash + 코드 버전은
eval/baselines/qa_latest.json의_meta블록에 인라인. 상세 표(14 벤치 FTS vs Full pipeline + 멀티턴 agent) 는 COMPARISON.md §4 참조.
bge-m3 embedder + bge-reranker-v2-m3 (cuda:0, FP16) 기준:
| 데이터셋 | 유형 | MRR | vs FTS-only |
|---|---|---|---|
| KRRA Easy (20q) | 문서 | 0.975 | +0.008 |
| X2BEE Easy (20q) | 정형 | 1.000 | 0 |
| HotPotQA-24 | 영어 multi-hop | 0.979 | +0.104 |
| Allganize RAG-ko (200q) | 문서 | 0.983 | +0.036 |
| Allganize RAG-Eval (300q) | 문서 | 0.955 | +0.044 |
| PublicHealthQA (77q) | 의료 문서 | 0.748 | +0.201 |
| AutoRAG (720q) | retrieval | 0.806 | −0.100 ⚠ |
14 벤치 평균 FTS 0.615 → Full 0.647 (+5.2%). v0.17.1 에서 처음으로 Full pipeline 평균이 FTS-only 평균을 상회.
graph.chat() (v0.18-alpha 공개 API) 로 실측:
| 데이터셋 | 결과 | v0.13 baseline (GPT-4o-mini) |
|---|---|---|
| X2BEE Hard | 19/19 (100%) | 17/19 (89%) |
| assort Hard | 30/33 (91%) | 13/15 (87%) |
| assort Conv | 22/24 (92%) | 20/24 (83%) |
| X2BEE Conv | 25/27 (93%) | 22/27 (81%) |
| KRRA Hard | 30/39 (77%) | 11/15 (73%) |
| KRRA Conv | 14/30 (47%) ⚠ | 21/30 (70%) |
| 평균 | 140/172 = 81.4% |
정형 데이터 질의(필터/집계/FK 조인)가 그래프 기반 도구로 end-to-end 동작. 6개 벤치 중 5개에서 GPT-4o-mini baseline 초과 — 자체 서빙 모델만으로 상업 API 이상 품질. KRRA Conv 만 회귀 (Qwen 한국어 conversational 약점, v0.18 조사 트랙).
- MuSiQue-Ans (영어 shortcut-heavy multi-hop): R@5 0.453 vs HippoRAG2 publish 0.747 (−0.294). OpenIE triple 기반 KG 로의 아키텍처 교체 검토 중.
→ TUTORIAL.md: 30분 안에 따라할 수 있는 단계별 튜토리얼
→ CONCEPTS.md: 3세대 GraphRAG, 검색 파이프라인, 그래프 구조 심화
→ ARCHITECTURE.md: Hebbian Learning, Memory Consolidation 등 초기 설계
→ COMPARISON.md: 다른 GraphRAG 라이브러리와의 비교
→ ROADMAP.md: 향후 로드맵
→ ../README.md: 2줄 설치, API 예제
synaptic-mcp --db my_graph.db --embed-url http://localhost:11434/v1Claude Desktop/Code에서 36개 도구를 쓸 수 있게 됩니다.
Q. RAG와 뭐가 달라요? A. RAG는 보통 "임베딩으로 top-k 검색 → LLM에 주입" 한 단계입니다. Synaptic Memory는 그래프 구조 + 멀티턴 탐색 + 구조적 쿼리까지 지원합니다.
Q. 벡터 DB 없이 되나요? A. 네. 기본은 SQLite FTS5 + usearch (HNSW) 만으로 10만 노드까지 충분합니다. 벡터 없이 BM25만 써도 돌아갑니다.
Q. 한국어는 지원되나요? A. Kiwi 형태소 분석기 내장으로 한국어 FTS 품질이 매우 높습니다. Allganize RAG-Eval 300q MRR 0.955, PublicHealthQA 77q MRR 0.748 등 한국어 코퍼스에서 강합니다.
Q. 그래프 DB가 필요한가요? A. 아니요. SQLite로 충분합니다. 엣지 테이블을 자체적으로 관리합니다. Kuzu (임베디드 그래프 DB)도 선택적으로 지원합니다.
Q. 비용이 얼마나 드나요? A. 인덱싱 비용 0원 (LLM 미사용). 검색 시 임베딩 API 호출 (옵션), 에이전트 쿼리 시 LLM 토큰 (직접 호출). Ollama로 로컬 모델을 쓰면 완전 무료.
Q. 데이터가 업데이트되면?
A. mode="cdc"로 인제스트하면 두 번째 호출부터 변경분만 동기화됩니다.
X2BEE 프로덕션 PostgreSQL (19,843행) 검증 결과: full reload 35초 vs CDC
incremental sync 6초 (~6× 빠름). 검색 품질은 동일 (regression test로
잠금). SQLite / PostgreSQL / MySQL 지원.
Q. CDC를 켜면 검색 결과가 달라지나요?
A. 아니요. CDC는 노드 ID 생성 방식만 바꿉니다 (random UUID → deterministic
hash). 검색 알고리즘은 그대로입니다. tests/test_cdc_search_regression.py가
같은 데이터를 mode="full"과 mode="cdc"로 빌드해서 top-k가 일치하는지
매번 확인합니다.
Q. 프로덕션에서 쓰기 안전한가요?
A. 현재 PyPI 최신은 v0.17.2 (Apache-2.0 라이선스 전환 + agent_loop
ID-extraction fix). v0.18-alpha 는 graph.chat() agent-loop 공개.
942개 단위 테스트 통과, 프로덕션 PostgreSQL (X2BEE) CDC 검증 완료.
단일 저자 오픈소스이므로 대규모 운영 사례는 제한적이며, 중요 데이터는
백업을 권장합니다.
- CONCEPTS.md — 3세대 GraphRAG·검색 파이프라인 심화
- TUTORIAL.md — 단계별 실습
- ARCHITECTURE.md — 원래 설계 문서 (신경망 영감)
- COMPARISON.md — GraphRAG / LightRAG / LazyGraphRAG 비교
- GitHub Issues — 버그 리포트 / 피드백
- CHANGELOG.md — 버전별 변경 이력
Apache-2.0 License · 작성자: Son Seongjun