Продвинутый

Архитектура DeepSeek Harness: всё — это плагин

Алексей Кузнецов
Алексей Кузнецов
Системный администратор11 сентября 2026 г.20 мин чтения

Разбираем архитектуру DeepSeek Harness для AI-агентов: философия «всё — это плагин», роль Cordis, YAML-конфиги и деплой на Proxmox или Kubernetes.

Архитектура DeepSeek Harness: всё — это плагин

Разбираем архитектуру DeepSeek Harness для AI-агентов: философия «всё — это плагин», роль Cordis, YAML-конфиги и деплой на Proxmox или Kubernetes.

Что такое DeepSeek Harness

Что такое DeepSeek Harness

DeepSeek Harness — это фреймворк для построения AI-агентов, который сам по себе не делает почти ничего. И в этом его сила.

Звучит парадоксально, но на практике именно такой подход даёт максимальную гибкость. Вместо того чтобы тащить в ядро фреймворка поддержку всех возможных провайдеров, инструментов и протоколов, авторы Harness оставили в ядре только самый минимум: запуск модели, обработку промптов, цикл диалога. Всё остальное — LLM-клиенты, интеграции с MCP-серверами, плагины для внешних API — вынесено в отдельные модули, которые подключаются по необходимости.

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

Философия «всё — это плагин»

Если посмотреть на репозиторий deepseek-ai/DeepSeek-Harness, архитектурная идея считывается с первого взгляда. Ядро (пакет dsh) предоставляет базовый класс агента и контракт для плагинов, а дальше начинается собственно сборка.

С практической точки зрения это означает три вещи.

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

Во-вторых, расширяемость через плагины (dsh-plugin-*). Нужен доступ к GitHub — подключаете соответствующий плагин. Нужна работа с файловой системой — другой плагин. Нужно интегрировать собственный инструмент — пишете свой плагин по документации, и он встраивается точно так же, как и штатные.

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

Пример минимального агента с подключением плагина через конфиг выглядит примерно так:

yaml
# harness.config.yaml
agent:
  name: home-assistant
  model: deepseek-chat
  system_prompt: |
    Ты ассистент для управления домашней лабораторией.
    Отвечай кратко, используй только те инструменты, которые доступны.
plugins:
  - dsh-plugin-shell
  - dsh-plugin-http

Сам по себе этот конфиг ещё ничего не делает — он лишь описывает, какие модули подключить. Дальше Harness стартует агент, регистрирует плагины в контейнере зависимостей и передаёт управление циклу диалога.

Роль Cordis в AI-оркестрации

Cordis — это сервисный контейнер, на котором построен Harness. Если проводить аналогию из мира, который мне ближе, Cordis для Harness — это как systemd для Linux: не самая очевидная для новичка абстракция, но именно она держит на себе всю архитектуру.

Технически Cordis — это IoC-контейнер с поддержкой жизненного цикла сервисов. Плагины в Harness регистрируются как сервисы, объявляют зависимости друг от друга через декораторы, а Cordis сам разруливает порядок инициализации и завершения. Когда агент стартует, Cordis последовательно поднимает плагины в правильном порядке, инжектит зависимости и следит за тем, чтобы при остановке всё корректно свернулось в обратном порядке.

Для оркестрации AI-агента это критично. У плагина, который ходит в LLM, есть зависимость на конфиг. У плагина, который ходит во внешний API, есть зависимость на HTTP-клиент и, возможно, на тот же конфиг. Если попытаться разруливать это руками, быстро получится клубок из импортов и побочных эффектов. Cordis берёт эту работу на себя.

С практической точки зрения Cordis даёт ещё один полезный эффект: ленивая загрузка. Плагин не поднимается до тех пор, пока его не попросят. Можно держать в конфиге десяток модулей, но пока агент реально не вызовет соответствующий инструмент — этот модуль не съест ни мегабайта памяти.

Возвращаясь к теме расширяемости: если вы пишете собственный плагин, вы просто наследуетесь от базового класса и регистрируете сервис через декоратор. Никакой магии:

typescript
import { Service } from '@cordis/core';
import { definePlugin } from 'dsh';

class GitHubPlugin extends Service {
  async fetchIssue(repo: string, num: number) {
    const resp = await this.ctx.http.get(
      `https://api.github.com/repos/${repo}/issues/${num}`
    );
    return resp.data;
  }
}

export default definePlugin({
  name: 'github',
  services: [GitHubPlugin],
});

Дальше этот плагин подключается через тот же harness.config.yaml — и агент получает новый инструмент. Ядро Harness про этот плагин ничего не знает и знать не должно.

Именно эта комбинация — минимальное ядро, плагинная архитектура поверх сервисного контейнера — делает Harness удобной базой для экспериментов с AI-агентами в домашней инфраструктуре. Можно начать с одного плагина, постепенно добавлять интеграции и не бояться, что очередное обновление сломает половину сценариев использования.

Если тема AI-агентов и построения графов знаний по кодовой базе вам близка, имеет смысл заглянуть в материал по созданию графа знаний кодовой базы с помощью Graphify — там хорошо раскрыта смежная идея: маленькое ядро и подключаемые модули под конкретную задачу.

Установка и первый запуск

Развёртывание на Proxmox или Kubernetes

Прежде чем запускать Harness, определитесь с площадкой. У меня дома три ноды Proxmox (Винни-Пух, Пятачок и Сова — про имена серверов в честь советских мультфильмов я уже писал, и традиция жива), плюс k3s-кластер для экспериментов. Для Harness подходят оба варианта, но подход разный.

Если вы уже работаете с Proxmox — проще всего использовать LXC-контейнер. Не путайте с полноценной виртуалкой: для Harness не нужна изоляция на уровне гипервизора, достаточно контейнера с доступом к сети. На ноде Proxmox:

bash
pveam available | grep debian
pveam download local debian-12-standard_12.2-1_amd64.tar.zst

Создайте контейнер. Идём в веб-интерфейс Proxmox либо через CLI:

bash
pct create 240 local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst \
  --hostname harness-01 \
  --cores 4 \
  --memory 8192 \
  --rootfs local-lvm:32 \
  --net0 name=eth0,ip=192.168.1.240/24,gw=192.168.1.1,bridge=vmbr0 \
  --features nesting=1
pct start 240
pct enter 240

Внутри контейнера ставим Node.js 20 и pnpm. Без nvm — это лишний слой, который потом мешает systemd-юнитам:

bash
apt update && apt install -y curl ca-certificates gnupg
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
corepack enable && corepack prepare pnpm@latest --activate

Дальше — клонируем репозиторий и ставим зависимости:

bash
git clone https://github.com/deepseek-ai/DeepSeek-Harness.git /opt/harness
cd /opt/harness
pnpm install
pnpm build

Теперь самое интересное — как это вообще запускается. Harness — это Node.js-процесс, который держит Cordis-контейнер с активными плагинами. Под неё нужен обычный systemd-юнит, без всяких менеджеров процессов уровня pm2. Они только мешают, когда нужно нормально логировать через journald.

bash
useradd -r -s /bin/false harness
mkdir -p /etc/harness /var/log/harness
chown -R harness:harness /opt/harness /var/log/harness

Конфиг кладём в /etc/harness/harness.yaml. Подробнее о его структуре поговорим в следующем разделе, а пока — минимальный рабочий вариант:

yaml
# /etc/harness/harness.yaml
plugins:
  - dsh-plugin-config
  - dsh-plugin-http
  - dsh-plugin-agent
log:
  level: info
  destination: /var/log/harness/harness.log

Сам юнит:

ini
# /etc/systemd/system/harness.service
[Unit]
Description=DeepSeek Harness AI Agent Runtime
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=harness
Group=harness
WorkingDirectory=/opt/harness
EnvironmentFile=-/etc/harness/harness.env
ExecStart=/usr/bin/node /opt/harness/dist/index.js
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Не забудьте systemctl daemon-reload и systemctl enable --now harness. Проверяем:

bash
systemctl status harness
journalctl -u harness -f

Если видите в логах что-то вроде plugin dsh-plugin-agent loaded in 142ms — всё, базовый рантайм живой.

С Kubernetes подход другой, но не принципиально. Для экспериментов у меня крутится k3s на двух Raspberry Pi 5 (8 ГБ) — туда я и закидываю Harness, когда нужно проверить, как оно работает под оркестратором. Базовый манифест:

yaml
# harness-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: harness
  labels:
    app: harness
spec:
  replicas: 1
  selector:
    matchLabels:
      app: harness
  template:
    metadata:
      labels:
        app: harness
    spec:
      containers:
        - name: harness
          image: ghcr.io/deepseek-ai/harness:latest
          args: ["--config", "/etc/harness/harness.yaml"]
          ports:
            - containerPort: 8080
              name: http
          volumeMounts:
            - name: config
              mountPath: /etc/harness
              readOnly: true
            - name: plugins
              mountPath: /opt/harness/plugins
          resources:
            requests:
              cpu: "500m"
              memory: "1Gi"
            limits:
              cpu: "2"
              memory: "4Gi"
      volumes:
        - name: config
          configMap:
            name: harness-config
        - name: plugins
          emptyDir: {}

ConfigMap с конфигом — отдельный манифест:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: harness-config
data:
  harness.yaml: |
    plugins:
      - dsh-plugin-config
      - dsh-plugin-http
      - dsh-plugin-agent
    log:
      level: info

С практической точки зрения, для домашней лаборатории LXC на Proxmox проще и предсказуемее: виден весь стек, легко снять дамп памяти, если что-то пошло не так, а ресурсы расходуются экономнее, чем под отдельной виртуалкой. Kubernetes оправдан, только если вы уже подняли там Prometheus, Grafana и хотите единый мониторинг — тогда добавьте scrape-конфиг и снимайте метрики с плагина dsh-plugin-metrics. Без этого смысла городить k3s ради одного пода нет.

Для продакшн-окружения однозначно выбирайте Kubernetes — но это уже за рамками домашней лаборатории.

Создание первого плагина через dsh create-plugin

Вот тут начинается самое интересное — философия «всё — это плагин» в действии. Если посмотреть на исходники репозитория, то сам по себе Harness не делает почти ничего: HTTP-сервер, логгер и runtime для плагинов. Всё остальное — агенты, коннекторы к LLM, интеграции с внешними системами — это плагины, которые подключаются через Cordis.

Чтобы создать заготовку плагина, в репозитории есть CLI-команда dsh create-plugin. Она генерирует шаблон с правильной структурой, манифестом и точкой входа:

bash
cd /opt/harness
pnpm run dsh create-plugin @myorg/dsh-plugin-greeter

После выполнения в директории plugins/@myorg/dsh-plugin-greeter появится типичный для Cordis-плагина набор файлов. Структура примерно такая:

plugins/@myorg/dsh-plugin-greeter/
├── package.json
├── src/
│   ├── index.ts
│   └── config.ts
└── README.md

Главное в этом наборе — package.json, потому что именно оттуда Harness узнаёт, что вообще нужно подгрузить. Посмотрите на сгенерированный манифест:

json
{
  "name": "@myorg/dsh-plugin-greeter",
  "version": "0.1.0",
  "description": "Example greeting plugin for Harness",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "harness": {
    "name": "greeter",
    "config": {
      "schema": "./dist/config.js"
    }
  },
  "cordis": {
    "service": "greeter"
  }
}

Поле harness — это контракт между плагином и рантаймом. Здесь указывается имя сервиса (внутренний идентификатор в Cordis-контейнере) и путь к схеме конфигурации. Поле cordis.service дублирует это для самой Cordis — так работает её механизм внедрения зависимостей.

Точка входа src/index.ts содержит базовый класс сервиса. Cordis использует декораторы для регистрации обработчиков событий, поэтому сгенерированный код выглядит примерно так:

typescript
import { Service, Context } from 'cordis';
import { Schema } from 'dsh-plugin-config';

interface GreeterConfig {
  greeting: string;
  language: 'ru' | 'en';
}

export class GreeterService extends Service {
  static inject = ['config'];

  constructor(ctx: Context, private options: GreeterConfig) {
    super(ctx, 'greeter');
    ctx.on('ready', () => {
      this.ctx.logger('greeter').info(
        `${this.options.greeting}, language=${this.options.language}`
      );
    });
  }
}

export default GreeterService;

Статическое поле inject = ['config'] — это запрос зависимости. Cordis-контейнер при инициализации плагина найдёт сервис с тегом config (его предоставляет dsh-plugin-config) и передаст его экземпляр в конструктор. Если зависимость не зарегистрирована — получите внятную ошибку на старте, а не падение через час в продакшне. Это одна из тех мелочей, которые делают Cordis предсказуемой штукой.

Файл src/config.ts отвечает за валидацию YAML-конфигурации. Схема — обычная Zod-схема, обёрнутая в декоратор:

typescript
import { Schema } from 'dsh-plugin-config';

@Schema({ expose: true })
export class GreeterSchema {
  greeting: string = 'Привет';
  language: 'ru' | 'en' = 'ru';
}

Что здесь происходит: декоратор @Schema регистрирует схему в плагине конфигурации, а expose: true означает, что поля можно переопределить через harness.yaml. Если поле не указано — используется значение по умолчанию из класса. Это даёт предсказуемость: разработчик видит дефолты прямо в коде, а не ищет их в документации.

После того как код готов, соберите плагин:

bash
cd plugins/@myorg/dsh-plugin-greeter
pnpm install
pnpm build

В dist/ появится скомпилированный JS с типизацией. Чтобы Harness подхватил плагин, есть два пути.

Первый — локальный, через директорию plugins/ в репозитории. Добавьте плагин в pnpm-workspace.yaml, если используете монорепо (а Harness его использует):

yaml
# pnpm-workspace.yaml
packages:
  - 'plugins/*'
  - 'plugins/@*/*'

Затем пересоберите корень и перезапустите сервис:

bash
cd /opt/harness
pnpm install
pnpm build
systemctl restart harness

Второй путь — npm-реестр. Если плагин опубликован, в harness.yaml достаточно указать имя пакета в секции plugins:

yaml
plugins:
  - dsh-plugin-config
  - dsh-plugin-http
  - dsh-plugin-agent
  - '@myorg/dsh-plugin-greeter'

Harness на старте пройдёт по списку, загрузит каждый пакет, зарегистрирует его в Cordis-контейнере и свяжет через inject-зависимости. Если на каком-то этапе что-то отвалится — увидите это в journalctl с указанием конкретного плагина.

Несколько практических замечаний, прежде чем двигаться дальше. Во-первых, не пихайте всю логику в один плагин. Cordis располагает к композиции: один плагин отвечает за транспорт (HTTP), другой за аутентификацию, третий за интеграцию с LLM. Если плагин разросся — это сигнал, что его стоит разбить. Во-вторых, всегда объявляйте зависимости через static inject. Иначе получите неявный порядок инициализации, и через полгода сами не вспомните, почему всё работает только в определённой последовательности. В-третьих, версии плагинов фиксируйте. Cordis не придирчив к semver, но вы при регрессии — придирчивы.

Похожий подход к плагинам используется и в других AI-инструментах — например, в Ponytail для Claude Code тоже сделана ставка на расширяемость через дополнительные модули. Но там это скиллы для конкретного клиента, а здесь — полноценный runtime с собственной системой сервисов.

Если вам интересно копнуть глубже в смежные темы — например, как строить граф знаний поверх всего этого хозяйства — посмотрите настройку Graphify и руководство по оптимизации AI-агентов. Там архитектурные идеи пересекаются.

Анатомия плагина: YAML, TypeScript и IDashPlugin

Структура YAML-конфигурации

Прежде чем лезть в TypeScript, посмотрим на внешний слой — YAML-конфиг. DeepSeek Harness читает его через Cordis и превращает в дерево зависимостей. Файл делится на секции, каждая из которых описывает либо метаданные плагина, либо его конфигурацию, либо регистрацию middleware.

Минимальный рабочий конфиг выглядит так:

yaml
# config.yaml
plugins:
  - name: my-plugin
    enabled: true
    config:
      apiKey: ${API_KEY}
      timeout: 30
    middleware:
      - request
      - response

Здесь name — это идентификатор плагина, по которому Cordis будет искать соответствующий TypeScript-модуль. Директива enabled позволяет выключить плагин без удаления его кода, что удобно для staging-среды. Блок config пробрасывается в конструктор плагина, а middleware объявляет точки расширения конвейера.

Если плагин требует внешних сервисов, их описывают в секции dependencies:

yaml
plugins:
  - name: postgres-plugin
    enabled: true
    dependencies:
      - name: postgresql
        host: ${DB_HOST}
        port: 5432
        database: agents
    config:
      poolSize: 10

Cordis разрешает зависимости автоматически — если postgres-plugin зависит от postgresql, фреймворк сначала зарегистрирует драйвер, затем передаст его инстанс в конструктор плагина. С практической точки зрения это убирает ручную инициализацию: нет нужды вручную вызывать injector.get(...) внутри плагина, фреймворк сделает это за вас через декораторы.

Переменные окружения подставляются через синтаксис ${VAR}. На стадии парсинга YAML Cordis выполняет интерполяцию, поэтому отсутствующая переменная уронит загрузку с понятной ошибкой — это лучше, чем молчаливый undefined в рантайме.

Интерфейс IDashPlugin и его методы

Теперь переходим к TypeScript-стороне. Каждый плагин реализует интерфейс IDashPlugin, который задаёт контракт между фреймворком и вашим кодом. Упрощённо он выглядит так:

typescript
interface IDashPlugin {
  readonly name: string;
  readonly version: string;
  
  apply(ctx: PluginContext, config: Record<string, unknown>): void | Promise<void>;
  
  onStart?(ctx: PluginContext): void | Promise<void>;
  onStop?(ctx: PluginContext): void | Promise<void>;
  
  // Хуки конвейера (опциональны)
  beforeRequest?(req: Request): void | Promise<void>;
  afterResponse?(res: Response): void | Promise<void>;
}

Метод apply — точка входа. Cordis вызывает его первым, передавая PluginContext (по сути обёртку над DI-контейнером) и распарсенный блок config. Здесь плагин регистрирует свои сервисы, обработчики, middleware. Например:

typescript
import { IDashPlugin, PluginContext } from 'dsh';

export default class LoggingPlugin implements IDashPlugin {
  readonly name = 'logging-plugin';
  readonly version = '1.2.0';

  apply(ctx: PluginContext, config: Record<string, unknown>): void {
    const level = config.level ?? 'info';
    
    ctx.register('logger', () => new Logger(level));
    ctx.on('request', this.logRequest);
  }

  private logRequest = (req: any) => {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  };

  async onStart(ctx: PluginContext): Promise<void> {
    const logger = ctx.get('logger');
    logger.info('LoggingPlugin started');
  }

  async onStop(ctx: PluginContext): Promise<void> {
    const logger = ctx.get('logger');
    logger.info('LoggingPlugin stopped');
  }
}

Жизненный цикл плагина состоит из трёх фаз: apply (регистрация), onStart (инициализация ресурсов после старта всех плагинов) и onStop (корректное завершение). Такой порядок гарантирует, что к моменту запуска все зависимости уже загружены — плагин может смело запрашивать их через ctx.get(...).

Хуки beforeRequest и afterResponse подключают плагин к конвейеру обработки запросов. Они вызываются синхронно или асинхронно — фреймворк дожидается Promise, если хук его вернул. Это позволяет строить цепочки middleware, где каждый участник модифицирует запрос или ответ. В реальной практике я использую эту механику для трассировки, rate limiting и кэширования — каждый из этих плагинов весит 30–50 строк и не знает о существовании соседей.

Отдельно стоит упомянуть регистрацию плагина в фреймворке. Поскольку DeepSeek Harness — это «плагин для плагинов», сам фреймворк тоже реализует IDashPlugin. Если вы пишете собственный оркестратор поверх Harness, ваш код станет плагином в иерархии фреймворка — такая рекурсия выглядит странно, но на практике даёт предсказуемость композиции: поведение системы полностью описывается списком загруженных плагинов.

Если хотите копнуть глубже в смежную тему кодовой базы, посмотрите создание графа знаний с помощью Graphify — там разобран похожий подход к декларативной конфигурации инструментов, а оптимизационные приёмы для AI-агентов собраны в руководстве по affaan-m/ECC.

Сравнение с альтернативами

DeepSeek Harness против LangChain и AutoGen

Прежде чем влезать в технические детали, давайте определимся с терминами. DeepSeek Harness — это не фреймворк для построения нейросетей и не SDK для вызова LLM. Это runtime для AI-агентов, построенный вокруг идеи «всё — это плагин». Если LangChain — это швейцарский нож с кучей насадок, а AutoGen — это конструктор диалогов между агентами, то Harness — это сборочный цех, где каждая деталь лежит на своём месте и подключается через единую шину.

Самое важное различие — в точке расширения. В LangChain вы наследуете класс BaseTool или BaseChain, импортируете нужные модули из langchain-community и надеетесь, что версии зависимостей не поедут. В AutoGen вы описываете агентов как объекты с system_message и регистрируете функции через декораторы. В обоих случаях расширение — это код на Python, и ничего больше.

В Harness всё иначе. Плагин — это директория с тремя обязательными файлами:

/etc/dsh/plugins/weather-plugin/
├── plugin.yaml
├── index.ts
└── README.md

plugin.yaml — это манифест:

yaml
name: weather
version: 1.2.0
runtime: nodejs20
entry: index.ts
permissions:
  - network:outbound
  - storage:read
hooks:
  - on_agent_init
  - before_tool_call

Никаких setup.py, никаких pyproject.toml, никаких регистраций в глобальном реестре через PR в основной репозиторий. Cordis (движок плагинов внутри Harness) находит плагины по манифесту, загружает их в изолированный контекст и прокидывает зависимости через систему инъекций. Это очень похоже на то, как Cordis работает в экосистеме Koishi, и это не случайно — проект явно вдохновлён этой философией.

С практической точки зрения, это даёт три вещи, которых нет у конкурентов.

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

Во-вторых, разрешения как first-class citizen. Секция permissions в манифесте — это не декоративная строчка. Cordis парсит её и применяет через capabilities на уровне V8-isolates. Плагин, заявивший storage:read, физически не сможет записать файл за пределы выделенной директории. В LangChain и AutoGen вопросы песочницы решаются на уровне ОС или вообще остаются на совести разработчика.

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

yaml
agent:
  id: research-assistant
  model: deepseek-chat
  system_prompt: |
    Ты исследователь. Ищи информацию, проверяй источники,
    формируй структурированный отчёт.
  plugins:
    - web-search
    - pdf-parser
    - citation-formatter
  memory:
    backend: postgres
    retention: 30d
  rate_limits:
    requests_per_minute: 30
    tokens_per_hour: 100000

Такой конфиг можно хранить в Git, можно рендерить через Ansible, можно передавать через ConfigMap в Kubernetes. В LangChain аналогичная логика размазана по Python-коду и часто требует отдельного слоя абстракции, чтобы не хардкодить параметры модели.

Не стоит воспринимать это как агитацию против LangChain. У LangChain огромная экосистема интеграций, и если ваша задача — быстро склеить пайплайн из готовых компонентов, он справится лучше. Harness целесообразен, когда вы строите долгоживущую систему, в которой плагины будут появляться от разных команд и обновляться независимо.


Когда стоит выбирать плагинную архитектуру

Плагинная архитектура — это не серебряная пуля. Она оправдана в конкретных сценариях, и попытка применить её там, где она не нужна, закончится overengineering.

Когда выбирать Harness:

  • У вас несколько команд разработчиков, которые пишут инструменты для агента независимо друг от друга. Плагины решают проблему координации версий и зависимостей без центрального релиз-менеджера.
  • Агент работает в продакшене и должен переживать обновления без даунтайма. Hot-reload плагинов в Cordis — это не маркетинговая фича, а реальный механизм, который можно наблюдать через dsh plugin reload weather.
  • Вам важна аудитируемость. Манифест плагина с явными permissions и hooks — это уже половина документации для compliance. Остальное собирается из логов Cordis.
  • Инфраструктура у вас на Kubernetes или Proxmox, и вы привыкли к тому, что всё декларативно. Harness ложится в этот стек естественно: плагины упаковываются в OCI-образы, конфиги агентов едут через Helm-чарты.

Когда НЕ стоит выбирать Harness:

  • Вы пишете прототип на выходные. Оверхед на описание манифеста, настройку Cordis и деплой плагина не окупится.
  • У вас один агент с тремя статичными инструментами. Плагинная архитектура добавит сложности без выгоды.
  • Стек жёстко завязан на Python, а команда не готова поддерживать Node.js-рантайм. Да, у Harness есть экспериментальная поддержка Python через cordis-python, но она пока сырая.

С практической точки зрения, граница проходит по количеству плагинов и частоте их обновлений. Если у вас меньше пяти инструментов и они меняются раз в квартал — берите LangChain. Если десять и больше, и они обновляются каждую неделю от разных авторов — Harness окупится.

Если вы уже работаете с AI-агентами и оптимизируете их производительность, посмотрите на руководство по оптимизации AI-агентов с affaan-m/ECC. Там разбираются подходы, которые хорошо ложатся на плагинную модель — например, вынос тяжёлой обработки в отдельные плагины с собственными лимитами.

Ещё один аргумент в пользу Harness — совместимость с инструментами вроде Graphify. Когда граф знаний кодовой базы строится отдельным плагином с собственными permissions: storage:write, основной агент остаётся чистым и не разрастается в монолит. Подробнее о связке таких подходов — в материале про создание графа знаний с помощью Graphify.

Итог: DeepSeek Harness — это не замена LangChain или AutoGen, а инструмент для другого класса задач. Если ваша система похожа на операционную систему с пакетами, а не на скрипт из двадцати строк — плагинная архитектура даст ту самую предсказуемость, которая отличает домашнюю лабораторию от продакшена.

Часто задаваемые вопросы

Чем DeepSeek Harness отличается от LangChain или LlamaIndex на практике?

Если коротко — шириной ядра и предсказуемостью. Ядро Harness (dsh) делает буквально одну вещь: запускает цикл «промпт → модель → ответ», всё остальное подключается плагинами. В LangChain за годы развития накопилось столько абстракций, что отладка типичного агента превращается в археологическую экспедицию по слоям колбэков. Для домашней лаборатории, где агент обычно один и задачи у него конкретные, Harness удобнее именно за счёт читаемости — открываете код ядра и за десять минут понимаете, что и в каком порядке выполняется.

Зачем нужен Cordis, если есть обычные плагины?

Cordis — это не альтернатива плагинам, а инфраструктура для их жизненного цикла: регистрация, разрешение зависимостей между плагинами, корректный запуск и остановка. С практической точки зрения Cordis решает типичную боль плагинных систем: когда плагин A зависит от плагина B, а тот — от C, руками разруливать порядок загрузки и обработку ошибок инициалисти неудобно. Cordis делает это по контракту, поэтому предсказуемость поведения сохраняется даже при десятке подключённых модулей.

Можно ли запустить DeepSeek Harness без YAML-конфига?

Технически — да, минимальный агент стартует и с дефолтами, потому что ядро само по себе почти ничего не требует. Но смысл YAML в том, чтобы явно описать, какие плагины подключены и с какими параметрами. Для домашнего использования я рекомендую всё-таки заводить конфиг: во-первых, его удобно коммитить в Git и отслеживать изменения, во-вторых, при обновлении плагинов сразу видно, что именно у вас включено. Файлы конфигурации у Harness человекочитаемые, так что это не та история, где «yaml в yaml поверх yaml».

Как лучше деплоить Harness — на Proxmox в контейнере или в Kubernetes?

Если у вас уже есть кластер на Proxmox и вы запускаете агента штучно — LXC-контейнер или VM с Docker Compose будет проще и экономичнее. Никакого смысла тащить k3s ради одного пода нет. Kubernetes оправдан, когда агентов несколько, они используют разные модели, и хочется единообразно управлять секретами (API-ключи провайдеров), лимитами и мониторингом через Prometheus. В моём случае на домашней лаборатории живёт один агент в LXC на ноде «Сова», и для этой нагрузки k8s был бы оверкилом.

Что делать, если плагин после обновления перестал работать?

Во-первых, не паниковать и не катить обновление сразу в работающий агент — это общее правило для любых плагинных систем. Во-вторых, посмотреть journalctl -u dsh-agent или логи контейнера: Harness пишет, какой именно плагин упал и на каком этапе жизненного цикла. В-третьих, проверить changelog конкретного плагина — обычно ломается совместимость контракта, и откат на предыдущую версию (dsh-plugin-foo==1.2.3 в Compose-файле) решает вопрос быстрее, чем разбор причин. Долгосрочное решение — фиксировать версии плагинов в манифесте зависимостей и поднимать их осознанно.

Поделиться:TelegramX / TwitterVK

Читайте также