Files
task-6a1864f7-ekzamen-rag-a…/main.py
T

143 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
from pathlib import Path
# Загрузка переменных окружения (TAVILY_API_KEY)
try:
from dotenv import load_dotenv
load_dotenv()
except Exception: # pragma: no cover
pass
# Основные зависимости LangChain и Ollama
from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_chroma import Chroma
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.tools import tool
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.messages import HumanMessage
# Импорт вспомогательных функций из других файлов проекта
try:
from vectorstore import create_vectorstore, load_documents # noqa: F401
except Exception: # pragma: no cover
# Если модули не найдены – создаём простые заглушки для запуска примера
def create_vectorstore(persist_directory="./chroma_db"):
return Chroma(
persist_directory=persist_directory,
embedding_function=OllamaEmbeddings(model="nomic-embed-text"),
)
def load_documents(directory, vectorstore):
pass
# --------------------------------------------------------------------------- #
# 1. Создаём векторное хранилище и загружаем документы (если ещё нет)
# --------------------------------------------------------------------------- #
CHROMA_DIR = "./chroma_db"
DOCS_DIR = "./documents"
vectorstore = create_vectorstore(persist_directory=CHROMA_DIR)
# Если коллекция пустая – загрузим документы из каталога
if not vectorstore.get_ids():
load_documents(DOCS_DIR, vectorstore)
# --------------------------------------------------------------------------- #
# 2. Определяем инструменты агента
# --------------------------------------------------------------------------- #
@tool("search_local_kb")
def search_local_kb(query: str, top_k: int = 3) -> str:
"""
Семантический поиск по локальной базе знаний (ChromaDB).
Возвращает объединённый текст найденных сегментов.
"""
retriever = vectorstore.as_retriever(search_kwargs={"k": top_k})
docs = retriever.get_relevant_documents(query)
if not docs:
return "Ничего не найдено в локальной базе."
# Собираем контент из документов
content = "\n\n".join(doc.page_content for doc in docs)
return f"[Local KB]\n{content}\nИсточник: chromadb"
@tool("web_search")
def web_search(query: str) -> str:
"""
Поиск в интернете через Tavily.
Возвращает краткое резюме найденных результатов.
"""
from tavily import TavilyClient
client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
results = client.search(query=query, max_results=3)
if not results:
return "Ничего не найдено в интернете."
snippets = "\n\n".join(
f"{res['title']}\n{res['content']}" for res in results
)
return f"[Web Search]\n{snippets}\nИсточник: tavily"
# --------------------------------------------------------------------------- #
# 3. Создаём агента с выбором источника
# --------------------------------------------------------------------------- #
llm = ChatOllama(model="llama3")
tools = [search_local_kb, web_search]
agent = create_openai_tools_agent(
llm=llm,
tools=tools,
system_message=(
"Ты помощник, отвечающий на вопросы. "
"Если вопрос относится к содержимому локальных документов, используй инструмент search_local_kb; "
"если требуется актуальная информация из интернета – web_search. "
"В ответе обязательно указывай источник (chromadb или tavily)."
),
)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=False)
# --------------------------------------------------------------------------- #
# 4. CLI чат‑цикл
# --------------------------------------------------------------------------- #
def main() -> None:
print("=== RAG-агент с ChromaDB и Tavily ===")
print("Введите 'exit' для выхода.\n")
while True:
try:
query = input("Запрос: ").strip()
except (KeyboardInterrupt, EOFError):
print("\nВыход.")
break
if not query or query.lower() == "exit":
print("До свидания!")
break
# Запускаем агента
response = agent_executor.invoke({"input": query})
answer = response.get("output", "")
# Выводим ответ и источник (если он есть в тексте)
source_line = ""
if "[Local KB]" in answer:
source_line = "Источник: chromadb"
elif "[Web Search]" in answer:
source_line = "Источник: tavily"
print("\nОтвет:")
# Убираем маркеры из ответа
cleaned_answer = answer.replace("[Local KB]\n", "").replace(
"[Web Search]\n", ""
)
print(cleaned_answer.strip())
if source_line:
print(f"\n{source_line}\n")
if __name__ == "__main__":
main()