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.asyncio import Redis SYSTEM_PROMPT = """ Ты — карьерный копилот для ИТ. Требования к ответам: - Пиши кратко (до 5–6 строк, буллеты приветствуются). - Всегда проверяй факты: бери данные о вакансиях только из контекста и ссылок в web-поиске. - В ответ всегда давай источники (минимум 1, лучше 2–3): ссылка на публичный канал или сообщение в телеграмме. - Если явно нет ссылки на сообщение о вакансии из telegram, собери ее из доступных chat_id и message_id. - Вакансии можно брать только из контекста, либо обращаться к web-поиску. Не давай вакансию, если у тебя нет о ней информации в контексте. - Всегда указывай дату вакансии и ссылку на нее. - Если данных недостаточно: честно скажи «не хватает надёжных источников», предложи расширить период/переформулировать, либо выполнить веб-поиск. - После полезного ответа предложи один мягкий следующий шаг. Отвечай простым текстом, не используй форматирование markdown. Если в контексте ты получил вакансию с форматированием markdown, то убери это форматирование. Поиск в интернете можно делать не более 1 раза за запрос пользователя. """ redis = Redis() llm = ChatOpenAI(model_name="gpt-5") embedding = DeepInfraEmbeddings(model_id="Qwen/Qwen3-Embedding-8B") vectorstore = Clickhouse(embedding, ClickhouseSettings(port=8123, username="default", password="", index_type="vector_similarity")) search_tool = DuckDuckGoSearchRun() async def get_relevant_vacancies(requirements: str): """Получает релевантные вакансии из базы данных по переданным требованиям.""" documents = await vectorstore.asimilarity_search(requirements, k=5) return "\n\n".join(document.page_content for document in documents) async def get_user_resume(user_id: int): """Получает резюме пользователя для подбора вакансий.""" resume_bytes = await redis.get(user_id) return resume_bytes.decode("utf-8") agent = create_agent( model=llm, tools=[search_tool, get_relevant_vacancies, get_user_resume], system_prompt=SYSTEM_PROMPT, checkpointer=InMemorySaver(), )