*사내의 서비스를 자동화 한 오늘의 집의 오리(ORI) 서비스의 아티클을 보면서 인상깊어 정리해야겠다고 생각했다!
오늘의집 전사 지식 탐색 시스템 ‘ORI(오리)’ 개발기 - 오늘의집 블로그
흩어진 사내 지식을 하나로 연결하다
www.bucketplace.com
✍🏻 핵심질문은, 어떻게 하면 AI가 맥락을 검색하게끔 만들까?
이 프로젝트는 단순히 챗봇 답변을 조금 더 똑똑하게 만드는 수준을 목표로 하지 않습니다.
중요한 것은, 사내 의사결정의 맥락을 결정하게 만드는 것이었습니다.
-오늘의 집 아티클 中
(1) '오늘의집'의 문제정의

해당 아티클을 읽어보면,
기존의 문제를 이렇게 정의내릴 수 있다.
질문의 형태가 반복적이고,
정보의 위치가 제각각이며,
정보의 공유가 정형화되어 있지 않고 예외로 처리되는 건들이 있었다는 점들.
사내에서 사용하고 있는 슬랙은 각각 다른 전사 Q&A 채널들이 존재하고,
이 채널들에는 비슷한 유형의 질문이 반복적으로 올라오게 된다. (사실 이건 모든 회사가 동일하지 않을까?)
답변하는 쪽에서는 이미 한 번 설명했던 내용을 다시 정리해 붙여 넣거나,
예전에 있었던 유사 이슈의 링크를 찾아와 공유하는 방식으로 대응하고 있었으며, 이 과정은 하루 수 시간 단위로 누적되는 경우도 적지 않았습니다. 한마디로, ‘아는 사람이 계속 직접 답해줘야만 굴러가는 구조’가 기본 상태가 된다.
이 문제의 원인은 정보의 위치가 제각각이라는 점이다.
어떤 요청이 승인 가능한지에 대한 공식 기준은 Notion에 문서화되어 있지만, 실제로 비슷한 요청이 과거에 어떤 조건으로 허용되었는지는 Slack 스레드에만 남아 있는 경우가 많았다.
반대로, Notion에는 절차가 적혀 있지 않은데 Slack 대화에는 “이 경우에는 예외로 처리해도 된다”는 사실상의 합의가 남아 있는 경우도 있다.
심지어 중요한 결정이 공개 채널이 아닌 개인 DM이나 소규모 스레드에서 내려진 뒤,그 맥락이 이후에 공유되지 않는 일도 있었다.
회사 입장에서는 분명히 ‘답’이 존재하지만, 그 답이 여러 소스에 나뉘어 저장되고
서로 연결되지 않아 한 번에 검색해서 맥락까지 따라가기 어렵다는 것이 반복 문의의 구조적 원인이다
(2) 챗봇이랑은 다른 서비스!
챗봇은 결국 정해진 답변을 응답하는 대화형태라,
오늘의 집에서 만든 ORI의 서비스를 챗봇 서비스라고 볼 수는 없다.
그 이유가 해당 글에 자세히 적혀 있는데
단순함 매뉴얼만 필요한 것이 아니라,
슬랙과 노션 등 사내 지식 소스에서 자동으로 수집, 연결해 각 조직이 이미 가지고 있는 경험과 기준을
다른 사람도 재사용할 수 있도록 전사 지식 인프라를 지향한다.
즉, 이 프로젝트는 단순히 챗봇 답변을 조금 더 똑똑하게 만드는 수준을 목표로 하는 것이 아니라, 중요한 목적은 사내 의사결정의 맥락을 검색 가능하게 만드는 것이다!
✍🏻💬 문제 정의 : 사내 Q&A의 반복과 정보 접근의 비효율
사내에서 나오는 질문들에는 결국 매뉴얼 뿐만 아니라 '실제 맥락'이 필요하다.
'지난달에는 어떻게 처리되었는지', '누가 최종 승인자였는지', '예외가 허용되었던적이 있는지'와 같은 실제 맥락이 필요하다.
결국 특정 팀만 알고 있던 운영 지식을 회사 전체가 필요할 때 찾아볼 수 있도록 해야하기 때문에,
Slack 과 Notion을 중심으로 사내 지식을 수집하고, 정규화하고 RAG 기반 아키텍쳐를 통해 기술적 선택을 하게 된 과정이 나와있다.
기존 사내챗봇과 각 조직의 Q&A채널에서 연결하여 전사적 인프라를 구축한 아티클이다.
참고로, 기존에도 비슷한 문제를 제기하여 문제를 해결하려던 과정이 있었다.
다만, 한계가 있었다!
(1) FAQ는 시간이 지나면 바로 낡아졌고, 실제 운영 맥락까지 반영하지는 못한다.
(2) 수동 검색은 결국 특정 사람의 기억력과 판단력에 의존하기 때문에, 담당자가 자리를 비우면 지식 자체가 멈춰 공유가 어렵다.
(3) 그럴듯하지만 실제로는 맞지 않는 답을 주는 경우가 반복적으로 생긴다.
즉, 기존 방식은 문서를 보여줄 수는 있지만, 실제로 회사 내부에서 어떤 식으로 결정하고 처리하는지에 대한 맥락까지는 전달하지 못하여, 한 번 질문하면 회사 안에서 이미 존재하는 모든 맥락을 가져올 수 있도록 하자.
따라서, 결정 사례, 최근 처리 이력, 공식 정책, 담당 범위, 후속 액션까지 연결하여 즉시 보여주자.
😶🌫️✏️ 어떤 방법으로 했을까?
→ RAG 기반 시스템으로의 전환
정책은 노션 문서 안에, 실제 사례와 예시는 슬랙 스레드 안에 존재하기 때문에 서로 다른 형태의 데이터가 혼재된 환경에서는 단순한 키워드 검색만으로는 충분하지 않다.
즉, 단순히 검색된 결과를 보여주는 것이 아니라, 관련 맥락을 불러와 의미 단위로 응답을 구성할 수 있게 해야한다.
RAG는 두 데이터 소스 간의 비정형성과 시차 문제를 흡수하여, 슬랙과 노션의 맥락을 하나의 응답 내에서 자연스럽게 엮을 수 있는 구조이다.
📍 파이프라인 구성
(1) 데이터 수집
(2) 전처리 및 마크다운 변환
(3) 메타데이터 부착
(4) AWS Bedrock Knowledge Base 인덱싱으로 데이터 등록
(5) Hybrid Search Reranking 과정을 통해 검색 품질을 향상
(6) Langraph 가 검색 결과를 조합해 답변 생성
(7) Langfuse가 이를 로깅, 평가하여 피드백 루프를 구성
🧐 이 과정에서 비정형 문서는 모두 마크다운으로 변환되어 일관된 형태로 처리되어,
전체 데이터 흐름이 단순하고 추적 가능한 형태로 유지된다.
결국 다른 문서이기 때문에 명확히 표준화하는 것이 중요하다고 생각했는데
역시 문서 포맷을 표준화하는 것을 알 수 있었다.
모든 문서는 마크다운(.md) 형태로 변환해 저장하며, 텍스트 기반 표현으로 통일했다고 한다.
노션에서 생성된 표는 구조를 유지한 채 마크다운 테이블 형태로 변환해 저장하도록 하고,
이러한 설계는 “모든 문서는 문자열로 표현될 수 있다”는 전제에 기반하며,
다양한 출처의 데이터를 하나의 검색 파이프라인으로 통합하기 위한 기초가 된다.
🧐 여기서 잠깐! RAG가 뭐지?
RAG는 Retrieval-Augmented Generation의 줄임말로,
검색 증강 생성 이라고 번역할 수 있다.
기존의 언어 모델에서 외부 지식을 결합하여 더욱 정확하고 최신의 정보를 제공하는 혁신적인 접근 방식이다.
RAG는 자연어 이해와 생성 분야에서 획기적인 성능을 보여주고 있으며,
다양한 응용 가능성으로 인해 많은 관심을 받고 있다.


RAG은 검색 증강 생성(Retrieval-Augmented Generation)의 약자로, 검색 증강 생성(RAG) 은 대규모 언어 모델의 출력을 최적화하여 응답을 생성하기 전에 훈련 데이터 소스 외부의 신뢰할 수 있는 기술 자료를 참조하도록 하는 프로세스이다. 쉽게 말해서 단순히 미리 학습된 데이터에 의존해 답변을 생성하는 것이 아니라, 외부 데이터베이스나 문서에서 관련 정보를 검색한 후, 이를 활용하여 답변을 생성하는 기법이다.

그러니까, 기존의 LLM은 방대한 양의 이미 학습된 데이터를 기반으로 하기 때문에,
최신의 기술이 업데이트 되기가 어렵다.
만약 이렇게 하려면 LLM 모델 자체를 최신 데이터로 재학습시켜야 하지만, 쉽지 않기 때문에 RAG를 사용하여 최신 문서나 데이터베이스에서 검색한 후, 최신 정보가 포함된 상태로 답변을 생성해야 한다
왜냐면! LLM은 결국 특정 데이터셋으로 학습을 하는 것이기 때문에, 특정 데이터셋으로 계속해서 재학습시켜주어야 하는데
RAG를 활용하면 LLM을 수정하지 않고도 활용할 수 있다.
즉, 외부 검색 시스템과 결합하여 필요한 정보를 즉시 반영할 수 있어서, 재학습보다는 RAG를 사용하여 검색한 정보를 기반으로 즉시 답변을 생성하는 것이 효율적인 것이다.
🪈다시 돌아와서, RAG를 활용한 파이프라인을 살펴보자.

각 문서에는 별도의 메타데이터 파일(.metadata.json)이 자동으로 생성되어 S3 내 동일 경로에 저장된다.
Bedrock KnowledgeBase는 이 파일을 자동으로 인식하고, 추가적인 필드 정보를 인덱싱 시 함께 수집한다.
별도의 커스텀 인덱싱 로직을 구현하지 않아도 되기 때문에, 구현 복잡도를 크게 줄일 수 있었다.
즉, 메타데이터를 정리하기 때문에,
fanout_urls 는 문서 간 참조 관계를 나타내고, domain_id는 Slack·Notion 등 데이터 출처를 명시한다.
이러한 구조는 향후 연관 문서 탐색이나 프로젝트 단위의 관계 기반 검색으로 확장할 수 있는 기반이 된다.
예를 들어 특정 주제의 Notion 문서에서 fanout_urls를 통해 Slack 대화 기록으로 연결되면,
단일 문서 중심의 검색을 넘어 ‘맥락적 탐색’이 가능해진다.

🔎🔎RAG를 차근차근 도입하여 구조를 잡아보자.
다시 정의를 들여다보자.
Retrieval(검색) - Augmented(증강) - Generation(생성)
즉,
Retrieval : 어딘가에 가서 요청된 무엇인가를 집어와서 가져오는 것
Augmented : 원래 것에 뭔가 덧붙이거나 보태는 것
Generation : 만들어내는 것. 프롬프트라고 하는 사용자 질문, 질의에 대한 응답을 텍스트로 생성하는 것
그렇다면 ORI를 개발하기 위해서도 이러한 방식을 고수하여 기술을 도입했다.
먼저, Retrieval은 문서에서 가져오는 것이기 때문에 '문서 탐색 정확도를 높이기' 위한 방식인 Hybrid Search 를 활용하였다.
짧은 검색어는 키워드 검색어, 장황한 질의는 벡터 검색이 강점을 가지는 경향이 있는데
키워드 기반 검색과 벡터 기반 검색을 결합하면 짧고 명확한 요청과 길고 복합적인 질문 모두에 안정적인 결과를 가질 수 있다.
아티클을 읽어보면, 초기에는
BM25 검색 결과
+
벡터 검색 결과
↓
RRF로 합쳐서 하나의 후보 리스트 만들기
를 유지했었는데 이때 문제는
- VPN 같은 짧은 검색어에서 오탐(틀린 문서가 높은 순위) 이 자주 나왔고
- 정답 문서가 있어도 순위가 너무 낮아 최종 출력에서 제외됨
(예: 상위 n개 문서만 가져오는데 정답이 8등 → 잘림)
따라서, 개선한 구조가
[B0] BM25 검색
[B1] 벡터 검색
↓
Hybrid Search (RRF로 결합)
↓
LLM Reranker (Cohere rerank-3.5)
↓
최종 정렬된 문서 리스트 → RAG 생성에 전달
즉, Hybrid Search(=BM25+벡터+RRF)의 결과가 나온 다음에
그 리스트를 다시 LLM이 판단해서 재정렬 하는 구조가 추가된 것이다.
Hybrid Search 로 1차 필터링을 하고, Reranker로 2차 정교 정렬이 이루어진다.
따라서, Reranker를 통해 초기 검색 결과의 순위를 재정렬하여 보다 관련성이 높은 정보를 상위에 배치한다.
이는 일반적인 검색 엔진이나 AI 기반 질의 응답 시스템에서 사용된다.
즉, Reranker는 문서와 쿼리 간의 유사도를 더욱 정확하게 측정하여 최적의 답변을 제공할 수 있도록 돕게 된다.
이를 통해 사용자는 보다 정확하고 유용한 정보를 빠르게 얻을 수 있어 초기 검색에서 놓쳤을 수 있는 문맥이나 의미적 관련성을 재확인해 정보 손실을 줄이고 보다 신뢰할 수 있는 결과를 제공한다.
👀 Slack 데이터는 어떻게 수집할까? Batch 에서 Event 기반으로
초기에는
슬랙 메시지를 5분마다 흝어서 가져오는 batch 방식
📍 문제!
- 실시간 반영이 안된다
- 메시지가 너무 많아지면 다 가져오지 못한다.
- Slack Api가 제한을 걸어버린다.
따라서 나중에는,
슬랙이 '메시지 생겼어!' 라고 먼저 알려주는 Event Subscription 방식
📍어떻게 적용되지?
- 서버가 필요 없이 Socket Mode로 실시간으로 안전하게 메시지를 받게 해준다.
- 이 메시지를 곧바로 S3 -> Lambda -> Bedrock 으로 홀려보낸다.
따라서! 완전한 실시간 슬랙이 RAG 자동화로 사용할 수 있게 된다.

(으아 사실 여기서 너무 어려워서 중간에 하차할 뻔했다 ㅎㅎ..)
다시 중간부터 읽어봤다.
1️⃣ Batch 방식이 무엇일까!

배치 처리는 컴퓨터가 주기적으로 대량의 반복적인 데이터 작업을 완료하기 위해 사용하는 방식이다.
즉, 한 번에 여러 작업을 처리하거나 여러 데이터 항목을 처리하기 위해 실행된다.
일정 주기나 특정한 일정에 따라 실행되는데, 예를 들어, 매일 밤에 특정 시간에 주문 데이터를 처리하거나, 매주 월요일에 주간 보고서를 생성하는 등의 작업이 포함된다.
하루 종일 주문을 수신하는 전자 상거래 시스템을 예로 들면, 시스템에서 주문을 그때그때 처리하는 대신
하루가 끝날 때 모든 주문을 수집하고 주문 처리 팀과 하나의 배치로 공유할 수 있다.
다만, 슬랙에서는
실시간으로 올라오는 메시지를 처리하기 어렵고, 슬랙의 메시지가 자주, 혹은 많이 늘어날수록 배치의 한계가 명확해진다.
2️⃣ 그래서 Event Subscription 방식은 무엇일까!

이벤트 기반 아키텍처에서 이벤트 구독자는 특정 이벤트 주제, 영역 또는 메시지와 관련된 변경 사항을 '수신'하고 지속적으로 푸시해서, 이벤트에 대한 메시지를 수신한다.
즉, 이벤트 구독자가 이벤트에 대한 정보를 수신하면 데이터베이스 업데이트, 이메일 전송, 스토리지 버킷에 오브젝트 추가, 워크플로우 요청 등 다양한 방법으로 정보를 처리하고 응답할 수 있다.
이벤트 기반 아키텍처에서 이벤트 구독자는 이벤트가 발생하는 순간 이벤트에 대해 파악할 수 있으므로
앱, 시스템, 사람, 기업이 실시간으로 대응할 수 있다.
즉, Slack Event Api 는 이런 이벤트를 바로 알려줄 수 있다.
- 누가 메시지 올렸다든지,
- 누가 댓글을 썼다든지,
- 파일을 업로드했다든지,
- 멘션이 들어왔다든지 등
슬랙이 먼저 알려줌으로써 실시간이 가능해지는 것이다.
3️⃣ 이번엔 Socket Mode가 무엇일까?
기본적으로 Slack 이벤트를 받으려면,
서버 URL을 슬랙이 호출하는 Webhook 구조이다.
그렇지만 기업 내부 환경에서는 외부에서 접근 가능한 서버 URL을 만들기 어렵고, 보안상 내부망만 허용되는 경우가 많다.
하지만 Socket Mode는 슬랙이 Websocket의 연결을 유지해서 이벤트를 푸시해주는 방식이기 때문에
서버가 필요하지 않고, 외부 인터넷에 대한 노출이 없이 내부에서 안전하게 이벤트 수신을 할 수 있게 되는 것이다.
즉 정리를 하자면!
슬랙 이벤트를 정확히 통신하기 위해
배치 방식이 아니라 이벤트 구독 기반으로 데이터를 수집하고,
서버와는 Web socket mode로 통신하게 되는 것이다.
👀 노션 데이터는 어떻게 수집할까? 너~무 많은 문서를 안정적으로 수집해야한다!
슬랙이 실시간성에 초점을 두었다면,
노션은 '방대한 양의 데이터'를 가져오는 것이 넘넘 중요했다.
노션은 많은 양의 데이터들을 쉽게 정리할 수 있고, 동시성을 가질 수 있어 사내에서 당연히 잘 사용하는 툴이지만,
이를 찾는데에는 꽤나 복잡한 구조를 가지고 있는 것이 사실이다.
따라서 오늘의 집도 비슷한 문제를 겪었고 문제를 해결하는 과정이 인상깊었다.
1️⃣ 전체 문서 탐색 크롤링을 하자! -Teamspaces 기반으로 계층적 크롤링을 활용해서!
노션은 그냥 크롤링을 하게 되면 페이지-페이지-페이지...로 이루어져있기 때문에 쉽게 크롤링이 되지 않는다.
또한 노션api에는 모든 문서를 조회할 수 있는 엔드포인트가 없다!
따라서, Teamspaces의 가장 최상위 페이지에서 시작해 하위 참고 (child pages) 를 재귀적으로 탐색하는 너비 우선 탐색 방식을 채택한다.
이렇게 층별로 쫙 흝는 BFS 방식으로 찾아, 이 방식은 추출 대상으로 포함될 필요가 없는 문서들은 걸러줄 수 있고, 최종적으로 Teamspaces에서부터, 생성된 약 40만 개 문서를 찾을 수 있었다.

BFS 방식은 가까운 인접 노드부터 탐색하는 방식으로 재귀함수가 쓰이지않고
queue를 사용해서 현재 노드에서 인접해 있는 노드를 queue에 넣는 방식으로 작동한다.
(해당 내용은 알고리즘에 가까워서.. 개념만 대충 이해하고 넘어갔다 ㅎㅎ)
2️⃣ 무한루프의 문제가 발생한다! -Redis 기반으로 중복 제거
결국 Notion문서들은 서로를 자유롭게 참고할 수 있었기 때문에
“문서 A → 문서 B → 문서 A”와 같은 순환 참조가 빈번했다고 한다.
또한 초기에느 BFS큐에 문서 reference를 단순 추가하였기 때문에 문제가 생겨도 크롤러가 종료되지 않았다고 한다.
따라서 Redis의 Set자료구조를 활용하여 각 문서의 처리상태 (성공, 실패 진행 중)을 기록했고 이미 처리된 것은 스킵하도록 하여
처음 본 문서만 처리하고, 이미 본 문서는 건너뛰게 하여 무한 루프 없이 효율적으로 탐색이 가능하도록 했다.
3️⃣ 데이터 구조 다양성과 API 구조의 불안정성 해결하기
노션의 문서 구조가 너무너무 제각각이기 때문에, (예를 들어 어떤 문서는 표만 있고, 글만 있거나, 혹은 어떤 방은 블록이 300개 들어있고 어떤 방은 또 다른 방으로 연결이 되어있거나...) 각 타입의 구조가 제각각이라 모든 경우를 일관되게 처리하기가 어렵다.
따라서 이를 해결하기 위해 Notion Parser를 구축하여 해결했다고 한다.
문서의 id를 기반으로 metadata를 조회하고
문서인지, 데이터 베이스인지 판단하고, 하위 페이지가 있는지 확인하고, 표인지 텍스트인지 이미지인지 분류하여 파싱 로직을 분기 처리하도록 설계했다고 한다.
하지만, API 가 불안정하기 때문에 특정 하위 콘텐츠를 가져오지 못하는 경우에는,
Fallback 로직을 추가하여 노션의 파일 다운로드 기능을 직접 호출하여 원문을 복원한다.
즉, api 가 실패하면, 노션의 문서 내보내기(Export) 기능을 대신 호출하여,
파일을 직접 다운로드 하여 원문을 복구하고 다시 문서 구조를 재조립하여 누락된 데이터까지 복원하는 구조이다.
4️⃣ 문서가 많아도 너~무 많아서 오래 걸린다!
아무리 그래도 많아도 너~무 많으니, 문서 1건을 처리하는 데에 평균 3.6초가 걸린다고 하였다.
단순하게 계산하면 약 40만 건을 처리하기 위해 약 400시간이 필요한 셈이니, 이 문제를 해소하기 위해 다중 APi Key를 병렬로 처리하는 구조를 설계했다고 한다.
즉, API Key를 여러 개 동시에 사용하여 속도를 증가하였으나, 매일 새로 생성되거나 수정되는 것까지 반영하기는 어려워서
Notion Search API의 최신순 정렬 기능을 활용하여 매일 생성, 수정된 문서를 수집하는 일 배치 작업을 추가 구축하여
문서 최신성이 하루 단위로 개선이 될 수 있도록 하였다.
따라서 전체 동기화는 주말 한 번,
평일에는 '오늘 수정된 문서'만 가져오게 하여 문서 최신성을 유지할 수 있었다.

관련된 성과가 인상깊었는데,
ORI 통합 이후, 전사적 활용률이 뚜렷하게 증가했습니다. 통합 이전 오집사는 회사의 맥락을 인식하지 못해 호출 빈도가 낮았으나, ORI가 슬랙과 노션 데이터를 연결하면서 퍼블릭 채널 기준 약 3배 이상 호출량이 증가했습니다.
퍼블릭 채널, 개인 메시지, 자동화 호출을 모두 포함하면 3개월간 누적 수천 건 규모의 질의가 처리된 것으로 추산됩니다.
이는 AI 응답이 단순한 참고 단계를 넘어 실제 업무 프로세스 일부로 정착되었음을 보여줍니다.
-오늘의 집 아티클
채널톡 AI 에이전트, 슬랙 에이전트가 나왔다는 아티클을 보고 찾아보다가
이런 글을 보게 되었는데
어쩌다보니 기술쪽에 집중되어서 보게 된 것 같다.ㅎㅎ...
그래도 원리를 이해해서 재미있었다!
다음엔 채널톡이나 슬랙 에이전트를 알아봐야겠당
참고
https://ssoontory.tistory.com/entry/%EB%B0%B0%EC%B9%98-%EC%9E%91%EC%97%85batch-job%EC%9D%B4%EB%9E%80
https://www.donga.com/news/Economy/article/all/20251118/132747428/1
https://aws.amazon.com/ko/what-is/retrieval-augmented-generation/
'AI' 카테고리의 다른 글
| [AI] 2026 AI 트렌드는 어떻게 될까? (1) | 2026.01.12 |
|---|---|
| [AI] 나노바나나, 나도 써봤다! (0) | 2025.12.03 |
| [AI] 검색(1)-이커머스 AI에이전트 (0) | 2025.11.12 |
| [AI] AI 검색 최적화, GEO 이해하기! (0) | 2025.11.02 |