Агент с RAG‑памятью: tools.py
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
# tools.py
|
||||||
|
"""
|
||||||
|
Модуль с инструментами для агента.
|
||||||
|
В файле определены два инструмента:
|
||||||
|
1. search_knowledge_base – семантический поиск в Qdrant.
|
||||||
|
2. add_to_knowledge_base – добавление документа (с чанками) в базу.
|
||||||
|
|
||||||
|
Инструменты реализованы через декоратор @tool из langchain.tools,
|
||||||
|
что позволяет автоматически использовать их в агентах LangChain.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
# ──────────────────────── Зависимости ────────────────────────
|
||||||
|
from langchain.embeddings.ollama import OllamaEmbeddings
|
||||||
|
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||||
|
from langchain.vectorstores.qdrant import QdrantVectorStore
|
||||||
|
from langchain.tools import tool
|
||||||
|
|
||||||
|
# ──────────────────────── Конфигурация ────────────────────────
|
||||||
|
# Путь к локальной базе Qdrant (предполагается, что она уже запущена)
|
||||||
|
QDRANT_URL = "http://localhost:6333"
|
||||||
|
COLLECTION_NAME = "knowledge_base"
|
||||||
|
|
||||||
|
# Создаём один экземпляр векторного хранилища и эмбеддеров,
|
||||||
|
# чтобы не создавать их каждый раз при вызове инструментов.
|
||||||
|
embeddings = OllamaEmbeddings(model="nomic-embed-text")
|
||||||
|
vectorstore = QdrantVectorStore(
|
||||||
|
client_kwargs={"url": QDRANT_URL},
|
||||||
|
collection_name=COLLECTION_NAME,
|
||||||
|
embedding_function=embeddings.embed_query, # функция для получения эмбеддингов
|
||||||
|
)
|
||||||
|
|
||||||
|
# ──────────────────────── Инструмент: поиск ────────────────────────
|
||||||
|
@tool("search_knowledge_base",
|
||||||
|
description="Семантический поиск в базе знаний. "
|
||||||
|
"Возвращает список строк с найденными документами и их релевантностью.")
|
||||||
|
def search_knowledge_base(query: str, max_results: int = 5) -> List[Tuple[str, float]]:
|
||||||
|
"""
|
||||||
|
Выполняет семантический поиск по запросу.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query (str): поисковый запрос.
|
||||||
|
max_results (int): максимальное количество результатов.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Tuple[str, float]]: список кортежей (текст документа, релевантность).
|
||||||
|
"""
|
||||||
|
# similarity_search_with_score возвращает [(Document, score), ...]
|
||||||
|
results = vectorstore.similarity_search_with_score(query, k=max_results)
|
||||||
|
return [(doc.page_content, score) for doc, score in results]
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────── Инструмент: добавление ────────────────────────
|
||||||
|
@tool("add_to_knowledge_base",
|
||||||
|
description="Добавляет новый документ в базу знаний. "
|
||||||
|
"Документ разбивается на чанки и сохраняется с метаданными.")
|
||||||
|
def add_to_knowledge_base(content: str, title: str) -> str:
|
||||||
|
"""
|
||||||
|
Добавляет текстовый контент в Qdrant.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content (str): полный текст документа.
|
||||||
|
title (str): заголовок/имя документа.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: сообщение об успешном добавлении и количестве чанков.
|
||||||
|
"""
|
||||||
|
# Разбиваем документ на чанки
|
||||||
|
splitter = RecursiveCharacterTextSplitter(
|
||||||
|
chunk_size=1000,
|
||||||
|
chunk_overlap=200,
|
||||||
|
separators=["\n\n", "\n", " ", ""],
|
||||||
|
)
|
||||||
|
chunks = splitter.split_text(content)
|
||||||
|
|
||||||
|
# Создаём объекты Document с метаданными
|
||||||
|
from langchain.schema import Document
|
||||||
|
|
||||||
|
documents: List[Document] = [
|
||||||
|
Document(page_content=chunk, metadata={"title": title})
|
||||||
|
for chunk in chunks
|
||||||
|
]
|
||||||
|
|
||||||
|
# Добавляем векторные представления в Qdrant
|
||||||
|
vectorstore.add_documents(documents)
|
||||||
|
|
||||||
|
return f"Документ '{title}' добавлен. Количество чанков: {len(chunks)}"
|
||||||
Reference in New Issue
Block a user