가장 기본적인 에이전트로, llm의 추론(Reasoning)을 통해 행동(Acting)하고, 다시 행동의 결과로 추론(Reasoning)-행동을 반복하는 구조를 갖고 있다.
이 에이전트는 텍스트 생성을 넘어 환경과 상호작용하는 것이 주 목적임.
더 정확하게는 3단계로 동작한다.
💡 관련해서 ReAct 논문에 대해 살펴봐도 좋을 듯
레스토랑 메뉴와 관련된 챗봇으로 실습해보자. 이 챗봇은 RAG + 웹 검색 두가지를 지원한다.
첫번째로 RAG를 진행하는 도구
from langchain_chroma import Chroma
from langchain_ollama import OllamaEmbeddings
from langchain_core.tools import tool
from typing import List
embeddings_model = OllamaEmbeddings(model="bge-m3")
# Chroma 인덱스 로드
vector_db = Chroma(
embedding_function=embeddings_model,
collection_name="restaurant_menu",
persist_directory="./chroma_db",
)
# Tool 정의
@tool
def search_menu(query: str) -> List[str]:
"""레스토랑 메뉴에서 정보를 검색합니다."""
docs = vector_db.similarity_search(query, k=2)
formatted_docs = "\\n\\n---\\n\\n".join(
[
f'<Document source="{doc.metadata["source"]}"/>\\n{doc.page_content}\\n</Document>'
for doc in docs
]
)
if len(docs) > 0:
return formatted_docs
return "관련 메뉴 정보를 찾을 수 없습니다."
두번째는 웹 검색을 지원하는 도구
from langchain_community.tools import TavilySearchResults
# Tool 정의
@tool
def search_web(query: str) -> List[str]:
"""데이터베이스에 존재하지 않는 정보 또는 최신 정보를 인터넷에서 검색합니다."""
tavily_search = TavilySearchResults(max_results=3)
docs = tavily_search.invoke(query)
formatted_docs = "\\n\\n---\\n\\n".join(
[
f'<Document href="{doc["url"]}"/>\\n{doc["content"]}\\n</Document>'
for doc in docs
]
)
if len(docs) > 0:
return formatted_docs
return "관련 정보를 찾을 수 없습니다."