Привет! Спустя 500 часов с OpenClaw, я уже не просто чинил и настраивал агента, его системы и навыки, а начал решать проблемы изначальной архитектуры OpenClaw. Так и начался мой путь в опенсорс-разработку. Эта статья — с примерами кода и скиллами, которые сделали работу с агентом на порядок качественней и приятней.
Слой 1: Память, которая не врёт
У OpenClaw из коробки ужасная память. Просто катастрофа. Даже если какие-то модули работают нормально, спустя длинную сессию он теряет контекст и начинает путаться в собственных файлах.
На первый взгляд всё сделано хорошо: память в файлах, memory-записи, ежедневные логи, даже предустановленные модули, которые помогают решать часть проблем. Но всё не совсем так. Память в OpenClaw — реально сомнительная штука, и пришлось активно с ней работать.
У меня больше 2000 файлов. Очень часто приходится говорить агенту «вспомни, найди в своей памяти» — а он начинает решать задачу заново, потому что память потерялась.
В интернете масса гайдов от других пользователей — каждый решал по-своему. Ваш агент тоже будет предлагать экзотические способы, а на популярном сайте с видео найдутся штуки, которые не всегда работают. Пришлось искать своё решение.
Что пробовал и не взлетело:
18 марта поставил плагин Cognee. 27 марта выключил — работал криво. В тот же день попробовал LightRAG — тоже мимо. Потом ClawMem. Потом lossless-claw — у него вообще конфликт версий.
Проблема была не в конкретном плагине. Проблема — четыре плагина памяти дрались друг с другом. Каждый тянул контекст в свою сторону. Агент путался ещё больше.
Я всё выключил и собрал свою систему. Четыре слоя, каждый делает своё.
Векторный поиск
Файл chat_vectors.db — под сотню тысяч чанков (чанк — это фрагмент текста на несколько предложений) с эмбеддингами. Все старые чаты нарезаны на куски и превращены в векторы. Поиск по cosine similarity.
Эмбеддинги делает Google gemini-embedding-2-preview. Если гугл недоступен — fallback на локальный Ollama.
CHUNK_SIZE = 600 # символов на чанк
CHUNK_OVERLAP = 100 # перекрытие между чанками
BATCH_SIZE = 20 # текстов на батч (Google batchEmbedContents)
# Fallback: если Google API недоступен — Ollama локально
OLLAMA_HOST = "http://<local-server>:11434"
OLLAMA_MODEL = "nomic-embed-text"
GOOGLE_EMBED_MODEL = "models/gemini-embedding-2-preview"
Скрипт build_vector_index.py берёт все чаты, режет на чанки по 600 символов с перекрытием 100. Батчами по 20 отправляет в Google на эмбеддинг. Результат — SQLite-база, по которой агент ищет.
Граф сущностей
Файл entity_graph.db — 50 тысяч сущностей и 100 тысяч связей между ними. Это как будто бы карта всего, о чём мы говорили.
Сущности извлекаются через spaCy (ru_core_news_sm) плюс регулярки. Хранятся в SQLite с FTS5-индексом для быстрого полнотекстового поиска.
def rag_search(query, limit=10):
"""Search entity graph for entities and relations."""
fts_query = re.sub(r'[^\w\s]', '', query)
terms = fts_query.split()
fts_expr = ' OR '.join(terms)
rows = conn.execute("""
SELECT e.name, e.type, COUNT(DISTINCT e.chunk_id) as mentions
FROM entity_fts f
JOIN entities e ON e.id = f.rowid
WHERE entity_fts MATCH ?
GROUP BY e.name, e.type
ORDER BY mentions DESC
LIMIT ?
""", (fts_expr, limit)).fetchall()
Запрос разбивается на слова. FTS5 ищет по всем сущностям. Результат — список сущностей, отсортированный по количеству упоминаний.
Файловая память
Самый понятный слой. Обычные markdown-файлы:
MEMORY.md— курированная долгосрочная память. Главное, что агент должен знать всегда.memory/YYYY-MM-DD.md— дневные заметки. Что было сегодня, что решили, что поменяли.state/*.md— текущее состояние разных подсистем.SOUL.md— идентичность агента. Кто он, как себя ведёт.AGENTS.md— операционные правила. Что можно, что нельзя, как действовать.
Кайф в том, что это всё редактируется руками. Никакой магии. Открыл файл, поправил — агент сразу знает.
Автоинъекции
SOUL.md, AGENTS.md и результаты memory tool вставляются в каждый промпт автоматически. Агент не может их забыть. Это шпаргалка, которая всегда перед глазами.
Плюс к этому продолжает работать нативный LCM и плагин memory-lancedb. Они не мешают — просто добавляют ещё один слой.
⚠️ LanceDB из коробки не поддерживает русский токенайзер. Полнотекстовый поиск по русским словам работает плохо — не умеет склонения и словоформы. Поэтому для русского языка я использую отдельный FTS5-индекс в SQLite.
Слой 2: Кроны, которые не падают
В OpenClaw fallback цепочки есть у агентов — но не у cron-событий. Это дыра: одна недоступная модель кладёт все отложенные задачи. Молча.
Решение: fallback.py. Sonnet недоступен → идём к локальной Ollama → Gemini Flash → Groq. Задача выполнится, даже если несколько провайдеров лежат.
Fallback chain: каждый уровень — страховка от простоя
Слой 3: Автономность, а не имитация
Soul Daemon — оркестратор по принципу «сначала Python, потом LLM».
- soul_collect.py (без LLM) собирает сигналы: открытые треды, погода, новые регистрации.
- soul_decide.py — правила тишины (молчать 10–16 МСК, ночью) и пороги сигналов.
- Только если сигнал прошёл фильтр — вызывается g-flash агент с краткой сводкой.
Soul Daemon: LLM вызывается только когда сигнал прошёл Python-фильтр
Слой 4: Python > LLM для детерминированных задач
Проверить доступность модели, собрать погоду, сравнить delta подписчиков — это не задачи для нейросети. Перевод на Python дал −50% ежедневного расхода токенов.
Правило простое: если задача детерминированная и не требует понимания языка — пишем Python, не промт.
Финал
Весь код: github.com/artlooi/looi-clawd
Берите, разворачивайте, присылайте PR. Или дайте ссылку своему агенту — он разберётся сам.
Подписывайтесь на @cronbun в Telegram — там мой агент ведёт канал про то, как всё это работает изнутри.