import os from langchain.agents import create_agent from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import InMemorySaver from langchain_community.tools import DuckDuckGoSearchRun from langchain_community.vectorstores import Clickhouse, ClickhouseSettings from langchain_community.embeddings import DeepInfraEmbeddings from redis import Redis from redis.asyncio import Redis as AsyncRedis SYSTEM_PROMPT = """ Ты — карьерный копилот для ИТ. Требования к ответам: - Пиши кратко (до 5–6 строк, буллеты приветствуются). - Всегда проверяй факты: бери данные о вакансиях только из контекста и ссылок в web-поиске. - В ответ всегда давай источники (минимум 1, лучше 2–3): ссылка на публичный канал или сообщение в телеграмме. - Если явно нет ссылки на сообщение о вакансии из telegram, собери ее из доступных chat_id и message_id. - Вакансии можно брать только из контекста, либо обращаться к web-поиску. Не давай вакансию, если у тебя нет о ней информации в контексте. - Всегда указывай дату вакансии и ссылку на нее. - Если данных недостаточно: честно скажи «не хватает надёжных источников», предложи расширить период/переформулировать, либо выполнить веб-поиск. - После полезного ответа предложи один мягкий следующий шаг. Отвечай простым текстом, не используй форматирование markdown. Если в контексте ты получил вакансию с форматированием markdown, то убери это форматирование. Поиск в интернете можно делать не более 1 раза за запрос пользователя. """ redis = Redis(host=os.getenv("REDIS_HOST", "127.0.0.1")) async_redis = AsyncRedis(host=os.getenv("REDIS_HOST", "127.0.0.1")) llm = ChatOpenAI(model_name="gpt-5") embedding = DeepInfraEmbeddings(model_id="Qwen/Qwen3-Embedding-8B") vectorstore = Clickhouse(embedding, ClickhouseSettings( host=os.getenv("CLICKHOUSE_HOST", "127.0.0.1"), port=8123, username="default", password="", index_type="vector_similarity", )) search_tool = DuckDuckGoSearchRun() def get_relevant_vacancies(requirements: str): """Получает релевантные вакансии из базы данных по переданным требованиям.""" formatted_vacancies = "" for document in vectorstore.similarity_search(requirements, k=5): metadata = document.metadata formatted_vacancies += f"chat_id = {metadata['chat_id']}\ntelegram_id = {metadata['telegram_id']}\n{document.page_content}" return formatted_vacancies def get_user_resume(user_id: int): """Получает резюме пользователя для подбора вакансий.""" resume_bytes = redis.get(user_id) return resume_bytes.decode("utf-8") if resume_bytes else "" agent = create_agent( model=llm, tools=[search_tool, get_relevant_vacancies, get_user_resume], system_prompt=SYSTEM_PROMPT, checkpointer=InMemorySaver(), )