ДОбился запуска

This commit is contained in:
2026-04-01 00:53:21 +05:00
parent 0af4730b3c
commit 71891765fb
4 changed files with 80 additions and 75 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
__pycache__
agent_env
.lock
.sqlite
qdrant_data
qdrant_storage

View File

@@ -1,15 +1,13 @@
from typing import TypedDict, List, Optional, Annotated from typing import TypedDict, List, Optional, Annotated
import operator import operator
from langchain_community.llms import Ollama from langchain_community.llms import Ollama
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Qdrant from langchain_community.vectorstores import Qdrant
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
from langgraph.graph import StateGraph, END from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages from langgraph.graph.message import add_messages
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage from langchain_core.messages import AIMessage, SystemMessage
from langchain.tools import tool from langchain.tools import tool
from langchain.agents import AgentExecutor, create_react_agent # from langchain.agents import AgentExecutor, create_react_agent
import numpy as np import numpy as np
# Определяем состояние агента # Определяем состояние агента
@@ -22,16 +20,11 @@ class AgentState(TypedDict):
# Инициализация LLM через Ollama # Инициализация LLM через Ollama
llm = Ollama( llm = Ollama(
model="llama3.2:3b", model="qwen2.5-coder-16k:14b",
temperature=0.1, # Низкая температура для консистентности temperature=0.1, # Низкая температура для консистентности
num_predict=1024, # Максимальная длина ответа num_predict=1024, # Максимальная длина ответа
) )
# Инициализация эмбеддингов
embeddings = OllamaEmbeddings(
model="nomic-embed-text", # Хорошие локальные эмбеддинги
)
# Создаем инструменты для агента # Создаем инструменты для агента
@tool @tool
def search_knowledge_base(query: str) -> str: def search_knowledge_base(query: str) -> str:
@@ -127,6 +120,3 @@ def create_agent_graph():
workflow.add_edge("generate", END) workflow.add_edge("generate", END)
return workflow.compile() return workflow.compile()
# Создаем и компилируем граф
agent_graph = create_agent_graph()

View File

@@ -1,6 +1,10 @@
import gradio as gr import gradio as gr
import asyncio import asyncio
import os
from typing import List from typing import List
from agent_core import create_agent_graph
from local_knowledge_base import LocalKnowledgeBase
from langchain_core.messages import HumanMessage
class AgenticRAGInterface: class AgenticRAGInterface:
def __init__(self, agent_graph, knowledge_base): def __init__(self, agent_graph, knowledge_base):
@@ -61,8 +65,15 @@ class AgenticRAGInterface:
self.conversation_history = [] self.conversation_history = []
return "История очищена", "" return "История очищена", ""
# Инициализируем базу
kb = LocalKnowledgeBase()
# Загружаем документы (если есть)
if os.path.exists("./documents"):
kb.load_documents("./documents")
# Создаем интерфейс # Создаем интерфейс
interface = AgenticRAGInterface(agent_graph, kb) interface = AgenticRAGInterface(create_agent_graph(), kb)
# Создаем Gradio интерфейс # Создаем Gradio интерфейс
def create_gradio_interface(): def create_gradio_interface():

View File

@@ -1,19 +1,28 @@
import os import os
from qdrant_client import QdrantClient from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct from qdrant_client.models import Distance, VectorParams, PointStruct
from langchain_community.document_loaders import TextLoader, PyPDFLoader, DirectoryLoader from langchain_community.document_loaders import (
from langchain.text_splitter import Language TextLoader,
PyPDFLoader,
DirectoryLoader,
)
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
from langchain_community.embeddings import OllamaEmbeddings
class LocalKnowledgeBase: class LocalKnowledgeBase:
def __init__(self, collection_name="documents", persist_dir="./qdrant_data"): def __init__(self, collection_name="documents", persist_dir="./qdrant_data"):
# Инициализируем клиент Qdrant # Инициализируем клиент Qdrant
self.client = QdrantClient( self.client = QdrantClient(
path=persist_dir, # Локальное хранение path=persist_dir, prefer_grpc=True # Локальное хранение
prefer_grpc=True
) )
self.collection_name = collection_name self.collection_name = collection_name
self.embeddings = embeddings
# Инициализация эмбеддингов
self.embeddings = OllamaEmbeddings(
model="nomic-embed-text", # Хорошие локальные эмбеддинги
)
# Создаем коллекцию если её нет # Создаем коллекцию если её нет
self._create_collection() self._create_collection()
@@ -28,22 +37,21 @@ class LocalKnowledgeBase:
collection_name=self.collection_name, collection_name=self.collection_name,
vectors_config=VectorParams( vectors_config=VectorParams(
size=768, # Размерность эмбеддингов nomic-embed-text size=768, # Размерность эмбеддингов nomic-embed-text
distance=Distance.COSINE distance=Distance.COSINE,
) ),
) )
print(f"Создана коллекция {self.collection_name}") print(f"Создана коллекция {self.collection_name}")
def load_documents(self, directory_path: str): def load_documents(self, directory_path: str):
"""Загрузка документов из директории""" """Загрузка документов из директории"""
loaders = { loaders = {
'.pdf': PyPDFLoader, ".pdf": PyPDFLoader,
'.txt': lambda path: DirectoryLoader(path, glob="**/*.txt"), ".txt": lambda path: DirectoryLoader(path, glob="**/*.txt"),
'.docx': lambda path: DirectoryLoader(path, glob="**/*.docx"), ".docx": lambda path: DirectoryLoader(path, glob="**/*.docx"),
'.hpp': lambda path: TextLoader(path, encoding='utf-8'), ".hpp": lambda path: TextLoader(path, encoding="utf-8"),
'.cpp': lambda path: TextLoader(path, encoding='utf-8'), # добавить ".cpp": lambda path: TextLoader(path, encoding="utf-8"), # добавить
'.h': lambda path: TextLoader(path, encoding='utf-8'), # добавить ".h": lambda path: TextLoader(path, encoding="utf-8"), # добавить
'.cc': lambda path: TextLoader(path, encoding='utf-8'), # добавить ".cc": lambda path: TextLoader(path, encoding="utf-8"), # добавить
} }
all_documents = [] all_documents = []
@@ -65,7 +73,7 @@ class LocalKnowledgeBase:
language=Language.CPP, language=Language.CPP,
chunk_size=1000, chunk_size=1000,
chunk_overlap=200, chunk_overlap=200,
length_function=len length_function=len,
) )
chunks = text_splitter.split_documents(all_documents) chunks = text_splitter.split_documents(all_documents)
@@ -91,26 +99,20 @@ class LocalKnowledgeBase:
"text": doc.page_content, "text": doc.page_content,
"source": doc.metadata.get("source", "unknown"), "source": doc.metadata.get("source", "unknown"),
"page": doc.metadata.get("page", 0), "page": doc.metadata.get("page", 0),
"file_type": "cpp" "file_type": "cpp",
} },
) )
points.append(point) points.append(point)
# Пакетная загрузка каждые 100 точек # Пакетная загрузка каждые 100 точек
if len(points) >= 100: if len(points) >= 100:
self.client.upsert( self.client.upsert(collection_name=self.collection_name, points=points)
collection_name=self.collection_name,
points=points
)
points = [] points = []
print(f"Индексировано {i+1} документов") print(f"Индексировано {i+1} документов")
# Загружаем оставшиеся # Загружаем оставшиеся
if points: if points:
self.client.upsert( self.client.upsert(collection_name=self.collection_name, points=points)
collection_name=self.collection_name,
points=points
)
print(f"Индексация завершена. Всего документов: {len(documents)}") print(f"Индексация завершена. Всего документов: {len(documents)}")
@@ -120,26 +122,22 @@ class LocalKnowledgeBase:
query_embedding = self.embeddings.embed_query(query) query_embedding = self.embeddings.embed_query(query)
# Ищем в Qdrant # Ищем в Qdrant
search_result = self.client.search( search_result = self.client.query_points(
collection_name=self.collection_name, collection_name=self.collection_name,
query_vector=query_embedding, query=query_embedding,
limit=top_k limit=top_k,
) )
# Форматируем результаты # Форматируем результаты
results = [] results = []
for hit in search_result: for hit in search_result.points:
results.append({ results.append(
"text": hit.payload["text"], {
"score": hit.score, "text": hit.payload["text"],
"source": hit.payload.get("source", "unknown") "score": hit.score,
}) "source": hit.payload.get("source", "unknown"),
}
)
return results return results
# Инициализируем базу знаний
kb = LocalKnowledgeBase()
# Загружаем документы (если есть)
if os.path.exists("./documents"):
kb.load_documents("./documents")