惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Cyber Attacks, Cyber Crime and Cyber Security
Security Latest
Security Latest
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
S
Schneier on Security
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Full Disclosure
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
大猫的无限游戏
大猫的无限游戏
MyScale Blog
MyScale Blog
Hacker News: Ask HN
Hacker News: Ask HN
G
Google Developers Blog
H
Heimdal Security Blog
O
OpenAI News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LangChain Blog
C
Cisco Blogs
云风的 BLOG
云风的 BLOG
IT之家
IT之家
Cyberwarzone
Cyberwarzone
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Know Your Adversary
Know Your Adversary
博客园 - 聂微东
The Cloudflare Blog
C
Check Point Blog
K
Kaspersky official blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
月光博客
月光博客
T
Tor Project blog
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
P
Proofpoint News Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
A
About on SuperTechFans
小众软件
小众软件
Cloudbric
Cloudbric
A
Arctic Wolf

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
ИИ-агент двойного назначения
Георгий Тормозов · 2026-05-29 · via Все публикации подряд на Хабре

ИИ-агент двойного назначения

Средний

8 мин

6.4K

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

Введение

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

Если вам интересно собственноручно попробовать наш Go анализатор, то вы можете принять участие в программе раннего доступа. EAP доступно для языков JavaScript, TypeScript и Go.

Как говорится, куй железо, пока горячо, поэтому приступим к проверке проектов.

Проверка проектов

New-api

Начнём с агрегатора и балансировщика нагрузки для множества AI-провайдеров — new-api. Он позволяет управлять десятками API-ключей от разных провайдеров через единый шлюз. Это достаточно крупный и популярный проект (33 тыс. звёзд на GitHub), но даже в таких проектах встречаются баги и подозрительный код. Коммит 22b6b16.

func GetChannel(group string, model string, retry int) (*Channel, error) {
  var abilities []Ability

  var err error = nil
  channelQuery, err := getChannelQuery(group, model, retry)
  if err != nil {
    return nil, err
  }
  if common.UsingSQLite || common.UsingPostgreSQL {
    err = channelQuery.Order("weight DESC").Find(&abilities).Error
  } else {
    err = channelQuery.Order("weight DESC").Find(&abilities).Error
  }
  ....
}

Предупреждение PVS-Studio: V8005 The ‘then’ statement is equivalent to the ‘else’ statement. ability.go 114

Анализатор сообщает, что if с условием common.UsingSQLite || common.UsingPostgreSQL по сути бесполезен, поскольку в then и else части выполняется одинаковый код.

Аналогичная проблема была найдена в следующем отрывке кода:

func StreamResponseClaude2OpenAI(....) .... {
  ....
  if claudeResponse.Type == "message_start" {
    ....
  } else if claudeResponse.Type == "content_block_start" {
    ....
  } else if claudeResponse.Type == "content_block_delta" {
    ....
  } else if claudeResponse.Type == "message_delta" {
    ....
  } else if claudeResponse.Type == "message_stop" {
    return nil
  } else {
    return nil
  }
  ....
}

Предупреждение PVS-Studio: V8005 The ‘then’ statement is equivalent to the ‘else’ statement. relay-claude.go 474

Сложно понять, действительно ли это ошибка, либо же для claudeResponse.Type == "message_stop" пока попросту отсутствует логика.

Tau

Теперь рассмотрим срабатывание в коде tau — open-source платформе для создания автономных облачных инфраструктур. Коммит 1e5036f.

func (p *pluginInstance) makeFunc(....) reflect.Value {
  ....
  _out := make([]reflect.Value, len(cOut))
  for idx := 0; idx < len(cOut); idx++ {
    switch retTypes[idx] {
    case vm.I32Type:
      _out[idx] = reflect.ValueOf(int32(cOut[idx]))
    case vm.I64Type:                                            // <=
      _out[idx] = reflect.ValueOf(int64(cOut[idx]))
    case vm.F32Type:
      _out[idx] = reflect.ValueOf(math.Float32frombits(uint32(cOut[idx])))
    case vm.I64Type:                                            // <=
      _out[idx] = reflect.ValueOf(math.Float64frombits(cOut[idx]))
    }
  }
  ....
}

Предупреждение PVS-Studio: V8010 Two or more case branches have equivalent expressions. instance.go 93

Здесь мы можем наблюдать, что для разных case используется одно и то же выражение I64Type. В таком коде нет смысла, поскольку код внутри второго кейса никогда не будет выполнен. И, скорее всего, вместо второго I64Type предполагалось использовать F64Type:

switch retTypes[idx] {
  case vm.I32Type:
    _out[idx] = reflect.ValueOf(int32(cOut[idx]))
  case vm.I64Type:
    _out[idx] = reflect.ValueOf(int64(cOut[idx]))
  case vm.F32Type:
    _out[idx] = reflect.ValueOf(math.Float32frombits(uint32(cOut[idx])))
  case vm.F64Type: 
    _out[idx] = reflect.ValueOf(math.Float64frombits(cOut[idx]))
 }

Кстати, подобный паттерн ошибок также был найден в коде популярного блокировщика рекламы AdGuardHome. Об этом мы писали в статье “Go vet не поможет. Статический анализ Golang проектов с помощью PVS-Studio”.

Sub2api

Перейдём к прокси-серверу для AI-сервисов — Sub2API. Коммит 0f03393.

func cleanJSONSchemaRecursive(value any) any {
  ....
  if hasKey(schemaMap, "properties") {
    schemaMap["type"] = "object"
  } else {
  // 默认为 string ? or object? Gemini 通常需要明确 type
    schemaMap["type"] = "object"
  }
  ....
}

Предупреждение PVS-Studio: V8005 The ‘then’ statement is equivalent to the ‘else’ statement. schema_cleaner.go 310

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

Рассмотрим другой фрагмент:

func classifyOpsPhase(errType, message, code string) string {
  ....

  switch errType {
  case "authentication_error":
    return "auth"
  case "billing_error", "subscription_error":
    return "request"                                  // <=         
  case "rate_limit_error":
    if .... {
      return "request"
    }
    return "upstream"
  case "invalid_request_error":
    return "request"                                  // <=
  case "upstream_error", "overloaded_error":
    return "upstream"
  case "api_error":
    if strings.Contains(msg, opsErrNoAvailableAccounts) {
      return "routing"
    }
    return "internal"
  default:
    return "internal"
  }
}

Предупреждение PVS-Studio: V8009 Two or more case branches perform the same actions. ops_error_logger.go 1125

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

Видим, что первый кейс, который возвращает значение request, содержит в себе несколько выражений case "billing_error", "subscription_error". И в таком случае было бы логично через запятую написать выражение case "invalid_request_error" из второго кейса, если они всегда должны приводить к одному и тому же исходу.

Однако стоит обратить внимание на другой кейс:

case "rate_limit_error":
    if .... {
      return "request"
    }
    return "upstream"

Отсюда также может быть возвращено значение request, но здесь есть дополнительная обработка. Это приводит нас к мысли, что, возможно, во втором кейсе с одинаковым телом также должна быть какая-то дополнительная обработка. Но из контекста сложно понять, что именно должно быть, поэтому анализатор подсвечивает странный фрагмент кода.

Похожий случай в функции classifyopsErrorSource:

func classifyOpsErrorSource(phase string, message string) string {
  // Standardized sources: client_request|upstream_http|gateway
  switch phase {
  case "upstream":
    return "upstream_http"
  case "network":
    return "gateway"                                  // <=
  case "request", "auth":
    return "client_request"
  case "routing", "internal":
    return "gateway"                                  // <=
  default:
    if strings.Contains(strings.ToLower(message), "upstream") {
      return "upstream_http"
    }
    return "gateway"
  }
}

Предупреждение PVS-Studio: V8009 Two or more case branches perform the same actions. ops_error_logger.go 1220

С одной стороны, возможно, это не ошибка и стоит объединить case "routing", "internal" с case "network". А с другой стороны, есть вероятность, что не хватает какого-то дополнительного кода, как в кейсе default.

Photoprism

PhotoPristm — self-hosted менеджер фотографий с открытым исходным кодом. Проект интересен тем, что обладает встроенным AI и REST API, который позволяет агенту управлять фотобиблиотекой. Коммит 93bb435.

func (c *opticsClusterer) extract() {
  ....
  switch {
  case math.Abs(d) <= c.xi:
    cs = areas[j].start
    ce = ue
  case d > c.xi:
    for k := areas[j].end; k > areas[j].end; k-- {                    // <=
      if ....{
        cs = k
        break
      }
    }
    ce = ue
  default:
    cs = areas[j].start
    for k := i; k < e; k++ {
      if ....{
        ce = k
        break
      }
    }
  }
  ....
}

Предупреждение PVS-Studio: V8016 The loop condition will never be met. Inspect initial and final values in the ‘for’ loop. optics.go 321

Анализатор сообщает, что условие for никогда не будет выполнено, поскольку начальное и конечное значение равны areas[j].end. Скорее всего, здесь опечатка, и условие должно выглядеть следующим образом:

for k := areas[j].end; k > areas[j].start; k-- {
  ....
}

Axonhub

Ещё один прокси — axonhub. Коммит bfc11e01.

func AggregateStreamChunks(....) ([]byte, llm.ResponseMeta, error) {
  ....

  if event.Delta.Thinking != nil {
    if contentBlocks[index].Type == "thinking" {
      if contentBlocks[index].Thinking == nil {
        contentBlocks[index].Thinking = lo.ToPtr("")
      }

      *contentBlocks[index].Thinking += *event.Delta.Thinking
    } else {
      // Convert to thinking block if it's not already
      contentBlocks[index].Type = "thinking"
      contentBlocks[index].Thinking = event.Delta.Thinking
    }
  }

  if event.Delta.Signature != nil {                                      // <=
    // Handle signature delta - append to thinking block signature
    if contentBlocks[index].Type == "thinking" {
      if event.Delta.Signature != nil {                                  // <=
        if contentBlocks[index].Signature == nil {
          contentBlocks[index].Signature = event.Delta.Signature
        } else {
          contentBlocks[index].Signature = lo.ToPtr(....)
        }
      }
    } else {
      // Convert to thinking block if it's not already
      contentBlocks[index].Type = "thinking"
      contentBlocks[index].Signature = event.Delta.Signature
    }
  }

  ....
}

Предупреждение PVS-Studio: V8020 Recurring check. The ‘event.Delta.Signature != nil’ condition was already verified on line 96. aggregator.go 96

Анализатор обнаружил рекурсивную проверку event.Delta.Signature != nil. Повторная проверка бессмысленна, поскольку она всегда будет истинной.

LocalAI

На очереди LocalAI — открытый движок для локального использования моделей искусственного интеллекта. Коммит dd8e74a.

func (r *RunCMD) Run(ctx *cliContext.Context) error {
  ....

  if r.DisableMetricsEndpoint {
    opts = append(opts, config.DisableMetricsEndpoint)
  }

  if r.DisableRuntimeSettings {
    opts = append(opts, config.DisableRuntimeSettings)
  }

  if r.EnableTracing {
    opts = append(opts, config.EnableTracing)
  }

  if r.EnableTracing {
    opts = append(opts, config.EnableTracing)
  }
  opts = append(opts, config.WithTracingMaxItems(r.TracingMaxItems))

  ....
}

Предупреждение PVS-Studio: V8017 The conditions of the ‘if’ statements situated alongside each other are equivalent. Check lines: 158, 162. run.go 158

Можно заметить, что в функции Run дублируются строчки:

if r.EnableTracing {
    opts = append(opts, config.EnableTracing)
  }

С большой вероятностью это ошибка, которая может привести к тому, что opts = append(opts, config.EnableTracing) будет выполнена два раза, если r.EnableTracing имеет значение true.

Также возможно, что вместо второго r.EnableTracing и config.EnableTracing должно быть что-то другое, и часть функционала попросту утеряна. Скорее всего, эта ошибка допущена в результате copy-paste.

Перейдём к следующему срабатыванию:

func parseXMLWithFormat(s string, format *XMLToolCallFormat) (....) {
  ....

  for _, match := range toolCallMatches {
    if len(match) < 3 {
      continue
    }

    ....

    var functionContent string
    if len(match) >= 3 {
      if format.ToolSep == "" && format.KeyStart != "" {
        functionContent = match[2]
      } else {
        functionContent = match[2]
      }
    }
    ....
  }
  ....
}

Предупреждение PVS-Studio: V8005 The ‘then’ statement is equivalent to the ‘else’ statement. parse.go 902

Невооружённым глазом видно, что then и else блоки идентичны, и в таком случае нет смысла использовать if.

Скорее всего, это ошибка copy-paste, и во второй строке functionContent = match[2] забыли изменить индекс.

И сразу три срабатывания V8005 было выдано на три похожих фрагмента:

func ChatEndpoint(....) echo.HandlerFunc {
  ....
  if len(cleanedContent) > len(lastEmittedCleanedContent) &&  
    strings.HasPrefix(cleanedContent, lastEmittedCleanedContent) {
    deltaContent = cleanedContent[len(lastEmittedCleanedContent):]
    lastEmittedCleanedContent = cleanedContent
  } else if cleanedContent != lastEmittedCleanedContent {
    // If cleaned content changed but not in a simple append, 
    // extract delta from cleaned content
    // This handles cases where thinking tags are removed mid-stream
    if lastEmittedCleanedContent == "" {
      deltaContent = cleanedContent                             // <=
      lastEmittedCleanedContent = cleanedContent                // <=
    } else {
      // Content changed in non-append way, use the new cleaned content
      deltaContent = cleanedContent                             // <=
      lastEmittedCleanedContent = cleanedContent                // <=
    }
  }
  ....
}

Предупреждение PVS-Studio: V8005 The ‘then’ statement is equivalent to the ‘else’ statement. chat.go 85

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

Заключение

На этом всё. Если вам интересны разборы проектов, предназначенных для использования AI и агентной разработки, то можете написать об этом в комментариях, и мы учтём ваше мнение :)

Напомню, что недавно в PVS-Studio появилась программа раннего доступа к нашим новым анализаторам, в которой вы можете принять участие! EAP доступно для языков JavaScript, TypeScript и Go.

Если вы хотите самостоятельно проверить проект с помощью PVS-Studio, то попробовать анализатор можете по ссылке!

Берегите себя и свой код!

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Georgii Tormozov. Double AI agents: What’s hiding in your Golang code.