25년 5월 2주차 그래프 오마카세

AI Agents on Knowledge Graphs to answer multihop questions

blog link : https://www.dynocortex.com/news-and-blog/ai-agents-on-knowledge-graphs-to-answer-multihop-questions/

youtube link : https://youtube.com/watch?v=1rLBec8Kcq8&si=UsLZoweyNotrJgmz

credit : DynoCortex blog
  • 그래프 중심 생성형 AI 소프트웨어를 제공하는 Dynocortex 라는 기업에 대해 들어보신 적 있으신가요? 저도 최근에 알게 되었는데요. 회사 설명을 읽어보면 AI Reliability (신뢰도)를 중요하게 생각하여 LLM의 환각 현상을 잡기 위한 지식 그래프를 활용한 자세한 구현 프로세스를 공식 블로그를 통해 공유하고 다양한 유저들과 소통하고 있습니다.
  • 포괄적인 GraphRAG 관련 문제들을 다루고 있는 것으로 보이며, 최근에는 해당 이름과 같이 'AI 에이전트를 결합한 지식 그래프 기반 멀티홉 질문에 대한 답변' 을 제공할 수 있는 새로운 워크플로를 설명한 게시글 및 유튜브 영상을 발견하여, 독자 여러분들께 소개해드리고자 이번주 오마카세로 전달해드리게 되었습니다.
  • 해당 블로그 글에서는 LLM에 결합된 GraphRAG의 한계점을 제시합니다. 특히, 거대 지식 그래프로부터 반환된 노드 및 엣지 (관계) 집합 세트가 불완전하거나 원하는 답변을 얻기 위한 추가 처리가 필요한 경우를 고려합니다. 다음 내용에 해당합니다.
    • 벡터 저장소에서 문서를 검색하여 LLM으로 보낼 수 없는 이유는 문서가 너무 많기 때문입니다. 또한 모든 정보가 포함된 단일 문서가 없습니다.
    • 미세 조정된 LLM을 사용하면 환각이나 오래된 정보를 얻을 수 있습니다.
    • GraphRAG는 관련 정보에 대한 요약을 제공하지만 실제 답변은 요약에 숨겨져 있거나 전혀 캡처되지 않을 수 있습니다.
    • 복잡한 멀티홉 질문에 답하기 위해 LLM을 사용하여 순진하게 그래프 쿼리를 생성하면 매우 취약한 결과를 얻을 수 있습니다. 이러한 쿼리는 지식 그래프의 누락된 링크와 불일치로 인해 어려움을 겪습니다.
  • 직접적인 솔루션 구현 방법은 그래프 데이터베이스 쿼리의 불안정성으로 인해 원하는 결과를 얻지 못하는 경우가 많았으며, 복잡한 멀티홉 질문에 대하여 단순한 그래프 쿼리를 LLM에 제공하였을 때 취약한 결과를 얻을 수 있습니다. 그로부터 에이전트 방식의 지식 그래프 쿼리 변환이 위의 문제점을 해결할 수 있다는 사실을 발견하고, 그로부터 지식 그래프 AI 에이전트 시스템을 개발하였습니다.
  • AI 에이전트를 활용하였을 때 얻을 수 있는 장점을 아래와 같이 소개하고 있습니다.
    • 검증 가능하고 설명 가능한 아웃풋 결과로부터 지식 그래프를 신뢰할 수 있는 정보 소스로 활용 가능
    • 다양한 매개 변수를 갖는 LLM 템플릿을 호출 가능
    • 복잡한 워크 플로우를 여러 모듈로 나누어 접근성을 높히고, 다른 모듈의 개별적인 호출 기능으로부터 중복성을 낮춤
    • 비용 효율적이며 빠른 동작
  • 에이전트 기반 지식 그래프 쿼리 모듈은 위의 그림과 같이 크게 5가지 쿼리를 받아 처리하는 4가지 오퍼레이터들로 구성되어 있습니다 (Generator, Validator, Corrector, Executor). 해당 오퍼레이터들은 자체 내부 워크플로를 가지고 있으며, 다른 서비스에 대한 호출에 의존합니다.
    • Generator : 입력된 유저의 질문 및 유사 질문에 대응하는 Cypher 코드 및 그래프 데이터베이스 스키마의 하위 집합을 사용하여 LLM 호출을 통해 Cypher 쿼리를 공식화합니다. 그리고 의미론적 유사 예제 선택기 (Semantic similarity example selector)를 사용하여 few-show 기반 프롬프팅에 대한 최적의 예제 답변을 생성하여 Validator에게 넘겨줍니다.
    • Validator : Generator로부터 생성된 답변의 유효성을 검사합니다. Corrector와 소통하며 해당 구문을 자세하게 설명하게 하고 LLM을 호출하여 설명 상의 문제점을 발견하도록 합니다. 그로부터 유저 질문에 좀더 유효한 Cypher 구문으로 수정, 정제하여 Executor에게 넘겨줍니다.
    • Corrector : Validator와 소통하며 Cypher 구문과 LLM에 대한 호출을 수정하는 역할을 담당합니다.
    • Executor : 그래프 데이터베이스에서 Cypher 쿼리 실행을 처리하고, 결과 집합 및 구조 정보, 오류 등을 재반환하여 스키마 필터 모듈로 전달합니다.
  • 스키마 필터 모듈을 통해 최종 답변 결정을 위한 모든 관련 노드 및 관계 피쳐 유형을 반환합니다. 필터링 결과에 따라 초기 워크플로로 돌아가서 유한 루프 형태로 위 과정을 반복하고 최종 답변을 생성합니다.
    • Cypher 쿼리 생성 - 검증 - 수정 및 답변 실행 방식으로 동작하며, 입력 및 출력 결과의 지속적인 평가를 통한 복잡한 멀티홉 질문에 대응하는 접근 방식을 제공합니다. 오픈 소스로 제공될 예정이라고 합니다.
  • 유튜브 영상을 통해서도 담당 엔지니어 분께서 위 내용을 자세하게 설명해주고 있으니 직접 시청해보시면 더욱 명확하게 이해하실 수 있을 것으로 생각합니다. 참고하시어 여러분들께 많은 도움이 되었기를 바랍니다.

[Contact Info]

Gmail: jhbae1184@akane.waseda.jp

Twitter (X): @jhbae1184

LinkedIn


안녕하세요 정이태입니다. 3주차입니다. 이번주차엔 멘티분들이 LightRAG 를 잘 활용할 수 있게 인프라를 구현했고, 각 인프라를 어떻게 이용하는지를 주로 다뤘습니다. 구현하며 겪은 Lesson learned 들도 담아보았으니, 함께 보시죠.

Overview

이번주차 진행내용

Team1

Team1에서는 Entity extraction & linking 을 통해 지식그래프를 구축하는게 핵심입니다. LightRAG 엔진에서 활용할 재료를 잘 가공하는 작업을 진행하죠. 여기에서 지식그래프 기반이 되는 온톨로지를 재료라고 가정해보겠습니다. 즉, 재료의 재료가 되는거죠. 현재, 구축된 온톨로지가 LightRAG의 최적 온톨로지인지를 알 수 없기 때문에, 다양한 관점에서 추출 및 실험을 해보아야합니다.

실험을 위해선 LightRAG 엔진의 결과물로 도출된 Retrieval 결과와 Generation 결과를 vector only 관점과 대조합니다. 이때, 대조의 기준은 Vector 도 가능한 쿼리 , Graph 관점을 보완하면 더 정확해질거라 예상되는 쿼리가 되는거죠. 여기에서 Graph 관점이 적용된 쿼리는 Team3 의 기획에 기반해서 생성합니다. 이 쿼리를 활용할 고객 그리고 데이터셋 상황(multi-hop) 두 가지가 프롬프트에 반영되어 evaluation dataset을 만듭니다.

다시 돌아와서 Team1은 지식그래프를 만들때 필요한 프롬프트 속 테크닉들 중 무엇이 최적인지를 고민해보고 판단해야합니다. 그를 위해, 단일 관점이 아닌 다양한 관점으로 엔티티를 추출하고, 엔티티간 linking을 통해 만듭니다. 더나아가, 결과물 지식그래프의 품질이 과연 evaluation 까지 유의미한 영향(긍정적,부정적)을 미치는가를 정성적, 정량적으로 분석해야합니다.

이 모든게 진행되기 위해 선행되어야할게 있습니다. 바로, 프롬프트 관리입니다. 프롬프트 관리라 함은 여러 관점으로 접근할 수 있겠지만, 여기에선 버저닝 & 팀 내 다른 멘티들간의 협업 관점으로 접근합니다. 너무나도 많은 선택지가 존재했습니다. .py , .txt, langchain 의 load_prompt 를 도입할지 등등 여러 선택지가 있었지만, Langchain은 배제하고 최대한 vanilla LightRAG를 활용해보자 라는 철학을 지켜보고자, hydra 를 선택합니다.

아래 그림은 현재 프롬프트 관련 tree입니다. hydra 의 default config 를 가장 상단 폴더의 config.yaml 에 설정해주고, 저희가 활용할 모델을 관리해주는 model config , team1과 3분들이 활용할 각각의 prompt.yaml 이렇게 구성되어 있습니다. 뜬금없이 model config가 나와서 의아하실 수 있습니다.

지금 멘토링에는 단일 모델 openai 만을 활용하지만, 추후에 멘티분들이 이 코드를 활용해서 타모델들 (open & closed model)별로 이 프롬프팅들을 적용할 수 있는 확장성을 고려해서 model 또한 config 범주로 넣어줍니다. 관련해서 자세한 내용은 테디노트님 영상에서 각 모델별 NER 결과 그리고 LLM as judgement 부분을 보시면 이해가 되실겁니다.
https://www.youtube.com/watch?v=zHN2jDZHvI0&t=10358s , 1:55:00

프롬프트 및 hydra 사용법을 리뷰했습니다. 굉장히 간단한 인터페이스와 사용법 덕분에, 러닝커브를 최소화 한 상태에서 활용할 수 있지않을까 생각하네요.

좌측이 entity extraction 을 위한 프롬프트이고, 우측이 entity(knowledge graph) 기반으로 evaluation data를 만드는 프롬프트 입니다.좌측은 엔티티 타입들이 눈에 띕니다. LLM에게 청크 내 특정 엔티티들만 추출해야한다라는 암묵적인 룰을 명시해준거죠.

이후에, 엔티티들간 semantic(relationship)은 LLM이 프롬프트 내 맥락을 반영하여 추출합니다. 이때 멘티분께서 질문 주신내용 하나가 인상깊었는데요. entity 뿐만아니라, relationship 타입도 지정해주는게 어떨까 라는 고민이 있다 혹시 그렇게 하게되면 장단이 어떨지 모르겠다.라는 고민이 담긴 질문이였습니다.

relationship 도 저희가 사전정의를 해줘버리면, 키워드 서치와 별반차이가 없기때문에(chunk 내 사전정의한 entity,relationship을 키워드서치하면 되는 부분이기때문) 최소한의 범주를 지정해주는 기능으로써 entity 를 입력해주는 것이다.

NER 프롬프트의 목적은 domain의 암묵지를 엔티티로 LLM에게 입력해주고, 인간이 인지하기 어려운 semantic 들을 relationship으로 발굴해내는게 LLM의 핵심 과업이다. 라고 답변을 드렸습니다. NER 프롬프트는 경우의수가 다양하기때문에, 어느게 최선일지라는 고민에서 나온 질문이였지 않았을까 싶네요. 다음은 우측 graph eval prompt 입니다.

다양한 knowledge graph로부터 도출된 엔티티기반으로 multi-hop question의 대표적인 케이스인 comparsion, Inference, Compositional 그리고 Bridge-Comparsion을 명시해주고 이 케이스들마다 example 들을 프롬프트에 넣어줍니다. 최종적으로 input 은 Team1에서 추출된 knowledge graph가 되겠죠. 바로 이 부분이 GraphRAG가 '잘' 하는 부분이라고 할 수 있습니다.

@hydra.main
hydra 데코레이터에서 config 들이 담긴 path를 입력해줍니다. 이때, 가장 상단의 config 파일에 입력해둔 default 값들을 가져옵니다. 이 default 값들은 prompt 들이 실제 어느 디렉토리에 위치해있는가가 적혀있습니다. 더불어 각 config 별로 특정 작업을 할 때 로깅할 수 있는 부분도 config에 입력을 할 수 있습니다. 때문에, config 조합별 성능 측정이 편리해집니다. 다음은,

cfg.prompt_entity.prompt_template.format
각 entity prompt 그리고 NER 을 수행하는 모델의 프롬프트 config 들을 불러옵니다. yaml에 key형태로 적혀있는 값들을 한번에 불러와서 object형태로 넣어줄 수 있는거죠.

cfg.model.model_name
NER을 수행하는 모델의 config를 불러옵니다. 어떤 모델을 활용할지, temperature를 어떻게 셋업할지 등을 모두 적용해서 활용할 수 있습니다.

chunk 결과물 기반 entity extraction prompt 활용 방식 설명

작업을 위해 데이터셋때문에 골치아플 일이 생기는 일을 방지하고자 S3 에 USTR 데이터셋을 적재해놓았고, 팀1,2,3 모두 동일한 환경에서, 리소스에 구애받지 않고 활용할 수 있게 코랩으로 베이스라인을 전달했습니다. 이전 주차에서 언급한 USTR 데이터셋 3개 중 press release 를 활용합니다.

Team2

팀2는 LightRAG engine과 Team1에서 만든 지식그래프를 적재한 Neo4j 를 관리하는 역할을 합니다. 엔진을 주로 관리하기에, 특정 상황별 엔진 동작에 따라 어떤 결과물이 도출되는지를 분석하는게 중요합니다. 예를들어, LightRAG engine 의 input으로 지식그래프가 입력이 되는데, 이때 입력되는 graph storage인 Neo4j에서는 해당 지식그래프를 조회하기 위해 얼마만큼의 시간, 메모리가 소요되었는지 latency 와 throughput 을 확인합니다. 프로덕션 레벨에서 어떻게 GraphRAG 튜닝을 하면 좋을지 고민하고 해결하는 방식을 배워가는게 Team2의 lesson learned 가 되겠죠.

팀2에서는 LightRAG (engine) <-> neo4j*dozerdb(backend) <-> FastAPI(Frontend) <-> Monitoring(Promethus & Grafana) 에 대해 이야기합니다.

진행하기에 앞서, 올려둔 서버 neo4j 에 적재된 스키마 설명을 합니다. 이전 주차에서는 그림으로 추상적인 맥락만 전달했기에, 실제로 Neo4j에선 어떻게 구현이 되어있고 이를 어떻게 조회할지 간단한 시나리오 함께 이야기했습니다. 데이터 크롤링은 너무 기초적인 내용이라 생략을 했고, 가져온 데이터셋을 어떻게 Document -> Event 로 연결했는지를 이야기합니다.

그리고 Supply chain graph 는 csv 파일로 존재하는데 이를 어떻게 적재하는지도 이야기하구요. 끝으로, 연관성이 없어보이는 2개의 그래프를 Event 라는 노드 즉, Snapshot노드를 통해 어떻게 연결이 되고 이 연결로 하여금 어떤 시나리오를 통해 우리가 GraphRAG를 장점을 잘 어필할 수 있을지 이야기합니다.

적재하기

적재 부분입니다. 이번 멘토링에선 Neo4j 의 Graph data science 모듈을 활용해서 Python kernel <-> bolt <-> Neo4j runtime 형태로 그래프를 구축했지만, 이 방식은 1.python kernel <-> bolt communication cost 2.serialization data load 라는 한계가 존재합니다.때문에, 현업에서는 dataframe 이 필수. python 을 통해 적재해야하는 조건이 아니라면, neo4j cypher-shell 을 통해 csv bulk load 하는게 효율적이기때문에 이에 대해서도 간략히 언급합니다.

loadcsv 관련 내용 : https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/

code review. NoSQL 에 속한 GDBMS 인 Neo4j 이기때문에, schema-less 합니다. 즉, table에서는 특정 데이터를 적재하려면 column , value type 까지 지정된 스키마에 insert하는 반면, NoSQL GDBMS는 그렇지않습니다. CREATE, MERGE 명령어로 간편하게 정합성 검토를 최소화한 상태로 데이터를 적재할 수 있는거죠. 때문에, schema-less 라는 걸 장점이자 단점으로 언급합니다.

이런 배경 가운데, 현재 설계한 스키마에는 event node는 날짜 property 외에 변동사항이 없기 때문에 constraint 를 지정해주어 앞서 이야기한 schema-less 즉 node 의 스키마를 고정해줍니다. 다른 프로퍼티나 엣지가 적재되는 트랜잭션이 발생하면 에러가 발생하는거죠. pydantic과 유사하다라고 봐주셔도 됩니다. 마이너할거 같지만, 시계열 데이터가 포함된 그래프 스키마에서는 중요한 요소이기때문에, 한 번 언급하고 넘어갑니다.

다음 그림은 적재된 결과물들 중 subgraph입니다. 여기에선 당연하게 Event 노드와 모두 연결이 되어있기에 product 나 plant 와 event 노드간 엣지에 특정 조건을 걸어주며 조회를 해야합니다. 여기에선 Factory issue 가 0이 아닌 즉, Factory issue 가 발생한 product기준으로 결과값을 가져옵니다.

각각 USTR document graph 와 supply chain graph 가 Event 라는 시간 기준을 담고있는 노드기반으로 연결됩니다. 스냅샷과 유사합니다. 이를 통해 특정 날짜에 발표가 있었을시, 해당 날짜 기준으로 distribution , sales order 등 supply chain에 무슨 변화가 있었는지를 볼 수 있습니다. 반대로는 supply chain에서 비정상적인 패턴이 발생했을시, 이후에 어떤 발표가 있었는지를 살펴볼 수가 있기에, 이 스키마는 상관성에서 더 나아가 인과성까지 유추할 수 있는 기능을 가집니다.

하나 시나리오를 예를 들어서 어떻게 활용할지 생각해볼까요?
위 서브그래프는 5월 9일에 USTR 워싱턴에서 발표했을때 때마침 1130 에 위치(아마도 국가인데 익명화한거 같네요)한 공장에서 생산된 Group S 에 속한 Product 가 각각 35를 유통 , 45의 공장 이슈 50개가 판매되었네요. 보기만해도 복잡하네요.

** 엣지 초록 생산량 , 노랑 ; 유통량 , 파랑 ; 공장 이슈 빨강 ; 주문량

공장에서 단일 상품만 생산하지 않겠죠? 다른 동일한 상품 그룹군에 속한 S 들또한 해당일에 어떤 일이 발생했는지 살펴보면 다음과 같습니다.

추가로, 해당 공장에서 생산된 물품들이 다른날(7월 20일 전후 7일) 엔 어떤 값들이 존재할지도 찾아보니 다음과 같습니다. 7월 20일로부터 5일 경과된 날 어떤 성명이 발표되었고 마찬가지로 Factory issue 가 있었네요.

Factory issue 가 존재하는 공장 , 상품부터 해당 공장으로부터 생산되는 동일 상품군의 상품들 그리고 성명 발표 결과 전후를 비교하며 상관성을 알아보기위한 시계열 관점까지 알아봤습니다. 이처럼 단일 서브그래프에서 파생될 수 있는 시나리오가 가지각색이기 때문에 , 이 데이터 분석 결과 값이 어떤 문제를 해결하는데 도움이 될 것인가 즉 , Team3에서 도출된 페르소나 문제 정의가 중요하다 라고 할 수 있습니다.

위 결과들 너무나도 유용해보였지만, 여기에는 LightRAG이슈가 존재했는데요. Document graph(Lexical) 을 특정해서 구현한 알고리즘이다보니, keyword search 부터 시작해서 vector search 그리고 마지막에 graph search 3가지 체이닝 구조를 가진 querying 시스템이였기에, 특정 날짜 기준으로 조회를 해야하는 temporal graph search 가 미비한 상태였습니다.

때문에, temporal cypher search 기능을 가진 agent를 개발해야하구요. 이 부분이 아마 오픈소스에 기여할 수 있는 영역이지 않을까 싶네요. 직접 활용하다보며 느낀 문제점들을 직접 구현하며 개선해가는 것. 멘토링의 취지가 여기에서 돋보이지 않을까 싶습니다.

Team3

팀3은 만들어진 Graph schema 기반으로 어떤 유저들이 활용하면 그 가치를 잘 전달할 수 있을지 기획하는 부분과 GraphRAG 평가 데이터셋을 만드는 역할을 합니다. GraphRAG 구현을 진행하다보면, 이 Graph Querying 결과물을 누가 활용하고, 기존 vector RAG pipeline 대비 GraphRAG pipeline 의 유용성을 증명하기 위해 무엇이 필요한가 라는 점을 고민하고 해결하는 팀입니다.

Graph 기획

팀3에서는 사전 조사로 이 데이터셋을 누가 활용하면 무슨 가치를 얻을 수 있을지 대략 10개의 직군을 조사했고, 다 적절한 직군이지만 가장 임팩트있는 직군부터 우선순위를 잡고 진행해보는게 좋겠다 라는 생각에 다음 4가지 직군을 현재 후보군으로 생각하고 진행하고 있습니다.

  1. 공급망 기획 (Supply Chain Planner)
  2. 구매 전문가 (Procurement Specialist)
  3. 리스크 및 규정 준수 관리자 (Supply Chain Risk & Compliance)
  4. 물류 담당자 (Logistics Coordinator/Manager)

동일한 목적으로 supply chain을 분석하겠지만, 각자 데이터셋을 바라보는 관점이 다를거란 가정을 둡니다. 이 다름이 결국 도메인이 되겠고 도메인은 결국 비즈니스를 위해 특정 직군이 데이터를 해석하고 활용하는 관점인 온톨로지가 되는거죠. 그럼 궁금하실텐데요.

동일한 데이터지만, 각 직군들이 바라보는 관점이 다를지를요. 때문에, 샘플 데이터셋 하나를 예시로 들고 LLM에게 중요한 엔티티를 추출해달라고 요청합니다. 아래 그림이 그 결과구요. 보시다시피, 각기 다른 entity type들이 결과로 나옴을 확인할 수 있습니다. 여기에서 다시 Team1의 과업으로 들어가면, 이 중요시하는 Entity type과 역할들이 NER prompt 의 핵심 재료라고 할 수 있습니다. 제가 늘 강조하는 prompt 에 business domain을 입혀야한다라는 것의 예시입니다.

Graph evaluation prompt 적용

서두에 언급한 Graph Evaluation 프롬프트를 적용한 결과도 이야기합니다.

(이 부분은 보완이 필요한 부분이 있어서 다음 주차에서 다루겠습니다..!)

문제 해결해야할 것들

구현하며 참 많은 에러들을 만났습니다. 여러분들의 디버깅에 도움을 드리고자 간단히 몇 가지만 이야기합니다.

docker-compose overview

도커 컴포즈는 다음과 구성되어 있습니다. 기존에는 neo4j <-> lightrag server만 있었지만, 모니터링을 위해 프로메테우스와 그라파나를 추가했습니다. Team2에서 쿼리를 분석하고 튜닝하려면 모니터링 도구가 필요하니깐요. 아래는 docker compose up 시 동작하는 컨테이너들입니다. 지금보니, 예전에 해봤으니 비슷할거 같은데? 별거 아니겠구나 했던 저를 반성하게 되네요. 굉장히 많은 시행착오가 있었습니다.

1.backend neo4j graph storage 모니터링을 위한 query.log 가 쌓이지않는다.

-> fastapi 로 run_query 그리고 프로메테우스 & 그라파나 대시보드로 대체

사실 모니터링 툴을 만들지 예상못했습니다. 그 이유는 query.log 가 DBMS 동작시 log폴더에 있어서 당연하게 찍히고, 파싱도 문제 없을줄 알았다. 하지만, 그렇지 않았음. 때문에 show transaction 내부 프로시저를 활용하거나 자체적으로 api swagger 에서 쿼리 입력하면 로깅해서 프로메테우스로 전달하는 방식을 택해야했습니다. show transaction을 로깅하다보면 cpu 병목이 걸릴거 같다라는 생각에, 이벤트 발생시 해당 이벤트만 수집하는 형태가 적합하다 생각해서 다음 2개의API를 만듭니다.run_neo4j_query(dozerdb) , run_query(lightRAG engine)

다행히도 별탈없이 구현이 된 결과물입니다. 총 화면을 3개부로 나누어 상단에는 쿼리들이 얼마나 latency가 발생했는지 , 하단 두개는 쿼리들 상세와 topk 쿼리들을 볼 수 있게 구성해뒀습니다. 모니터링이 목적이니까, 핵심들만 잘 담았다고 생각합니다.

2.lightrag 의 engine 과 backend graph storage가 연동되지 않는다.

-> customkg , test graphstorage

neo4j create database 이슈가 계속 발생했음. 결국 dozerdb 로 다시 올려야했습니다.

supply chain graph와 USTR graph 관련 내용을 lightRAG engine 모드를 다 동원해서 쿼리해봤는데, 그 결과가 나오지 않은 이유가 있었습니다. 바로 backend 에러였습니다. docker compose 에 Neo4j community 버전으로 셋업이 되어있어서 당연히 lightrag engine과 Neo4j가 붙어있을줄 알았습니다. query 결과가 계속 missing 으로 발생하기에, query가 문제인가하면서 evaluation dataset 을 계속 점검했었어요.

디버깅하며 저는 왜이렇게 무기력한 사람인가 라는 자괴감에 빠져있던 도중 backend 문제일수도 있겠는데?라는 생각을하고, tests/test_neo4j.py 로 찾아가서 실행합니다. 아니나다를까 test_neo4j 를 하는순간 multiple-database 에러가 발생하더군요. 야속하게도 중국어로 주석이 달려있고, 작동 확인을 위해 적재될 노드 엣지 조차도 중국어로 되어있어서, 이 부분을 영어로 한 번 전환했습니다.

test_graph_storage.py 를 실행하면 볼 수 있는 테스팅 옵션들..해석이 불가했음.

1을 선택하면 entity_type, keywords, description, entity_id 4가지 프로퍼티와 함께 다음 서브그래프가 적재 된다.

마이너하지만, 혹시나 비슷한 에러를 겪으실분들이 계실까하여 마지막으로 하나만 더 이야기해보겠습니다.

3.비동기로 동작하는 LightRAG query와 Fastapi 이벤트 루프 충돌

에러를 마주하기 전에 다음 3가지들을 리캡 할게요.

  • Python의 asyncio하나의 이벤트 루프(Event Loop) 위에서 async 함수(coroutine)를 관리합니다.
  • FastAPI는 자체적으로 asyncio 이벤트 루프 위에서 작동합니다.
  • 이벤트 루프는 하나의 루프 안에서만 await 체인을 타고 계속 실행돼야 합니다.

def query(...): loop = asyncio.get_event_loop() return loop.run_until_complete(self.aquery(...))

이미 돌아가고 있는 FastAPI의 루프 안에서
또 다른 루프를 강제로 실행(run_until_complete) 하려는 시도

RuntimeError: This event loop is already running

즉, "하나의 루프 안에서 또 다른 루프를 강제로 돌리려다 충돌난다"는 것입니다.
production level 을 고려한 나머지, 웬만한 함수들이 비동기형태로 구현이 되어있습니다. 이를 간과한 상태에서 구현한 나머지 FastAPI 기반 인터페이스에서 LightRAG의 query() 함수를 호출하려다가, 이미 실행 중인 비동기 이벤트 루프에서 run_until_complete()가 중첩 실행되어 런타임 에러가 발생했던거죠.여러분들은 이런 실수를 하지 않으시길 바랍니다..

여러 이슈들이 있었네요.. LightRAG 오픈소스를 활용하기 위해 고군분투하고 있는게 잘 느껴지실까요. 이 경험들이 여러분들에게 도움이 되었으면 하네요. 그럼 다음주에 뵙겠습니다. 즐거운 연휴되세요.

Subscribe for daily recipes. No spam, just food.