안녕하세요, 기술 열정가 여러분! 오늘은 Web Research Agent와 인공지능 기반 도구들이 지식 탐색을 혁신하는 흥미진진한 세계에 몸을 담궈보겠습니다. LangChain Retrieval는 그 중에서도 혁신적인 도구로서 주목 받고 있습니다. 이 블로그에서는 우리가 웹 리서치 에이전트를 구축하려고 시작한 여정, 그 에이전트의 변화, 그리고 효율적이고 매우 구성 가능한 리트리버의 탄생에 대해 이야기하겠습니다. 그러니 여러분의 좋아하는 음료를 따라서 쉬고, 준비되셨나요? 그러면 출발해봅시다!
사실 이 연구 방법은 2020년 RAG라는 논문에서 소개된 원리를 차용한 것입니다.
이와 관련하여 리뷰한 블로그 글들이 있으니, 참고해보시면 좋을거 같습니다.
- https://dajeblog.co.kr/논문-리뷰-internet-augmented-dialogue-generation/
- https://dajeblog.co.kr/10-ai-chatbot-sentient-인터넷-검색-엔진-살펴보기/
- https://dajeblog.co.kr/47-2/
탐구
Web Research Agent의 미래
웹 리서치는 인간의 학습과 문제 해결에 핵심적인 역할을 항상 해왔습니다. 우리는 gpt-researcher와 AI 검색 엔진과 같은 프로젝트들이 어떻게 웹 리서치의 미래를 상상하는지에 대해 큰 관심을 가지고 있었습니다. 호기심과 야망을 가지고 우리는 웹 리서치 에이전트를 구축하기 위해 움직였는데, 이 에이전트는 인공지능 연구원처럼 인터넷의 방대한 정보를 자동으로 찾아내는 것이었습니다.
웹 리서치는 킬러 LLM(언어 모델) 응용 분야 중 하나입니다. Greg Kamradt는 이를 자신이 원하는 인공지능 도구 중 하나로 강조하며, gpt-researcher와 같은 오픈 소스 저장소는 인기가 높아지고 있습니다. 우리는 이에 도전하기로 결정했고, 처음에는 다른 많은 사람들처럼 웹 리서치 에이전트를 구축하는 것을 목표로 하였습니다. 그러나 연구자들은 어딘가 다른 곳에 도달했습니다. 상당히 간단한 리트리버가 효과적이고 쉽게 구성 가능하다는 것을 알게 되었습니다. 예를 들어, PrivateGPT와 같은 프로젝트에서 인기 있는 “프라이빗” 모드로 실행할 수 있습니다. 이 블로그에서는 langchain 연구자들의 탐구와 생각 과정, 구축 방법, 그리고 다음 단계에 대해 이야기합니다.
- gpt-researcher
- GPT Researcher란? 다양한 작업에 대한 포괄적인 온라인 연구를 위해 설계된 자율 에이전트입니다.
- 에이전트는 관련 리소스, 개요 및 교훈에 초점을 맞추기 위한 사용자 지정 옵션을 사용하여 상세하고 사실적이며 편향되지 않은 연구 보고서를 생성할 수 있습니다. AutoGPT 및 최근 Plan-and-Solve 논문 에서 영감을 받은 GPT Researcher는 속도 및 결정론 문제를 해결하여 동기식 작업과 달리 병렬화된 에이전트 작업을 통해 보다 안정적인 성능과 향상된 속도를 제공합니다.
- 우리의 임무는 AI의 힘을 활용하여 개인과 조직에 정확하고 편향되지 않은 사실에 입각한 정보를 제공하는 것입니다.
- gpt-researcher 개발 배경
- 수동 조사 작업에 대한 객관적인 결론을 내리려면 올바른 리소스와 정보를 찾는 데 몇 주가 걸릴 수 있습니다.
- 현재 LLM은 환각의 위험이 큰 과거 및 오래된 정보에 대해 교육을 받았기 때문에 연구 작업과 거의 관련이 없습니다.
- 웹 검색을 가능하게 하는 솔루션(예: ChatGPT + 웹 플러그인)은 경우에 따라 피상적인 결론이나 편향된 답변을 초래하는 제한된 리소스만 고려합니다.
- 선택한 리소스만 사용하면 연구 질문이나 작업에 대한 올바른 결론을 결정할 때 편견이 생길 수 있습니다.
- 아키텍쳐
- 주요 아이디어는 “기획자”와 “실행” 에이전트를 실행하는 반면, 플래너는 연구할 질문을 생성하고 실행 에이전트는 생성된 각 연구 질문을 기반으로 가장 관련성이 높은 정보를 찾습니다. 마지막으로 플래너는 모든 관련 정보를 필터링 및 집계하고 연구 보고서를 생성합니다. 에이전트는 gpt3.5-turbo-16k 및 gpt-4를 모두 활용하여 연구 작업을 완료합니다.
- 주어진 작업에 대한 객관적인 의견을 함께 형성하는 일련의 연구 질문을 생성합니다.
- 각 연구 질문에 대해 주어진 작업과 관련된 정보에 대한 온라인 리소스를 스크랩하는 크롤러 에이전트를 트리거합니다.
- 스크랩한 각 리소스에 대해 관련 정보를 기반으로 요약하고 소스를 추적합니다.
- 마지막으로 요약된 모든 소스를 필터링 및 집계하고 최종 연구 보고서를 생성합니다.
- GPT Researcher란? 다양한 작업에 대한 포괄적인 온라인 연구를 위해 설계된 자율 에이전트입니다.
- privateGPT
- LLM의 기능을 사용하여 인터넷 연결 없이 문서에 질문하십시오. 100% 비공개, 어떠한 데이터도 실행 환경을 벗어나지 않습니다. 인터넷 연결 없이 문서를 수집하고 질문할 수 있습니다. 이를 활용하면 내부 데이터 유출 없이도 ChatGPT를 사용할 수 있습니다.
초기 접근법과 도전 과제
우리의 초기 에이전트는 프롬프트와 도구 세트를 받아서 인간 리서처처럼 독립적으로 인터넷을 탐색할 수 있도록 설계되었습니다. 에이전트는 관련 페이지를 검색하고, 해당 페이지의 가치 있는 정보를 추출하며, 그 결과를 일관되게 제시할 수 있도록 도구로 갖추어져야 했습니다. 하지만 계속 진행하면서 우리는 반복적인 검색 프로세스가 인간의 탐색과 유사하게 느리고 비효율적이라는 공통적인 문제에 부딪혔습니다.
- 위에서 언급한 gpt-researcher와 AI 검색 엔진(perplexity.ai)과 같은 프로젝트들은 웹 리서치가 어떻게 다시 이미지화될 수 있는지에 대한 초기 모습을 제공합니다. 많은 사람들과 마찬가지로, 우리도 먼저 웹을 자율적으로 스캔하는 에이전트를 만들기 위해 프롬프트와 도구 세트를 주고 발을 내딛었습니다! 이를 위해서, 먼저 다음과 같은 도구들이 명확하게 필요했습니다.
- 페이지를 검색하고 반환하는 기능
- 반환된 페이지의 전체 내용을 스크래핑하는 기능
- 페이지에서 관련 정보를 추출하는 기능
- 이러한 도구들을 이용하여, 에이전트는 인간이 하는 것과 비슷한 작업을 근사할 수 있었습니다: 주제를 검색하고, 선택된 링크를 선택하고, 유용한 정보를 얻기 위해 링크를 스캔하고, 반복적인 탐사를 통해 검색에 돌아올 수 있었습니다. 우리는 에이전트를 만들었고, 이러한 도구들을 적용했습니다… 하지만, 인간과 비슷하게 반복적인 검색 과정에서 천천히 해맸다는 사실을 발견했습니다!
개선
인공지능의 병렬 처리 활용
도전에 직면한 후, 우리는 인공지능이 독특하게 활용할 수 있는 장점을 깨닫게 되었습니다. 바로, 병렬 처리입니다. 여러 검색을 동시에 시작하고, 결과적으로 병렬로 여러 페이지를 “읽을” 수 있었습니다. 물론 순차적으로 진행하는 경우에는 첫 번째 순차 검색에서 필요한 모든 정보가 있는 경우 효율성이 떨어질 수 있습니다. 하지만 AI 연구원이 필요로 하는 복잡한 질문의 경우, 이러한 위험이 어느 정도 완화되었습니다. 우리는 이러한 접근 방법을 지원하기 위해 기본 도구들을 추가했습니다.
리서처에서 리트리버로의 진화
여러 페이지에서 병렬로 수집한 정보를 가지고 가장 관련성 높은 청크들을 검색하고, 그것들을 LLM의 컨텍스트 창으로 로드하는 것이 합리적으로 보였습니다. 이 단계에서 우리는 우리의 에이전트가 리트리버로 변화하고 있다는 사실을 깨달았습니다!
Retrieval
Retrieval 프로세스 개요
이제 랑체인 리트리버가 내부에서 어떻게 작동하는지 살펴봅시다. 먼저, LLM을 사용하여 여러 관련 검색 쿼리를 생성합니다. 그런 다음 리트리버는 각 쿼리에 대한 검색을 실행하고, 병렬로 여러 개의 쿼리당 상위 K개의 링크를 선택합니다. 선택된 링크들로부터 정보를 수집하고, 이를 벡터 스토어에 인덱싱합니다.
글로 보니 작동 순서가 햇갈리시죠? 이를 아래와 같이 순서대로 정리해보았습니다.
- LLM을 사용하여 여러 관련 검색 쿼리를 생성합니다 (하나의 LLM 호출).
- 각 쿼리에 대해 검색을 실행합니다.
- 각 쿼리당 상위 K개의 링크를 선택합니다 (여러 검색 호출로 병렬 처리).
- 선택된 모든 링크들로부터 정보를 로드합니다 (페이지를 병렬로 스크래핑).
- 이러한 문서들을 벡터스토어에 인덱싱합니다.
- 원본으로 생성된 각 검색 쿼리에 가장 관련성이 높은 문서를 찾습니다.
이러한 단계들은 리트리버가 검색 증강 생성(flow used for retrieval augmented generation)에 따라 수행됩니다.
LangChain Retrieval: 설정과 사용법
우리는 리트리버를 다양하게 구성하여 사용하기 쉽게 만들고 싶었습니다. 따라서 LangChain 리트리버를 만들었고, 사용법에 대한 포괄적인 설명서를 제공했습니다. 이러한 유연성은 사용자들이 자신의 필요에 맞게 리트리버를 맞춤화하는 것을 가능케 합니다.
프로세스 시각화와 검증
리트리버가 어떻게 작동하는지 시각적으로 살펴볼까요? 예를 들어, “LLM Powered 자율 에이전트는 어떻게 작동합니까?”라는 질문을 물었습니다. LangSmith를 사용하여 리트리버의 프로세스를 시각화하고 검증해 볼 수 있었습니다. 이를 통해 리트리버가 신뢰할만한 소스로부터 정보를 로드하고 검색하는 능력을 확인했습니다.
“프라이빗” 모드에서 실행하기
개인 정보 보호는 매우 중요합니다. 그래서 우리는 리트리버를 “프라이빗” 모드에서 실행할 수 있도록 설정했습니다. 사용자들은 LlamaV2와 GPT4all 임베딩을 사용하여 민감한 데이터를 안전하게 유지할 수 있습니다.
응용
Streamlit UI를 통한 리트리버 구현
리트리버를 사용자 친화적으로 만들기 위해 간단한 Streamlit UI로 래핑했습니다. 몇 줄의 코드만으로 사용자들은 LLM, 벡터스토어, 그리고 선택한 검색 도구를 구성할 수 있으며, 이를 통해 리트리버의 힘을 간단하게 활용할 수 있습니다.
import streamlit as st
from langchain.callbacks.base import BaseCallbackHandler
from langchain.chains import RetrievalQAWithSourcesChain
from langchain.retrievers.web_research import WebResearchRetriever
@st.cache_resource
def settings():
# Vectorstore
import faiss
from langchain.vectorstores import FAISS
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.docstore import InMemoryDocstore
embeddings_model = OpenAIEmbeddings()
embedding_size = 1536
index = faiss.IndexFlatL2(embedding_size)
vectorstore_public = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})
# LLM
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(model_name="gpt-3.5-turbo-16k", temperature=0, streaming=True)
# Search
from langchain.utilities import GoogleSearchAPIWrapper
search = GoogleSearchAPIWrapper()
# Initialize
web_retriever = WebResearchRetriever.from_llm(
vectorstore=vectorstore_public,
llm=llm,
search=search,
num_search_results=3
)
return web_retriever, llm
class StreamHandler(BaseCallbackHandler):
def __init__(self, container, initial_text=""):
self.container = container
self.text = initial_text
def on_llm_new_token(self, token: str, **kwargs) -> None:
self.text += token
self.container.info(self.text)
class PrintRetrievalHandler(BaseCallbackHandler):
def __init__(self, container):
self.container = container.expander("Context Retrieval")
def on_retriever_start(self, query: str, **kwargs):
self.container.write(f"**Question:** {query}")
def on_retriever_end(self, documents, **kwargs):
# self.container.write(documents)
for idx, doc in enumerate(documents):
source = doc.metadata["source"]
self.container.write(f"**Results from {source}**")
self.container.text(doc.page_content)
st.sidebar.image("img/ai.png")
st.header("`Interweb Explorer`")
st.info("`I am an AI that can answer questions by exploring, reading, and summarizing web pages."
"I can be configured to use different moddes: public API or private (no data sharing).`")
# Make retriever and llm
web_retriever, llm = settings()
# User input
question = st.text_input("`Ask a question:`")
if question:
# Generate answer (w/ citations)
import logging
logging.basicConfig()
logging.getLogger("langchain.retrievers.web_research").setLevel(logging.INFO)
qa_chain = RetrievalQAWithSourcesChain.from_chain_type(llm,
retriever=web_retriever)
# Write answer and sources
retrieval_streamer_cb = PrintRetrievalHandler(st.container())
answer = st.empty()
stream_handler = StreamHandler(answer, initial_text="`Answer:`\n\n")
result = qa_chain({"question": question},callbacks=[retrieval_streamer_cb, stream_handler])
answer.info('`Answer:`\n\n' + result['answer'])
st.info('`Sources:`\n\n' + result['sources'])
혹시 streamlit이 무엇인지 모르는 분들을 위해 간단하게 설명드리겠습니다.
Streamlit은 데이터 과학자들과 개발자들이 인터랙티브한 웹 애플리케이션을 쉽게 만들 수 있도록 도와주는 Python 라이브러리입니다. Streamlit을 사용하면 데이터 시각화, 머신 러닝 모델 배포, 데이터 분석 결과 공유 등을 간단하게 웹 앱으로 변환할 수 있습니다.
Streamlit은 간결하고 직관적인 문법을 제공하여 사용자가 빠르게 웹 앱을 구축할 수 있도록 합니다. 일반적인 Python 스크립트에서 사용하는 함수들을 사용하여 웹 앱의 UI를 구성하고, 시각화를 추가하고, 데이터 처리를 수행할 수 있습니다.
Streamlit의 주요 특징은 다음과 같습니다:
- 간편한 사용: Streamlit은 쉬운 문법과 도구를 제공하여 웹 앱을 만들기 쉽고 빠르게 할 수 있습니다. 기존의 Python 스크립트에 몇 줄의 코드만 추가하면 됩니다.
- 인터랙티브한 웹 앱: 사용자와 상호작용하는 웹 앱을 만들 수 있습니다. 사용자 입력을 받고, 그에 따라 즉각적으로 결과를 업데이트할 수 있습니다.
- 다양한 컴포넌트: Streamlit은 다양한 종류의 컴포넌트를 지원합니다. 버튼, 텍스트 박스, 슬라이더, 표, 그래프 등 다양한 형태의 UI 요소를 쉽게 추가할 수 있습니다.
- 빠른 반영: 코드 수정 후 새로고침을 하지 않고도 변경사항이 바로 반영되어 빠르게 개발할 수 있습니다.
- 무료 오픈 소스: Streamlit은 오픈 소스 라이브러리이며, 무료로 사용할 수 있습니다.
- 머신 러닝 모델 지원: 머신 러닝 모델을 쉽게 통합하여 배포할 수 있으며, 사용자가 모델의 입력을 제어하고 결과를 확인할 수 있습니다.
Streamlit은 데이터 과학자, 개발자, 비전문가 모두에게 유용한 도구로서 웹 앱을 통해 데이터를 시각화하고 공유하는 등 다양한 용도로 사용됩니다.
streamlit과 파이썬 코드를 활요하여 아래와 같이 만들 수 있습니다.
결론
이 놀라운 여정을 마무리하며, 우리는 웹 리서치 에이전트를 구축하려는 노력이 효율적이고 맞춤 가능한 리트리버의 탄생으로 이어졌음을 깨달았습니다. 현재의 리트리버만으로도 강력하지만, 더 많은 특성을 가미할 수 있다는 것을 인정합니다. 예를 들어, 초기 검색 후에 LLM에게 추가 정보가 필요한지 묻거나, 최종 답변을 구성하는 데 여러 “작성” 및 “수정” 에이전트를 사용할 수 있습니다. 이러한 아이디어가 흥미롭다면, 프로젝트에 기여하시기 바랍니다.
처음에는 자율 웹 리서치 에이전트를 구축하려는 시도로 시작되었지만, 결국은 상당히 간단하고 효율적이며 사용자 정의 가능한 리트리버로 진화하게 되었습니다. 그러나 이것은 단지 첫 번째 단계에 불과합니다. 이 프로젝트에는 다음과 같은 많은 에이전트적 특성들을 추가하는 것이 도움이 될 수 있습니다:
- 초기 검색 후에 LLM에게 더 많은 정보가 필요한지 묻기
- 최종 답변을 작성하는 데 여러 “작성” 및 “수정” 에이전트 사용하기
이러한 추가 사항 중에 흥미로운 것이 있다면, 기본 레포지토리에 PR을 참여해보시는 것도 추천드립니다.
또한, Bard나 Perplexity.ai와 같은 대형 모델로 호스팅되는 AI 검색은 극도로 성능이 우수하지만, 웹 리서치에 대한 더 가벼운 경량 도구들도 중요한 장점을 가지고 있습니다. 이러한 장점으로는 개인 정보 보호(예: 데이터를 외부에 공유하지 않고 노트북에서 로컬로 실행 가능), 구성 가능성(예: 특정 오픈 소스 구성 요소 선택 가능), 그리고 관찰 가능성(예: LangSmith와 같은 도구를 사용하여 “뒷단”에서 무슨 일이 일어나고 있는지 확인) 등이 있습니다.
FAQ (자주 묻는 질문)
Q1: 랑체인 리트리버를 다른 AI 모델과 통합할 수 있나요?
물론! 리트리버는 높은 구성 가능성을 가지고 있어서 여러분이 선택한 다양한 AI 모델과 도구들과 원활하게 통합될 수 있습니다.
Q2: 리트리버는 복잡한 연구 쿼리에 적합한가요?
네, 랑체인 리트리버는 AI 연구원의 도움이 필요한 복잡한 질문을 처리하는 데 능숙합니다. 병렬 처리 능력으로 정보 검색에 강력한 솔루션을 제공합니다.
Q3: “프라이빗” 모드에서 실행하는 것은 사용자에게 어떤 이점이 있나요?
“프라이빗” 모드에서 실행하면 데이터를 안전하게 유지하고, 데이터를 외부적으로 공유하지 않고 사용자의 장치에서 실행할 수 있습니다.
Q4: 리트리버를 학문적인 연구 목적으로 사용할 수 있나요?
물론 가능합니다! 리트리버의 효율성과 구성 가능성은 학문적인 연구에 매우 적합하며, 연구자들이 빠르고 편리하게 관련 정보에 접근할 수 있도록 도와줍니다.
Q5: 랑체인 리트리버 프로젝트에 기여하려면 어떻게 해야 하나요?
우리는 커뮤니티의 기여를 환영합니다! 리트리버를 개선하거나 에이전트적 특성을 추가하고 싶다면, 기초 레포지토리에 PR을 열어주세요. 함께 웹 리서치의 미래를 함께 만들어봅시다