Langchain을 통한 개인블로그 RAG 프로젝트

Minchan Kim
Cloud Villains
Published in
8 min readMar 18, 2024

#RAG#Langchain#Streamlit#Milvus#Obsidian

# 대상

  • langchain을 통해 RAG를 구현한 방법에 관심이 있으신 분들
  • LLM 애플리케이션을 만들 때 고민거리에 대해 관심이 있으신 분들

# 개요

- 프로젝트 시작 동기: 습관을 위한 개인 동기 + LLM 관련 개인 흥미 + 개인 브랜딩 등에 도움이 될 것이라 생각
- 진행 중인 프로젝트 소개: 웹 플랫폼, LLM 애플리케이션 RAG
- 프로젝트 진행하면서 겪은 고민 트러블슈팅: 많은 제품과 추상화 된 내용을 빠르게 쓸 수 있는 레벨이 되기
- RAG에서 중요한 토큰 줄이기 구현: 모든 파일 업데이트가 아닌 개별 entity 업데이트
- 직접 제품을 만들면서 느낀 점: 고도화에는 끝이 없다

# 내용

# 프로젝트 시작 동기

해당 프로젝트는 기록하는 습관을 만드는 일 + LLM 애플리케이션 + 개인 브랜딩과 같은 요소들을 해결하기 위해 시작된 혼자 진행하고 있는 프로젝트입니다.

그래서 현재 두 개의 프로젝트가 진행 중 입니다.

  • 하나는 기록된 markdown기반 텍스트 문서 데이터 생산 및 관리를 위한 웹 플랫폼

https://murphybooks.me

  • 다른 하나는 이 데이터를 사용한 RAG를 사용할 수 있는 LLM 애플리케이션

https://murphybooks.streamlit.app

  • (현재 해당 애플리케이션은 동작이 자주 멈출 수도 있음)

운영 관리를 고려하여 두 배포 방식은 varcel과 streamlit cloud, milvus serverless 통해 인프라 관리를 솔루션에 맡김으로써 운영 관리와 비용을 줄이는 방법을 선택했습니다.

# 웹 플랫폼

기록하는 습관을 만들기 위해 플랫폼을 고민하면서 이것저것 써보았습니다. 노션, 에버노트, 티스토리, 깃헙 페이지 등…
고려한 부분은 마크다운, SEO 등이 있었지만 가장 중요한 것은 내가 이 기록을 다시 볼 때 지식을 얻을 수 있느냐 였습니다. 흔히 기록만 하는 Archive용도가 아니라 insight를 얻고자 하는 용도이기에 그 목표로 로컬 환경 기반 옵시디언을 선택하고, 무료 웹 배포 플러그인을 활용하게 됐습니다.

해당 방식을 통해 얻게 된 가장 큰 이점은 데이터 스키마의 자유로운 조작이었습니다. 후술 할 LLM 애플리케이션을 사용하기 위한 데이터 소스로 작성한 markdown파일을 사용하는데 데이터의 이름 ,데이터 path, metadata등의 빈번한 수정이 있었는데 로컬 환경기반이어서 이런 문제들을 해결할 수 있었습니다.

# LLM 애플리케이션 RAG

LLM 애플리케이션의 경우 명확한 목적이 중요했습니다. 목적의 경우 모델을 구현한 chatbot이기에 프론트와 백엔드를 배우는데 시간을 너무 많이 써버리지 않으면서도, 적당한 프로덕트의 기능이 구현가능해야한다는 점이 중요했습니다. 그 결과 지인 분의 추천을 받아 streamlit이라는 프레임워크와 널리 알려진 langchain을 선택하게 됐습니다. 두 프레임워크를 통해 LLM 관련 기능을 langchain으로 구현하며, 이 결과를 쉽게 stramlit을 사용해 프로덕트로 만들 수 있었습니다.

현재 해당 프로젝트는 계속 업데이트 중입니다. 예를 들어 Admin페이지를 구현하기 위한 방법, 메모리 관리, RAG에서 큰 단위와 작은 단위 필터링을 통한 구현 등…

# 프로젝트 진행하면서 겪은 고민 트러블슈팅

프로덕트를 만들다 보니 실제 현실에서 고민해야 할 것들을 배우게 됩니다.

모니터링 지표 고민하기: 페이지 조회수를 어떻게 할까부터 시작하여, 페이지 default 언어를 영어로 바꾸기까지
- 처음에는 페이지 조회수를 집계하기 위한 방법을 찾고, 그걸 모든 페이지마다 구현할 방법을 찾기 위한 조건을 고려하는 인사이트를 얻었습니다. 그리고 Google Analytics라는 적절한 플러그인을 발견해서 그걸 웹 플랫폼에 구현해보며 해당 플랫폼이 영어권에서 오는 사람이 많다는 것을 깨닫고 플랫폼 기본언어를 영어로 설정하기로 하였습니다. 페이지에 머무르는 시간이나 인기 있는 페이지 등도 알 수 있어서 프로덕트 운영에서 모니터링 지표에 대한 자그마한 insight를 얻었습니다
Langchain의 추상화: 문제가 생겼을 때 너무 추상화 되다보니 문제가…

- LLM 구현 시 langchain을 사용했는데 추상화가 너무 돼있어서 커스텀하는 부분에서 파라미터가 숨겨져있다던가 하는 문제가 있었습니다. langchain의 경우 타고 타고 타가다보며 문제를 해결해야하는 경우가 많았습니다. 프로덕션레벨에서의 langchain이 어려운 부분이 언급이 나오는데 특히 데이터의 파라미터가 너무 추상화 돼 있다던가, docs와 가이드 등에서 stream이나 async등의 고급기능이 예제가 부족하다던가 하는 부분도 많았습니다.

외부 VectorDB 사용 기준: 레퍼런스 많은 걸로…
- 외부 벡터 DB를 사용할 때 지속 가능한 운영을 위해 요금,확장성, 커스텀 가능 정도, 오픈소스여부 등의 기준을 세운다던가, 실제 구현 시 솔루션에 한정된 vectordb의 upsert특정 기능에 따라 auto_id와의 충돌로 본인의 환경에 맞춘 구현방법으로 해결하는 과정 등이 있었습니다. 조금만 더 설명을 추가하자면 일단 langchain에서의 milvus라는 벡터 DB 를 구현하는 가이드와 Milvus에서 langchain을 구현하기 위한 가이드가 다르기 때문에 이를 이해하는데 시간이 많이 걸렸습니다. 또한 Milvus로 구현시 upsert의 id를 명시할 경우 id를 명시하지 않아야한다는 auto_id와의 충돌이 발생하는데 이에 대한 설명이 많이 부족해 직접 테스트해보며 깨달을 수 있었습니다. 결론적으로는 저와 같은 생각을 하는 사람이 겪은 레퍼런스가 많았다면 낭비되는 시간을 많이 줄일 수 있었을텐데라는 아쉬움이 남았습니다.

# RAG에서 중요한 토큰 줄이기 구현

특히 가장 최근에 추가 된 업데이트는 LLM 애플리케이션에서 개별 아티클만 업데이트 하는 기능입니다.
RAG를 통해 웹 플랫폼의 context를 임베딩 하여 업데이트 할 때 나중에 페이지가 많아질수록 시간과 코스트가 우려됐습니다. 예를 들어 오늘 수정한 한 페이지를 업데이트하기 위해 모든 페이지를 임베딩하는 경우가 생길 수 밖에 없는 로직이었습니다. 특히 텍스트가 많아지면 많아질수록 문제는 커지기에 단일 파일만 업데이트하는 기능을 만들기로 했습니다.

해당 내용을 구성하기 위해 Milvus 공식 홈페이지에서 Entity에 대한 upsert를 먼저 찾아본 후 시도 하였습니다. 편한 기능이 있다면 바로 구현할 수 있을것이라 생각했지만, 실제로는 원하는 대로 동작하지 않았습니다. 그래서 여러 테스트 후 구조적으로 불가능하다는 것을 깨닫고 upsert가 아닌 delete insert형태로 구조를 만들게 됐습니다.

현재 기준으로 모든 파일에 대한 임베딩이 약 1500 토큰이 소모되는데, 내가 수정한 단일 파일만 업데이트를 한 경우 40 토큰이 소모됨으로서 속도와 비용을 크게 줄일 수 있습니다.

# 직접 제품을 만들면서 느낀 점

고도화에는 끝이 없다고 느껴집니다…

버전 정책, 운영 관리를 위한 선언적 방식, 최대한 결합도를 약하고 응집도를 높이는 모듈식 구성, 민감한 변수 다루기
그리고 가장 중요한 실제 프로덕트로서의 목적을 잃지 않으면서도 납득할만한 가치를 내기 위한 점 등…
예를 들어 지금 하면 좋긴 하지만 이걸 하기 위해서 전체적인 플랜이나 우선순위가 높은 것들이 느려지면 안되는데, 이를 적절한 타이밍을 느끼는 그런 감 같은 것이 필요한 것 같습니다.

스스로에 질문을 던지며 계속 업데이트 중인 프로젝트들입니다.
웹 플랫폼
- 모든 파일에 대한 description 작성 (base template을 위한) -> 수동
- 모든 아티클 파일(a,b,c와 같은 문자가 붙은)에 대한 내용 작성 -> 수동
- 유저 친화적인 UI Component 재배치 (설명글 제거, 버튼 방식을 통한 파일 접근, guestbook 플러그인)
- 중앙 관리 env작성 (필요한 정보들 기입.streamlit사용 시 사용 변수, milvus 벡터 db 사용 시 필요한 권한 및 변수 등)

LLM 애플리케이션
- 메모리 문제 해결을 통한 Chat방식 구현(비용, 속도, 확장성, 보안 등 운영을 위한 메모리 방식으로 선정)
- 유저 별 history 관리, 유저 별 세션 관리 기능 추가
- 모니터링을 통한 정확한 함수 또는 api 별 속도, 성능 파악 -> Langsmith 공부

이런 과정을 history로 남길 필요가 생기고, 그에 따라 버저닝 정책을 어떻게 가져가야 할 것인가 같은 부분도 고려됐습니다. 그래서 현재 major.minor.path-(LB,PY,FE,OB)라는 저만의 버저닝 정책 등도 만들게 되보네요
https://www.murphybooks.me/projects/library/manage/history-of-library/ (해당 내용을 기록하는 library 역사관)

## 결론
1. 개인 동기로 시작한 프로젝트가 웹 플랫폼과 LLM애플리케이션을 만드는 프로젝트로까지 이어지고 실제로 만들면서 얻을 수 있는 insight가 있다는 것을 배움
2. streamlit과 langchain을 통해 RAG를 구현하며 구현 도중 여러 솔루션을 사용해보고 트러블 슈팅하며 프로덕트를 구현
3. 레퍼런스가 많은 솔루션이 확실히 낭비되는 시간을 줄일 수 있으며, 고도화에는 끝이 없음

--

--