ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 위키링크가 곧 엣지다 — LLM 호출 없이 지식 그래프를 짓는 방법
    IT 2026. 8. 16. 21:00

    ▶ 동영상 개요 — 위키링크가 곧 엣지다 — LLM 호출 없이 지식 그래프를 짓는 방법

    7분 40초 — 개체 추출을 문법으로 대체한 설계와 그 대가를 짚는다 — NotebookLM 동영상 개요로 생성

    🎧 오디오 개요 — 두 진행자가 따라가는 '개체 추출 없는 그래프'

    17분 56초 — 개체 추출을 문법으로 대체한 설계와 그 대가로 무엇을 내줬는지를 대화로 풀어낸다. 화면은 이 글의 인포그래픽 한 장 고정 — NotebookLM 오디오 개요로 생성

    벡터 검색으로 개인 문서를 뒤지다 보면 잘 안 되는 질문 유형이 있다. "지난달 회고 문서 찾아줘"는 잘 찾는다. 그런데 "그 회사에 다니는 사람이 누구였지"는 잘 못 찾는다. 답이 한 문서 안에 통째로 들어 있지 않고 여러 문서에 흩어진 관계로만 존재하기 때문이다.

    이건 벡터 검색의 결함이라기보다 성격이다. 벡터 검색은 의미가 비슷한 덩어리를 찾는 도구지 관계를 따라가는 도구가 아니다. 그래서 관계를 다루려면 그래프를 따로 얹어야 한다는 것이 상식이 됐다. 문제는 그 그래프를 무슨 수로 만드느냐다. 4월에 공개된 gbrain이라는 에이전트 기억 시스템이 이 지점에서 흔치 않은 선택을 했다. 그래프를 만들면서 언어 모델을 한 번도 부르지 않는다.

    보통은 이렇게 만든다

    문서에서 인물, 회사, 프로젝트 같은 개체(entity)와 그들 사이의 관계를 뽑아내는 일을 개체 추출이라고 부른다. 요즘 표준적인 방법은 언어 모델에게 문서를 통째로 주고 "여기 나오는 인물과 그 관계를 목록으로 뽑아라"라고 시키는 것이다.

    diagram

    ▲ 방식 A — 언어 모델로 추출하기

    다이어그램 설명. 문서를 저장할 때마다 언어 모델 호출이 한 번씩 끼어드는 구조다. 잘 동작하고, 자유롭게 쓴 글에서도 관계를 뽑아낸다는 큰 장점이 있다. 대신 대가가 셋 붙는다. 첫째, 문서 한 장당 비용이 든다. 문서가 10만 장이면 호출도 10만 번이다. 둘째, 저장이 느려진다. 저장 버튼을 누르고 모델 응답을 기다려야 한다. 셋째가 가장 성가신데, 같은 문서를 두 번 넣으면 다른 그래프가 나올 수 있다. 언어 모델은 같은 입력에도 매번 똑같이 답하지 않기 때문이다. 그래프는 한번 잘못 연결되면 이후 모든 질의가 그 위에서 돌아가므로, 이 비결정성이 조용히 누적된다.

    gbrain은 문법을 계약으로 삼는다

    gbrain의 선택은 다른 방향이다. 글에서 관계를 알아내려 하지 않고, 글을 쓸 때 관계를 표시하게 한다.

    diagram

    ▲ 방식 B — 문법에서 그대로 읽어내기

    다이어그램 설명. 언어 모델 호출이 있던 자리에 문자열 검색이 들어와 있다. 본문에서 이중 대괄호로 감싼 링크 표기를 찾고, 그 표기가 어떤 형태였는지에 따라 관계의 종류를 정하고, 엣지로 남긴다. 전부 정규식 수준의 작업이라 비용이 사실상 0이고, 저장이 느려지지 않고, 무엇보다 같은 문서는 언제나 같은 그래프를 만든다. 방식 A와 비교했을 때 잃은 것도 분명하다. 방식 A는 아무렇게나 쓴 문장에서도 관계를 뽑아내지만, 방식 B는 사람이 링크를 걸어 준 관계만 안다. 즉 이 설계는 추출 문제를 푼 게 아니라 추출이 필요 없는 형식으로 문제를 옮긴 것이다. 이걸 "더 나은 추출 방법"으로 이해하면 나중에 기대가 어긋난다.

    관계에 이름을 붙이는 자리

    단순 링크만으로는 "언급했다" 정도의 약한 관계밖에 안 남는다. 그래서 gbrain은 링크에 종류를 붙이는 표기를 함께 쓴다. 소속을 뜻하는 관계, 참석을 뜻하는 관계, 투자를 뜻하는 관계, 창업을 뜻하는 관계, 자문을 뜻하는 관계 같은 것들이 미리 정의돼 있다.

    말로만 보면 감이 잘 안 오니 문서 한 장을 그대로 옮겨 본다. 인물 노트에 이렇게 적는다고 하자.

    2년 전 [[invested_in:companies/acme]]에 투자했고,
    요즘은 [[advises:companies/beta]] 쪽 자문을 맡고 있다.
    지난주 [[events/2026-데모데이]]에서 오랜만에 만났다.
    

    예시 설명. 앞의 두 링크는 관계 종류를 앞에 붙였다. 그래서 이 문서에서 acme로 "투자했다" 엣지가, beta로 "자문한다" 엣지가 각각 생긴다. 세 번째 링크는 종류를 안 붙였으니 가장 약한 "언급했다" 엣지로만 남는다. 사람이 쓴 문장 세 줄이 그대로 엣지 세 개가 되는 것이고, 그 사이에 언어 모델이 끼어드는 자리는 없다.

    이렇게 쌓인 엣지가 여러 문서에 걸쳐 이어지면 이런 모양이 된다.

    people/김OO  --invested_in-->  companies/acme
    people/김OO  --advises------>  companies/beta
    people/이OO  --works_at----->  companies/acme
    

    예시 설명. 세 줄 모두 각자 다른 문서에서 나온 것이지만, 대상 경로가 같으면 자동으로 같은 노드에 붙는다. 그래서 "acme에 투자한 사람이 자문하는 다른 회사"를 물으면 첫 줄에서 김OO를 찾고 둘째 줄로 건너뛰어 beta를 답할 수 있다. 어느 문서에도 "김OO가 beta를 자문한다는 사실이 acme와 관련 있다"라고 적혀 있지 않은데도 답이 나온다는 게 그래프를 얹는 이유다.

    이게 왜 중요한가? 관계에 이름이 붙어야 여러 칸을 건너뛰는 질문이 가능해진다. "그 회사에 투자한 사람이 자문하는 다른 회사"처럼 두세 단계를 타고 가는 질문은, 엣지에 종류가 없으면 방향을 잡을 수 없다. 모든 엣지가 그냥 "관련 있음"이면 두 칸만 건너가도 온 세상이 다 연결된다.

    직접 만들어 본다면 이 정도 코드로 시작할 수 있다.

    import re
    
    # 이중 대괄호 링크에서 대상 경로와 관계 종류를 함께 뽑는다.
    # 예) 관계 표기가 붙은 링크 / 표기가 없는 맨 링크 둘 다 처리한다.
    LINK = re.compile(r"\[\[([a-z_]+):([^\]]+)\]\]|\[\[([^\]]+)\]\]")
    
    def extract_edges(page_id: str, body: str) -> list[tuple[str, str, str]]:
        edges = []
        # 1단: 본문을 한 번만 훑는다 — 모델 호출도, 네트워크도 없다
        for m in LINK.finditer(body):
            typed_rel, typed_target, plain_target = m.groups()
            # 2단: 관계 종류가 명시됐으면 그대로 쓰고, 없으면 가장 약한 관계로 떨어뜨린다
            rel = typed_rel if typed_rel else "mentions"
            target = typed_target if typed_target else plain_target
            edges.append((page_id, rel, target.strip()))
        # 3단: 같은 문서를 다시 넣어도 결과가 동일하다 — 그래서 저장이 멱등해진다
        return edges
    

    코드 설명. 그래프 구축의 핵심이 정규식 한 줄과 반복문 하나로 끝난다는 것을 보여주는 최소 구현이다. 관계 종류가 명시된 링크는 그 종류를 쓰고, 종류 없이 걸린 맨 링크는 가장 약한 관계인 "언급"으로 떨어뜨린다. 여기서 눈여겨볼 설계는 약한 관계로 떨어뜨리되 버리지 않는다는 점이다. 사람이 매번 관계 종류를 붙일 리 없으니, 안 붙인 링크를 무시해 버리면 그래프에 구멍이 숭숭 뚫린다. 대신 약한 엣지로 남겨 두면 나중에 종류를 채워 넣을 여지가 생긴다. 함정도 하나 있다. 이 방식은 링크 대상이 실제로 존재하는 문서인지 확인하지 않는다. 오타가 난 링크는 조용히 유령 노드를 만든다. 실제 gbrain도 이 문제를 별도의 정비 작업으로 야간에 따로 처리한다.

    그래서 얼마나 좋아지는가

    gbrain 문서는 이 그래프가 만드는 차이를 숫자로 밝혀 놓았다. 240개 문서로 만든 평가 세트에서, 벡터 검색만 썼을 때보다 상위 5개 안에 정답이 들어 있는 비율이 31.4포인트 올랐다고 적혀 있다. 정밀도 지표는 검색 결과 상위 몇 개 안에 쓸모 있는 답이 얼마나 섞여 있는지를 재는 값이다.

    31.4포인트는 큰 값이다. 다만 이 숫자를 읽을 때 조심할 점이 있다. 평가 세트가 240개 문서 규모라 크지 않고, 무엇보다 이 평가에 쓰인 문서들이 이미 링크가 잘 걸린 문서일 가능성이 있다. 링크가 없는 문서 더미에 이 방식을 적용하면 그래프가 비어 있으니 개선폭도 없다. 즉 이 숫자는 "그래프를 얹으면 이만큼 좋아진다"가 아니라 "링크를 성실히 건 문서 더미에 그래프를 얹으면 이만큼 좋아진다"로 읽는 게 정확하다.

    이 설계가 실제로 지불하는 대가

    공짜처럼 보이지만 비용은 옮겨 갔을 뿐이다. 언어 모델이 내던 비용을 글 쓰는 사람이 낸다. 문서를 쓸 때 인물 이름을 그냥 적지 않고 링크로 걸어야 하고, 가능하면 관계 종류까지 붙여야 한다.

    이 비용이 감당할 만한지는 상황에 달렸다. 이미 위키링크 습관이 있는 사람이라면 추가 비용이 거의 없다. 링크를 걸어 본 적 없는 문서 더미를 가져오면 그래프가 텅 빈 채로 시작한다. 실제로 이 시스템에 대한 리뷰들이 공통적으로 지적하는 것도 빈 브레인 문제다. 처음 설치하면 아무것도 모르는 상태라, 기존 문서를 들여오지 않으면 첫날에는 쓸모가 없다.

    또 하나가 있다. 사람이 안 건 관계는 시스템도 모른다. 회고 문서에 "그때 그 사람이 반대했다"라고만 적고 링크를 안 걸었으면, 나중에 "누가 반대했었지"라고 물어도 그래프는 답하지 못한다. 벡터 검색이 그 문장을 찾아 줄 수는 있지만 관계로는 남지 않는다.

    정리 — 추출을 잘하는 것과 추출이 필요 없게 만드는 것

    이 설계에서 가져갈 교훈은 지식 그래프에 국한되지 않는다. 어려운 문제를 만났을 때 그 문제를 더 잘 푸는 방법을 찾는 길이 있고, 그 문제가 생기지 않는 형식으로 입력을 바꾸는 길이 있다. 개체 추출은 어려운 문제고, 링크 표기를 읽는 것은 쉬운 문제다. gbrain은 두 번째 길을 골랐고, 그 대가로 사람에게 표기 규율을 요구했다.

    내 개인 문서 더미에 적용한다면 이렇게 시작하겠다. 새 문서부터 인물과 프로젝트를 링크로 걸기 시작하고, 관계 종류는 자주 쓰는 서너 개만 정한다. 처음부터 종류를 열다섯 개 정의하면 그중 셋만 쓰게 된다. 규율은 지킬 수 있는 크기로 시작해야 남는다.


    참고한 공개 자료:


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.