Pavel Zloi
2.71K subscribers
610 photos
54 videos
2 files
881 links
директор ИИ · инженер‑интегратор
@eprogrammist | https://github.com/EvilFreelancer

20 лет в IT
∈ 10 лет в разработке
∈ 3 года в ML/AI
∈ 1 год - вайбмастер

Поддержать автора:
https://pay.cloudtips.ru/p/937f48ac
Download Telegram
Про тесты

Вы наверно замечали, разрабатывая вайбкод проекты, одну неприятную штуку: фичи, заложенные на первых итерациях, часто удаляются агентом или ломаются в процессе добавления новых фичей, если у проекта нет никаких тестов.

А если тесты есть, они начинают работать как рельсы. Они вынуждают модель писать код так, чтобы даже самые старые фичи продолжали работать ровно так, как задумано. И эта мысль меня долго не отпускала.

Я много думал и в итоге осознал занятную истину, которая одинаково верна и для вайбкодинга, и для классического кодинга. Сформулировал её для себя так:

тесты это долгосрочная память проекта


В отличие от абстракций, которые живут в контексте агента или где-то в векторном пространстве, тесты это память формализованная и воспроизводимая. Она не зависит от температуры модели, от качества промпта или того, что агент "забыл" по ходу пьесы, от того какой агент работает или кто из команды на своей локальнй машине их запустил.

Тесты каждый раз задают один и тот же вопрос: "Это все ещё работает как задумано изначально?".

Если ответ "нет", значит проект потерял часть свой бизнес-логики. Именно поэтому без тестов вайбкод проект неизбежно деградирует, потому как агент оптимизирует генерацию решения под текущую задачу и текущий контекст, а прошлые решения он может по незнанке почистить.

Получается простой вывод.

Тесты это не про бюрократию и не про "идеальный код" или модный паттерн, это способ один раз формализовать ожидание, и дальше оно становится частью проекта, которую сложно случайно выкинуть или сломать незаметно.
1👍40💯15🔥12
Pavel Zloi
Закинул модельку evilfreelancer/GLM-4.7-Flash-GGUF к себе в публичный API, пользоваться вот так: curl https://api.rpa.icu/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer https://t.me/evilfreelancer" \ -d '{ …
В нашем уютном чатике порекомендовали попробовать опцию -kvu, --kv-unified для инференса модели GLM-4.7-Flash на llama.cpp, вроде как должен быть двукратный прирост в скорости генерации.

Проверил без этой опции, в среднем скорость в районе 40-41 токена в секунду, а со включенной опцией 75-77 токенов в секунду.

Скрипт запуска теперь такой:
llama-server --host 0.0.0.0 --port 8080 -hf evilfreelancer/GLM-4.7-Flash-GGUF:MXFP4_MOE -fa 1 -ctk q8_0 -ctv q8_0 -ngl 99 -ub 4092 -b 4092 -c 128000 --jinja -np 10 -t 48 --context-shift --temp 1.0 --min-p 0.01 --top-p 0.95 --dry-multiplier 1.1 --kv-unified

В общем метод ускорения работает.
🔥165😱31
Вопросик к читателям канала, рассматриваю Tarantool Column Store для одного проекта, но никогда раньше ею не пользовался, подскажите кто пробовал, какие с ней проблемы и подводные камни? Что по железу рекомендуют? Есть шардирование, бэкапирование и инетграция в доменку?
🔥2
Приехала ещё одна приблуда для сервера, она позволяет синхронизировать запуск двух блоков питания. Взял вариант с релешкой, так как в транзисторном исполнении как-то сомнительно брать.

Ну а для чего она мне думаю вы и так уже догадались ;)

#server
1🔥8👍3🤔1
Готовлю патчик небольшой в проект SGR Agent Core, давно хотел добавить простенький CLI, чтобы можно было общаться с агентами интерактивно, но так чтобы агент помнил историю сообщений.

На скрине пример работы через эталонную gpt-4.1-mini, но я ещё и на локальных потестирую.

Пришлось под это дело писать кастомного агента, который расширяет некоторые методы уже имеющегося, получилось вполне годно, плюс метод этот можно применять и на других агентах.
👍13😁1
Судя по шумихе всю последнюю неделю коллеги по вайб-цеху хайпуют на теме OpenClaw (он же ClawdBot, он же MeltBot, он же Гоша, ну вы поняли), решил и я запрыгнуть на хайптрен, загуглил исходники и принялся читать доку.

И так, OpenClaw это такой локальный агент, который может тригерить скрипты и работать с компьютером напрямую, но лично я считаю, что давать боту прямой доступ к своему компьютеру есть не самая адекватная идея, мало того что LLM суть недерменированные системы, так ещё и у бота могут быть пользователи помимо меня.

Ну а те кто давно меня читают скорее всего знают, что я обожаю on-prem модельки и Docker.

Короче решил запустить своего Telegram-бота используя on-prem модельку GLM 4.7 Flash (которую я ранее конвертнул в GGUF) в Docker-контейнере, кстати, я изначально думал запустить полноразмерную GLM 4.7 Flash, но vLLM всё никак не добавят поддержку оной.

В официальной доке есть информация о запуске в докер и о работе с локальными openai-совместимыми серверами, но по их инструкции я так и не смог ничего толком настроить, начал разбираться, по итогу смог всё запустить и по ходу пьесы как обычно делал заметки.

А сегодня увидел на канале у Александра (@dealerAI) пост про настройку OpenClaw в гугловом облаке и решил по образу и подобию конвертировать свои заметки в формат эдакой развёрнутой инструкции.

По итогу:
1. воскресил моего бота @pavel_gpt_bot (можно добавлять в группы и писать боту в личку)
2. создал https://github.com/EvilFreelancer/openclaw-docker с документом в котором детально изложил процесс настройки агента в Docker используя локальные модели

upd. подключил модель gpt-oss:120b, спасибо Валерию (@neuraldeep) за ключик.
2🔥11👍4👀21
Вчера в процессе группового изучения возможностей OpenClaw придумал такой вот #meme
😁2114🔥6💯4👍2
Методы сжатия контекста агентов

Сегодня хочу затронуть тему разных хитростей которые я применяю при разработке агентов, данные приёмы позволяют экономить токены за счёт уменьшения количества токенов в контекстном окне, это имеет несколько побочных эффектов: модель работает быстрее (меньше токенов -> выше скорость генерации), модель работает точнее (максимальный контекст обычно в два раза больше чем эффективный).


Английский язык

Один из самых простых способов оптимизации контекста подразумевает режим работы при котором в истории чата будут храниться сообщения на английском языке, так как большинство моделей и токенизаторов оптимизированы прежде всего на работу с текстами на английском языке и как следствие модели требуется меньше токенов для хранения сопоставимого объёма информации.

Хотя на самом деле язык может быть не только английский, может быть китайский (если говорим про Qwen, DeepSeek и т.д.) или русский (GigaChat, Vikhr, ruAdapt и так далее), в общем следует использовать в модели тот язык который доминировал в корпусе на котором производилось обучение токенизатора.

При использовании такого подхода придётся писать промты на оптимальном языке или подключать механизмы автоматического перевода, будь то апишки или какие-нибудь локальные модели.


Фильтрация тулов

Самый простой метод оптимизации контекста это фильтрация тулов доступных function call модели в момент получения запроса пользователя, принцип работы этого метода очень простой, у нас есть некая функция или метод который принимает на вход список доступных тулов и их описания, а так же пользовательский запрос.

Внутри при помощи регулярных выражений, алгоритма bm25/tfidf или эмбеддинговых моделей (или всего и сразу, плюс скажем реранкер) мы определяем какие тулы наиболее релевантны запросу пользователя, после чего возвращаем только их и уже этот список отправляется на вход модели.

Данный метод полезен когда тулов очень много, например 100+ или скажем много тулов которые выполняют похожие задачи, но немного отличаются друг от друга.


Долгосрочная память

Пожалуй моя самая любимая тема, решать вопросы с долгосрочной памятью можно по разному, например через специализированный сабагент памяти или при помощи тестов, ещё можно просить агента скидывать полезные сведения на диск в виде Markdown файлов и так далее.

Предполагается, что данные из долгосрочной памяти читаются только тогда когда нужно и что после попадания в память информация будет удаляться из контекста (при условии, что она более ненужна).

Данный метод очень полезен в агентах как общего назначения (условная чат-болталка с тулами) так и специализированного назначения (навроде кодинговых или финансовых и так далее агентов).


Суммаризация

Предполагает выполнение сжатия контекста при достижении определённых пороговых значений по токенам, подобный механизм реализован в Cursor, когда контекстное окно у модели уже вот-вот закончится происходит небольшая пауза, модель суммаризирует данные, заменяет старый контекст новым саммари и продолжает далее уже с учётом оного.

Работает это следующим образом: некий метод или функция принимает messages, считает токены, далее определяет, что количество токенов преодолело некие пороговые значения, если да то после этого она берёт несколько сообщений с конца, допустим все до N-5 от последнего сообщения юзера, сохраняет их, а все остальные отправляет в модель с просьбой выполнить суммаризацию (в промте могут быть разные уточнения как её делать и на что обратить внимание, но суть остаётся прежней). В результате получаем некий ответ с подробным саммари, который мы кладём в начало нового массива messages с ролью assistant, а далее те N-5 сообщений которые мы сохранили. Полученный массив уходит далее.

Полезно при разработке кодинговых и файловых агентов, так как описания алгоритмов и последовательностей действий хорошо поддаются сжатию без значительной потери качества.


Послесловие

Вот такая вот подборочка получилась, все перечисленные приёмы я использовал и надеюсь какие-то из указанных методов пригодятся и вам.

А какие методы сжатия контекста используете вы?
2🔥25👍143
Pavel Zloi pinned «Про тесты Вы наверно замечали, разрабатывая вайбкод проекты, одну неприятную штуку: фичи, заложенные на первых итерациях, часто удаляются агентом или ломаются в процессе добавления новых фичей, если у проекта нет никаких тестов. А если тесты есть, они начинают…»
Намедни наткнулся на очень любопытный интерфейс для визуализации пайпланов под названием daggr, от инженеров из Hugging Face.

Данный UI позиционируется как аналог ComfyUI, полез смотреть демки, и пока что кажется, что наконец появился приличный и простой аналог, потому как с комфи работать лично мне крайне неудобно из-за того что это low-code система и вместо того чтобы заниматься творчеством приходится часам искать подходящие ноды в подборках или у блогеров, или писать свои кастомные, а потом мышкой проводить связи.

Для daggr тоже можно писать ноды на python, но они имеют универсальные выходы и входы, точнее какие ноды с какими связаны описывается в python-коде, а не в псевдокоде экспортируемом в JSON-объект. Ну а самое удобное с точки зрения UI - в случае возникновения ошибки на одной из нод возможность не перезапускать весь пайплан, достаточно внести необходимые правки и перезапустить только неисправную ноду. В процессе изучения оказалось, что предполагается работа через апишку на железе HF, но можно и локально запустить.

Одна из главных фичей, которая меня больше всего впечатлила это возможность отладки через популярные кодовые агенты, просто ставим пакет, отвечаем на вопросы инсталятора, далее запускаем агент и пилим код.

Короче ещё одна полезная штука в копилку технологий.
👍202
Фанаты sgr-agent-core регулярно спрашивают нас, с чего мы взяли, что они наши фанаты?

Уже неделю чувствую себя ненормированно свободным, впервые за долгое время проснулось кодовдохновение. А потому - делюсь! Много мыслей и немного кода.

В чем экзистенциальный ужас платформенной разработки? Приходится поддерживать и учитывать разные платформы, их версии, ограничения. И как бы я ни бегал от мрака версионности, всё-же напоролся на примере sgr core

Итак, проблема:
Фреймворк построен на Structured Output, но его поддерживают далеко не все конфигурации локальных/проприетарных LLM. Что самое страшное, даже если поддерживают, то не всегда однородно! Требуемые JSON схемы могут различаться.
Если фреймворк может работать, а может не работать на неопределённом множестве моделей - это ужасненько.

Structured output(SO) по моему скромному мнению это железная база, без которой сложно представить взаимодействие агентов хаоса вольного контекста и неопределëнных суждений и системы требующей, как правило, некоторой детерминированности, свойственной формальным языкам.


Примеры:
- Кто-то гарантирует ответ строго по формату, а кто-то может допустить ошибки даже при заданной схеме
- Кто-то поддерживает вложенные AnyOf и прочие агрегаты схем, а кто-то нет
- Где-то можно прокинуть ограничения min_length=1, max_length=3, а где-то нет, они в лучшем случае будут проигнорированы
- Кто-то хавает литералы и сопутствующие им enums, а кто-то отказывается

Как общий знаменатель пришла мысля создать решение, которое бы эмулировало независимый от ллмки SO без реальной в нём потребности на стороне провайдера . Идея "попроси модель сделать как надо" далеко не нова, и тем не менее было полезно посмотреть, насколько хорошо и стабильно это могут делать современные LLM


Концепция:
class ToolInstantiator принимает в свой init Pydantic модель, и имеет два основных метода интерфейса:
- Сгенерить промпт с описанием схемы для LLM
- Провалидировать полученный ответ LLM на предмет возможности билда инстанса Pydantic модели
На каждом следующем этапе промпт,выдаваемый классом, учитывает ошибки и проблемы предыдущей итерации, корректируя/фокусируя LLM

Путём некоторых экспериментов было выявлено, что прямая json схема для LLM сложновата ввиду нотации и неконсистентной информации о полях и их типах. А ещё иногда модельки путались и выдавали JSON schema аналогичную промптовой в ответ. Поэтому появился класс-помогатор SchemaSimplifier, разбирающий схему и преобразующий в более минималистичную нотацию

Ещё была интересная концепция, где каждое поле валидировалось по отдельности и даже если модель выдала в общем не полностью корректный JSON, часть верных полей принимались и не требовались на дальнейших итерациях генерёжки. Идея была отброшена ввиду нелицеприятности кодреализации такой фичи.
Лучше никому не видеть мою попытку в конвертацию типов raw context regex parsing -> json string->python type -> pydantic validator

Вот тут реализация - почти хорошо

работает следующим образом
for attempt in range(max_retries):
async with self.openai_client.chat.completions.stream(
messages=messages + [{"role": "user", "content": instantiator.generate_format_prompt()}],
) as stream:
completion = await stream.get_final_completion()
try:
content = completion.choices[0].message.content
tool_instance = instantiator.build_model(content)
return tool_instance
except ValueError:
continue
🥰5👍1
OpenAPI to MCP это врапер между API и MCP

На этих выходных уже в который раз пришлось пилить MCP обёртку над API, чтобы подключить его к агенту.

Надоело повторяться, решил сделать standalone-сервер, который в формате nocode генерит MCP-сервер по документации из OpenAPI/Swagger, а потом ещё и проксирует запросы из тулов на этот API в соответствии со спеками.

Допустим в документации API есть такие эндпоинты:
- GET /messages
- POST /messages
- GET /status
- GET /users

Прокси конвертирует их в тулы вот с такими именами:
- get_messages
- post_messages
- status
- users

Вызов же тула через MCP превращается в HTTP-запрос к API, ответ API через MCP возвращается обратно пользователю.

Запуск одним контейнером, вот к примеру демка OpenAPI:
docker run --rm -p 3100:3100 \
-e MCP_OPENAPI_SPEC=https://raw.githubusercontent.com/readmeio/oas-examples/refs/heads/main/3.1/json/petstore-simple.json \
-e MCP_API_BASE_URL=http://localhost:8080/v1 \
evilfreelancer/openapi-to-mcp:latest

Полный docker-compose,yaml тут.

Дальше можно подключить этот MCP куда угодно, например в Cursor вот так:
{
"mcpServers": {
"demo": {
"url": "http://localhost:3100/mcp"
}
}
}

После чего Cursor подтянет тулы и покажет их список, само собой можно подключить этот MCP сервер не только в курсор, а куда угодно.

Исходники: https://github.com/EvilFreelancer/openapi-to-mcp
Docker-образ: https://hub.docker.com/r/evilfreelancer/openapi-to-mcp
120👍11🔥5👏1
Media is too big
VIEW IN TELEGRAM
Подосоветовали утилитку CodeGraphContext, она позволяет проанализировать исходники проекта и построить из них граф кодовой базы, да не простой, а такой с которым можно через MCP подружить любой кодовый агент. Вроде как обещают, что агент должен начать грамотнее генерить код.

Плюс можно по кодовой базе такую вот занятную визуализацию построить, в качестве примера взял мой проект openapi-to-mcp, на вид очень неплохо получилось, дальше попробую повайбкодить его со включенным MCP.
3🔥163👍1
Тестирую API'шку по одному проекту мечты, который я давно откладывал в дальний ящик и вот наконец собрал волю в курсор и за неделю, без лишней спешки запилил прототип системы которая кравлит из телеги и ищет по постам.

На днях хочу зарелизить поисковик с возможность добавления каналов пользователями и публичный MCP сервер.

PS. С апишкой из курсора работаю через openapi-to-mcp проксик.
1🔥25👍6
Обновил описание канала, раньше я был вебмастер, а теперь вайбмастер 😎
2😁2361👍1😢1😐1
Текс, ну что же, пробую запустить мою вторую MCP, на этот раз заточенную на поиск сообщений в телеграм.

У меня там комплексное решение из мантикоры, кафки, фриды и юзерботоа, которое наблюдает за новыми постами на каналах и очень аккуратно подтягивает новые данные, чтобы не вылезти за лимиты телеги.

Система ищет в трёх режимах:
- полнотекстовый поиск
- векторный поиск
- гибритный поиск (полнотекст + вектор, по умолчанию)

Помимо этого система наблюдает за обновлениями каналов и время от времени подтягивает свежие данные о постах (с глубиной до недели).

Пока что каналов не много, около 30, но думаю буду помаленьку добавлять.

Для полнотекста используется ManticoreSearch Engine, она хорошо умеет в bm25, а для векторного поиска.... тоже мантикора, с недавних пор в ней есть поддержка векторного поиска, модельку использую FRIDA (про её запуск тут) использую префиксы search_document и search_query.

Конфиг подключения такой вот:
{
"mcpServers": {
"tg-mcp": {
"url": "https://mcp.rpa.icu/mcp",
"headers": {
"Authorization": "Bearer https://t.me/evilfreelancer"
}
}
}
}

Сервер покажет два тула: telegram_channels и telegram_messages, первый - ищет каналы в базе, а второй - сообщения.

PS. У меня конечно не так эпично как у Валерия @neuraldeep получилось, но мне интересно было именно с нуля нечто подобное запустить )

PPS. Для подключения к апишке кравлера использую openapi-to-mcp проксик, по ходу дела заметил, что описания параметров не передаются, так что накатил на него патчик.
211
Очень хочется рассказать про один небольшой сторонний проект, который я решил попробовать собрать.

Называется штука coddy, это аббревиатура фразы COmmunity Driven Development, Yep.

Идея очень простая: создать бота который сможет следить за репозиторием, ловить задачки пользователей и выполнять запрошенные работы.

Работает бот сейчас так: он следит за issue на github (в планах добавлю gitlab и bitbucket), и если видит, что появилась новая задачка, то создаёт ветку, переключается на неё, запускает кодового агента cursor cli (пока только его, но хочу добавить и другие), кодовому агенту на вход передаётся описание из issue, он выполняет работу, коммитает правки и пушит их в реп, после чего создаёт PR и завершается.

Пока что система в стадии очень глубокого прототипа, я ещё не добавил часть про уточнение требований пользователей в issue и реагирование на код ревью в PR, но это в самых ближайших планах.

Ссылка на реп: https://github.com/EvilFreelancer/coddy

Приглашаю всех принять участие в работе над проектом!
2🏆11👍6😱53
Pavel Zloi
OpenAPI to MCP это врапер между API и MCP На этих выходных уже в который раз пришлось пилить MCP обёртку над API, чтобы подключить его к агенту. Надоело повторяться, решил сделать standalone-сервер, который в формате nocode генерит MCP-сервер по документации…
Чуть прокачал openapi-to-mcp, за неделю зарелизил 6 новых билдов, добавил кучу новых фичей и пофиксил пачку багов.

Вот кратенько, что было сделано:
- теперь спеку можно определить переменной MCP_OPENAPI_SPEC, система сама разберётся файл там или ссылка
- добавил конвертацию дескрипшенов HTML в Markdown, опция MCP_CONVERT_HTML_TO_MARKDOWN, отключено по дефолту
- можно указывать свои инструкции через MCP_INSTRUCTIONS_FILE и менять режим их отображения MCP_INSTRUCTIONS_MODE, по дефолту отображается то что написано в site.description из OpenAPI-конфига
- пофиксил баг с переменными в path, теперь эндпоинты типа /user/{username} система конвертирует в тул user_username

Задействовал это решение уже в десяти моих проектах, развёртывание MCP ещё никогда не было таким простым и удобным.
18🔥5👍1🆒1
Наблюдаю за собой странный эффект, вызванный кодовыми агентами, появилось ощущение бесконечных возможностей которых попросту не было до кодовых агентов, а точнее даже до того как я научился ими эффективно пользоваться, это вызывает в сознании неуемное стремление творить, творить и творить.

Вместо того чтобы лечь пораньше думаю о проектах, во сне приходят идеи которые только и успеваю записывать и делать. Папка с проектами на диске занимает уже под полсотни гигабайт.

Какое-то приятное чувство азарта, сложно сравнить это с чем-то ещё, похожее ощущение было когда учился в колледже, когда мир программирования и инженерии казался ещё чем-то загадочным и таинственным.

И если просуммировать эту мысль, то могу сказать, что вайб-код и кодовые агенты открыли второе дыхание.
💯3619👍10💊2🤔1🤡1🤣1
Вчера прям основательно решил поработать над coddy, вместо того чтобы делать по наитию продумал архитектуру дотошно, составил план работ.

1. поизучал аналоги, наткнулся на два прикольных проекта: ralph и ralphy, она они реализуют т.н. ralph-loop, это когда любая задача декомпозируется на шаги и решение её представляется в виде графа, поэтому я решил разделить на две подсистемы, observer смотрит за гитхабом и worker делает вещи.

2. с учётом этого разделения выполнил большой рефакторинг, задокументировал и наконец сам понял, что хочу достичь.

3. перебрался с пуллинга на вебхуки, это очень упростило логику запуска автоматики, на вебхук наблюдателя приходит запрос от гитхаба, в нём вся необходимая информация о том, что произошло (была создана/изменена/закрыта issue, был добавлен/удалён исполнитель, был добавлен/изменен/удалён комментарий в задачке и заглушка для приёма информации о PR).

4. в папке .coddy/ организовал хранилище pr и issue в виде yaml файлов, в них задокументировано всё что происходило с сущностями, изначально думал хранить в markdown, но запарился дебажить их парсер.

5. папка .coddy/ создаётся и рулится в папке workspace, это директория в которой находится git репозиторий и проводится вся работа, иными словами я планирую хранить в индексе репа логи процесса разработки и потом ещё и действия агентов (не подробный вызов тулов, а отчёт что был сделано на текущем шаге)

Делаю всё по BDD, сначала пишу спеки, потом по ним планирую действия и пинаю ИИ.

Вот такой прогресс, думаю за сегодня смогу добить ещё автоматический запуск ralph-loop и прикручу к этому логику создания PR, про мою моё мнение к оригинальной петле и о порочности полной и бесконтрольной автоматизации кодогенерации расскажу в другой раз.
👍13🔥7🤣1