Приветик! Я — Михаил Гурбанов, тимлид и разработчик.
Мой основной язык — Python, но на своем пути я успел заглянуть в DevOps, Typescript и Rust. Сейчас много занимаюсь приложениями на основе искусственного интеллекта и бэкендами, которые с ним работают.
В этом канале я делюсь тем, что помогает делать разработку проще и понятнее: заметки из практики, решения, которые реально работают. Это не будет учебник по синтаксису или глубочайшие технические разборы — скорее взгляд изнутри на инструменты и подходы, которые экономят время и нервы.
Иногда буду кидать ссылки на митапы и конференции, где выступаю или просто захожу послушать.
Мечтаю залететь в open source, но залетел лишь в аниме.
Это Dev no Sekai — мир разработки и всего, что рядом с ней. Добро пожаловать ⚡
Мой основной язык — Python, но на своем пути я успел заглянуть в DevOps, Typescript и Rust. Сейчас много занимаюсь приложениями на основе искусственного интеллекта и бэкендами, которые с ним работают.
В этом канале я делюсь тем, что помогает делать разработку проще и понятнее: заметки из практики, решения, которые реально работают. Это не будет учебник по синтаксису или глубочайшие технические разборы — скорее взгляд изнутри на инструменты и подходы, которые экономят время и нервы.
Иногда буду кидать ссылки на митапы и конференции, где выступаю или просто захожу послушать.
Мечтаю залететь в open source, но залетел лишь в аниме.
Это Dev no Sekai — мир разработки и всего, что рядом с ней. Добро пожаловать ⚡
⚡4❤3
В последние годы все только и говорят про AI и LLM.
И это неудивительно: эти инструменты могут решать задачи, которые раньше казались слишком сложными или требовали огромных ресурсов.
Но что это значит для нас, разработчиков?
Это значит, что нужно учиться правильно с ними общаться — задавать контекст, контролировать формат ответов и управлять процессом.
К счастью, сообщество не стоит на месте, и для Python есть отличный инструмент — pydantic-ai
Вот, с чем он может помочь:
• Гибкая конфигурация клиента — работает с разными провайдерами, от OpenAI до Grok, а также с кастомными inference серверами
• Гарантировать, что LLM ответит строго по заданной JSON-схеме, что помогает избегать галлюцинаций
• Предоставляет LLM возможность вызывать инструменты и ходить во внешние системы
• Дает удобный интерфейс для работы с LLM как с «клиентом»
В итоге с LLM становится удобно работать в привычной для разработчиков парадигме: чёткие контракты, предсказуемое поведение и простая интеграция в приложение или сервис.
И это неудивительно: эти инструменты могут решать задачи, которые раньше казались слишком сложными или требовали огромных ресурсов.
Но что это значит для нас, разработчиков?
Это значит, что нужно учиться правильно с ними общаться — задавать контекст, контролировать формат ответов и управлять процессом.
К счастью, сообщество не стоит на месте, и для Python есть отличный инструмент — pydantic-ai
Вот, с чем он может помочь:
• Гибкая конфигурация клиента — работает с разными провайдерами, от OpenAI до Grok, а также с кастомными inference серверами
• Гарантировать, что LLM ответит строго по заданной JSON-схеме, что помогает избегать галлюцинаций
• Предоставляет LLM возможность вызывать инструменты и ходить во внешние системы
• Дает удобный интерфейс для работы с LLM как с «клиентом»
В итоге с LLM становится удобно работать в привычной для разработчиков парадигме: чёткие контракты, предсказуемое поведение и простая интеграция в приложение или сервис.
Pydantic Docs
Pydantic AI
How Python does AI: agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.
❤4👎3
Продолжая истерию, вокруг LLM, нельзя обойти стороной протокол MCP. Его основная задача - дать возможность LLM выполнять произвольный код при помощи
Тот же самый Cursor уже имеет в себе MCP-клиент, что позволяет ему обращаться к внешним серверам для выполнения дополнительной логики. Чтобы это работало, нужен MCP-сервер. Такой сервер можно поднять буквально в несколько строк с помощью fastmcp:
Теперь любая LLM с MCP-клиентом сможет вызвать этот add и получить результат в предсказуемом формате.
А вот так выглядит минимальный клиент, который подключается к серверу и вызывает инструмент:
Этот пример складывает два числа, но в реальных сценариях через MCP можно давать модели доступ к базе данных, API или внутренним сервисам. Главное — всё по единому протоколу, и это действительно удобно: теперь любой MCP-клиент сможет переиспользовать ту же самую логику.
tool. В то же время этот протокол задает единый язык общения между LLM и приложением.Тот же самый Cursor уже имеет в себе MCP-клиент, что позволяет ему обращаться к внешним серверам для выполнения дополнительной логики. Чтобы это работало, нужен MCP-сервер. Такой сервер можно поднять буквально в несколько строк с помощью fastmcp:
from fastmcp import FastMCP
mcp = FastMCP("Demo 🚀")
@mcp.tool
def add(a: int, b: int) -> int:
"""Складывает два числа"""
return a + b
if __name__ == "__main__":
mcp.run()
Теперь любая LLM с MCP-клиентом сможет вызвать этот add и получить результат в предсказуемом формате.
А вот так выглядит минимальный клиент, который подключается к серверу и вызывает инструмент:
from fastmcp import Client
import asyncio
async def main():
async with Client("my_server.py") as client:
tools = await client.list_tools()
print("Доступные инструменты:", tools)
result = await client.call_tool("add", {"a": 5, "b": 3})
print("Результат:", result.content[0].text)
asyncio.run(main())
Этот пример складывает два числа, но в реальных сценариях через MCP можно давать модели доступ к базе данных, API или внутренним сервисам. Главное — всё по единому протоколу, и это действительно удобно: теперь любой MCP-клиент сможет переиспользовать ту же самую логику.
👍5❤2
Нашел еще один blazingly fast тайпчекер на rust - zuban
Как обычно все, что написано на rust быстрее, чем предыдущие решения во много раз (по крайне мере, так заявляют)
И это решение не исключение, разработчик заявляет, что zuban быстрее mypy в 20-200 раз
Я поглядел на бенчи и пока что меня терзает сильный скепсис в отношении этих цифр
Хочу погонять его на реальных проектах и посмотреть, что из этого выйдет
Но в целом выглядит довольно многообещающе, особенно с учетом вот этих тестов
По ним можно видеть, что zuban поддерживает практически то же самое, что и mypy
Хочу подетальнее рассмотреть это решение, так как это уже не первый тайп-чекер, написанный на rust, ведь ty уже с нами какое-то время, хоть он и в альфе
Возможно, пришло время поменять mypy на что-то побыстрее 🤔
Как обычно все, что написано на rust быстрее, чем предыдущие решения во много раз (по крайне мере, так заявляют)
И это решение не исключение, разработчик заявляет, что zuban быстрее mypy в 20-200 раз
Я поглядел на бенчи и пока что меня терзает сильный скепсис в отношении этих цифр
Хочу погонять его на реальных проектах и посмотреть, что из этого выйдет
Но в целом выглядит довольно многообещающе, особенно с учетом вот этих тестов
По ним можно видеть, что zuban поддерживает практически то же самое, что и mypy
Хочу подетальнее рассмотреть это решение, так как это уже не первый тайп-чекер, написанный на rust, ведь ty уже с нами какое-то время, хоть он и в альфе
Возможно, пришло время поменять mypy на что-то побыстрее 🤔
GitHub
GitHub - zubanls/zuban: Python Type Checker / Language Server
Python Type Checker / Language Server. Contribute to zubanls/zuban development by creating an account on GitHub.
👍7
Там, кстати, вышел Python 3.14.
Кратенько о том, что нового и прикольного в нем появилось.
PEP 750 — t-строки
Раньше у нас были f-строки, которые сразу подставляют значения.
Теперь появились
Самый простой пример может выглядеть как-то так:
Смысл в том, что строка не форматируется сразу.
Её можно передать в другой модуль, отложить подстановку или использовать свой шаблонизатор.
Это особенно удобно, когда шаблон — не просто текст, а часть логики. Такое особенно часто встречается при генерации кода.
Раньше для этого приходилось хранить строки вручную, вызвать .format(), следить за фигурными скобками и экранированием.
Но теперь за этим будет следить сам Python, тк шаблон - это не просто строка, а специальный объект.
Можно динамически собирать куски кода, генерировать Python-функции, SQL-запросы или промпты для LLM — не превращая всё это в нечитабельные строки.
В эпоху генеративного ИИ это выглядит как очень своевременное нововведение.
Будет совсем здорово, если появятся подсказки типов и автодополнение для переменных внутри таких шаблонов — как будто бы, это вполне реально.
PEP 649 + PEP 749 — ленивые аннотации
До Python 3.14 аннотации вычислялись сразу, и если сослаться на класс или тип, которые ещё не определены, то всё падало.
Например:
Такой код раньше выдавал:
Приходилось писать костыли —
Теперь это больше не нужно.
Python сохраняет аннотации в виде исходного текста и вычисляет их только тогда, когда они реально понадобятся — например, при проверке типов, в Pydantic, IDE или еще где.
То есть аннотации больше не влияют на рантайм до тех пор, пока к ним не произойдет обращения.
Теперь при определении класса Python не пытается вычислить Profile — он просто помнит, что там аннотация 'Profile'.
И только когда произойдет обращение к
Это нововведение дает:
• Меньше циклических импортов
• Более быстрый старт модулей
• Предсказуемое поведение при анализе типов
Это далеко не все, что принес нам Python 3.14, на остальное тоже посмотрим!
Кратенько о том, что нового и прикольного в нем появилось.
PEP 750 — t-строки
Раньше у нас были f-строки, которые сразу подставляют значения.
Теперь появились
t-строки. С их помощью появилась возможность создавать шаблоны, в которые можно динамически подставлять значения. И функциональность гораздо шире, чем у обычного форматирования строк.Самый простой пример может выглядеть как-то так:
tmpl = t"Hello, ${name}!"
print(tmpl.substitute(name="Michael"))Смысл в том, что строка не форматируется сразу.
Её можно передать в другой модуль, отложить подстановку или использовать свой шаблонизатор.
Это особенно удобно, когда шаблон — не просто текст, а часть логики. Такое особенно часто встречается при генерации кода.
CLIENT_TEMPLATE = t'''
class SomeClient:
def __init__(self, base_url):
self.base_url = ${base_url}
def ${method_name}(self, payload):
return requests.${http_method}(f"{self.base_url}/${endpoint}", json={param_name})
'''
generation_config = {
"base_url": "https://whatever.com",
"method_name": "create_user",
"endpoint": "users",
"http_method": "post",
}
# И вот тут получается готовый клиентский код
CLIENT_TEMPLATE.substitute(**generation_config)
Раньше для этого приходилось хранить строки вручную, вызвать .format(), следить за фигурными скобками и экранированием.
Но теперь за этим будет следить сам Python, тк шаблон - это не просто строка, а специальный объект.
Можно динамически собирать куски кода, генерировать Python-функции, SQL-запросы или промпты для LLM — не превращая всё это в нечитабельные строки.
В эпоху генеративного ИИ это выглядит как очень своевременное нововведение.
Будет совсем здорово, если появятся подсказки типов и автодополнение для переменных внутри таких шаблонов — как будто бы, это вполне реально.
PEP 649 + PEP 749 — ленивые аннотации
До Python 3.14 аннотации вычислялись сразу, и если сослаться на класс или тип, которые ещё не определены, то всё падало.
Например:
class User:
def __init__(self, profile: Profile):
self.profile = profile
class Profile:
def __init__(self, user: User):
self.user = user
Такой код раньше выдавал:
NameError: name 'Profile' is not defined.Приходилось писать костыли —
from __future__ import annotations или аннотировать через строки вот так: "Profile".Теперь это больше не нужно.
Python сохраняет аннотации в виде исходного текста и вычисляет их только тогда, когда они реально понадобятся — например, при проверке типов, в Pydantic, IDE или еще где.
То есть аннотации больше не влияют на рантайм до тех пор, пока к ним не произойдет обращения.
Теперь при определении класса Python не пытается вычислить Profile — он просто помнит, что там аннотация 'Profile'.
И только когда произойдет обращение к
User.__annotations__, Python аккуратно развернёт это в реальный типы.Это нововведение дает:
• Меньше циклических импортов
• Более быстрый старт модулей
• Предсказуемое поведение при анализе типов
Это далеко не все, что принес нам Python 3.14, на остальное тоже посмотрим!
👍5⚡3
В продолжение о том, что нам даёт свежевышедший Python 3.14
PEP 779 — Free-Threaded Python
В 3.13 можно было собрать Python без GIL вручную, но теперь это официально поддержано.
Сборка без глобальной блокировки позволяет потокам действительно выполняться параллельно, а не по очереди под контролем GIL.
Что это значит на практике:
• CPU-bound задачи теперь можно распараллелить обычным threading, без multiprocessing и сериализации данных между процессами
• Классические примеры вроде работы с большими матрицами, парсинга или рендеринга теперь могут масштабироваться по ядрам
Раньше такой код давал почти нулевой прирост — теперь он реально распределяет нагрузку.
Главное ограничение — не все расширения C готовы к новой модели, так что экосистема некоторое время будет адаптироваться. Поэтому не ждите, что все сразу заработает на сборке без GIL (скорее всего все у вас разломается)
PEP 734 — Multiple Interpreters
Теперь можно запускать несколько независимых интерпретаторов Python в одном процессе — со своей памятью и модулями.
Это что-то между процессами и потоками.
Главная идея — изолировать код, не платя за межпроцессное взаимодействие и сериализацию данных, как в multiprocessing.
Что это даёт:
• Можно параллельно выполнять независимые задачи, не деля общие модули и состояние
• Подходит для запуска чужого или потенциально «грязного» кода внутри одного сервиса
Тут каждый run_task выполняется в своём мини-интерпретаторе. Никаких конфликтов, утечек или shared-state — всё изолировано.
Ну теперь почти как в go, осталось добавить удобный keyword для запуска таких интерпретаторов и можно больше не задумываться о том, чтобы сменить язык 🤡
Но в целом можно сказать, что это плюс для языка, все-таки в каком-то смысле Python и правда становится быстрее
PEP 779 — Free-Threaded Python
В 3.13 можно было собрать Python без GIL вручную, но теперь это официально поддержано.
Сборка без глобальной блокировки позволяет потокам действительно выполняться параллельно, а не по очереди под контролем GIL.
Что это значит на практике:
• CPU-bound задачи теперь можно распараллелить обычным threading, без multiprocessing и сериализации данных между процессами
• Классические примеры вроде работы с большими матрицами, парсинга или рендеринга теперь могут масштабироваться по ядрам
import threading
def calc(x):
# что-то сложное на математическом
...
threads = [threading.Thread(target=calc, args=(10_000_000,)) for _ in range(8)]
for t in threads: t.start()
for t in threads: t.join()
Раньше такой код давал почти нулевой прирост — теперь он реально распределяет нагрузку.
Главное ограничение — не все расширения C готовы к новой модели, так что экосистема некоторое время будет адаптироваться. Поэтому не ждите, что все сразу заработает на сборке без GIL (скорее всего все у вас разломается)
PEP 734 — Multiple Interpreters
Теперь можно запускать несколько независимых интерпретаторов Python в одном процессе — со своей памятью и модулями.
Это что-то между процессами и потоками.
Главная идея — изолировать код, не платя за межпроцессное взаимодействие и сериализацию данных, как в multiprocessing.
Что это даёт:
• Можно параллельно выполнять независимые задачи, не деля общие модули и состояние
• Подходит для запуска чужого или потенциально «грязного» кода внутри одного сервиса
from concurrent.interpreters import InterpreterPoolExecutor
def run_task(x):
import math
return math.sqrt(x)
with InterpreterPoolExecutor(max_workers=4) as pool:
results = pool.map(run_task, range(10))
Тут каждый run_task выполняется в своём мини-интерпретаторе. Никаких конфликтов, утечек или shared-state — всё изолировано.
Ну теперь почти как в go, осталось добавить удобный keyword для запуска таких интерпретаторов и можно больше не задумываться о том, чтобы сменить язык 🤡
Но в целом можно сказать, что это плюс для языка, все-таки в каком-то смысле Python и правда становится быстрее
👍6
OpenAI выпустила ChatGPT Atlas — новый браузер со встроенной GPT-моделью.
Что умеет:
• Чат прямо в боковой панели — можно обсуждать текущую страницу (ничего нового, но теперь нативно)
• Agent Mode — ассистент сам действует на сайте: переходит по ссылкам, кликает, ищет, оформляет
• Внешне — Chrome, но по сути — фундамент для веб-приложений, где интерфейсом управляет ИИ
Что это значит для разработчика:
• Браузер превращается из «окна» в интерфейс к знаниям и действиям, которыми модель реально управляет
• Выглядит так, что надо будет заниматься не только SEO оптимизацией, но еще и AI-оптимизацией сайтов. Опять работа, да
• В общем, скоро у топ-менеджмента начнёт ехать кукуха, а мы будем пилить AI-driven фронтенды
Но выглядит прикольно, мне нравится, попробую попользоваться
Что умеет:
• Чат прямо в боковой панели — можно обсуждать текущую страницу (ничего нового, но теперь нативно)
• Agent Mode — ассистент сам действует на сайте: переходит по ссылкам, кликает, ищет, оформляет
• Внешне — Chrome, но по сути — фундамент для веб-приложений, где интерфейсом управляет ИИ
Что это значит для разработчика:
• Браузер превращается из «окна» в интерфейс к знаниям и действиям, которыми модель реально управляет
• Выглядит так, что надо будет заниматься не только SEO оптимизацией, но еще и AI-оптимизацией сайтов. Опять работа, да
• В общем, скоро у топ-менеджмента начнёт ехать кукуха, а мы будем пилить AI-driven фронтенды
Но выглядит прикольно, мне нравится, попробую попользоваться
OpenAI
Introducing ChatGPT Atlas
This post introduced ChatGPT Atlas, a browser with ChatGPT built in. Atlas has since been deprecated.
🤓5
ChatGPT 5 потерял более 65% капитала в инвестиционном эксперименте nof1, в то время как полностью бесплатный DeepSeek 3.1 дал плюс 10% буквально за пару дней!
В рамках эксперимента всем популярным нейронками дали по дал по $10 тысяч с возможностью делать случайные сделки
Результаты же сделок можно видеть на онлайн-графиках
Помимо DeepSeek в плюс также вышли Grok 4 и Qwen 3 MAX
А Claude, Grok и Gemini также в минусе, как и ChatGPT
Ну вот, теперь можно трейдить через DeepSeek, чтобы оплачивать подписку на ChatGPT 🫠
В рамках эксперимента всем популярным нейронками дали по дал по $10 тысяч с возможностью делать случайные сделки
Результаты же сделок можно видеть на онлайн-графиках
Помимо DeepSeek в плюс также вышли Grok 4 и Qwen 3 MAX
А Claude, Grok и Gemini также в минусе, как и ChatGPT
Ну вот, теперь можно трейдить через DeepSeek, чтобы оплачивать подписку на ChatGPT 🫠
😁6😱1
Потихоньку начинаю поглядывать в сторону фреймворков, которые поддерживают протокол A2A (Agent-to-Agent) — когда агенты могут общаться между собой самостоятельно для достижения поставленной цели.
До недавнего времени удобных вариантов особо не было.
В pydantic-ai можно было поднять сервер, но клиента не было — говорить всё равно не с кем.
А в a2a-python поддержка вроде как есть, но интерфейс не супер-удобный, да и весь код синхронный.
И вот теперь в AG2 (autogen 2) тоже завезли поддержку A2A 👉 релиз 0.10.0
Теперь можно:
• поднять сервер агента с А2А интерфейсом
• подключиться к нему как к удалённому агенту
• заставить их общаться друг с другом по протоколу А2А
Выглядит как первый по-настоящему удобный способ строить распределённые агентные системы, где каждый агент — отдельный сервис, говорящий на общем языке.
А вот тут лежит дока, можно поглядеть.
До недавнего времени удобных вариантов особо не было.
В pydantic-ai можно было поднять сервер, но клиента не было — говорить всё равно не с кем.
А в a2a-python поддержка вроде как есть, но интерфейс не супер-удобный, да и весь код синхронный.
И вот теперь в AG2 (autogen 2) тоже завезли поддержку A2A 👉 релиз 0.10.0
Теперь можно:
• поднять сервер агента с А2А интерфейсом
• подключиться к нему как к удалённому агенту
• заставить их общаться друг с другом по протоколу А2А
from autogen import ConversableAgent, LLMConfig
from autogen.a2a import A2aAgentServer, A2aRemoteAgent
agent = ConversableAgent(
name="python_coder",
system_message="You are an expert Python developer...",
llm_config=LLMConfig({"model": "gpt-4o-mini"}),
)
# поднимаем сервер
server = A2aAgentServer(agent).build()
# подключаемся как к удалённому агенту
remote = A2aRemoteAgent(
url="http://localhost:8000",
name="python_coder",
)
Выглядит как первый по-настоящему удобный способ строить распределённые агентные системы, где каждый агент — отдельный сервис, говорящий на общем языке.
А вот тут лежит дока, можно поглядеть.
🔥10❤3
Не люблю писать тесты.
Мечта любого разработчика: пока ты пьёшь кофе — ИИ сам написал тесты, CI зелёный, жизнь удалась. Но как обычно, дьявол в деталях.
Уже существует немало решений, которые умеют генерить тесты на основе LLM или без нее, тут посмотрим на самые рабочие.
⚙️ Pynguin — мутации ради покрытия
Pynguin анализирует код, типы и зависимости, а затем подбирает входные данные, чтобы пройтись по всем веткам выполнения. Что-то вроде hypothesis, только без вас.
Допустим, у нас есть модуль my_module.py:
Теперь запускаем генерацию тестов:
Pynguin создаст в tests/generated что-то вроде:
Покрытие — есть и вроде бы все здорово. Смысл — зависит от исходного кода. Но вот если бы, например, divide() тихо возвращал None вместо исключения, Pynguin всё равно зафиксировал бы это в тесте как нормальное поведение, хотя это очевидный баг. И вот в вашей кодовой базе есть тесты, которые делают только хуже.
🕵️ Keploy — тесты через подслушивание
Пример: у вас есть простой FastAPI-сервис.
Дальше вы запускаете приложение под контролем Keploy:
Keploy поднимет приложение, начнёт слушать трафик и запишет все ваши действия — например, когда будет сделан запрос, его результат будет сохранен в YAML-файле. Этот YAML-файл будет считаться эталонным и не его основе будут производиться проверки при запуске тестов.
Далее можно прогнать сохранённые сценарии и сравнить, совпадают ли ответы с тем, что сохранено у нас в сгенеренных файлах. Если что-то не совпадает — тест упадёт.
Плюс — язык неважен, работает с любыми стековыми связками. Минус — сложнее встраивать в защищённые среды, тк эта штука любит ходить в облако.
Выглядит так, что сейчас автоматическая генерация "хороших" тестов скорее не “магическая кнопка”, а поле для экспериментов: можно поиграться локально, посмотреть, что получится, но рассчитывать на безболезненную интеграцию в CI/CD пока рано.
Тем не менее, направление интересное — как минимум, оно заставляет нас задуматься, что именно мы проверяем тестами и кто ещё может это сделать за нас.
Мечта любого разработчика: пока ты пьёшь кофе — ИИ сам написал тесты, CI зелёный, жизнь удалась. Но как обычно, дьявол в деталях.
Уже существует немало решений, которые умеют генерить тесты на основе LLM или без нее, тут посмотрим на самые рабочие.
⚙️ Pynguin — мутации ради покрытия
Pynguin анализирует код, типы и зависимости, а затем подбирает входные данные, чтобы пройтись по всем веткам выполнения. Что-то вроде hypothesis, только без вас.
Допустим, у нас есть модуль my_module.py:
def add(a: int, b: int) -> int:
return a + b
def divide(a: int, b: int) -> float:
if b == 0:
raise ValueError("division by zero")
return a / b
Теперь запускаем генерацию тестов:
pynguin \
--project-path ./my_project \
--output-path ./tests/generated \
--module-name my_module
Pynguin создаст в tests/generated что-то вроде:
def test_addition_works():
result = my_module.add(2, 2)
assert result == 4
def test_divide_by_zero():
with pytest.raises(ValueError):
my_module.divide(1, 0)
Покрытие — есть и вроде бы все здорово. Смысл — зависит от исходного кода. Но вот если бы, например, divide() тихо возвращал None вместо исключения, Pynguin всё равно зафиксировал бы это в тесте как нормальное поведение, хотя это очевидный баг. И вот в вашей кодовой базе есть тесты, которые делают только хуже.
🕵️ Keploy — тесты через подслушивание
Пример: у вас есть простой FastAPI-сервис.
from fastapi import FastAPI
app = FastAPI()
@app.get("/hello/{name}")
def hello(name: str):
return {"message": f"Hello, {name}!"}
Дальше вы запускаете приложение под контролем Keploy:
keploy record --command "uvicorn main:app"
Keploy поднимет приложение, начнёт слушать трафик и запишет все ваши действия — например, когда будет сделан запрос, его результат будет сохранен в YAML-файле. Этот YAML-файл будет считаться эталонным и не его основе будут производиться проверки при запуске тестов.
name: Test-hello-endpoint
request:
method: GET
url: /hello/Alice
response:
status: 200
body: '{"message":"Hello, Alice!"}'
Далее можно прогнать сохранённые сценарии и сравнить, совпадают ли ответы с тем, что сохранено у нас в сгенеренных файлах. Если что-то не совпадает — тест упадёт.
Плюс — язык неважен, работает с любыми стековыми связками. Минус — сложнее встраивать в защищённые среды, тк эта штука любит ходить в облако.
Выглядит так, что сейчас автоматическая генерация "хороших" тестов скорее не “магическая кнопка”, а поле для экспериментов: можно поиграться локально, посмотреть, что получится, но рассчитывать на безболезненную интеграцию в CI/CD пока рано.
Тем не менее, направление интересное — как минимум, оно заставляет нас задуматься, что именно мы проверяем тестами и кто ещё может это сделать за нас.
👍6
Выходные в самом разгаре — а у меня уже руки чешутся потрогать что-то новое и прикольное.
Недавно наткнулся на MCP Market — платформу, где можно найти MCP-сервер почти под любую задачу.
💡Что это вообще такое
MCP (Model Context Protocol) — протокол, с помощью которого можно подключить LLM-ассистента к реальным инструментам: git, API, файлам, CI/CD, таск-трекерам.
А MCP-серверы — это готовые модули, через которые ассистент получит возможность выполнять какие-то активные действия. Масштаб такх активных действий ограничен только сознанием разработчика MCP-сервера.
🔧 Несколько интересных примеров
— Хочешь залететь в open source, но не дружишь с git?
Тогда GitHub MCP Server поможет работать с GitHub API на естественном языке: коммиты, пул-реквесты, ревью — всё из диалога с ассистентом.
— Для любителей no-code full-swag n8n тоже есть решение - n8n MCP Server. Вам даже не придется погружаться в то, что такое n8n, эта штука позволяет создавать сценарии, запускать воркфлоу и автоматизировать процессы без кликов в интерфейсе.
— А если ты уже давно перетаскиваешь таски внутри таск-трекера (соболезную, понимаю) — посмотри на Task Master.
Этот сервер даёт возможность управлять туду-листами и задачами прямо через чат с ассистентом.
И самое приятное — все эти серверы доступны бесплатно.
Так что если вы давно хотели, чтобы ассистент умел не только болтать и отвечать на вопросы, но и работать вместе с вами — самое время собрать свой набор MCP-сервисов.
Пусть теперь он делает рутину, а вы — интересное.
Недавно наткнулся на MCP Market — платформу, где можно найти MCP-сервер почти под любую задачу.
💡Что это вообще такое
MCP (Model Context Protocol) — протокол, с помощью которого можно подключить LLM-ассистента к реальным инструментам: git, API, файлам, CI/CD, таск-трекерам.
А MCP-серверы — это готовые модули, через которые ассистент получит возможность выполнять какие-то активные действия. Масштаб такх активных действий ограничен только сознанием разработчика MCP-сервера.
🔧 Несколько интересных примеров
— Хочешь залететь в open source, но не дружишь с git?
Тогда GitHub MCP Server поможет работать с GitHub API на естественном языке: коммиты, пул-реквесты, ревью — всё из диалога с ассистентом.
— Для любителей no-code full-swag n8n тоже есть решение - n8n MCP Server. Вам даже не придется погружаться в то, что такое n8n, эта штука позволяет создавать сценарии, запускать воркфлоу и автоматизировать процессы без кликов в интерфейсе.
— А если ты уже давно перетаскиваешь таски внутри таск-трекера (соболезную, понимаю) — посмотри на Task Master.
Этот сервер даёт возможность управлять туду-листами и задачами прямо через чат с ассистентом.
И самое приятное — все эти серверы доступны бесплатно.
Так что если вы давно хотели, чтобы ассистент умел не только болтать и отвечать на вопросы, но и работать вместе с вами — самое время собрать свой набор MCP-сервисов.
Пусть теперь он делает рутину, а вы — интересное.
🔥9⚡1
Dev no Sekai | Михаил Гурбанов
ChatGPT 5 потерял более 65% капитала в инвестиционном эксперименте nof1, в то время как полностью бесплатный DeepSeek 3.1 дал плюс 10% буквально за пару дней! В рамках эксперимента всем популярным нейронками дали по дал по $10 тысяч с возможностью делать случайные…
Там, кстати, завершили этот эксперимент и вот результаты
По итогу победил Qwen3 Max и заработал 500$
В самом низу топа оказались модели Grok 4 и ChatGPT 5, им доверять денежки я бы не стал 🤡
Вот вам и рецепт бесплатных денежек, если, конечно, у вас в доступе есть Qwen3 Max
По итогу победил Qwen3 Max и заработал 500$
В самом низу топа оказались модели Grok 4 и ChatGPT 5, им доверять денежки я бы не стал 🤡
Вот вам и рецепт бесплатных денежек, если, конечно, у вас в доступе есть Qwen3 Max
🤡2
Чем старше проект — тем больше автоматизаций спасают нервы.
И если вы уже устали писать скрипты “на коленке”, самое время познакомиться с n8n.
💡 Что это
n8n — open-source альтернатива Zapier, только с возможностью писать свои ноды на JavaScript и запускать всё у себя.
Можно соединять API, базы данных, LLM-модели, GitHub и почти всё, у чего есть REST или SDK.
🛠 Примеры, где n8n действительно удобен:
— ML-пайплайны: забирать результаты из S3, триггерить постобработку и уведомлять в Telegram.
— RAG-системы: обновлять векторный индекс после каждого пуша в Git.
— Боты и интеграции: от напоминаний о новых PR до сборки внутренних отчётов
— И любые другие автоматизации
Главное — всё это можно собрать без строчки кода.
Интерфейс позволяет накликать флоу из готовых нод, а если чего-то не хватает — легко дописать свою.
🎯 Почему это становится особенно интересно сейчас
С появлением протоколов вроде MCP и A2A, n8n превращается в полноценный инструмент для построения агентных систем.
Любой агент — это по сути API, а n8n умеет работать с API так, как будто создан для этого.
В итоге: n8n — не полностью no-code, а скорее less-code, так как в каких-то случаях инструментов из коробки может и не хватить.
С точки зрения храненя проекта подойдет тот же самый gitlab/githab/whatever. Флоу простой, вы натыкиваете флоу через интрефейс, экспортируете его в yaml или json и кладете в репозиторий. Можно даже сделать так, чтобы эти флоу сами сохранялись в нужный для вас репозиторий (да, через тот же самый n8n)
В общем, n8n — это когда ты всё ещё инженер, просто теперь автоматизация занимает минуты, а не дни.
Скоро принесу пару примерчиков автоматизаций из жизни ⚡️
И если вы уже устали писать скрипты “на коленке”, самое время познакомиться с n8n.
💡 Что это
n8n — open-source альтернатива Zapier, только с возможностью писать свои ноды на JavaScript и запускать всё у себя.
Можно соединять API, базы данных, LLM-модели, GitHub и почти всё, у чего есть REST или SDK.
🛠 Примеры, где n8n действительно удобен:
— ML-пайплайны: забирать результаты из S3, триггерить постобработку и уведомлять в Telegram.
— RAG-системы: обновлять векторный индекс после каждого пуша в Git.
— Боты и интеграции: от напоминаний о новых PR до сборки внутренних отчётов
— И любые другие автоматизации
Главное — всё это можно собрать без строчки кода.
Интерфейс позволяет накликать флоу из готовых нод, а если чего-то не хватает — легко дописать свою.
🎯 Почему это становится особенно интересно сейчас
С появлением протоколов вроде MCP и A2A, n8n превращается в полноценный инструмент для построения агентных систем.
Любой агент — это по сути API, а n8n умеет работать с API так, как будто создан для этого.
В итоге: n8n — не полностью no-code, а скорее less-code, так как в каких-то случаях инструментов из коробки может и не хватить.
С точки зрения храненя проекта подойдет тот же самый gitlab/githab/whatever. Флоу простой, вы натыкиваете флоу через интрефейс, экспортируете его в yaml или json и кладете в репозиторий. Можно даже сделать так, чтобы эти флоу сами сохранялись в нужный для вас репозиторий (да, через тот же самый n8n)
В общем, n8n — это когда ты всё ещё инженер, просто теперь автоматизация занимает минуты, а не дни.
Скоро принесу пару примерчиков автоматизаций из жизни ⚡️
n8n.io
n8n.io - AI workflow automation platform
n8n is a workflow automation platform that uniquely combines AI capabilities with business process automation, giving technical teams the flexibility of code with the speed of no-code.
🔥9⚡2
✨ Litestar: фреймворк, который тихо стал нормальной альтернативой FastAPI
Litestar — фреймворк, который появился абсолютно незаметно для python-мира, но при этом уже готовится стать заменой FastAPI.
Этот фреймворк мы заметили еще в далеком 23-м году, когда никто ничего он нем не знал. Но он нам очень сильно понравился и вот почему:
1. Человеческий DI
В Litestar зависимости — это обычные функции.
Не классическая FastAPI-магия.
Прозрачно, тестируемо и самое главное - понятно. Более того, его можно комбинировать с такими библиотеками, как: dishka, that-depends и даже старый-добрый dependency-injector.
2. Контроллеры, которые не превращают проект в мешанину
Litestar даёт возможно писать обработчики внутри классов, чтобы наши модули не превращались в большую кучу непонятно каких функций
Когда сервис растёт — проект остаётся читаемым.
3. Нормальные DTO (того, чего FastAPI очень не хватало)
DTO в Litestar позволяют разорвать связку
ORM → API → запросы → ответы.
То есть можно отдельно описывать:
• Что приходит в запросе
• Как выглядит модель внутри сервиса
• Что именно отдаёшь наружу
Да, оно под капотом переделает модельку алхимии и вернет нам json, который содержит все поля из UserModel, кроме
Очень удобно, такой подход позволяет нам меньше задумываться о том, как описать ту или иную схему и больше сосредоточиться на бизнес-логике.
4. Advanced Alchemy: приятная ORM-интеграция
Вместо того чтобы прикручивать SQLAlchemy вручную, Litestar отлично работает с Advanced Alchemy — современным слоем над SQLAlchemy, где уже есть:
• Асинхронные сессии
• Репозитории и CRUD
• Жизненный цикл сессии, привязанный к запросу
• Интеграция с DTO
Самое важное — не нужно оборачивать SQLAlchemy в самописный сервисный слой: всё уже готово.
Например, вот так вы можете сделать репозиторий, в котором уже будут все необходимые CRUD методы.
Да, вот так просто, без огромной кучи самописных SQL запросов и боли.
Небольшой итог:
В принципе, Litestar позволяет делать то же самое, что и FastAPI, но лучше 😁
• Простой и понятный DI
• Контроллеры, которые легко масштабируются
• Неплохие DTO
• Хорошая интеграция с Advanced Alchemy
Кстати, вот тут делали бенчмарки FastAPI, Litestar и других разных фреймворков. Litestar очень даже шустрый (да, шустрее FastAPI)!
Так что если вы задумываетесь о том, что бы еще такого прикольного попробовать на Python, очень рекомендую данный фреймворк.
P.S.
Чуваки даже написали гайд, как мигрировать с FastAPI.
Litestar — фреймворк, который появился абсолютно незаметно для python-мира, но при этом уже готовится стать заменой FastAPI.
Этот фреймворк мы заметили еще в далеком 23-м году, когда никто ничего он нем не знал. Но он нам очень сильно понравился и вот почему:
1. Человеческий DI
В Litestar зависимости — это обычные функции.
Не классическая FastAPI-магия.
def create_awesome_service():
return YourAwesomeService(...)
@get("/", dependencies={"awesome_service": Provide(create_awesome_service)})
async def list_something_cool(awesome_service: YourAwesomeService):
return await awesome_service.list_very_cool_things(...)
Прозрачно, тестируемо и самое главное - понятно. Более того, его можно комбинировать с такими библиотеками, как: dishka, that-depends и даже старый-добрый dependency-injector.
2. Контроллеры, которые не превращают проект в мешанину
Litestar даёт возможно писать обработчики внутри классов, чтобы наши модули не превращались в большую кучу непонятно каких функций
class UserController(Controller):
path = "/users"
@get("/")
async def list_users(self):
return [{"id": 1, "name": "Alice"}]
Когда сервис растёт — проект остаётся читаемым.
3. Нормальные DTO (того, чего FastAPI очень не хватало)
DTO в Litestar позволяют разорвать связку
ORM → API → запросы → ответы.
То есть можно отдельно описывать:
• Что приходит в запросе
• Как выглядит модель внутри сервиса
• Что именно отдаёшь наружу
# Моделька пользователя на алхимии
class UserModel(sqlalchemy.orm.DeclarativeBase):
email: orm.Mapped[str]
name: orm.Mapped[str]
password_hash: orm.Mapped[str]
# Данные для создания пользователя
class CreateUserRequest(pydantic.BaseModel):
email: str
name: str
password: str
# Вот эту штуку мы вернем через API после создания
class UserReadDTO(DataclassDTO[User]):
# Чем-то похоже на секцию exclude в DRF
config = {"exclude": {"password_hash"}}
@post("/users", dto=CreateUser, return_dto=UserReadDTO)
async def create_user(data: CreateUserRequest) -> UserModel:
user = UserModel(...)
return user
Да, оно под капотом переделает модельку алхимии и вернет нам json, который содержит все поля из UserModel, кроме
password_hash, которое мы исключили в конфиге DTO.Очень удобно, такой подход позволяет нам меньше задумываться о том, как описать ту или иную схему и больше сосредоточиться на бизнес-логике.
4. Advanced Alchemy: приятная ORM-интеграция
Вместо того чтобы прикручивать SQLAlchemy вручную, Litestar отлично работает с Advanced Alchemy — современным слоем над SQLAlchemy, где уже есть:
• Асинхронные сессии
• Репозитории и CRUD
• Жизненный цикл сессии, привязанный к запросу
• Интеграция с DTO
Самое важное — не нужно оборачивать SQLAlchemy в самописный сервисный слой: всё уже готово.
Например, вот так вы можете сделать репозиторий, в котором уже будут все необходимые CRUD методы.
from advanced_alchemy import SQLAlchemyAsyncRepository
class UserRepository(SQLAlchemyAsyncRepository[UserModel]):
model_type = UserModel
Да, вот так просто, без огромной кучи самописных SQL запросов и боли.
Небольшой итог:
В принципе, Litestar позволяет делать то же самое, что и FastAPI, но лучше 😁
• Простой и понятный DI
• Контроллеры, которые легко масштабируются
• Неплохие DTO
• Хорошая интеграция с Advanced Alchemy
Кстати, вот тут делали бенчмарки FastAPI, Litestar и других разных фреймворков. Litestar очень даже шустрый (да, шустрее FastAPI)!
Так что если вы задумываетесь о том, что бы еще такого прикольного попробовать на Python, очень рекомендую данный фреймворк.
P.S.
Чуваки даже написали гайд, как мигрировать с FastAPI.
🔥11👍3🏆1🆒1
Запуск нового сервиса часто превращается в повторяющуюся рутину: настроить логи, метрики, трейсинг и еще кучу всяких штук.
Чтобы не выполнять это вручную в каждом проекте, мы сделали библиотеку microbootstrap.
microbootstrap — тонкий слой, который автоматически поднимает инфраструктурную часть сервиса.
Все параметры — через единый Pydantic-класс настроек, что делает конфигурацию простой и централизованной.
Пример (всё сразу): настройки, FastAPI, Sentry, метрики, трейсинг
Microbootstrap сам инициализирует Sentry, opentelemtry, prometheus, cors и много чего еще на старте: подключает error-handler’ы, включает distributed tracing и автоматически привязывает события к вашему сервису — достаточно указать параметры в Settings в декларативном виде.
Мы также сделали удобный bootstrap для Litestar и Faststream.
Единая структура настроек и точно такой же bootstrap-механизм.
Так что эта библиотека подойдет как для синхронных приложений, работающих через HTTP, так и для асинхронных, на основе очередей.
P.S.
Если у вас есть какой-то кейс, которого тут не хватает - смело пишите мне или закидывайте issue!
P.S.S.
И обязательно ставьте звездочки! Так мы поймем, что проект действительно полезен и у нас будет больше мотивации его дорабатывать!
Чтобы не выполнять это вручную в каждом проекте, мы сделали библиотеку microbootstrap.
microbootstrap — тонкий слой, который автоматически поднимает инфраструктурную часть сервиса.
Все параметры — через единый Pydantic-класс настроек, что делает конфигурацию простой и централизованной.
Пример (всё сразу): настройки, FastAPI, Sentry, метрики, трейсинг
from microbootstrap import FastApiSettings
from microbootstrap.bootstrappers.fastapi import FastApiBootstrapper
class ServiceSettings(FastApiSettings):
# Базовые параметры
service_name: str = "my-awesome-service"
service_debug: bool = False
# Метрики
prometheus_metrics_path: str = "/metrics"
# Трейсинг
opentelemetry_endpoint: str = "http://otel-collector:4318/v1/traces"
# Sentry (пример настройки инструмента)
sentry_dsn: str = "https://public_key@sentry.io/12345"
sentry_traces_sample_rate: float = 1.0 # включаем полную выборку трейсов
sentry_profiles_sample_rate: float = 0.1 # профили на 10% запросов
# Все конфиги — в одном месте
settings = ServiceSettings()
# Метод bootstrap подключает логи, метрики, трейсинг, Sentry и health-checks автоматически
# И в итоге вы получаете готовое приложение, которое можно запускать
app = FastApiBootstrapper(settings).bootstrap()
Microbootstrap сам инициализирует Sentry, opentelemtry, prometheus, cors и много чего еще на старте: подключает error-handler’ы, включает distributed tracing и автоматически привязывает события к вашему сервису — достаточно указать параметры в Settings в декларативном виде.
Мы также сделали удобный bootstrap для Litestar и Faststream.
Единая структура настроек и точно такой же bootstrap-механизм.
Так что эта библиотека подойдет как для синхронных приложений, работающих через HTTP, так и для асинхронных, на основе очередей.
P.S.
Если у вас есть какой-то кейс, которого тут не хватает - смело пишите мне или закидывайте issue!
P.S.S.
И обязательно ставьте звездочки! Так мы поймем, что проект действительно полезен и у нас будет больше мотивации его дорабатывать!
GitHub
GitHub - community-of-python/microbootstrap: Bootstrap your microservices in a second!
Bootstrap your microservices in a second! Contribute to community-of-python/microbootstrap development by creating an account on GitHub.
🔥11👍6
А вот ещё одна open-source библиотека, к которой мне довелось приложить руку ⚡️.
Когда-то мы начали писать свою ORM. И чтобы выделяться на фоне остальных - нам в голову пришла идея написать для нее драйвер на rust. Но по итогу ORM мы больше не разрабатываем, а вот драйвер - наоборот.
Так появился psqlpy — асинхронный PostgreSQL-драйвер на Rust.
Да, Rust внутри Python — классика 2025 года.
Почему вообще стоит рассматривать этот драйвер?
Главная фишка psqlpy — ядро на Rust.
Это даёт драйверу предсказуемую производительность и высокую пропускную способность. Он просто быстрее классических Python-клиентов, особенно под нагрузкой.
Вторая важная штука — совместимость с asyncpg API.
Если вы работали с asyncpg, переход не займёт много времени: те же методы, те же паттерны, но под капотом — более быстрый и безопасный Rust.
Как это выглядит в коде:
Кроме пула коннектов, в драйвере есть еще пара важных штук
Вот они, сверху вниз:
— Connection - когда не хочется работать с объектом пула коннектов, можно использовать выделенное соединение.
— Transaction - если нужно выполнить много операций вместе.
— Cursor - в случае, если надо вычитать много записей из БД.
А если вы любите работать с ORM, то уже написан пакет с движком на psqlpy под sqlalchemy: psqlpy-sqlalchemy
Устанавливаете его и дальше все точно так же, как при работе с алхимией:
Этот пакет пока выглядит немного сырым, но в принципе пробовать уже можно.
В общем, если вы любите писать на чистых SQL запросах — можете использовать используйте psqlpy как чистый драйвер.
А если любите работать с объектами — подключайте его как движок для SQLAlchemy.
Кстати, я тут в 2024-м году как раз рассказывал про этот драйвер на PyCon. Можете глянуть, если хотите узнать, что у него под капотом.
Мы даже запилили бенчмарки, которые показали нам, что psqlpy до 3-х раз быстрее, чем asyncpg и psycopg. Но как известно, все бенчмарки обычно врут, поэтому можете запустить у себя сами и убедиться!
Подводя итог, psqlpy — это сочетание:
— Очень удобного асинхронного пула соединений.
— Скорости низкоуровневого Rust-драйвера.
— Привычного asyncpg-подобного интерфейса.
А еще у нас есть чат в телеге, так что по любым вопросам, связанным с драйвером смело можете писать туда.
Когда-то мы начали писать свою ORM. И чтобы выделяться на фоне остальных - нам в голову пришла идея написать для нее драйвер на rust. Но по итогу ORM мы больше не разрабатываем, а вот драйвер - наоборот.
Так появился psqlpy — асинхронный PostgreSQL-драйвер на Rust.
Да, Rust внутри Python — классика 2025 года.
Почему вообще стоит рассматривать этот драйвер?
Главная фишка psqlpy — ядро на Rust.
Это даёт драйверу предсказуемую производительность и высокую пропускную способность. Он просто быстрее классических Python-клиентов, особенно под нагрузкой.
Вторая важная штука — совместимость с asyncpg API.
Если вы работали с asyncpg, переход не займёт много времени: те же методы, те же паттерны, но под капотом — более быстрый и безопасный Rust.
Как это выглядит в коде:
from typing import Final
from psqlpy import ConnectionPool
async def main() -> None:
with ConnectionPool( # создаем пул коннектов
dsn="postgres://postgres:postgres@localhost:5432/postgres",
max_db_pool_size=10,
) as db_pool:
# ConnectionPool сам открывается и подключается
await db_pool.execute("SOME_SQL")
# ConnectionPool сам закрывается и отключается
# Вот тут приложение уже не держит в себе никаких коннектов с БД
Кроме пула коннектов, в драйвере есть еще пара важных штук
Вот они, сверху вниз:
— Connection - когда не хочется работать с объектом пула коннектов, можно использовать выделенное соединение.
— Transaction - если нужно выполнить много операций вместе.
— Cursor - в случае, если надо вычитать много записей из БД.
А если вы любите работать с ORM, то уже написан пакет с движком на psqlpy под sqlalchemy: psqlpy-sqlalchemy
Устанавливаете его и дальше все точно так же, как при работе с алхимией:
from sqlalchemy import create_engine, text
engine = create_engine(
"psqlpy+postgresql://postgres:postgres@localhost/postgres"
)
with engine.connect() as conn:
print(conn.execute(text("SELECT 1")).all())
Этот пакет пока выглядит немного сырым, но в принципе пробовать уже можно.
В общем, если вы любите писать на чистых SQL запросах — можете использовать используйте psqlpy как чистый драйвер.
А если любите работать с объектами — подключайте его как движок для SQLAlchemy.
Кстати, я тут в 2024-м году как раз рассказывал про этот драйвер на PyCon. Можете глянуть, если хотите узнать, что у него под капотом.
Мы даже запилили бенчмарки, которые показали нам, что psqlpy до 3-х раз быстрее, чем asyncpg и psycopg. Но как известно, все бенчмарки обычно врут, поэтому можете запустить у себя сами и убедиться!
Подводя итог, psqlpy — это сочетание:
— Очень удобного асинхронного пула соединений.
— Скорости низкоуровневого Rust-драйвера.
— Привычного asyncpg-подобного интерфейса.
А еще у нас есть чат в телеге, так что по любым вопросам, связанным с драйвером смело можете писать туда.
GitHub
GitHub - psqlpy-python/psqlpy: Asynchronous Python PostgreSQL driver written in Rust
Asynchronous Python PostgreSQL driver written in Rust - psqlpy-python/psqlpy
⚡5❤2🫡2👍1
Вышел очередной агентный фреймворк!
Как же все эти ребята любят префикс
Вот, как это дело можно использовать
Что тут важно:
— Worker - это по сути мост между A2A и реальным агентом. Именно тут вызывается ваша логика: LLM, AG2, PydanticAI — любой движок, который умеет отвечать.
— Storage и Broker - заменяемые штуки: в примере in-memory, но можно прикрутить Redis, Kafka или свою БД.
— FastA2A - обычное ASGI-приложение, которое можно поднять через uvicorn или granian. Но снаружи это будет выглядеть как А2А сервер.
Но самое забавное здесь то, что пока не очень понятно, как именно это всё должно дружить с pydantic-ai (как будто бы это основная библиотека).
В документации у PydanticAI этот проект ещё даже не упоминается, но, кажется, это вопрос времени.
В общем, теперь придётся следить ещё за одним решением агентной проблемы. Хотя если ребята интегрируются с pydantic-ai, то будет очень удобно разрабатывать системы на основе mcp и a2a и не тащить при этом миллион пакетов. Буду мониторить, посмотри, что из этого выйдет
Как же все эти ребята любят префикс
fast, я не могу. В общем, чуваки из Pydantic сделали отдельную библиотеку под протокол а2а - fasta2a. Это легковесная прослойка над A2A-протоколом на основе Starlette, которая позволяет быстро создавать агентные системы.Вот, как это дело можно использовать
from fasta2a import FastA2A, Worker
from fasta2a.broker import InMemoryBroker
from fasta2a.schema import Message, TaskSendParams, TextPart
from fasta2a.storage import InMemoryStorage
Context = list[Message]
class InMemoryWorker(Worker[Context]):
async def run_task(self, params: TaskSendParams) -> None:
# Вот это идет по спеке А2А. Правда, на данном этапе это все делается вручную
# Все эти адйдишники и контексты - часть спецификации протокола А2А
task = await self.storage.load_task(params["id"])
assert task is not None
await self.storage.update_task(task["id"], state="working")
context = await self.storage.load_context(task["context_id"]) or []
context.extend(task.get("history", []))
# Здесь вы вызываете своего агента
message = Message(
role="agent",
parts=[TextPart(text=f"Context length: {len(context) + 1}", kind="text")],
kind="message",
message_id=str(uuid.uuid4()),
)
context.append(message)
await self.storage.update_context(task["context_id"], context)
await self.storage.update_task(task["id"], state="completed", new_messages=[message])
storage = InMemoryStorage()
broker = InMemoryBroker()
worker = InMemoryWorker(storage=storage, broker=broker)
@asynccontextmanager
async def lifespan(app: FastA2A) -> AsyncIterator[None]:
async with app.task_manager:
async with worker.run():
yield
app = FastA2A(storage=storage, broker=broker, lifespan=lifespan)
Что тут важно:
— Worker - это по сути мост между A2A и реальным агентом. Именно тут вызывается ваша логика: LLM, AG2, PydanticAI — любой движок, который умеет отвечать.
— Storage и Broker - заменяемые штуки: в примере in-memory, но можно прикрутить Redis, Kafka или свою БД.
— FastA2A - обычное ASGI-приложение, которое можно поднять через uvicorn или granian. Но снаружи это будет выглядеть как А2А сервер.
Но самое забавное здесь то, что пока не очень понятно, как именно это всё должно дружить с pydantic-ai (как будто бы это основная библиотека).
В документации у PydanticAI этот проект ещё даже не упоминается, но, кажется, это вопрос времени.
В общем, теперь придётся следить ещё за одним решением агентной проблемы. Хотя если ребята интегрируются с pydantic-ai, то будет очень удобно разрабатывать системы на основе mcp и a2a и не тащить при этом миллион пакетов. Буду мониторить, посмотри, что из этого выйдет
GitHub
GitHub - datalayer/fasta2a: Convert an AI Agent into a A2A server! ✨
Convert an AI Agent into a A2A server! ✨. Contribute to datalayer/fasta2a development by creating an account on GitHub.
🔥6
В Python долго считалось, что DI - штука чужая.
Не нужен нам контейнер, не нужны провайдеры: «создам объект в конструкторе - и поехали».
Это действительно работает… пока у тебя не появляется десяток сервисов, клиенты, кеши, пулы и фоновые задачи.
И вот уже каждый новый объект тянет за собой ещё пару зависимостей - и слой, который должен быть простым, превращается в хаос.
Чтобы этот хаос остановить, и существуют DI-библиотеки.
Мы у себя используем that-depends - она ближе всего нам по синтаксису и ощущению.
Проект, по сути, вырос после того, как популярный dependency-injector не стал поддерживать Python 3.12 (сейчас они поддержали, но уже поздно!!), и мы внезапно остались без удобного DI под современный стек.
Самое приятное в that-depends - он не ломает привычный стиль разработки и не требует изучать «новый мир».
Он просто позволяет декларативно описать, как создаются зависимости, и хранить всё это в одном месте.
Сервис-слой перестаёт расползаться, а тесты перестают превращаться в мококарнавал.
🔹 Пример - асинхронный ресурс
Жизненный цикл ресурса определён контейнером.
Бизнес-логика пользуется пулом, не думая о его устройстве.
В тестах Container.db можно заменить одной строкой - без танцев.
🔹 Пример из реальной жизни
Не нужно протаскивать зависимости через пять уровней конструкторов.
Не нужно хранить singletons в модулях.
Не нужно вручную собирать граф объектов - контейнер делает это сам.
И вот за это подход и нравится:
все зависимости лежат в одном месте, ими удобно управлять, легко подменять и переиспользовать.
Код становится чище, архитектура - прозрачнее, тесты - проще.
that-depends, конечно, не единственный DI в экосистеме.
Но это тот вариант, который ощущается по-питоновски: лёгкий, понятный, без магии и лишнего шума - и при этом действительно полезный в живых проектах.
Не нужен нам контейнер, не нужны провайдеры: «создам объект в конструкторе - и поехали».
Это действительно работает… пока у тебя не появляется десяток сервисов, клиенты, кеши, пулы и фоновые задачи.
И вот уже каждый новый объект тянет за собой ещё пару зависимостей - и слой, который должен быть простым, превращается в хаос.
Чтобы этот хаос остановить, и существуют DI-библиотеки.
Мы у себя используем that-depends - она ближе всего нам по синтаксису и ощущению.
Проект, по сути, вырос после того, как популярный dependency-injector не стал поддерживать Python 3.12 (сейчас они поддержали, но уже поздно!!), и мы внезапно остались без удобного DI под современный стек.
Самое приятное в that-depends - он не ломает привычный стиль разработки и не требует изучать «новый мир».
Он просто позволяет декларативно описать, как создаются зависимости, и хранить всё это в одном месте.
Сервис-слой перестаёт расползаться, а тесты перестают превращаться в мококарнавал.
🔹 Пример - асинхронный ресурс
from that_depends import BaseContainer, providers, inject, Provide
async def create_pool():
pool = await make_pool()
try:
yield pool
finally:
await pool.close()
class Container(BaseContainer):
db = providers.Resource(create_pool)
@inject
async def handle_user(pool = Provide[Container.db]):
async with pool.acquire() as conn:
return await conn.fetch("SELECT 1")
Жизненный цикл ресурса определён контейнером.
Бизнес-логика пользуется пулом, не думая о его устройстве.
В тестах Container.db можно заменить одной строкой - без танцев.
🔹 Пример из реальной жизни
class Config:
url = "https://api.example.com"
class Client:
def __init__(self, config: Config):
self.config = config
class Service:
def __init__(self, client: Client):
self.client = client
class Container(BaseContainer):
config = providers.Singleton(Config)
client = providers.Factory(Client, config.cast)
service = providers.Factory(Service, client.cast)
# готовый сервис со всеми зависимостями
svc = Container.service.resolve_sync()
Не нужно протаскивать зависимости через пять уровней конструкторов.
Не нужно хранить singletons в модулях.
Не нужно вручную собирать граф объектов - контейнер делает это сам.
И вот за это подход и нравится:
все зависимости лежат в одном месте, ими удобно управлять, легко подменять и переиспользовать.
Код становится чище, архитектура - прозрачнее, тесты - проще.
that-depends, конечно, не единственный DI в экосистеме.
Но это тот вариант, который ощущается по-питоновски: лёгкий, понятный, без магии и лишнего шума - и при этом действительно полезный в живых проектах.
GitHub
GitHub - modern-python/that-depends: Simple, typed dependency-injection framework for Python
Simple, typed dependency-injection framework for Python - modern-python/that-depends
👍12🔥5🤯1
