Последние несколько месяцев я довольно плотно занимаюсь агентом на OpenClaw и постепенно подключаю его к рабочим системам, добавляю инструменты, пробую автоматизировать разные процессы. Иногда все получается довольно быстро, а иногда приходится возвращаться к тому, что уже давно работало и разбираться почему оно вдруг начало ломаться.
За это время накопилось несколько историй, которые решил собрать в одной статье. В основном это внутренние рабочие задачи, без каких‑то необычных архитектурных решений, но мне самому интересно наблюдать, как постепенно развивается агент, что ему можно поручить, а где лучше вообще не привлекать LLM и оставить обычный код.
Расскажу про три вещи, которыми занимался — разбор зависшего обработчика лидов, выгрузку задач из 1С прямо через телегу и эксперимент с отдельным агентом для отдела продаж.
Как разбирались с зависшей обработкой лидов
Началось все с обычного рабочего процесса — в компанию приходят заявки на почту, их нужно разобрать, определить какие относятся к продажам, выбрать ответственного менеджера и отправить ему информацию в телегу.
У нас для этого уже был обработчик, который забирал письма, классифицировал их и распределял между менеджерами по очереди. В старой реализации часть работы выполнялась через вложенного агента. Основной процесс запускал его, ждал результат и дальше продолжал обработку.
В один из дней очередной запуск завис почти на 7 минут. Дочерний агент не вернул результат за отведенное время, а в состоянии начали появляться записи с timeout.
Вроде ничего необычного, процесс не успел завершиться, значит нужно разобраться с причиной и повторить обработку, но когда начали смотреть, что происходило в телеге, выяснилось, что некоторые карточки менеджерам уже отправились.
Получалось, что агент успевал выполнить действие, но не возвращал родительскому процессу финальный ответ, а тот считал выполнение неуспешным.
Сразу возник вопрос, что теперь делать с такими заявками — если отправить их повторно, менеджеры получат дубли, а если просто пропустить, можно потерять те заявки, которые на самом деле никуда не ушли.
Что нашли в коде
Сначала проверили состояние очереди менеджеров и то, как обработчик отмечает письма обработанными.
Там обнаружилась довольно неприятная логика, по которой в старом коде функция выбора следующего менеджера сразу меняла индекс очереди:
def get_next_manager(state): managers = state.get("active_managers", []) if not managers: return None idx = state.get("current_index", 0) % len(managers) manager = managers[idx] state["current_index"] = (idx + 1) % len(managers) return manager
Само по себе это не особо страшно, но вот дальше обработчик добавлял письмо в список обработанных, сохранял назначение менеджера и обновлял состояние и только потом отправлял карточку в Telegram. То есть в сохраненных данных заявка уже считалась обработанной, хотя сообщение еще даже не было отправлено.
Если отправка падала, мы получали ситуацию, когда очередь сдвинулась, письмо отмечено обработанным, а менеджер мог ничего не получить.
С вложенным агентом было еще веселее.
Он мог отправить карточку, изменить состояние, но не успеть вернуть ответ и снаружи это выглядело как неудачная попытка, хотя часть действий уже произошла.
И еще «до кучи» выяснилось, что документация к обработчику не совсем соответствовала тому, что реально выполнялось. По описанию в регулярном процессе вообще не должно было быть LLM‑вызовов, но в рабочем коде вложенный агент продолжал использоваться.
Так что пришлось разбираться не только с ошибкой, но и с тем, как обработчик вообще устроен на тот момент.
Как восстанавливали состояние
К этому моменту накопилось 16 записей с неоднозначным результатом. Просто запустить все заново было нельзя, поэтому сначала сверили их с фактическими отправками.
6 заявок уже ушли менеджерам и очередь по ним успела сдвинуться. Еще 6 оказались служебными сообщениями или письмами, которые не относились к продажам. Оставалось 4 заявки, по которым нужно было отдельно проверить доставку.
И тут нашлась вторая проблема.
Оказалось, что тг‑клиент мог успешно отправить карточку, но зависнуть до возврата результата, то есть сообщение в чате есть, а вызывающий код продолжает ждать подтверждение.
По журналам шлюза нашли все 4 отправки. После этого восстановили записи в состоянии и аккуратно продвинули очередь на нужное количество позици, сами сообщения повторно не отправляли.
В результате удалось разобраться со всеми зависшими заявками без повторной рассылки карточек.
Что поменяли в обработчике
После этого решили убрать вложенного агента из маршрутизации. Здесь у нас довольно понятный процесс и дополнительный LLM‑вызов только усложнял контроль результата.
Выбор менеджера, формирование сообщения и отправку оставили обычному Python‑коду. Заодно поменяли порядок обновления состояния — теперь обработчик сначала рассчитывает, кому должна достаться заявка, но не сохраняет новый индекс очереди. Для этого используется временная переменная simulated_index.
queue_state = load_queue_state() managers = list(queue_state.get("active_managers", [])) simulated_index = int( queue_state.get("current_index", 0) or 0 ) def simulated_next_manager(): nonlocal simulated_index if not managers: return None idx = simulated_index % len(managers) manager = managers[idx] simulated_index = (idx + 1) % len(managers) return manager
Дальше формируется карточка и выполняется отправка:
manager = simulated_next_manager() message = format_sales_message( msg_id, classification, manager ) ok = send_to_telegram(SALES_CHAT_ID, message) if not ok: record["route_result"] = "telegram_error" record["updated_at"] = now_iso() errors += 1 continue queue_state["current_index"] = simulated_index record["status"] = "processed" record["stage"] = "routed" record["route_result"] = "sent_to_sales" record["assigned_manager"] = manager record["routed_at"] = now_iso()
Теперь если отправка не получила подтверждение, обработчик не записывает заявку как успешно обработанную и не продвигает постоянную очередь.
В функции отправки установили ожидание ответа до 10 секунд с обработкой HTTP‑ошибок и исключений.

После исправлений и сверки состояния получили 123 заявки со статусом доставленных и ни одной зависшей записи.
Правда, полностью проблему неоднозначной доставки это не решает. Если Telegram принял сообщение, а ответ до нас не дошел, обработчик все равно не сможет достоверно определить, была отправка или нет. Для этого уже нужна отдельная сверка и механизм защиты от повторной отправки.
Что из этого вынес
Больше всего проблем здесь создал даже не сам timeout, а то, что мы не могли однозначно понять, выполнилось действие или нет. Телеграм уже мог получить сообщение, а обработчик все еще ждал ответа и в итоге записывал ошибку.
Поэтому я бы теперь в подобных процессах в первую очередь смотрел на то, когда именно меняется состояние. Если отметить заявку обработанной до отправки, при сбое ее можно потерять, а если просто повторять отправку после каждого timeout, можно получить дубли.
В итоге маршрутизацию и отправку оставили обычному Python‑коду, а состояние стали обновлять только после подтверждения. Но и этого недостаточно для полной защиты от повторов, если ответ телеги потеряется, все равно потребуется сверка фактических отправок или отдельный механизм идемпотентности.
Сам старый конвейер позднее вывели из эксплуатации, но опыт оказался полезным. Не каждую часть процесса стоит отдавать агенту, особенно когда нужно точно контролировать внешние действия и их результат.
Выгрузка задач из 1С через Telegram
Следующая история — у нас разработка и внутренние процессы довольно сильно завязаны на 1С. Когда нужно передать разработчику задачу, одного ее номера обычно недостаточно. Нужна сама постановка, описание проблемы, ожидаемый результат, комментарии, события и вложения, если они есть.
Все это хранится в 1С, но не обязательно в одном месте, поэтому собрать нормальный комплект по задаче означало открыть карточку, посмотреть связанные события, найти файлы и подготовить документ.
Решил попробовать сделать выгрузку через агента — чтобы можно было просто написать номер задачи в телегу, а дальше он сам получал данные из 1С и собирал документ, который можно передать разработчику.
Для доступа к 1С использовали MCP, через него агент получает данные из корпоративной базы, а саму выгрузку выполняет отдельный обработчик.
Как это работает
1 Запустить выгрузку можно вручную, обратившись к боту:
@bot выгрузи задачу ЭР1234567
Но есть и автоматический вариант.
В рабочем чате монитор ищет сообщения, в которых встречается номер задачи формата ЭР и 7 цифр.
Для поиска используется обычное регулярное выражение:
ER_RE = re.compile(r"ЭР\d{7}")
Если в сообщении несколько номеров, обработчик может собрать несколько комплектов, а чтобы повторное чтение того же сообщения не запускало выгрузку заново, сохраняется пара из ID сообщения и номера задачи.
2 Дальше нужно получить содержимое задачи из 1С.
Сама карточка находится в объекте CRM_Задача, но комментарии и события связаны с ней через отдельные документы Событие. Вложения тоже хранятся отдельно, в ХранилищеДополнительнойИнформации.
Поэтому одним запросом получить весь комплект не получится.
Сначала через MCP ищем задачу по номеру, затем по ее ссылке получаем связанные события и комментарии, после этого ищем вложения и скачиваем оригинальные файлы.
Для небольших вложений содержимое может возвращаться в Base64, а для больших файлов используется отдельная ссылка на скачивание.
Здесь пришлось отдельно продумать работу с файлами. Например, если у оригинального вложения совпадало имя с документом, который сформировал обработчик, один файл мог заменить другой. Поэтому для исходников и обработанного описания сделали раздельное сохранение, а для совпадающих имен добавили защиту от перезаписи.
Что получается на выходе
После получения данных обработчик собирает DOCX с описанием задачи.
Внутри несколько разделов:
— текущая ситуация или проблема,
— ожидаемый результат,
— комментарии,
— события.
Оригинальные вложения сохраняются рядом, без попытки преобразовать их в текст.
Сам DOCX сейчас формируется через zipfile и XML. Это обычная структура документа Word, где внутри ZIP‑контейнера лежат XML‑файлы с содержимым и описанием связей.
После сборки проверяем целостность ZIP‑контейнера через testzip(), затем отправляем сформированный документ и оригинальные вложения в телегу.
Проверка, конечно, не гарантирует, что ворд правильно отобразит все содержимое, но хотя бы позволяет отсеять поврежденные архивы.

По сохраненным результатам за время работы сформировалось 53 комплекта задач. В 15 из них были оригинальные вложения, всего 17 файлов.
Что из этого вынес
В этой истории интересно, что агенту не пришлось поручать всю работу целиком. Через телегу удобно попросить выгрузить задачу, а дальше уже обычный обработчик получает связанные данные, собирает DOCX и сохраняет вложения.
Причем основные сложности оказались совсем не в работе LLM. Нужно было не запускать выгрузку повторно из одного сообщения, не перезаписывать файлы с одинаковыми именами и хотя бы проверять, что сформированный документ не поврежден.
Так что здесь агент скорее стал удобным интерфейсом к уже понятному процессу, а все, где нужен предсказуемый результат, оставили обычному коду.
Пока система работает в таком виде. Дальше хочу посмотреть, насколько удобно разработчикам пользоваться полученными документами и нужно ли что‑то менять в их структуре.
Отдельный агент для продаж
Третий эксперимент я решил не подключать сразу к рабочим процессам.
Основной агент уже использовался для разных внутренних задач, а продажи все‑таки немного другая история. Здесь ошибка может повлиять не только на результат автоматизации, но и на общение с клиентом. Например, агент неправильно поймет запрос, пообещает неподходящие условия или предложит скидку, которую никто не согласовывал.
Тем более у нас довольно специфичные продукты. Например, 42Clouds — сервис облачной 1С, где условия подключения зависят от конфигураций, количества пользователей, используемых баз, интеграций и других деталей.
Допустим, клиент хочет перейти от другого провайдера, потому что там все тормозит. Просто ответить ему, что мы можем помочь, недостаточно. Сначала нужно выяснить, какая у него конфигурация, сколько пользователей, какой объем данных и что вообще потребуется для переноса.
Поэтому решил собрать отдельного агента с продуктовой базой знаний, который будет помогать менеджерам разбирать такие обращения.
Но пока без самостоятельного общения с клиентами. На первом этапе пусть учится правильно анализировать запросы, предлагать уточняющие вопросы и готовить черновики ответов, подключать его к реальным действиям можно будет уже после проверки.
Что настроил
Для нового агента создали отдельное рабочее пространство OpenClaw. В нем лежат файлы с описанием роли, правилами поведения и продуктовой информацией.
Основные из них:
IDENTITY.md — кто этот агент и для каких задач он нужен;
SOUL.md — как он должен вести себя и какие действия требуют подтверждения;
SALES_PLAYBOOK.md — сценарии работы с входящими обращениями;
42CLOUDS_ECOSYSTEM_SKILL.md — информация о продуктах и типовых вопросах клиентов;
TOOLS.md — правила работы с инструментами.
Сами файлы еще не дают агенту никаких прав, они задают контекст, в котором он должен работать.
Отдельно ограничили действия, которые могут повлиять на клиентов или рабочие системы. Например, агент может подготовить текст коммерческого предложения, но не должен сам отправлять его клиенту. Может предложить следующий шаг по сделке, но не должен без подтверждения менять CRM, тарифы, доступы или настройки.
То же самое со сроками и скидками. Если условий недостаточно, лучше подготовить список вопросов для менеджера, чем придумать клиенту красивое предложение.
При этом одних правил в SOUL.md для реального ограничения доступа недостаточно. Поэтому новому агенту не подключали телегу, не копировали авторизации основного агента и не создавали правила маршрутизации входящих сообщений.
На момент проверки openclaw agents list показывал 0 routing rules для этого агента.
То есть пока это отдельная конфигурация с продуктовой базой знаний, а не агент, который уже принимает обращения клиентов.
Для проверки подготовили сценарий с потенциальным клиентом, у которого 8 пользователей, медленно работает текущий облачный сервис и есть запрос на срочный перенос с более низкой стоимостью. Но полноценные результаты тестирования пока не зафиксированы, поэтому оценивать качество его ответов рано.
Что из этого вынес
С агентом для продаж пока рано говорить о результате. Мы подготовили рабочее пространство, продуктовые материалы и ограничения, но полноценного тестирования на реальных запросах еще не проводили.
И я бы здесь вообще не торопился. Одно дело, когда агент ошибается при подготовке внутреннего документа и совсем другое когда он начинает самостоятельно общаться с клиентом, обещать сроки или предлагать условия, которых нет в продуктовых материалах.
Поэтому сначала хочу проверить его на разных сценариях и посмотреть, где он начинает ошибаться или придумывать ответы и только потом решать, какие инструменты и доступы ему действительно нужны.
Так что тут скорее просто делюсь мыслями и наработками. Кстати, может тоже поделитесь своими идеями по поводу такого «агента‑посредника».
Что дальше
Пока вот такие три истории накопились за последние месяцы.
С обработкой лидов пришлось разбираться из‑за зависаний и восстанавливать состояние по фактическим отправкам. Выгрузка задач из 1С уже работает и формирует комплекты документов. А отдельный агент для продаж пока существует как эксперимент с собственной базой знаний и ограниченными доступами.
Сейчас продолжаю добавлять основному агенту новые инструменты и смотреть, какие задачи действительно удобно через него решать.
И чем больше с этим работаю, тем меньше хочется просто давать агенту доступ ко всему подряд. В одной задаче он оказался полезен как интерфейс к обычному обработчику, в другой от его участия вообще пришлось отказаться, а в третьей пока разумнее не выпускать его за пределы тестового окружения.
Возможно, через какое‑то время соберу еще одну такую подборку. Пока решил зафиксировать то, что уже есть, так что эта статья скорее как заметка и предложение к обсуждению.
Спасибо за внимание, буду рад вашим мыслям в комментах.

