diff --git a/main.py b/main.py new file mode 100644 index 0000000..bdab7c2 --- /dev/null +++ b/main.py @@ -0,0 +1,100 @@ +"""Deep research agent: веб-поиск, виртуальные файлы, экспорт на диск. + +Основано на курсе deep agents from scratch: +https://github.com/langchain-ai/deep-agents-from-scratch/blob/main/notebooks/4_full_agent.ipynb +""" +from __future__ import annotations + +import os +import sys +from pathlib import Path + +from dotenv import load_dotenv +from deepagents import create_deep_agent +from deepagents.backends import LocalShellBackend +from langchain_openai import ChatOpenAI + +from export_tools import DEFAULT_OUTPUT_DIR, WORKSPACE_DIR, export_virtual_files, export_workspace_to_disk +from web_tools import get_page_content, web_search + +load_dotenv() + +SYSTEM_PROMPT = """\ +Ты исследовательский deep-агент (стиль deep agents from scratch). + +Твоя работа: +1. Искать информацию в интернете через web_search и при необходимости get_page_content. +2. Сохранять результаты во ВИРТУАЛЬНЫЕ файлы через write_file (например /research/query.md, + /research/summary.md, /research/sources.txt). Не оставляй всё только в чате. +3. Используй write_todos для плана исследования. +4. В КОНЦЕ обязательно вызови export_virtual_files с target_dir="./output", + чтобы выгрузить виртуальные файлы в реальную файловую систему. + +Правила: +- Один инструмент за шаг, если возможно. +- В файлах — структурированные заметки: запрос, источники, выводы. +- Отвечай на русском. +""" + + +def build_agent(): + WORKSPACE_DIR.mkdir(parents=True, exist_ok=True) + backend = LocalShellBackend( + root_dir=str(WORKSPACE_DIR.resolve()), + virtual_mode=True, + inherit_env=True, + ) + llm = ChatOpenAI( + model=os.getenv("OPENAI_MODEL", "openai/gpt-oss-20b:free"), + base_url=os.getenv("OPENAI_BASE_URL", "https://openrouter.ai/api/v1"), + api_key=os.getenv("OPENAI_API_KEY", "fake"), + temperature=0.2, + ) + return create_deep_agent( + model=llm, + tools=[web_search, get_page_content, export_virtual_files], + system_prompt=SYSTEM_PROMPT, + backend=backend, + ) + + +def run_research(query: str) -> None: + agent = build_agent() + print(f"Запрос: {query}\n") + print("Агент работает (поиск → виртуальные файлы → экспорт)...\n") + + result = agent.invoke( + { + "messages": [ + { + "role": "human", + "content": ( + f"Исследуй тему: {query}. " + "Сохрани заметки в виртуальные файлы и в конце выгрузи их через export_virtual_files." + ), + } + ] + } + ) + + last = result["messages"][-1] + print("\n--- Ответ агента ---") + print(getattr(last, "content", last)) + + # Гарантированный экспорт, даже если агент не вызвал инструмент + exported = export_workspace_to_disk(output_dir=DEFAULT_OUTPUT_DIR) + print(f"\n--- Файлы на диске ({DEFAULT_OUTPUT_DIR}) ---") + if exported: + for path in exported: + print(f" {path}") + else: + print(" (пусто — агент не создал файлов в agent_workspace)") + + +def main() -> None: + query = " ".join(sys.argv[1:]).strip() or "LangGraph deep agents и context engineering" + run_research(query) + + +if __name__ == "__main__": + main()