Самый востребованный навык в ИТ в 2026-м — навык создания ИИ-агентов
Мы полностью переработали курс «Разработка AI-агентов» под реалии 2026 года. Никакой долгой теории — с самого начала пишем код. Обучать и делиться набитыми шишками будут эксперты-практики из Газпромбанка, Альфа-Банка и других бигтехов.
В программе:
— архитектура автономных систем с тестированием, ReAct-циклами и контролем токенов;
— практическая работа с актуальными фреймворками
— настройка продвинутого RAG для парсинга документов и точного поиска;
— внедрение решений с учётом действующего законодательства (152-ФЗ);
— дипломная работа, за основу которой можно взять свой рабочий проект или задачу, которую предложим мы.
Эксперты поделятся инсайтами из реального продакшна — тем, о чём вам никогда не расскажет ни одна нейросеть.
Ах да, чуть не забыли! Дарим промокодAGENTSWEB на скидку 10 000 рублей и два курса сверху при покупке до 15 марта 🎁
→ Освоить разработку AI-агентов
Мы полностью переработали курс «Разработка AI-агентов» под реалии 2026 года. Никакой долгой теории — с самого начала пишем код. Обучать и делиться набитыми шишками будут эксперты-практики из Газпромбанка, Альфа-Банка и других бигтехов.
В программе:
— архитектура автономных систем с тестированием, ReAct-циклами и контролем токенов;
— практическая работа с актуальными фреймворками
LangGraph, AutoGen, MCP и CrewAI;— настройка продвинутого RAG для парсинга документов и точного поиска;
— внедрение решений с учётом действующего законодательства (152-ФЗ);
— дипломная работа, за основу которой можно взять свой рабочий проект или задачу, которую предложим мы.
Эксперты поделятся инсайтами из реального продакшна — тем, о чём вам никогда не расскажет ни одна нейросеть.
Запись первого открытого вебинара, на котором мы вместе с руководителем AI-направления в Альфа-Банке Полиной Полуниной пилили агента в прямом эфире.
Ах да, чуть не забыли! Дарим промокод
→ Освоить разработку AI-агентов
🥱20😁5👍2
Сколько раз можно вызвать cancel() из context.WithCancel до паники?
Большинство мидлов отвечают уверенно — и ошибаются. Не потому что не знают контексты, а потому что никогда не проверяли это руками и не читали исходники пакета context.
ctx, cancel := context.WithCancel(context.Background())
cancel()
cancel() // что будет?
cancel() // а теперь?
А там есть один нюанс, который меняет ответ.
Проверить себя → в канале с вопросами с собесов
📍 Навигация: Вакансии • Задачи • Собесы
#ReadySetGo
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
В Go инкапсуляция работает на уровне пакета. Всё с маленькой буквы видно только внутри пакета, всё с большой буквы доступно снаружи. Звучит просто, пока пакет небольшой.
Но когда пакет разрастается, внутри него появляется несколько файлов и сотни строк кода, и возникает вопрос: как ограничить доступ к конкретным структурам или функциям между файлами внутри одного пакета? В Java для этого есть
private. В Go такого нет.Почему это вообще проблема
В Go весь код внутри одного пакета видит всё, что объявлено в этом пакете, независимо от файла. Если у вас
payment пакет с файлами processor.go, validator.go и refund.go, то любая функция из refund.go может обратиться к любому unexported-идентификатору из processor.go. Компилятор не запрещает, конвенций нет, всё держится на дисциплине команды.Три подхода, которые используют в реальных проектах
• Разбить пакет на подпакеты
Первый и самый частый совет. Если логика достаточно самостоятельная, вынесите её в отдельный пакет. Тогда вы явно контролируете, что экспортировать, а что нет. Это идиоматичный Go.
payment/
processor.go
validator/
validator.go // видит только то, что экспортирует payment
refund/
refund.go
Минус: иногда код слишком связан, чтобы разбивать его на подпакеты без боли.
• Директория
internalЭто не просто конвенция, это механизм компилятора. Пакет внутри
internal можно импортировать только из пакетов, которые находятся в том же дереве директорий выше internal.myapp/
payment/
processor.go
internal/
cardutils/
cardutils.go // доступен только внутри payment/
cardutils не получится импортировать из myapp/order или любого другого места вне myapp/payment. Компилятор выдаст ошибку. Это настоящая изоляция, которую не обойти дисциплиной.// myapp/order/order.go
import "myapp/payment/internal/cardutils" // ошибка компиляции
• Интерфейсы для скрытия деталей
Если нужно скрыть конкретную реализацию от остальных частей пакета, можно работать через интерфейс. Другие части пакета видят только интерфейс, не конкретный тип.
// processor.go
type cardProcessor interface {
charge(amount int) error
}
// stripeProcessor.go
type stripeProcessor struct { ... }
func (s *stripeProcessor) charge(amount int) error { ... }
Это не запрещает доступ технически, но снижает связность. Команда знает, что работать нужно через интерфейс.
Go не даёт
private внутри пакета намеренно. Граница инкапсуляции здесь — это пакет, а не файл или структура. Если вы чувствуете, что пакет стал слишком большим и внутри него нужны границы, это сигнал его разбить, а не попытка заставить Go работать как Java.internal-директория закрывает вопрос на уровне модуля. Подпакеты закрывают вопрос на уровне логики. Остальное — это архитектура и договорённости в команде.📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🤔2❤1
Если в часто вызываемом коде есть цепочка append, то скорее всего там скрытая лестница аллокаций.
// аллокация #1
defaultFields := []zap.Field{...}
// аллокация #2 — вместимость кончилась
defaultFields = append(defaultFields, ...)
// аллокация #3 — финальное слияние
Log.Info("...", append(defaultFields, ...)...)
Каждый раз когда append упирается в capacity, Go выделяет новый массив, копирует данные, а старый уходит сборщику мусора. В логгере, который вызывается на каждый запрос, это поток короткоживущего мусора.
Решение простое — посчитать финальный размер заранее и передать его в make:
allFields := make([]zap.Field, 0, 7+len(fields))
allFields = append(allFields, zap.Int("status_code", code))
// ... остальные поля ...
Log.Info("Response sent", allFields...)
📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱13👍5❤2
Короткая рабочая неделя закончилась. Собрали чуток новостей и материалов.
— Go в Китае
Go занимает в Китае куда более заметное место, чем в остальном мире. В феврале 2026 года язык занял лишь 16-е место в индексе TIOBE глобально, но по данным Google Trends запросы по слову «golang» из Китая стабильно опережают любую другую страну.
— DI контейнер для Go
— По резюме не берут. Берут по рекомендации
— PVS-Studio запускает бета-тест анализатора для Go
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Если вы писали retry-логику руками, вы знаете, как это выглядит в итоге. Счётчик попыток, sleep с захардкоженной задержкой, иногда экспоненциальный backoff, скопированный со Stack Overflow.
Работает, пока не начинает ломаться под нагрузкой: все клиенты начинают повторять запросы одновременно и кладут и без того перегруженный сервис.
Resile — open-source библиотека для Go, которая реализует устойчивое выполнение операций в распределённых системах.
Самый простой случай — повторить операцию, которая возвращает ошибку:
err := resile.DoErr(ctx, func(ctx context.Context) error {
return db.PingContext(ctx)
})По умолчанию библиотека сделает 5 попыток, начиная с 100ms, максимум 30s. Ничего настраивать не нужно, если дефолты подходят.
Если нужно вернуть значение — используете Do с дженериками:
user, err := resile.Do(ctx, func(ctx context.Context) (*User, error) {
return apiClient.GetUser(ctx, userID)
}, resile.WithMaxAttempts(3))Библиотека даёт готовые решения для типичных проблем распределённых систем без лишних зависимостей.
📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍6🔥3🥱1
В Go нет встроенного множества. Это сознательное решение — язык не добавляет то, что можно сделать через уже существующие примитивы. И мапа справляется с задачей хорошо.
Два способа объявить множество
Первый — через
map[string]bool. Читается проще, но каждый bool занимает 1 байт:visited := make(map[string]bool)
visited["page1"] = true
visited["page2"] = true
if visited["page1"] {
fmt.Println("Already visited")
}
Второй — через
map[string]struct{}. Выглядит непривычно, но struct{} занимает 0 байт в памяти:seen := make(map[string]struct{})
seen["item1"] = struct{}{}
seen["item2"] = struct{}{}
if _, exists := seen["item1"]; exists {
fmt.Println("Already seen")
}Операции над множествами
Все три классические операции реализуются через перебор мапы.
Объединение — добавляем всё из обоих множеств:
setA := map[int]struct{}{1: {}, 2: {}, 3: {}}
setB := map[int]struct{}{2: {}, 3: {}, 4: {}}
union := make(map[int]struct{})
for k := range setA { union[k] = struct{}{} }
for k := range setB { union[k] = struct{}{} }
// union: {1, 2, 3, 4}Пересечение — только то, что есть в обоих:
intersection := make(map[int]struct{})
for k := range setA {
if _, ok := setB[k]; ok {
intersection[k] = struct{}{}
}
}
// intersection: {2, 3}Разность — то, что есть в A, но нет в B:
difference := make(map[int]struct{})
for k := range setA {
if _, ok := setB[k]; !ok {
difference[k] = struct{}{}
}
}
// difference: {1}Для большинства задач хватает обычного map. Добавлять зависимость ради множества скорее избыточно.
📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🥱3🤔2😁1
При массовой вставке данных в PostgreSQL из Go разработчики обычно выбирают между двумя подходами.
COPY работает быстро, но не поддерживает ON CONFLICT. Многострочный INSERT поддерживает конфликты, но медленнее. Есть способ получить оба свойства одновременно.Паттерн с промежуточной таблицей
Идея простая: сначала заливаем данные через
COPY во временную таблицу, потом перекладываем их в основную с обработкой конфликтов.-- 1. Создаём промежуточную таблицу
CREATE TEMP TABLE промежуточная (LIKE блоки INCLUDING ALL);
-- 2. Заливаем через COPY (быстро)
COPY промежуточная FROM ...;
-- 3. Перекладываем с обработкой конфликтов
INSERT INTO блоки
SELECT * FROM промежуточная
ON CONFLICT (хеш_блока) DO NOTHING;
-- 4. Чистим промежуточную таблицу
TRUNCATE промежуточная;
Два круговых обращения вместо одного, но для пакетов по 25 блоков накладные расходы незаметны. Пропускная способность остаётся близкой к чистому
COPY.Альтернатива через unnest
Если промежуточная таблица кажется избыточной, есть вариант через
unnest — передаём массивы значений одним запросом:_, err := db.Exec(`
INSERT INTO блоки (хеш, номер, метка_времени)
SELECT * FROM unnest($1::text[], $2::int[], $3::timestamptz[])
ON CONFLICT (хеш) DO NOTHING`,
pq.Array(хеши),
pq.Array(номера),
pq.Array(метки_времени),
)
Работает быстрее многострочного
INSERT с отдельными параметрами и поддерживает ON CONFLICT. Хорошее среднее между скоростью и простотой.Про lib/pq
Если используете
lib/pq — стоит присмотреться к переходу на pgx. Библиотека активно поддерживается, имеет встроенную поддержку COPY через CopyFrom и в целом быстрее:соединение, _ := pgx.Connect(ctx, строкаПодключения)
_, err := соединение.CopyFrom(
ctx,
pgx.Identifier{"блоки"},
[]string{"хеш", "номер", "метка_времени"},
pgx.CopyFromRows(строки),
)
Переход с
lib/pq на pgx в большинстве проектов занимает пару часов.Ограничение PostgreSQL
При многострочном
INSERT с параметрами помните про ограничение PostgreSQL — максимум 65 535 параметров на запрос. Делите на количество столбцов и получаете максимальное число строк за один запрос. При 10 столбцах это не больше 6 553 строк за раз.📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20❤3👍2
📅 Парсинг дат на человеческом языке
Когда пользователь вводит "5 minutes ago" или "next monday", стандартный
Что это такое
Библиотека для Go, которая превращает фразы на естественном языке в
Установка:
Как использовать
Основная функция —
Библиотека умеет игнорировать лишний текст вокруг даты, так что фраза
Поддерживаемые форматы:
Парсинг длительностей
Отдельная функция
Направление для неоднозначных выражений
Фраза «sunday» без контекста может означать прошлое или будущее воскресенье. По умолчанию библиотека выбирает прошлое. Это меняется через опцию:
Где пригодится
CLI-утилиты с фильтрацией по времени, поисковые интерфейсы, планировщики задач, любой интерфейс где пользователь вводит дату текстом. Библиотека изначально создавалась для поиска по логам в Apex Logs.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction
Когда пользователь вводит "5 minutes ago" или "next monday", стандартный
time.Parse бесполезен — он ждёт строгий формат вроде 2006-01-02T15:04:05. Писать парсер для произвольных человекочитаемых дат самостоятельно долго и скучно. naturaldate.go решает именно это.Что это такое
Библиотека для Go, которая превращает фразы на естественном языке в
time.Time. Форк tj/go-naturaldate с дополнительными возможностями. Под капотом — PEG-грамматика через pointlander/peg.Установка:
go get github.com/anatol/naturaldate.go
Как использовать
Основная функция —
naturaldate.Parse. Принимает строку и опорное время, возвращает time.Time:t, err := naturaldate.Parse("5 minutes ago", time.Now())
t, err := naturaldate.Parse("December 25th at 7:30am", time.Now())
t, err := naturaldate.Parse("last sunday at 5:30pm", time.Now())Библиотека умеет игнорировать лишний текст вокруг даты, так что фраза
"Restart the server in 5 days from now" отработает корректно — из неё достанется нужная часть.Поддерживаемые форматы:
now, today, yesterday
5 minutes ago
three days ago
last month / next month
one year from now
yesterday at 10am
last sunday at 5:30pm
next January / last February
December 25th at 7:30am
10am / 10:05pm / 10:05:22pm
Remind me on the 25th of December at 7:30am
Message me in two weeks
Парсинг длительностей
Отдельная функция
ParseDuration возвращает time.Duration из человекочитаемой строки:d, err := naturaldate.ParseDuration("1 year and 2 months", time.Now())
fmt.Println(d) // 10248h0m0s
// с указанием направления — в прошлое
p, err := naturaldate.ParseDuration("1 year and 2 months", time.Now(),
naturaldate.WithDirection(naturaldate.Past))
fmt.Println(p) // -10224h0m0sНаправление для неоднозначных выражений
Фраза «sunday» без контекста может означать прошлое или будущее воскресенье. По умолчанию библиотека выбирает прошлое. Это меняется через опцию:
// "sunday" = "next sunday"
t, err := naturaldate.Parse("sunday", time.Now(),
naturaldate.WithDirection(naturaldate.Future))
Где пригодится
CLI-утилиты с фильтрацией по времени, поисковые интерфейсы, планировщики задач, любой интерфейс где пользователь вводит дату текстом. Библиотека изначально создавалась для поиска по логам в Apex Logs.
📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍6
У «Библиотеки программиста» появился резервный канал в мессенджере MAX
Он нужен исключительно для связи с теми, кто не может следить за обновлениями здесь из-за трудностей с доступом. Поэтому, если вы видите это сообщение, распространите его среди жильцов вашего ЖЭКа.
Контент в MAX будет дублировать телеграмный — основной нашей площадкой был и остаётся Telegram. Надеемся, это временная мера.
→ Подписаться на «Библиотеку программиста» в MAX
Он нужен исключительно для связи с теми, кто не может следить за обновлениями здесь из-за трудностей с доступом. Поэтому, если вы видите это сообщение, распространите его среди жильцов вашего ЖЭКа.
Контент в MAX будет дублировать телеграмный — основной нашей площадкой был и остаётся Telegram. Надеемся, это временная мера.
→ Подписаться на «Библиотеку программиста» в MAX
😢33🌚16🔥3🥱2👾1
Кажется, мы окончательно перешли от игрушек к суровому AgentOps
Приглашаем на наш обновлённый курс по разработке ИИ-агентов. Никакой воды про «будущее нейросетей», только инженерный подход.
На курсе мы:
— пошагово строим готовые системы на
— настраиваем кэширование и роутинг, чтобы бот не сожрал токены;
— разбираемся со стейтом, учимся дебажить через time-travel и прикручиваем human-in-the-loop;
— выводим RAG в прод так, чтобы безопасники не завернули архитектуру из-за 152-ФЗ.
В пекло скучные лекции про общую инфраструктуру — сразу фокусируемся на агентных фреймворках и написании кода. Занятия ведут бывалые лиды из Газпромбанка и Альфы, набившие шишки на реальных задачах.
Сегодня последний день, когда можно забрать курс по старым ценам. Базовый тариф сейчас стоит 49 000 ₽ (вместо 62 990 ₽), продвинутый трек — 99 000 ₽ (вместо 124 990 ₽). Если не хочется отдавать всю сумму сразу, есть рассрочка. Торопитесь — на потоке осталось всего 5 мест!
→ Зафиксировать цену и перейти к сборке своих агентов
Приглашаем на наш обновлённый курс по разработке ИИ-агентов. Никакой воды про «будущее нейросетей», только инженерный подход.
На курсе мы:
— пошагово строим готовые системы на
LangGraph, CrewAI и MCP;— настраиваем кэширование и роутинг, чтобы бот не сожрал токены;
— разбираемся со стейтом, учимся дебажить через time-travel и прикручиваем human-in-the-loop;
— выводим RAG в прод так, чтобы безопасники не завернули архитектуру из-за 152-ФЗ.
В пекло скучные лекции про общую инфраструктуру — сразу фокусируемся на агентных фреймворках и написании кода. Занятия ведут бывалые лиды из Газпромбанка и Альфы, набившие шишки на реальных задачах.
Кстати, на днях мы пилили агента в прямом эфире, если пропустили — есть запись вебинара.
Сегодня последний день, когда можно забрать курс по старым ценам. Базовый тариф сейчас стоит 49 000 ₽ (вместо 62 990 ₽), продвинутый трек — 99 000 ₽ (вместо 124 990 ₽). Если не хочется отдавать всю сумму сразу, есть рассрочка. Торопитесь — на потоке осталось всего 5 мест!
→ Зафиксировать цену и перейти к сборке своих агентов
😁4
Одни слова в IT звучат невинно, но означают что-то неприятное. Другие — пугают с виду, но на деле просто описывают рабочий процесс. Разбираться в карьерном сленге важно не меньше, чем в технологиях.
Гостинг, квитинг, джоб-хоппинг и синдром тревожной пятницы — всё в новой статье.
👉 Разобраться в терминах
📍 Навигация: Вакансии • Задачи • Собесы
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍1
Senior Backend Engineer (Golang) — от 450 000 ₽, удаленно в Москве
Senior Go — от 328 200 ₽, удаленно
Разработчик WebRTC-сервисов на Go — от 250 000 до 500 000 ₽, офис/гибрид в Москва или в Санкт-Петербурге
#GoWork
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Если вы работаете с Go и используете Wire для генерации зависимостей, то наверняка знаете это чувство: запускаете
wire gen, ждёте секунду-две, и так сотни раз за день. Мелочь? Нет. Это накапливается. Go-Разработчик решил разобраться с этим и результат получился серьёзный.
В чём была проблема
Предыдущие попытки ускорить Wire давали 8-10x на отдельных сценариях, но не решали главное. На каждом запуске Wire заново делал одно и то же: полный обход графа зависимостей через
go/packages и полную проверку типов через go/types. Для большого проекта это 300-500 мс только на обнаружение зависимостей, и это при каждом запуске, даже если вы поменяли одну строчку в теле функции.
На крупных кодовых базах Wire легко уходил в 1-3 секунды на каждый прогон. Умножьте это на тысячи запусков за время разработки.
Что изменилось
Загрузчик пакетов был переписан с нуля. Теперь обнаружение зависимостей и проверка типов разделены на два независимых этапа. Оба кэшируются. При следующем запуске Wire смотрит, что именно изменилось, и переделывает только то, что реально затронуто правкой.
Результат по сценариям для проекта с 42 локальными, 243 стандартными и 342 внешними пакетами в графике к посту.
Холодный старт стал медленнее — это цена построения кэша. Но в реальной разработке холодный старт случается один раз, а повторные запуски идут в 14-74 раза быстрее.
Все существующие тесты Wire проходят. Добавлены новые тесты под конкретные сценарии кэширования. При любом подозрительном состоянии кэша Wire откатывается к полному пересчёту. Автор использует это в своей работе уже несколько недель.
Как попробовать
Установить тестовую сборку можно одной командой:
go install github.com/goforj/wire/cmd/wire@cf52879
Чтобы понять размер своей кодовой базы перед тестом:
go list -deps -json ./... | \
jq -r '
select(.ImportPath != null) |
if .Standard then "stdlib"
elif (.Module != null and .Module.Main == true) then "local"
else "external"
end
' | sort | uniq -c
Если вы уже используете Wire и у вас достаточно большой проект, именно ваши тесты сейчас нужны. Разработчик просит активно делиться результатами.
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤7🔥2
gRPC-Go сервер слишком мягко обрабатывал маршрутизацию: он принимал запросы, где в заголовке :path отсутствовал обязательный ведущий слэш — например, Service/Method вместо /Service/Method.
Сервер успешно направлял такие запросы нужному обработчику, но перехватчики авторизации, включая официальный пакет grpc/authz, проверяли сырую, неканоническую строку пути.
Кто под угрозой
Уязвимость затрагивает серверы, у которых одновременно:
• используются перехватчики авторизации по пути (grpc/authz, кастомные через info.FullMethod)
• политика содержит явные правила запрета + резервное «разрешить»
Атакующему достаточно отправить сырые HTTP/2-фреймы с кривым заголовком :path — без привилегий и взаимодействия с пользователем.
Лучшее решение — обновиться до v1.79.3, где запросы без ведущего слэша сразу отклоняются с ошибкой
codes.Unimplemented.📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤3🤩3🔥2😁1
Когда нужно скоординировать горутины, первый инстинкт — взять канал. Чаще всего это правильно. Но есть один конкретный сценарий, где
sync.Cond не просто уместен, а является единственным чистым решением.Проблема: оповестить произвольное число горутин
Допустим, у вас пул воркеров, которые ждут задачи в очереди. Воркеров может быть 3, может быть 50 — вы не знаете заранее.
Как оповестить их всех, когда появилась новая задача?
С каналом это неловко: нужно либо N отдельных каналов, либо закрыть канал, но это одноразово, либо делать fan-out горутину. Всё это хрупко, когда число потребителей меняется динамически.
sync.Cond решает это в одну строку: cond.Broadcast().Пример кода:
type Queue struct {
mu sync.Mutex
cond *sync.Cond
items []Job
}
func (q *Queue) Push(j Job) {
q.mu.Lock()
q.items = append(q.items, j)
q.cond.Broadcast() // будим всех ожидающих
q.mu.Unlock()
}
func (q *Queue) Pop() Job {
q.mu.Lock()
defer q.mu.Unlock()
for len(q.items) == 0 {
q.cond.Wait() // атомарно отпускает мьютекс и засыпает
}
j := q.items[0]
q.items = q.items[1:]
return j
}cond.Wait() делает две вещи атомарно: отпускает мьютекс и засыпает. Когда горутина просыпается мьютекс снова захватывается автоматически. Без этой атомарности между отпустил лок и заснул было бы гоночное окно.Broadcast или Signal:
Broadcast() будит всех ожидающих, а Signal() ровно одного. Используйте Broadcast, когда изменение состояния важно многим; Signal — когда продвинуться может только один.📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍9😢1
Почитали тут свежий отчёт по рынку ИИ-ускорителей в РФ: оказывается, 54% компаний тормозят внедрение ИИ исключительно из-за конских цен на инфраструктуру.
Ну, то есть написать пет-проект с вызовом API это задача на вечер, а вот запустить агента в продакшн так, чтобы он не сжёг бюджет отдела за неделю — суровая инженерия.
По сути, сейчас мало уметь собирать RAG. Нужно считать токены, настраивать
Также в программе:
— оценка качества, трейсинг и защита от деградации пайплайнов;
— мультиагентные паттерны и интеграция по протоколу
— локальный деплой Open Source под 152-ФЗ (когда данные нельзя выносить наружу).
Кажется, это единственный адекватный roadmap по переходу от блокнотов к enterprise-решениям.
Прямо сейчас можно урвать курс с увесистой скидкой(49 000 ₽ 62 990 ₽ за базовый тариф и 99 000 ₽ 124 990 ₽ за продвинутый трек) , но стоит поторопиться — на потоке осталось всего 5 мест.
👉 Зафиксировать цену и начать собирать агентов, за которых не стыдно в проде
Ну, то есть написать пет-проект с вызовом API это задача на вечер, а вот запустить агента в продакшн так, чтобы он не сжёг бюджет отдела за неделю — суровая инженерия.
По сути, сейчас мало уметь собирать RAG. Нужно считать токены, настраивать
time-travel дебаг в LangGraph и уметь роутить запросы на лету. Всё это мы учли в обновлённом курсе по разработке AI-агентов, где акцент сделан именно на AgentOps и жёсткий контроль ресурсов.Также в программе:
— оценка качества, трейсинг и защита от деградации пайплайнов;
— мультиагентные паттерны и интеграция по протоколу
MCP;— локальный деплой Open Source под 152-ФЗ (когда данные нельзя выносить наружу).
Кажется, это единственный адекватный roadmap по переходу от блокнотов к enterprise-решениям.
Прямо сейчас можно урвать курс с увесистой скидкой
👉 Зафиксировать цену и начать собирать агентов, за которых не стыдно в проде
🥱15👍2❤1🤔1
💻 Свой Git-сервер, который запускается на Raspberry Pi
Gogs — self-hosted Git-сервис, написанный на Go. Это веб-интерфейс для работы с репозиториями, который разворачивается у вас на сервере.
По функциям похож на GitHub: репозитории, пул-реквесты, задачи, вики, вебхуки, деплой-ключи, организации, защищённые ветки.
Из необычного: поддержка Jupyter Notebook и PDF прямо в браузере, миграция репозиториев с других хостингов, Git LFS, аутентификация через LDAP, SMTP, GitHub и reverse proxy с поддержкой 2FA.
Требования к железу минимальные: хватит Raspberry Pi или VPS за $5. Для командной работы рекомендуется 2 ядра и 512 МБ ОЗУ. ОЗУ при росте команды почти не растёт, только процессор.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction
Gogs — self-hosted Git-сервис, написанный на Go. Это веб-интерфейс для работы с репозиториями, который разворачивается у вас на сервере.
По функциям похож на GitHub: репозитории, пул-реквесты, задачи, вики, вебхуки, деплой-ключи, организации, защищённые ветки.
Из необычного: поддержка Jupyter Notebook и PDF прямо в браузере, миграция репозиториев с других хостингов, Git LFS, аутентификация через LDAP, SMTP, GitHub и reverse proxy с поддержкой 2FA.
Требования к железу минимальные: хватит Raspberry Pi или VPS за $5. Для командной работы рекомендуется 2 ядра и 512 МБ ОЗУ. ОЗУ при росте команды почти не растёт, только процессор.
📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥4😁2
Кажется, что ответ очевиден, но Go любит сюрпризы. Подумайте хорошенько, прежде чем скроллить вниз, ведь ответ
💡 Подсказка:
📍 Навигация: Вакансии • Задачи • Собесы
#ReadySetGo
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
sync.Pool это один из самых неправильно понимаемых типов в стандартной библиотеке. Выглядит как пул объектов, им и является, но с одной гарантией, которая удивляет: GC может выселить всё содержимое пула в любой момент, без предупреждения.Для чего он реально нужен
Один конкретный сценарий: снизить давление аллокаций для короткоживущих переиспользуемых объектов:
bytes.Buffer, структуры протокольных сообщений, временные срезы.var bufPool = sync.Pool{
New: func() any {
return new(bytes.Buffer)
},
}
func processRequest(data []byte) []byte {
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset() // обязательно: сбрасываем перед использованием
defer bufPool.Put(buf)
buf.Write(data)
return buf.Bytes()
}Две ошибки, которые случаются почти всегда
Забыть
Reset(). Пул переиспользует объект, но не его содержимое. Всё, что записал предыдущий пользователь, никуда не делось. Всегда сбрасывайте состояние перед работой с полученным объектом.Использовать объект после Put. Как только вызвали Put — объект принадлежит пулу. Обращение к
buf.Bytes() после возврата — это гонка данных, которая просто ещё не выстрелила.📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🙏4👍2