Files
Agent/agent_core.py

123 lines
4.9 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.
from typing import TypedDict, List, Optional, Annotated
import operator
from langchain_community.llms import Ollama
from langchain_community.vectorstores import Qdrant
from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langchain_core.messages import AIMessage, SystemMessage
from langchain.tools import tool
# from langchain.agents import AgentExecutor, create_react_agent
import numpy as np
# Определяем состояние агента
class AgentState(TypedDict):
messages: Annotated[List, add_messages] # История сообщений
knowledge_base: Optional[str] # Релевантные документы
current_step: str # Текущий шаг выполнения
needs_search: bool # Нужен ли поиск в RAG
final_answer: Optional[str] # Финальный ответ
# Инициализация LLM через Ollama
llm = Ollama(
model="qwen2.5-coder-16k:14b",
temperature=0.1, # Низкая температура для консистентности
num_predict=1024, # Максимальная длина ответа
)
# Создаем инструменты для агента
@tool
def search_knowledge_base(query: str) -> str:
"""Поиск информации в локальной базе знаний"""
# Здесь будет подключение к Qdrant
return "Найденная информация из базы знаний"
@tool
def calculate(expression: str) -> str:
"""Выполнение математических вычислений"""
try:
result = eval(expression)
return f"Результат: {result}"
except:
return "Ошибка в выражении"
@tool
def web_search(query: str) -> str:
"""Поиск в интернете (если нужно)"""
# Можно подключить локальный поиск через DuckDuckGo
return "Результаты поиска из интернета"
# Создаем граф агента
def create_agent_graph():
workflow = StateGraph(AgentState)
# Узел: анализ запроса
def analyze_query(state: AgentState):
messages = state["messages"]
last_message = messages[-1].content if messages else ""
# Простой анализ: проверяем, нужен ли поиск
search_keywords = ["информация", "документ", "найди", "ищи", "база знаний"]
needs_search = any(keyword in last_message.lower() for keyword in search_keywords)
return {
"needs_search": needs_search,
"current_step": "analyzing_query"
}
# Узел: поиск в RAG
def rag_search(state: AgentState):
if not state["needs_search"]:
return {"knowledge_base": None, "current_step": "generating_answer"}
# Получаем последний запрос
query = state["messages"][-1].content
# Здесь должен быть реальный поиск в Qdrant
# Пока заглушка
results = ["Документ 1: Информация о...", "Документ 2: Данные по..."]
return {
"knowledge_base": "\n".join(results),
"current_step": "generating_answer"
}
# Узел: генерация ответа
def generate_answer(state: AgentState):
messages = state["messages"]
knowledge = state.get("knowledge_base", "")
# Формируем промпт с контекстом
prompt = f"""Ты — интеллектуальный ассистент. Используй следующую информацию если она релевантна:
Контекст из базы знаний:
{knowledge}
История разговора:
{messages[-5:] if len(messages) > 5 else messages}
Текущий запрос: {messages[-1].content if messages else ''}
Ответь максимально полезно и точно:"""
response = llm.invoke(prompt)
return {
"final_answer": response,
"current_step": "completed",
"messages": messages + [AIMessage(content=response)]
}
# Добавляем узлы в граф
workflow.add_node("analyze", analyze_query)
workflow.add_node("search", rag_search)
workflow.add_node("generate", generate_answer)
# Определяем edges (переходы)
workflow.set_entry_point("analyze")
workflow.add_edge("analyze", "search")
workflow.add_edge("search", "generate")
workflow.add_edge("generate", END)
return workflow.compile()