회사에 산업 리포트 PDF가 수백 개 쌓여 있다. 내가 다루는 산업의 보고서, 경쟁사 분석, 시장 조사, 컨설팅 결과물이 매월 추가된다. 이걸 검색하려면 어떻게 해야 할까. M365 Copilot에 물어보면 된다고? 해봤다. 자료가 방대해지면 검색이 무너진다. 텍스트 매칭으로는 "A보고서가 인용한 B데이터" 같은 관계를 잡아낼 수 없다. 결국 남는 선택지가 하나 있다. 지식 그래프다. 그런데 그동안 문제가 있었다. 그래프를 누가 만들 것인가. 엔티티를 추출하고, 관계를 정의하고, 노드를 연결하는 작업을 사람이 손으로 할 수는 없다. PDF 수백 개를 Cypher 쿼리로 일일이 입력할 사람은 없다.
Neo4j LLM Graph Builder는 바로 그 부분을 자동화한다. 비정형 데이터 — PDF, 웹페이지, YouTube 자막, S3 버킷의 문서 — 를 LLM이 읽고, 엔티티와 관계를 자동 추출해서 Neo4j 그래프 데이터베이스에 저장한다. 텍스트를 그래프로 바꾸는 "text-to-graph" 경험을 오픈소스로 풀었다. 직접 아직 써보진 않았다. 하지만 써보고 싶다. 이 글은 왜 써보고 싶은지, 그리고 이 도구가 내 상황에서 어떤 의미인지 정리한 것이다.
LLM이 문서를 읽고 그래프를 그린다
LLM Graph Builder의 작동 방식은 단순하다. 문서를 업로드하면 LangChain 로더가 읽는다. 문서가 청크로 쪼개진다. 각 청크에서 LLM이 엔티티(사람, 조직, 프로젝트, 개념)를 식별하고, 엔티티 간 관계를 추출한다. 추출된 노드와 관계가 Neo4j에 저장된다. 여기에 임베딩이 계산되어 벡터 인덱스로 들어가고, 비슷한 청크끼리 SIMILAR 관계로 연결된다. k-nearest neighbors 그래프가 자동으로 구성된다.
여기까지가 "lexical graph"와 "entity graph"의 이중 구조다. 문서와 청크가 계층적으로 연결되고, 거기에 엔티티가 올라간다. 지원하는 LLM은 OpenAI, Gemini, Claude, Llama 3, Diffbot, Qwen 등이다. 로컬에서 Ollama로 Llama 3를 돌릴 수도 있다. 데이터가 외부로 나가면 안 되는 회사 환경에서는 이 부분이 중요하다.
여기서 멈추지 않는다. 그래프가 만들어지면 GraphRAG 챗봇으로 질문할 수 있다. "이 보고서에서 언급된 모든 경쟁사와 그 시장 점유율을 보여줘" 같은 질문이 가능하다. 리트리버 종류가 여럿 있다. Graph 리트리버는 엔티티 주변의 이웃을 따라가서 맥락을 수집한다. 질문에서 "경쟁사"를 식별하면, 그 경쟁사 노드에 연결된 시장 점유율, 제품, 파트너십 관계를 2홉까지 따라간다. Hybrid 리트리버는 벡터 검색과 그래프 검색을 결합한다. Global Community 리트리버는 Microsoft의 GraphRAG 논문을 구현한 것으로, 엔티티 클러스터를 요약해서 전체적인 질문에 답한다. "올해 소비재 트렌드의 큰 흐름이 뭐야?" 같은 질문은 개별 엔티티가 아니라 전체 구조를 봐야 한다. Global 리트리버가 여기서 힘을 발휘한다. 어떤 리트리버가 답을 생성했는지, 어떤 문서와 엔티티가 사용됐는지도 보여준다. 설명 가능성이 기본이다.
왜 이 도구가 내 상황에 맞는가
내가 아는 기술 안에서 "방대한 회사 데이터를 다루는 방법"을 찾으면 결국 지식 그래프밖에 없다. 텍스트 RAG는 한계가 명확하다. 각 문서를 독립적으로 검색한다. 문서 간 관계를 추론하지 못한다. "A보고서가 인용한 B데이터"를 잡을 수 없다. 이건 이미 RAG 진화 4단계 글에서 정리했다. GraphRAG가 그 간극을 메우고, GraphDB가 그래프를 영구 저장하는 단계다.
LLM Graph Builder는 Phase 3와 Phase 4를 한 번에 해결해주는 도구다. 문서를 넣으면 GraphRAG용 그래프가 만들어지고, Neo4j에 영구 저장된다. 직접 GraphRAG 엔진을 구성하고, 엔티티 추출 파이프라인을 짜고, Neo4j 스키마를 설계할 필요가 없다. 도구가 그걸 다 한다. 내가 정의해야 하는 것은 스키마뿐이다. 어떤 노드 타입을 쓸 것인지, 어떤 관계 라벨을 쓸 것인지. 나머지는 LLM이 한다.
내가 다니는 리서치 회사는 long-term trend, FMCG, 테크놀로지, 소비자 인사이트 등 여러 산업 카테고리를 다룬다. 한 보고서 안에서도 여러 산업이 교차한다. FMCG 트렌드가 기술 adoption에 미치는 영향, long-term 관점에서 본 시장 구조 변화 같은 분석이 한 리포트에 공존한다. 이런 다층 구조를 그래프로 표현하려면 스키마가 유연해야 한다. 노드 타입을 산업별로 고정하면 안 된다. 하나의 문서가 여러 산업에 걸쳐 있으니까.
LLM Graph Builder는 스키마를 직접 정의할 수 있다. 미리 정의된 스키마를 쓸 수도 있고, 기존 Neo4j 스키마를 불러올 수도 있고, LLM이 문서를 읽고 스키마를 제안하게 할 수도 있다. 세 번째 옵션이 내 상황에 흥미롭다. 리서치 리포트의 구조를 내가 완전히 알지 못하기 때문이다. LLM이 수백 개의 PDF를 읽고 "이 문서군에서 반복적으로 등장하는 엔티티 타입은 이것들이다"라고 제안해주면, 거기서 스키마를 다듬어 나갈 수 있다.
보안 이슈는 Azure OpenAI로 해결한다. 회사에서 Azure OpenAI 서비스를 쓸 수 있다. 데이터가 Microsoft 테넌트 안에서 처리되고, 외부 API로 나가지 않는다. LLM Graph Builder의 백엔드에서 OpenAI 호환 엔드포인트를 Azure로 지정하면 된다. OPENAI_API_KEY 대신 Azure 엔드포인트와 디플로이먼트 이름을 설정하는 것으로 충분하다. 로컬 LLM보다 품질이 좋고, 퍼블릭 OpenAI보다 안전하다. 회사 환경에서 쓸 수 있는 가장 현실적인 조합이다.
배포는 Docker Compose로 로컬에 띄운다. 백엔드는 Python FastAPI, 프론트엔드는 React다. 회사 안에서 Azure OpenAI를 쓸 수 있으니, 백엔드에서 Azure 엔드포인트만 잡아주면 된다. Ollama로 로컬 모델을 돌리는 옵션도 있지만, Azure OpenAI가 품질과 보안 두 마리 토끼를 잡아준다. 퍼블릭 API를 거칠 필요 없이, 회사 테넌트 안에서 전체 파이프라인이 돈다.
설치 핵심 단계:
- Neo4j 5.23+ 인스턴스 준비 (Aura 무료 tier 가능, APOC 필수)
- 저장소 클론 후
docker-compose up실행 - 백엔드
.env에 Neo4j 접속 정보 입력 - (옵션) Ollama Docker 이미지로 로컬 LLM 구동
- 프론트엔드에서 파일 업로드 → LLM 선택 → 그래프 생성
구성이 끝나면 PDF를 올리고, LLM을 고르고, "Generate Graph" 버튼을 누른다. 그러면 Neo4j에 노드와 관계가 쌓인다. Bloom이나 브라우저에서 그래프를 시각화할 수 있고, GraphRAG 챗봇으로 질문하면 된다.
내가 이 도구를 당장 써보고 싶은 이유는 단순하다. 내가 아는 한, 방대한 회사 데이터를 다루려면 결국 지식 그래프뿐이다. 그런데 그래프를 만드는 작업이 항상 병목이었다. LLM이 그 병목을 풀었다. PDF를 올리기만 하면 된다. 나머지는 기계가 한다. 내가 할 일은 스키마를 잘 설계하고, 결과를 검증하는 것이다. 어떤 모델을 쓰느냐, 스키마를 어떻게 잡느냐가 변수다. long-term trend 리포트에서는 거시적 엔티티(국가, 정책, 기술 트렌드)가 중심이 될 것이고, FMCG 리포트에서는 브랜드, 소비자 세그먼트, 유통 채널이 주요 노드가 될 것이다. 같은 도구에 다른 스키마를 먹이면 다른 그래프가 나온다. 그 변수를 내 손으로 만져보고 싶다.