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

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

![1377_GolangDoubleAgent_ru/image1.png](https://import.viva64.com/docx/blog/1377_GolangDoubleAgent_ru/image1.png)

## Введение

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


> Если вам интересно собственноручно попробовать наш Go анализатор, то вы можете принять участие в \[программе раннего доступа\]\(https://pvs\-studio\.ru/ru/pvs\-studio\-eap/\)\\\. EAP доступно для языков JavaScript, TypeScript и Go\\\.



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

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

### New\-api

Начнём с агрегатора и балансировщика нагрузки для множества AI\-провайдеров — [new\-api](https://github.com/QuantumNous/new-api)\. Он позволяет управлять десятками API\-ключей от разных провайдеров через единый шлюз\. Это достаточно крупный и популярный проект \(33 тыс\. звёзд на GitHub\), но даже в таких проектах встречаются баги и подозрительный код\. Коммит [`22b6b16`](https://github.com/QuantumNous/new-api/tree/22b6b16702b7a9a5a751d73b2641b334050f2206)\.

```cpp
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](https://pvs-studio.ru/ru/docs/warnings/v8005/) The 'then' statement is equivalent to the 'else' statement\. [ability\.go 114](https://github.com/QuantumNous/new-api/blob/5dd0d3bcbd7b1d523bd046a5f9cf9fc8ce28d579/model/ability.go#L114)

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

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

```cpp
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](https://pvs-studio.ru/ru/docs/warnings/v8005/) The 'then' statement is equivalent to the 'else' statement\. [relay\-claude\.go 474](https://github.com/QuantumNous/new-api/blob/5dd0d3bcbd7b1d523bd046a5f9cf9fc8ce28d579/relay/channel/claude/relay-claude.go#L507)

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

### Tau

Теперь рассмотрим срабатывание в коде [tau](https://github.com/taubyte/tau) — open\-source платформе для создания автономных облачных инфраструктур\. Коммит [`1e5036f`](https://github.com/taubyte/tau/tree/1e5036ffab19efee73a50c5b0453756995bcb7bf)\.

```cpp
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](https://github.com/taubyte/tau/blob/c080c757c12b4156cc950c26bca17d40ac950003/pkg/vm-orbit/satellite/vm/instance.go#L93)

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

```cpp
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](https://github.com/AdguardTeam/AdGuardHome)\. Об этом мы писали в статье "[Go vet не поможет\. Статический анализ Golang проектов с помощью PVS\-Studio](https://pvs-studio.ru/ru/blog/posts/go/1342/#ID5543A82B01)"\.

### Sub2api

Перейдём к прокси\-серверу для AI\-сервисов — [Sub2API](https://github.com/Wei-Shaw/sub2api)\. Коммит [`0f03393`](https://github.com/Wei-Shaw/sub2api/tree/0f0339301022c18ec7527382d1c7edc7b2933c8f)\.

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

Предупреждение PVS\-Studio: [V8005](https://pvs-studio.ru/ru/docs/warnings/v8005/) The 'then' statement is equivalent to the 'else' statement\. [schema\_cleaner\.go 310](https://github.com/Wei-Shaw/sub2api/blob/f5bd25bea045e728846b38bf18080ffa48d133c6/backend/internal/pkg/antigravity/schema_cleaner.go#L310)

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

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

```cpp
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](https://pvs-studio.ru/ru/docs/warnings/v8009/) Two or more case branches perform the same actions\. [ops\_error\_logger\.go 1125](https://github.com/Wei-Shaw/sub2api/blob/f5bd25bea045e728846b38bf18080ffa48d133c6/backend/internal/handler/ops_error_logger.go#L1125)

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

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

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

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

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

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

```cpp
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](https://pvs-studio.ru/ru/docs/warnings/v8009/) Two or more case branches perform the same actions\. [ops\_error\_logger\.go 1220](https://github.com/Wei-Shaw/sub2api/blob/f5bd25bea045e728846b38bf18080ffa48d133c6/backend/internal/handler/ops_error_logger.go#L1220)

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

### Photoprism

[PhotoPristm](https://github.com/photoprism/photoprism) — self\-hosted менеджер фотографий с открытым исходным кодом\. Проект интересен тем, что обладает встроенным AI и REST API, который позволяет агенту управлять фотобиблиотекой\. Коммит [`93bb435`](https://github.com/photoprism/photoprism/tree/93bb435203a9338da6e781ec8d55e7cdde1aed21)\.

```cpp
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](https://github.com/photoprism/photoprism/blob/464798234a9b7cfeb2ccda22d2f68b8103ea08ec/pkg/vector/alg/optics.go#L321)

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

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

### Axonhub

Ещё один прокси — [axonhub](https://github.com/looplj/axonhub)\. Коммит [`bfc11e01`](https://github.com/looplj/axonhub/tree/bfc11e0114f47726b271c9c800f9bcaa1557bf88)\.

```cpp
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](https://github.com/looplj/axonhub/blob/aab5159add6b8876571e9a222ff25a73f471f7a2/llm/transformer/anthropic/aggregator.go#L96)

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

### LocalAI

На очереди [LocalAI](https://github.com/mudler/LocalAI) — открытый движок для локального использования моделей искусственного интеллекта\. Коммит [`dd8e74a`](https://github.com/mudler/LocalAI/tree/dd8e74a486df34cdd2888f1643aecef0099d3a4a)\.

```cpp
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](https://pvs-studio.ru/ru/docs/warnings/v8017/) The conditions of the 'if' statements situated alongside each other are equivalent\. Check lines: 158, 162\. [run\.go 158](https://github.com/mudler/LocalAI/blob/dd8e74a486df34cdd2888f1643aecef0099d3a4a/core/cli/run.go#L158)

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

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

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

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

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

```cpp
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](https://pvs-studio.ru/ru/docs/warnings/v8005/) The 'then' statement is equivalent to the 'else' statement\. [parse\.go 902](https://github.com/mudler/LocalAI/blob/dd8e74a486df34cdd2888f1643aecef0099d3a4a/pkg/functions/parse.go#L902)

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

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

И сразу три срабатывания [V8005](https://pvs-studio.ru/ru/docs/warnings/v8005/) было выдано на три похожих фрагмента:

```cpp
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](https://pvs-studio.ru/ru/docs/warnings/v8005/) The 'then' statement is equivalent to the 'else' statement\. chat\.go 85

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

## Заключение

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


> Напомню, что недавно в PVS\\\-Studio появилась \[программа раннего доступа\]\(https://pvs\-studio\.ru/ru/pvs\-studio\-eap/\) к нашим новым анализаторам, в которой вы можете принять участие\\\! EAP доступно для языков JavaScript, TypeScript и Go\\\.



Если вы хотите самостоятельно проверить проект с помощью PVS\-Studio, то попробовать анализатор можете по [ссылке](https://pvs-studio.ru/ru/pvs-studio/try-free/)\!

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