
Предлагаю лаконичный гид по созданию мультиагентного чат-бота на основе LangGraph, RAG и долговременной памяти — инструмент для вашего бизнеса или личных проектов.
Внедрение эффективной системы памяти критично для ИИ-агента: она сохраняет ход диалога и используемые ранее данные, что позволяет поддерживать контекст и персонализацию.
На практике я часто сталкивался с тем, что долгое общение с ИИ-ассистентом обрывается из-за потери контекста — похоже, будто собеседник страдает амнезией и каждый раз начинает разговор заново.
В результате:
- агент не учитывает ваши предпочтения;
- теряется сквозная логика в долгосрочных проектах;
- приходится повторять одни и те же объяснения;
- невозможно выстроить доверительный диалог.
В общении людей ценятся общие воспоминания и понимание друг друга, и ИИ-ассистенты заслуживают такой же «памяти».
К счастью, решения для постоянного хранения данных существуют, и многие разработки с открытым исходным кодом уже позволяют решить эту задачу.
Одно из таких решений — Mem0, обеспечивающее надёжную долговременную память для LLM: система сохраняет информацию между сессиями, делая диалог более естественным и персонализированным.
Параллельно рекомендую сервис BotHub! — без VPN, с поддержкой российских карт, и подарок от меня: 100 000 бесплатных токенов для старта.
Теперь небольшой демо-пример работы живого чат-бота.

1. Инициализация рабочего пространства
При вводе запроса вызывается функция chat_with_memories:
- создаётся пустая среда с полями для воспоминаний, контекста документов и ответа;
- устанавливаются стартовые параметры ИИ-агента.
2. Извлечение воспоминаний
Агент ищет в памяти до 50 релевантных записей по запросу, формирует из них текстовый блок и добавляет в контекст.
3. Получение новостного контента
Через RSS-ленты Seeking Alpha, Yahoo Finance и Investing.com собираются актуальные статьи:
- парсинг через
requestsиBeautifulSoup; - выбор самых релевантных фрагментов для контекста.
4. Генерация ответа
ИИ объединяет пользовательский запрос, извлечённые воспоминания и новостной контент в системную подсказку и формирует ответ (~50 слов, по одному предложению на строку).
5. Сохранение истории
Динамика диалога сохраняется в памяти, чтобы при следующем запросе агент мог опираться на предыдущие сообщения.
Mem0 и другие решения для памяти
Ранее основной подход к «памяти» в ИИ — RAG (Retrieval-Augmented Generation), который извлекает данные из внешних источников. Однако у RAG нет встроенного хранилища, и для долгосрочного контекста требуется постоянное обновление базы.
Mem0 решает эту проблему, автоматически фиксируя любые пользовательские данные — текст, изображения, голосовые заметки, PDF — и формируя непрерывную базу знаний. Это обеспечивает стабильный контекст и более точные ответы в длительных сессиях.
Готовы кодить?
Установите зависимости:
pip install -r requirements.txt
Импортируем ключевые библиотеки:
import os
import logging
import warnings
from dotenv import load_dotenv
from mem0 import Memory
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.document_loaders import DirectoryLoader, UnstructuredFileLoader
from langchain_community.vectorstores import FAISS
from langchain_community.document_compressors import FlashrankRerank
from langchain.retrievers import ContextualCompressionRetriever
from langchain_core.messages import HumanMessage, SystemMessage
from langgraph.graph import StateGraph, END
from typing import TypedDict
from scraper import fetch_seekingalpha_trending_news
1. Веб-скрапер
Функция fetch_seekingalpha_trending_news() парсит RSS-ленты, скачивает страницы с новостями и сохраняет до 30 статей в ./data/news.txt.
import feedparser
import requests
from bs4 import BeautifulSoup
def get_folder_path(pre_path, folder_name):
path = f'{pre_path}/{folder_name}'
os.makedirs(path, exist_ok=True)
return path
def fetch_seekingalpha_trending_news():
feeds = [
'https://seekingalpha.com/feed.xml',
'https://feeds.finance.yahoo.com/rss/2.0/headline',
'https://www.investing.com/rss/news.rss',
]
data_dir = get_folder_path('.', 'data')
out_file = f'{data_dir}/news.txt'
entries = []
for url in feeds:
try:
feed = feedparser.parse(url)
entries.extend(feed.entries[:15])
except Exception as e:
print(f"Error parsing {url}: {e}")
headers = {'User-Agent': 'Mozilla/5.0'}
with open(out_file, "w", encoding="utf-8") as f:
for item in entries[:30]:
title = item.get('title', 'No title')
link = item.get('link', '')
try:
resp = requests.get(link, headers=headers, timeout=5)
soup = BeautifulSoup(resp.content, 'lxml')
paragraphs = soup.find_all('p')
content = "\n".join(p.get_text() for p in paragraphs[:10])
except:
content = BeautifulSoup(item.get('summary', ''), 'lxml').get_text()
f.write(f"{title}\n\n{content}\n\n{'-'*50}\n\n")
print(f"✓ Fetched {len(entries)} articles")</code></pre>
2. Настройка RAG и переранжирования
Конфигурируем модели и хранилище FAISS, оборачиваем его в ContextualCompressionRetriever с переранжером Flashrank.
chat_model = "gpt-4o"
emb_model = "text-embedding-3-small"
openai_api_key = os.getenv("OPENAI_API_KEY")
fetch_seekingalpha_trending_news()
loader = DirectoryLoader("./data/", glob="*.txt", loader_cls=UnstructuredFileLoader)
docs = loader.load()
vs = FAISS.from_documents(docs, OpenAIEmbeddings(model=emb_model, openai_api_key=openai_api_key))
reranker = FlashrankRerank(model="ms-marco-TinyBERT-L-2-v2", top_n=5)
compressed_retriever = ContextualCompressionRetriever(
base_retriever=vs.as_retriever(search_kwargs={"k": 5}),
base_compressor=reranker
)
3. Долговременная память
Инициализируем Mem0 и определяем функции для работы с памятью, документами и генерацией ответа:
memory = Memory()
llm = ChatOpenAI(model=chat_model, temperature=0, api_key=openai_api_key)
class GraphState(TypedDict):
message: str
user_id: str
memories_str: str
docs_ctx: str
response: str
def retrieve_memories(state: GraphState) -> GraphState:
mems = memory.search(query=state["message"], user_id=state["user_id"], limit=50)
state["memories_str"] = "\n".join(f"- {e['memory']}" for e in mems["results"])
return state
def retrieve_docs(state: GraphState) -> GraphState:
docs = compressed_retriever.invoke(state["message"])
state["docs_ctx"] = "\n".join(f"- {d.page_content}" for d in docs)
return state
def generate_response(state: GraphState) -> GraphState:
prompt = f\"\"\"
You are a helpful AI. Answer based on query, memories, and docs.
Reply in ~50 English words, each sentence on a new line.
User Memories:
{state["memories_str"]}
Docs:
{state["docs_ctx"]}
\"\"\"
messages = [SystemMessage(content=prompt), HumanMessage(content=state["message"])]
result = llm.invoke(messages)
state["response"] = result.content
return state
def save_to_memory(state: GraphState) -> GraphState:
history = [{"role":"user","content":state["message"]}, {"role":"assistant","content":state["response"]}]
memory.add(history, user_id=state["user_id"])
return state
4. Построение графа StateGraph
Определяем последовательность узлов: извлечение воспоминаний → получение документов → генерация ответа → сохранение в память. Затем компилируем граф в единый pipeline.
workflow = StateGraph(GraphState)
workflow.add_node("retrieve_memories", retrieve_memories)
workflow.add_node("retrieve_docs", retrieve_docs)
workflow.add_node("generate", generate_response)
workflow.add_node("save_memory", save_to_memory)
workflow.set_entry_point("retrieve_memories")
workflow.add_edge("retrieve_memories", "retrieve_docs")
workflow.add_edge("retrieve_docs", "generate")
workflow.add_edge("generate", "save_memory")
workflow.add_edge("save_memory", END)
graph = workflow.compile()
5. Интерфейс чата
Функция chat_with_memories(message, user_id) оборачивает вызов графа, а main() реализует консольный диалог с командой «exit» для завершения.
def chat_with_memories(message: str, user_id: str = "default_user") -> str:
result = graph.invoke({
"message": message,
"user_id": user_id,
"memories_str": "",
"docs_ctx": "",
"response": ""
})
return result["response"]
def main():
print("Deep Research AI Agent with Seeking Alpha Trending News")
print("Type 'exit' to quit.\n")
while True:
print("\n" + "-"6 + " Start of Response " + "-"6)
user_input = input("You: ").strip()
if user_input.lower() == "exit":
print("Goodbye!")
break
print("AI: ", end="", flush=True)
response = chat_with_memories(message=user_input, user_id="news_importer")
print(response)
print("\n" + "-"6 + " End of Response " + "-"6 + "\n")
if name == "main":
main()
Заключение
С ростом возможностей ИИ «память» станет краеугольным камнем интерактивных ассистентов. Mem0 предлагает масштабируемую архитектуру и интеллектуальные алгоритмы хранения, что позволит создавать персонализированные и экономичные решения на базе LLM.
Исходный код проекта на GitHub: смотреть репозиторий



