39 KiB
Neo4j GraphRAG Python 분석 및 기능명세
분석 대상: C:\Users\lasta\MyProject\AI\참고\neo4j-graphrag-python-main
분석일: 2026-05-13
프로젝트 버전: neo4j-graphrag 1.16.0
라이선스: Apache License 2.0 계열(LICENSE.APACHE2.txt, LICENSE.txt)
목표: 범용 온톨로지 구축 플랫폼의 기본 소스로 거의 변형 없이 재사용 가능한 기능과, 플랫폼 레이어에서 감싸야 할 기능을 식별한다.
1. 총평
neo4j-graphrag-python은 Neo4j가 공식 제공하는 GraphRAG Python 패키지이며, 단순 질의응답 RAG보다 “비정형 문서 → 스키마/온톨로지 후보 → 엔티티/관계 추출 → 그래프 정제 → Neo4j 저장 → 검색/질의응답” 흐름에 더 강하다.
우리 프로젝트가 지향하는 “범용 온톨로지 구축 플랫폼” 관점에서는 다음 모듈이 가장 중요하다.
| 영역 | 재사용 판단 | 핵심 소스 |
|---|---|---|
| KG 구축 파이프라인 | 높음 | experimental/pipeline/kg_builder.py, config/template_pipeline/simple_kg_builder.py |
| 컴포넌트형 파이프라인 엔진 | 높음 | experimental/pipeline/pipeline.py, component.py, orchestrator.py |
| 온톨로지/그래프 스키마 모델 | 매우 높음 | experimental/components/schema.py |
| 스키마 자동 추출 | 높음 | experimental/components/schema.py, graph_schema_extraction.py |
| 엔티티/관계 추출 | 높음 | experimental/components/entity_relation_extractor.py |
| 그래프 정제/스키마 준수 | 높음 | experimental/components/graph_pruning.py |
| Neo4j 저장 | 높음 | experimental/components/kg_writer.py, neo4j_queries.py |
| 엔티티 중복 해소 | 중간~높음 | experimental/components/resolver.py |
| 검색/RAG | 높음 | retrievers/*, generation/graphrag.py |
| LLM/임베딩 어댑터 | 높음 | llm/*, embeddings/* |
| 문서 로더 | 중간 | experimental/components/data_loader.py |
| 외부 벡터DB 연동 | 선택 | retrievers/external/* |
단, experimental 네임스페이스의 KG 구축 기능은 공식 문서상 API 변경 가능성이 있는 실험 기능이다. “그대로 복사”보다는 패키지 의존성으로 고정 버전을 사용하고, 우리 플랫폼의 안정 API를 별도 래퍼로 제공하는 방식이 안전하다.
2. 프로젝트 구조
src/neo4j_graphrag/
embeddings/ # OpenAI, Azure OpenAI, Ollama, VertexAI, Cohere, Bedrock, Mistral, SentenceTransformer 임베딩
llm/ # OpenAI, Azure, Ollama, VertexAI, Anthropic, Cohere, Bedrock, Mistral LLM
retrievers/ # Vector, Hybrid, Text2Cypher, Tools, Vector+Cypher 검색기
generation/ # GraphRAG, 프롬프트 템플릿, RAG 결과 타입
experimental/
components/ # KG 구축 컴포넌트: loader, splitter, schema, extractor, pruner, writer, resolver
pipeline/ # 비동기 DAG 파이프라인 엔진, 설정 파일 실행기
indexes.py # Neo4j 벡터/풀텍스트 인덱스 생성, 벡터 upsert
schema.py # 기존 Neo4j DB 스키마 조회/포맷팅/Text2Cypher용 스키마 생성
filters.py # 검색 필터 DSL → Cypher 변환
message_history.py # InMemory/Neo4j 대화 기록
tool.py # LLM tool schema 추상화
테스트 구조는 tests/unit, tests/e2e가 분리되어 있고, Neo4j/Weaviate/Pinecone/Qdrant 연동 E2E가 있다. 핵심 동작은 테스트가 비교적 넓게 잡혀 있어 베이스 소스로 신뢰도가 높다.
3. 의존성 및 실행 조건
3.1 기본 요구사항
- Python:
>=3.10,<3.15 - Neo4j Python driver:
neo4j>=5.17,<7 - Pydantic v2
pypdf,fsspec,json-repair,pyyaml,numpy,scipy,tenacity
3.2 Neo4j 요구사항
- Neo4j
>=5.18.1 - Neo4j Aura
>=5.18.0 - Neo4j
2026.01+:SEARCHclause 기반 in-index filtering 지원 - KG writer 및 entity resolver 일부 기능은 APOC 필요
- README의 KG construction 예시는 APOC core 설치를 요구한다.
SinglePropertyExactMatchResolver, similarity resolver는apoc.refactor.mergeNodes를 사용한다.
3.3 선택 의존성
| Extra | 용도 |
|---|---|
openai |
OpenAI/Azure OpenAI LLM 및 임베딩 |
ollama |
로컬 Ollama LLM/임베딩 |
google |
Vertex AI |
cohere |
Cohere |
anthropic |
Anthropic |
mistralai |
Mistral AI |
bedrock |
AWS Bedrock |
sentence-transformers |
로컬 임베딩 |
experimental |
KG 구축 파이프라인, LlamaIndex/LangChain splitter, Parquet |
nlp |
spaCy resolver. Python 3.14에서는 미지원 |
fuzzy-matching |
RapidFuzz 기반 중복 해소 |
weaviate, pinecone, qdrant |
외부 벡터DB retriever |
4. 핵심 아키텍처
4.1 전체 흐름
flowchart LR
A["문서/텍스트 입력"] --> B["DataLoader"]
B --> C["TextSplitter"]
C --> D["TextChunkEmbedder"]
C --> E["SchemaBuilder 또는 SchemaFromTextExtractor"]
E --> F["LLMEntityRelationExtractor"]
C --> F
F --> G["GraphPruning"]
G --> H["KGWriter: Neo4jWriter 또는 ParquetWriter"]
H --> I["EntityResolver"]
I --> J["Neo4j Knowledge Graph"]
J --> K["Retriever: Vector/Hybrid/Text2Cypher"]
K --> L["GraphRAG"]
4.2 설계 철학
이 프로젝트는 “하나의 거대한 KG builder”가 아니라 비동기 컴포넌트 DAG를 조립하는 방식이다.
- 각 컴포넌트는
Component를 상속한다. - 컴포넌트의
run은 PydanticDataModel을 반환한다. Pipeline.connect()로 이전 컴포넌트 출력 필드를 다음 컴포넌트 입력으로 매핑한다.PipelineRunner는 JSON/YAML 설정 파일로 파이프라인을 복원하고 실행한다.SimpleKGPipeline은 대표적인 템플릿 파이프라인이다.
우리 플랫폼에서는 이 구조를 그대로 “워크플로우 엔진”으로 활용할 수 있다. 별도 GUI나 API 서버에서는 SimpleKGPipeline 설정을 생성하고 실행 결과를 추적하는 레이어를 만들면 된다.
5. 데이터 모델 명세
5.1 문서 모델
DocumentInfo
| 필드 | 타입 | 설명 |
|---|---|---|
path |
str |
파일 경로 또는 inline text 식별자 |
metadata |
dict[str,str] | None |
문서 메타데이터. Document 노드 property로 저장 |
uid |
str |
UUID 기본 생성. Document id |
document_type |
pdf, markdown, inline_text |
문서 유형 |
LoadedDocument
| 필드 | 타입 | 설명 |
|---|---|---|
text |
str |
추출된 원문 |
document_info |
DocumentInfo |
문서 식별/메타데이터 |
5.2 텍스트 청크 모델
TextChunk
| 필드 | 타입 | 설명 |
|---|---|---|
text |
str |
청크 텍스트 |
index |
int |
원문 내 순서 |
metadata |
dict[str,Any] | None |
청크 메타데이터. embedding이 있으면 별도 embedding property로 분리 |
uid |
str |
UUID 기본 생성 |
TextChunks
| 필드 | 타입 | 설명 |
|---|---|---|
chunks |
list[TextChunk] |
청크 목록 |
5.3 그래프 모델
Neo4jNode
| 필드 | 타입 | 설명 |
|---|---|---|
id |
str |
내부 관계 연결용 id |
label |
str |
Neo4j label |
properties |
dict[str, PropertyValue] |
Neo4j property |
embedding_properties |
dict[str, list[float]] |
벡터 property |
Neo4jRelationship
| 필드 | 타입 | 설명 |
|---|---|---|
start_node_id |
str |
시작 노드 id |
end_node_id |
str |
끝 노드 id |
type |
str |
relationship type |
properties |
dict[str, PropertyValue] |
relationship property |
embedding_properties |
dict[str, list[float]] |
relationship vector property |
Neo4jGraph
| 필드 | 타입 | 설명 |
|---|---|---|
nodes |
list[Neo4jNode] |
노드 목록 |
relationships |
list[Neo4jRelationship] |
관계 목록 |
5.4 Lexical graph 설정
LexicalGraphConfig 기본값:
| 설정 | 기본값 | 의미 |
|---|---|---|
document_node_label |
Document |
문서 노드 label |
chunk_node_label |
Chunk |
청크 노드 label |
chunk_to_document_relationship_type |
FROM_DOCUMENT |
Chunk → Document |
next_chunk_relationship_type |
NEXT_CHUNK |
Chunk → 다음 Chunk |
node_to_chunk_relationship_type |
FROM_CHUNK |
Entity → Chunk |
chunk_id_property |
id |
chunk id property |
chunk_index_property |
index |
chunk 순서 property |
chunk_text_property |
text |
chunk 본문 property |
chunk_embedding_property |
embedding |
chunk embedding property |
온톨로지 플랫폼에서는 이 설정을 테넌트/프로젝트 단위로 고정하거나, 사용자가 “문서 그래프 모델”을 커스터마이즈할 수 있게 노출하면 된다.
6. 온톨로지/스키마 모델 명세
핵심 파일: src/neo4j_graphrag/experimental/components/schema.py
6.1 PropertyType
| 필드 | 타입 | 설명 |
|---|---|---|
name |
str |
property 이름 |
type |
Neo4j property type literal | STRING, INTEGER, FLOAT, BOOLEAN, DATE, LOCAL_DATETIME, POINT, LIST 등 |
description |
str |
LLM 추출 가이드 |
required |
bool |
deprecated. 존재 제약은 ConstraintType(EXISTENCE) 권장 |
6.2 NodeType
| 필드 | 타입 | 설명 |
|---|---|---|
label |
str |
노드 label |
description |
str |
의미 설명 |
properties |
list[PropertyType] |
허용 property. 최소 1개 |
additional_properties |
bool |
스키마 외 property 허용 여부 |
특이 동작:
- 문자열
"Person"으로 입력하면{label:"Person", properties:[{name:"name", type:"STRING"}], additional_properties:true}로 자동 변환된다. - label이
__로 시작하거나 끝나면 내부 예약 label로 보고 거부한다.
6.3 RelationshipType
| 필드 | 타입 | 설명 |
|---|---|---|
label |
str |
relationship type |
description |
str |
의미 설명 |
properties |
list[PropertyType] |
관계 property |
additional_properties |
bool |
스키마 외 property 허용 여부 |
문자열 "WORKS_AT" 입력도 허용된다.
6.4 ConstraintType
지원 제약:
| 타입 | 의미 |
|---|---|
UNIQUENESS |
노드 property unique. 복합 가능 |
EXISTENCE |
노드/관계 property 필수. 단일 property |
KEY |
Neo4j node key/relationship key. 필수 + unique. 복합 가능 |
범용 온톨로지 플랫폼에서는 이 모델을 “온톨로지 제약조건”의 기본 표현으로 재사용할 수 있다. 다만 OWL/RDFS의 class hierarchy, domain/range, cardinality, inverse property, equivalent class 같은 의미론적 제약은 별도 확장이 필요하다.
6.5 Pattern
Pattern은 (source node label, relationship label, target node label) 구조를 표현한다. 예:
("Person", "WORKS_AT", "Organization")
이것은 ontology의 relationship domain/range 후보로 직접 매핑 가능하다.
6.6 GraphSchema
GraphSchema는 다음 정보를 묶는다.
node_typesrelationship_typespatternsconstraintsadditional_node_typesadditional_relationship_typesadditional_patterns
스키마가 제공되면 LLM 추출 프롬프트의 grounding 정보가 되고, 이후 GraphPruning이 이 스키마에 맞지 않는 노드/관계/property를 제거한다.
7. KG 구축 기능명세
7.1 SimpleKGPipeline
파일: experimental/pipeline/kg_builder.py
SimpleKGPipeline은 비정형 텍스트나 PDF/Markdown 파일에서 KG를 만들기 위한 고수준 API이다.
생성자 입력
| 파라미터 | 필수 | 설명 |
|---|---|---|
llm |
예 | 엔티티/관계 추출용 LLM |
driver |
예 | Neo4j driver |
embedder |
예 | chunk embedding 생성기 |
schema |
아니오 | GraphSchema, dict, "FREE", "EXTRACTED", None |
from_file |
아니오 | True: file path 입력. False: text 입력 |
text_splitter |
아니오 | 기본 FixedSizeSplitter |
file_loader |
아니오 | 기본 extension 기반 PDF/Markdown loader |
kg_writer |
아니오 | 기본 Neo4jWriter |
on_error |
아니오 | "IGNORE" 또는 "RAISE" |
perform_entity_resolution |
아니오 | 기본 True |
prompt_template |
아니오 | 추출 프롬프트 템플릿 |
lexical_graph_config |
아니오 | Document/Chunk 그래프 label/relationship 커스터마이즈 |
neo4j_database |
아니오 | Neo4j database 이름 |
실행 입력
run_async(file_path=None, text=None, document_metadata=None)
| 입력 | 조건 | 설명 |
|---|---|---|
file_path |
from_file=True일 때 필요 |
PDF/Markdown 파일 경로 |
text |
from_file=False일 때 필요 |
직접 입력 텍스트 |
document_metadata |
선택 | Document node property로 저장 |
스키마 모드
| 모드 | 설정 | 동작 |
|---|---|---|
| 자동 추출 | schema=None 또는 "EXTRACTED" |
입력 텍스트에서 LLM으로 스키마를 한 번 추출한 뒤 전체 chunk 추출에 사용 |
| 자유 추출 | schema="FREE" 또는 empty schema |
스키마 없이 엔티티/관계 추출 |
| 고정 스키마 | dict 또는 GraphSchema |
사용자가 정의한 온톨로지 구조에 맞춰 추출 |
범용 온톨로지 플랫폼에서는 세 모드를 다음 UI/API로 제공하는 것이 적합하다.
- “자동 온톨로지 초안 생성”
- “스키마 없이 자유 그래프 생성”
- “승인된 온톨로지에 맞춰 인스턴스 추출”
7.2 DataLoader
파일: experimental/components/data_loader.py
제공 구현:
PdfLoader: PDF 텍스트 추출MarkdownLoader: Markdown 텍스트 로드- 내부 extension 기반 loader:
.pdf,.md,.markdown
기능명세:
| 기능 | 입력 | 출력 | 비고 |
|---|---|---|---|
| PDF 로드 | filepath, metadata |
LoadedDocument |
pypdf 사용 |
| Markdown 로드 | filepath, metadata |
LoadedDocument |
plain text로 처리 |
| 문서 메타데이터 생성 | path, metadata | DocumentInfo |
Document node에 연결 |
확장 필요:
- HTML, DOCX, PPTX, XLSX, CSV, 웹 크롤링 결과, API 문서 등 우리 프로젝트 입력 소스에 맞춘 loader 추가
- 이미 우리 프로젝트에 crawler가 있으므로 crawler output을
LoadedDocument로 변환하는 adapter 필요
7.3 TextSplitter
제공 구현:
FixedSizeSplitterLangChainTextSplitterAdapterLlamaIndexTextSplitterAdapter
기능명세:
| 기능 | 입력 | 출력 | 비고 |
|---|---|---|---|
| 고정 길이 chunking | text, chunk_size, overlap | TextChunks |
approximate=True이면 단어 중간 절단 회피 |
| LangChain splitter 감싸기 | LangChain splitter | TextChunks |
기존 생태계 활용 |
| LlamaIndex splitter 감싸기 | LlamaIndex splitter | TextChunks |
기존 생태계 활용 |
온톨로지 플랫폼에서는 도메인별 chunking 전략이 중요하다.
- 법령/규정: 조문 단위
- 논문: section/paragraph 단위
- 사내 문서: heading hierarchy 유지
- 웹 문서: URL, heading, DOM 경로 메타데이터 유지
따라서 기본 splitter는 재사용하되, “구조 보존 splitter”를 별도 컴포넌트로 추가하는 것이 좋다.
7.4 TextChunkEmbedder
파일: experimental/components/embedder.py
기능:
TextChunks의 각 chunk text를 embedder로 임베딩한다.- 임베딩을 chunk metadata의
embedding에 저장한다. LexicalGraphBuilder가embeddingmetadata를 chunk node의embedding_properties로 분리한다.
재사용 판단: 높음. 단, 대량 문서 처리에서는 batch embedding, rate limit, retry, cache가 플랫폼 레이어에 필요하다.
7.5 SchemaBuilder / SchemaFromTextExtractor
파일: experimental/components/schema.py, graph_schema_extraction.py
기능:
- 수동 schema dict 또는
GraphSchema를 검증한다. - 텍스트에서 자동으로 node type, relationship type, pattern, constraint 후보를 추출한다.
- OpenAI/VertexAI 등 structured output 지원 LLM에서는 JSON schema 기반 구조화 출력을 사용한다.
- 기존 Neo4j graph에서 schema를 읽어 schema 후보로 만들 수 있다.
기능명세:
| 기능 | 입력 | 출력 |
|---|---|---|
| 수동 스키마 검증 | node types, relationship types, patterns, constraints | GraphSchema |
| 자동 스키마 추출 | text/chunks, LLM, prompt | GraphSchema |
| 기존 graph 스키마 추출 | Neo4j driver | GraphSchema 후보 |
| schema visualization | GraphSchema |
시각화 graph |
우리 플랫폼 확장 포인트:
- 스키마 버전 관리
- 자동 추출 schema의 승인/반려 workflow
- label/property 표준화 규칙
- 한국어 label/영문 label alias 관리
- 온톨로지 class hierarchy 확장
7.6 LLMEntityRelationExtractor
파일: experimental/components/entity_relation_extractor.py
기능:
- 각 chunk에 대해 LLM으로
Neo4jGraph(nodes, relationships)를 추출한다. - chunk별 node id에 chunk UUID prefix를 붙여 충돌을 방지한다.
create_lexical_graph=True이면 Document/Chunk graph와 Entity → Chunk provenance 관계를 함께 생성한다.- JSON repair를 사용해 깨진 JSON 응답을 복구한다.
on_error=IGNORE이면 실패 chunk는 빈 graph로 처리한다.on_error=RAISE이면 LLM/JSON 오류를 예외로 올린다.max_concurrency로 LLM 호출 동시성을 제한한다.- structured output 지원 LLM이면
Neo4jGraphPydantic 모델을 response schema로 사용할 수 있다.
기능명세:
| 기능 | 입력 | 출력 | 중요 옵션 |
|---|---|---|---|
| chunk별 엔티티/관계 추출 | TextChunks, GraphSchema, examples |
Neo4jGraph |
max_concurrency |
| lexical graph 생성 | chunks, document_info | Document/Chunk 포함 graph | create_lexical_graph |
| 출처 연결 | extracted entity, chunk | FROM_CHUNK 관계 |
provenance 핵심 |
| 오류 처리 | LLM JSON 오류 | 빈 graph 또는 예외 | on_error |
온톨로지 플랫폼에서 매우 중요한 특성:
- 모든 추출 엔티티가 chunk와 연결되므로 근거 추적이 가능하다.
- 추출 결과를 바로 DB에 쓰기 전에
GraphPruning으로 스키마 위반을 제거할 수 있다. - 추출 결과를 사용자가 승인하는 “검수 큐”를 만들려면
Neo4jWriter이전에 graph를 저장/표시하는 컴포넌트를 끼우면 된다.
7.7 GraphPruning
파일: experimental/components/graph_pruning.py
기능:
- 추출 graph가
GraphSchema를 준수하도록 노드/관계/property를 제거한다. - lexical graph(Document/Chunk)는 별도로 보존한다.
- pruning 통계를 반환한다.
제거 사유:
| 사유 | 의미 |
|---|---|
NOT_IN_SCHEMA |
스키마에 없는 node/relationship/property |
MISSING_REQUIRED_PROPERTY |
필수 property 누락 |
NO_PROPERTY_LEFT |
유효 property가 하나도 없음 |
INVALID_START_OR_END_NODE |
관계의 양 끝 노드가 유효하지 않음 |
INVALID_PATTERN |
허용 pattern이 아님 |
MISSING_LABEL |
label 없음 |
기능명세:
| 기능 | 입력 | 출력 |
|---|---|---|
| 노드 정제 | graph, schema | 유효 node 목록 |
| 관계 정제 | graph, schema, valid nodes | 유효 relationship 목록 |
| property 정제 | node/relationship properties | 스키마에 맞는 property만 유지 |
| 통계 생성 | pruning 결과 | PruningStats |
우리 플랫폼에서는 pruning 결과를 “자동 폐기”만 하지 말고, 사용자에게 “추출됐지만 온톨로지에서 거부된 후보”로 보여주는 기능이 필요하다. 이것이 온톨로지 개선 루프의 핵심 데이터가 된다.
7.8 LexicalGraphBuilder
파일: experimental/components/lexical_graph.py
생성 그래프:
flowchart LR
C1["Chunk 0"] -->|FROM_DOCUMENT| D["Document"]
C2["Chunk 1"] -->|FROM_DOCUMENT| D
C1 -->|NEXT_CHUNK| C2
E1["Entity"] -->|FROM_CHUNK| C1
기능명세:
| 기능 | 생성물 | 설명 |
|---|---|---|
| Document node | Document |
path, createdAt, metadata, document_type |
| Chunk node | Chunk |
text, index, metadata, embedding |
| Chunk → Document | FROM_DOCUMENT |
문서 소속 |
| Chunk → Chunk | NEXT_CHUNK |
원문 순서 |
| Entity → Chunk | FROM_CHUNK |
추출 근거 |
온톨로지 플랫폼에서는 이 provenance 구조를 거의 그대로 사용하면 된다. 다만 문서 소스가 crawler/web이면 Document node에 url, crawl_job_id, source_type, retrieved_at, content_hash 같은 property를 추가하는 것이 좋다.
7.9 KGWriter
파일: experimental/components/kg_writer.py
제공 구현:
Neo4jWriterParquetWriter
Neo4jWriter
기능:
- node batch upsert
- relationship batch upsert
- non-lexical node에
__Entity__label 추가 - 임시 내부 id index 생성
- write 이후 임시 label/property 정리
- Neo4j 버전에 따라 dynamic label 및 variable scope clause 지원 여부 분기
중요 파라미터:
| 파라미터 | 기본값 | 설명 |
|---|---|---|
driver |
필수 | Neo4j driver |
neo4j_database |
None |
DB 이름 |
batch_size |
1000 |
batch write 크기 |
clean_db |
True |
writer 내부 임시 데이터 정리 |
출력:
{
"status": "SUCCESS",
"metadata": {
"statistics": {
"node_count": 0,
"relationship_count": 0,
"nodes_per_label": {},
"rel_per_type": {},
"input_files_count": 0,
"input_files_total_size_bytes": 0
},
"files": []
}
}
ParquetWriter
기능:
- node label별 Parquet 파일 생성
(head_label, relationship_type, tail_label)별 relationship Parquet 파일 생성- schema constraints를 metadata로 반영
- Neo4j bulk import 또는 데이터 레이크 연계를 위한 중간 산출물 생성
재사용 판단:
- 실시간/소규모 구축:
Neo4jWriter - 대량 batch/검수/승인 workflow:
ParquetWriter또는 custom writer 권장
7.10 EntityResolver
파일: experimental/components/resolver.py
제공 구현:
| Resolver | 방식 | 의존성 |
|---|---|---|
SinglePropertyExactMatchResolver |
같은 label + 같은 property 값이면 merge | APOC |
SpaCySemanticMatchResolver |
property text embedding cosine similarity | spaCy, numpy, APOC |
FuzzyMatchResolver |
RapidFuzz string similarity | rapidfuzz, APOC |
기능명세:
| 기능 | 설명 |
|---|---|
| 대상 선택 | 기본 MATCH (entity:__Entity__), filter_query로 scope 축소 |
| label별 그룹화 | __Entity__, __KGBuilder__ 제외 |
| property 비교 | 기본 name, 다중 property 가능 |
| merge | apoc.refactor.mergeNodes(..., {properties:'discard', mergeRels:true}) |
| 통계 | resolve 대상 수, 생성/merge 결과 수 |
주의:
- 기본 merge 정책은 property 충돌 시 discard이다.
- 온톨로지 플랫폼에서는 자동 merge 전 “후보 그룹 검수” 기능이 필요하다.
- 한국어/영문 alias, 약어, 조직명 변형 처리에는 custom resolver가 필요하다.
8. RAG 및 검색 기능명세
8.1 VectorRetriever
파일: retrievers/vector.py
기능:
- Neo4j vector index 기반 ANN 검색
query_text입력 시 embedder로 vector 생성query_vector직접 입력 가능top_k,effective_search_ratio, metadatafilters지원return_properties또는result_formatter로 반환 형식 커스터마이즈- Neo4j 2026.01+에서는
SEARCHclause와 filterable properties 활용 가능
8.2 VectorCypherRetriever
기능:
- vector 검색 결과를 시작점으로 custom Cypher traversal 수행
- “유사 chunk 검색 후 주변 entity/관계 확장” 패턴에 적합
온톨로지 플랫폼에서 매우 유용한 검색:
- 특정 문장과 유사한 chunk를 찾고, 해당 chunk에서 추출된 entity와 ontology class를 함께 반환
- 사용자의 질의와 관련된 provenance, source document, neighbor graph를 함께 표시
8.3 HybridRetriever / HybridCypherRetriever
기능:
- vector search + fulltext search 결합
- ranker 지원
- Cypher 확장형 retriever 제공
사용처:
- 고유명사/코드/제품명은 fulltext가 강하고, 의미 검색은 vector가 강하다.
- 온톨로지 탐색 UI에서는 hybrid 검색을 기본으로 두는 것이 좋다.
8.4 Text2CypherRetriever
파일: retrievers/text2cypher.py
기능:
- 자연어 질의를 LLM으로 Cypher로 변환
- 기존 Neo4j schema를 자동 조회하거나 수동 schema 입력
- few-shot examples 제공 가능
- 생성 Cypher에서 코드블록 추출, 공백 포함 label/property/type backtick 보정
- read-only query type만 허용하는 안전장치가 있다.
주의:
- 운영 환경에서는 사용자 권한별 schema 제한, allowlist, query timeout, result limit이 필요하다.
- ontology 관리 기능에 직접 연결할 경우 쓰기 쿼리는 별도 승인된 API로만 처리해야 한다.
8.5 ToolsRetriever
기능:
- 여러 tool/retriever를 LLM tool calling 방식으로 선택하게 한다.
- 질의 유형별로 vector/hybrid/text2cypher/custom tool을 라우팅하는 데 적합하다.
8.6 External Retriever
지원:
- Weaviate
- Pinecone
- Qdrant
패턴:
- 외부 vector DB에서 vector 검색
- 검색 결과 id를 Neo4j graph와 join
우리 프로젝트가 Neo4j 중심이면 초기에는 보류 가능하다. 다만 대규모 벡터 검색을 별도 인프라로 분리할 가능성이 있으면 adapter 구조는 참고 가치가 높다.
8.7 GraphRAG
파일: generation/graphrag.py
기능:
- retriever로 context 검색
- prompt template에 query/context/examples 주입
- LLM 호출
- answer 반환
- 옵션으로 retriever context 포함 반환
- message history가 있으면 질의에 대화 요약을 결합
입력:
| 파라미터 | 설명 |
|---|---|
query_text |
사용자 질문 |
message_history |
대화 기록 |
examples |
few-shot 예시 |
retriever_config |
retriever별 옵션. 예: top_k |
return_context |
검색 결과 포함 여부 |
response_fallback |
검색 결과가 없을 때 fallback 답변 |
우리 플랫폼 적용:
- “온톨로지 기반 질의응답”
- “이 entity가 어디서 나왔는가?”
- “이 class와 관련된 문서/근거/관계는?”
- “스키마에 맞지 않아 버려진 후보는?”
9. LLM 및 임베딩 어댑터
9.1 LLM
지원 구현:
OpenAILLM,AzureOpenAILLMOllamaLLMVertexAILLMAnthropicLLMCohereLLMMistralAILLMBedrockLLM
공통 특성:
LLMInterface,LLMInterfaceV2,LLMBase- sync/async invoke
- structured output 일부 지원
- rate limit retry 기본 내장
- max attempts: 3
- min wait: 1s
- max wait: 60s
- multiplier: 2
9.2 임베딩
지원 구현:
OpenAIEmbeddings,AzureOpenAIEmbeddingsOllamaEmbeddingsVertexAIEmbeddingsCohereEmbeddingsMistralAIEmbeddingsBedrockEmbeddingsSentenceTransformerEmbeddings
우리 프로젝트는 provider 독립성이 중요하므로 이 어댑터 계층은 거의 그대로 사용 가능하다. 플랫폼 설정에는 “LLM profile”, “Embedding profile” 개념을 두고, pipeline 실행 시 profile을 주입하는 구조가 좋다.
10. 설정 파일 기반 실행
PipelineRunner.from_config_file(file_path)로 JSON/YAML 파이프라인 실행이 가능하다.
기본 SimpleKGPipeline 설정 예:
version_: 1
template_: SimpleKGPipeline
neo4j_config:
params_:
uri: bolt://localhost:7687
user: neo4j
password:
resolver_: ENV
var_: NEO4J_PASSWORD
llm_config:
class_: OpenAILLM
params_:
model_name: gpt-5
api_key:
resolver_: ENV
var_: OPENAI_API_KEY
model_params:
temperature: 0
max_tokens: 2000
embedder_config:
class_: OpenAIEmbeddings
params_:
model: text-embedding-3-large
schema:
node_types:
- Person
- label: Organization
properties:
- name: name
type: STRING
relationship_types:
- WORKS_AT
patterns:
- ["Person", "WORKS_AT", "Organization"]
from_file: true
perform_entity_resolution: true
on_error: IGNORE
우리 플랫폼에서는 이 설정을 DB에 저장하고, GUI/API에서 생성/수정/버전 관리하도록 만들면 된다.
11. 범용 온톨로지 구축 플랫폼 적용 설계
11.1 그대로 재사용할 1차 기반
| 플랫폼 기능 | 사용할 소스 |
|---|---|
| 문서 → KG 실행 | SimpleKGPipeline |
| 커스텀 워크플로우 | Pipeline, Component |
| 온톨로지 스키마 표현 | GraphSchema, NodeType, RelationshipType, Pattern, ConstraintType |
| 자동 온톨로지 초안 | SchemaFromTextExtractor |
| 엔티티/관계 추출 | LLMEntityRelationExtractor |
| 스키마 정합성 검증 | GraphPruning |
| Neo4j 저장 | Neo4jWriter |
| 출처 그래프 | LexicalGraphBuilder |
| 중복 엔티티 병합 | SinglePropertyExactMatchResolver, FuzzyMatchResolver |
| 검색/QA | VectorRetriever, HybridRetriever, Text2CypherRetriever, GraphRAG |
11.2 플랫폼에서 추가해야 할 레이어
A. 프로젝트/테넌트 관리
- 온톨로지 프로젝트 생성
- 데이터소스 연결
- Neo4j database 또는 namespace 매핑
- LLM/embedding profile 매핑
B. 온톨로지 버전 관리
현재 GraphSchema는 schema 객체일 뿐 버전 관리 기능은 없다.
필요 기능:
- schema draft/published 상태
- version number
- 변경 diff
- migration plan
- label/property rename 이력
- 이전 버전 추출 결과와 새 버전 비교
C. 추출 결과 검수
현재 pipeline은 추출 후 pruning/write까지 자동으로 갈 수 있다.
필요 기능:
- 추출 graph 임시 저장
- node/relationship/property 단위 승인/반려
- pruning된 후보 복원/스키마 반영
- confidence score 또는 LLM rationale 저장
- 근거 chunk 하이라이트
D. 도메인별 document loader
추가 대상:
- crawler output loader
- HTML loader
- DOCX/PPTX/XLSX loader
- CSV/DB table loader
- API response loader
- code/documentation loader
E. Ontology semantics 확장
GraphSchema는 property graph schema에 가깝다. 범용 온톨로지 플랫폼이면 다음 개념이 필요할 수 있다.
| 온톨로지 개념 | 현재 지원 | 확장 필요 |
|---|---|---|
| Class/Entity type | 지원 | class hierarchy 추가 |
| Object property | relationship type으로 지원 | inverse/symmetric/transitive 추가 |
| Data property | property type으로 지원 | domain/range 강화 |
| Domain/Range | pattern으로 부분 지원 | 다중 domain/range, inheritance 반영 |
| Cardinality | 미지원 | min/max/exact cardinality |
| Equivalent class/property | 미지원 | alias/equivalence 모델 |
| Disjoint class | 미지원 | validation rule |
| SKOS concept | 미지원 | concept scheme, broader/narrower |
F. 운영 안정성
- LLM call budget 관리
- chunk/embedding cache
- 재시도/중단/재개
- job progress DB 저장
- 대량 batch queue
- Neo4j transaction timeout 설정
- Text2Cypher query sandbox
11.3 권장 내부 모듈 구조
우리 프로젝트에 통합할 때는 원본 소스를 직접 수정하기보다 다음 형태가 좋다.
crawler_platform/
ontology/
schemas.py # GraphSchema 래퍼, 버전/상태/소유자 메타데이터
pipeline_profiles.py # LLM/embedding/Neo4j profile
jobs.py # KG build job 상태
adapters/
documents.py # crawler output → LoadedDocument
schema.py # 우리 온톨로지 모델 ↔ GraphSchema
services/
kg_builder.py # SimpleKGPipeline 실행 래퍼
review.py # 추출 결과 검수
search.py # GraphRAG/Text2Cypher 래퍼
resolver.py # merge 후보/실행
12. 상세 기능명세
12.1 온톨로지 프로젝트 관리
| ID | 기능 | 설명 | 우선순위 |
|---|---|---|---|
| ONT-PROJ-001 | 프로젝트 생성 | 이름, 설명, Neo4j DB/profile, 기본 언어 설정 | P0 |
| ONT-PROJ-002 | 데이터소스 연결 | 파일, 크롤링 결과, URL, DB table 등록 | P0 |
| ONT-PROJ-003 | LLM profile 선택 | provider/model/key/params 선택 | P0 |
| ONT-PROJ-004 | Embedding profile 선택 | provider/model/dimension 설정 | P0 |
| ONT-PROJ-005 | 실행 이력 조회 | pipeline run 상태/시간/token/비용/오류 | P1 |
12.2 온톨로지 스키마 관리
| ID | 기능 | 설명 | 우선순위 |
|---|---|---|---|
| ONT-SCH-001 | 수동 schema 작성 | node type, relationship type, property, pattern 작성 | P0 |
| ONT-SCH-002 | 자동 schema 추출 | 문서 샘플에서 SchemaFromTextExtractor 실행 |
P0 |
| ONT-SCH-003 | schema 검증 | GraphSchema Pydantic validation + custom rule |
P0 |
| ONT-SCH-004 | schema 버전 발행 | draft → published | P0 |
| ONT-SCH-005 | schema diff | version 간 label/property/pattern 변경 비교 | P1 |
| ONT-SCH-006 | constraint 관리 | uniqueness/key/existence 제약 관리 | P1 |
| ONT-SCH-007 | class hierarchy | 상위/하위 class 정의 | P2 |
12.3 KG 구축
| ID | 기능 | 설명 | 우선순위 |
|---|---|---|---|
| ONT-KG-001 | 파일 기반 KG 구축 | PDF/Markdown → SimpleKGPipeline | P0 |
| ONT-KG-002 | 텍스트 기반 KG 구축 | crawler text 또는 inline text → SimpleKGPipeline | P0 |
| ONT-KG-003 | lexical graph 생성 | Document/Chunk/provenance graph 생성 | P0 |
| ONT-KG-004 | chunk embedding | Chunk embedding property 저장 | P0 |
| ONT-KG-005 | 스키마 기반 추출 | published GraphSchema로 LLM 추출 | P0 |
| ONT-KG-006 | 자동 스키마 추출 후 KG 구축 | schema="EXTRACTED" 사용 |
P1 |
| ONT-KG-007 | 자유 추출 | schema="FREE" 사용 |
P1 |
| ONT-KG-008 | pruning 통계 저장 | 제거 노드/관계/property 기록 | P0 |
| ONT-KG-009 | 추출 결과 임시 저장 | writer 전 검수용 graph 저장 | P1 |
| ONT-KG-010 | Parquet export | 대량 import 또는 검수 산출물 | P2 |
12.4 검수 및 승인
| ID | 기능 | 설명 | 우선순위 |
|---|---|---|---|
| ONT-REV-001 | 추출 후보 목록 | node/relationship/property 후보 조회 | P1 |
| ONT-REV-002 | 근거 chunk 표시 | FROM_CHUNK 관계 기반 원문 근거 표시 |
P1 |
| ONT-REV-003 | 승인/반려 | 후보 단위 상태 변경 | P1 |
| ONT-REV-004 | pruning 후보 검토 | 스키마 위반으로 제거된 후보 검토 | P1 |
| ONT-REV-005 | schema 개선 제안 | 반복 pruning된 후보를 schema 후보로 제안 | P2 |
12.5 엔티티 해소
| ID | 기능 | 설명 | 우선순위 |
|---|---|---|---|
| ONT-RES-001 | exact match merge | label + name exact match | P0 |
| ONT-RES-002 | fuzzy merge 후보 | RapidFuzz로 후보 계산 | P1 |
| ONT-RES-003 | semantic merge 후보 | spaCy 또는 embedding similarity | P2 |
| ONT-RES-004 | merge 검수 | 후보 그룹 승인 후 APOC merge | P1 |
| ONT-RES-005 | merge 이력 | 병합 전후 node id, property 충돌 기록 | P1 |
12.6 검색 및 질의응답
| ID | 기능 | 설명 | 우선순위 |
|---|---|---|---|
| ONT-SEA-001 | vector 검색 | Chunk vector index 검색 | P0 |
| ONT-SEA-002 | hybrid 검색 | vector + fulltext | P1 |
| ONT-SEA-003 | graph 확장 검색 | VectorCypher/HybridCypher로 주변 graph 반환 | P0 |
| ONT-SEA-004 | Text2Cypher | 자연어 → read-only Cypher | P1 |
| ONT-SEA-005 | GraphRAG 답변 | 검색 context 기반 답변 생성 | P1 |
| ONT-SEA-006 | provenance 포함 답변 | 답변에 문서/chunk 근거 포함 | P1 |
13. 통합 시 주의사항
13.1 원본 코드를 직접 수정하지 않는 것이 좋다
이 프로젝트의 KG builder는 experimental이다. 원본을 직접 수정하면 upstream 반영이 어려워진다. 권장 방식:
neo4j-graphrag==1.16.0으로 버전 고정- 우리 프로젝트에 adapter/wrapper 작성
- 필요한 custom component만 우리 namespace에 구현
- 원본 API 변경 시 wrapper만 수정
13.2 LLM JSON 품질
json-repair와 structured output이 있더라도 LLM 추출은 완전하지 않다.
필수 보완:
- 스키마 grounding prompt 강화
- examples few-shot 관리
- chunk별 실패율 기록
- pruning 결과 분석
- 사람이 승인하는 workflow
13.3 Neo4j/APOC 의존성
KG writer와 resolver는 Neo4j 버전/APOC에 민감하다.
운영 체크:
- Neo4j 버전 확인
- APOC core 설치 확인
apoc.refactor.mergeNodes사용 가능 여부 확인- vector/fulltext index 생성 권한 확인
- multi database 사용 시
neo4j_database일관성 유지
13.4 Text2Cypher 보안
Text2CypherRetriever는 read-only 검사를 갖지만, 운영 서비스에서는 추가 안전장치가 필요하다.
- 허용 schema 제한
- query timeout
- result limit
- 금지 키워드 검사
- 사용자별 권한 필터
- 쓰기/삭제/관리 명령 차단
14. 초기 적용 로드맵
Phase 1: 최소 KG 구축
목표: crawler 결과 또는 텍스트를 Neo4j KG로 저장.
작업:
neo4j-graphrag[openai,experimental]의존성 추가- Neo4j 연결 profile 모델 추가
- LLM/embedding profile 모델 추가
- crawler output →
LoadedDocumentadapter 작성 SimpleKGPipeline(from_file=False)실행 service 작성GraphSchema수동 입력 API 작성Neo4jWriter결과 통계 저장
Phase 2: 온톨로지 초안/검수
목표: 자동 schema 추출과 추출 결과 검수.
작업:
schema="EXTRACTED"실행 지원- 추출 schema draft 저장
GraphPruning결과 저장- pruned item 검토 화면/API
- 승인된 schema version 발행
Phase 3: 검색/질의응답
목표: 구축된 KG를 탐색하고 질의응답.
작업:
- Chunk vector index 생성 자동화
VectorCypherRetriever로 chunk → entity/provenance 검색HybridRetriever도입GraphRAGservice 작성- Text2Cypher read-only 질의 API 추가
Phase 4: 엔티티 해소/품질관리
목표: 중복 entity와 schema 품질 개선.
작업:
- exact match resolver 실행
- fuzzy 후보 생성
- merge 후보 검수
- merge 이력 저장
- 반복 pruning 기반 schema 개선 추천
15. 결론
neo4j-graphrag-python은 우리 범용 온톨로지 구축 플랫폼의 “KG 생성 엔진”과 “GraphRAG 검색 엔진”으로 매우 적합하다. 특히 GraphSchema, SimpleKGPipeline, LLMEntityRelationExtractor, GraphPruning, Neo4jWriter, VectorCypherRetriever, Text2CypherRetriever는 거의 그대로 가져다 쓸 수 있다.
다만 이 프로젝트가 제공하는 것은 “라이브러리/엔진”이지 “플랫폼”은 아니다. 우리 프로젝트의 핵심 차별점은 다음 레이어에서 만들어야 한다.
- 온톨로지 프로젝트/버전 관리
- schema draft/publish workflow
- 추출 결과 검수 및 provenance UI
- crawler 결과와의 자연스러운 연결
- 대량 실행 job 관리
- entity merge 후보 검수
- Text2Cypher 보안/권한 레이어
따라서 권장 전략은 원본 소스를 복사해 수정하기보다, neo4j-graphrag를 고정 버전 의존성으로 두고 우리 플랫폼 서비스가 이 라이브러리를 orchestration하는 방식이다. 필요한 경우 custom loader, custom splitter, custom resolver, custom writer만 우리 코드베이스에 추가한다.