import logging import os from typing import Optional, Dict from langchain_core.messages import SystemMessage, HumanMessage from core.llm_router import get_llm try: from tools.web_search import general_web_search except ImportError: from backend.tools.web_search import general_web_search logger = logging.getLogger(__name__) class ResearchAgent: """ Sub-Agent badawczy Projektu TITAN. Zadaniem tego agenta jest przeszukiwanie sieci (OSINT / Web Search) oraz interpretacja wyników w przypadku braku danych w dokumencie. Zastępuje człowieka w trybie pełnej automatyzacji, znacznie zwiększając skuteczność. """ def __init__(self): # Inicjalizacja LLM dla analizy wyników badawczych. self.llm = get_llm(task_type="creative") # Używamy creative/standard def deep_search(self, query: str, context: str) -> str: """ Głębokie poszukiwanie danych w zewnętrznych bazach i sieci, oraz ich synteza przy użyciu LLM. """ logger.info(f"🔎 [Research Agent TITAN] Rozpoczęto głębokie wyszukiwanie dla: {query}") # 1. Wykonanie rzeczywistego wyszukiwania w sieci search_results = general_web_search(query) # 2. Jeśli nie znaleziono lub brak klucza, zwracamy stosowną informację, # ale możemy spróbować odpowiedzieć z wiedzy LLM z uwzględnieniem kontekstu. if "Błąd" in search_results or "Brak klucza" in search_results: logger.warning(f"[Research Agent TITAN] Problem z wyszukiwarką: {search_results}") search_context = "Nie udało się pobrać aktualnych danych z sieci z powodu braku dostępu do API wyszukiwania." else: search_context = f"Wyniki wyszukiwania:\n{search_results}" system_prompt = ( "Jesteś zaawansowanym Agentem Badawczym OSINT. Twoim zadaniem jest dostarczenie " "wyczerpujących i merytorycznych informacji na podstawie podanego kontekstu projektu " "oraz wyników wyszukiwania z sieci.\n\n" "Zasady:\n" "1. Twoim celem jest odpowiedź na brakujące zapytanie (pytanie o brakujące dane).\n" "2. Wykorzystaj informacje z 'Wyników wyszukiwania', jeśli są dostępne.\n" "3. Oprzyj się na 'Kontekście projektu', aby odpowiedź była dopasowana do specyfiki firmy i projektu.\n" "4. Jeśli z danych sieciowych i kontekstu nie da się jednoznacznie określić faktów (np. precyzyjnego przychodu małej firmy), " "zaproponuj profesjonalne i wiarygodne oszacowanie lub standardowe dla branży wartości rynkowe i zaznacz, że to szacunek, " "aby wniosek dotacyjny mógł zostać wygenerowany jako pełny szkic (użyj znaczników np. [SZACOWANY_PRZYCHÓD: 1.5 mln PLN]).\n" "5. Pisz wyłącznie w języku polskim, stylem profesjonalnym, odpowiednim do wniosków unijnych i biznesplanów." ) human_content = f"Pytanie o brakujące dane: {query}\n\nKontekst projektu:\n{context}\n\n{search_context}" try: response = self.llm.invoke([ SystemMessage(content=system_prompt), HumanMessage(content=human_content) ]) final_answer = response.content if hasattr(response, 'content') else str(response) logger.info("[Research Agent TITAN] Zakończono syntezę wyników badawczych.") return final_answer except Exception as e: logger.error(f"[Research Agent TITAN] Błąd generowania odpowiedzi przez LLM: {e}") return f"Nie udało się wygenerować odpowiedzi analitycznej na temat: {query}. Spróbuj użyć [BRAK DANYCH]." research_agent = ResearchAgent()