Главная / Статьи

Всё — это плагин: дизайн Cordis в основе системы DeepSeek Harness

Как библиотека Harness от DeepSeek создаёт среду выполнения агентов на основе плагинов, используя идеи Cordis, такие как обратимые эффекты, реактивные зависимости и заменяемый цикл агента.

Издатель: REACTAPP.TOP19 мин чтения4403 слов

Источники: DeepSeek Quietly Built a Different Kind of AI Agent Framework

Типичный подход и его слабые места

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

User asks something
      ↓
LLM thinks
      ↓
LLM calls a tool
      ↓
Tool returns data
      ↓
LLM continues
      ↓
Final answer

По определению, это уже считается агентом. Проблемы начинаются, когда система растёт. Накапливаются требования: несколько поставщиков моделей, инструменты браузера, выполнение команд в терминале, серверы MCP, процессы утверждения, память, телеметрия, аутентификация, разные интерфейсы, фоновые агенты, пользовательские запросы, разрешения и горячая замена кода. Вскоре каждая часть становится зависимой от всех остальных. Изменение поставщика моделей влияет на работу цикла агентов, удаление плагина оставляет слушатели событий, а перезагрузка инструмента может нарушить работу агентов, выполняющихся в данный момент. Плагины также зависят от сервисов, которые могут появиться или исчезнуть в процессе работы.

DeepSeek Harness подходит к этой задаче совершенно иначе. Его основная идея звучит почти слишком просто: всё является плагином, включая те компоненты, которые большинство фреймворков считают ядром.

В основе всего этого лежит фреймворк под названием Cordis, возникший на основе исследовательской статьи под названием «Парадигма программирования для пространственно-временной композиционности». Эта статья представляет интерес, поскольку проект — это не просто ещё один способ организации модулей JavaScript. Он затрагивает более глубокий инженерный вопрос: как компоненты могут объединяться, удаляться, заменять друг друга и изменять зависимости в работающей программе, не приводя к хаосу во время её выполнения?

Что такое харнес

DeepSeek Harness, сокращённо dsh, — это open-source харнес для агентов, выпущенный DeepSeek. Харнес представляет собой инфраструктуру, окружающую модель. Независимо от того, является ли модель DeepSeek, Claude, GPT, Gemini или локальной, харнес обеспечивает управление всем, что связано с ней.

                    ┌───────────────┐
                    │      LLM      │
                    └───────┬───────┘
                            │
                 ┌──────────▼──────────┐
                 │    Agent Harness    │
                 │                     │
                 │ Prompt construction │
                 │ Tool execution      │
                 │ Session history     │
                 │ Permissions         │
                 │ Streaming           │
                 │ Agent lifecycle     │
                 │ Model adapters      │
                 └─────────────────────┘

Эта разница имеет огромное значение. Обычно внимание сосредотачивается на том, насколько умным является модель, однако создание таких инструментов, как Claude Code, Codex, Cursor или автономный агент с длительным временем работы, показывает, что параметры их работы имеют не меньшее значение. DeepSeek Harness обрабатывает этот процесс как набор динамически составляемых плагинов, а не как единое монолитное приложение, и это решение было прямо заимствовано из Cordis.

Загадка зависимостей

Представьте, что вы создаете кодинг-агента из трех плагинов.

GitPlugin
TerminalPlugin
CodingAgent

Для работы агента по кодированию требуются Git и Терминал. При запуске самый простой способ — загрузить их по очереди.

load Git
load Terminal
load CodingAgent

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

CodingAgent
   ↓ -------->depends on
GitPlugin

Если Git исчезнет, агент для программирования не должен продолжать вести себя так, будто он существует. А если позже появится другой поставщик Git, возможно, агенту следует снова начать работу. Здесь скрываются две отдельные проблемы, которые в статье Cordis называются временной композибельностью и пространственной композибельностью.

Временная композибельность: чистое завершение работы

Предположим, плагин загружается и регистрирует слушатель событий.

events.on("message", handler)

Позже плагин сбрасывается, и возникает вопрос: что становится с обработчиком событий. Если ничто не удаляет его, плагин исчезает по имени, но его часть продолжает работать. К тому же плагин мог запустить таймеры, открыть соединения с базой данных, зарегистрировать команды, изменить общее состояние, добавить инструменты, привязать обработчики событий и запустить фоновые процессы. Сброс плагина означает обратное выполнение всех этих действий.

Это и есть временная композиционность: компонент, вступающий в систему, должен позволять системе полностью отменить все, что он сделал. Cordis рассматривает такие изменения как возвратимые эффекты.

Эффекты без жаргона

Эффект — это просто то, что делает ваш код и что изменяет внешний мир или состояние во время выполнения. Возьмем, к примеру, регистрацию инструмента.

toolRegistry.add("search", searchTool)

До звонка реестр выглядит так.

tools = {}

После этого в нём остаётся новый инструмент.

tools = {
    search: searchTool
}

Операция сложения — это операция прибавления.

add(searchTool)

Однако Cordis хочет чего-то большего. Он хочет, чтобы операция имела свою собственную обратную процедуру. Концептуально эффект сочетает действие с его отменой.

Effect:
     do:   add search tool
     undo: remove search tool

Без математической нотации идея выглядит следующим образом.

state --effect--> new state
new state --inverse--> original state

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

Каждое изменение требует последующей корректировки

Cordis реализует это с помощью подобного следующему шаблона, при котором функция применяет изменение и возвращает функцию, которая его отменяет.

ctx.effect(() => {
    registerSomething()
    return () => {
        unregisterSomething()
    }
})

Во время выполнения применяется эффект, сохраняется функция очистки, которая затем вызывается, когда плагин удаляется.

apply effect
      ↓
store cleanup function
      ↓
plugin runs
      ↓
plugin unloads
      ↓
run cleanup

Когда плагин содержит несколько эффектов, они применяются в одном порядке.

effect A
effect B
effect C

Затем процесс очистки выполняется в обратном порядке, как разворачивается стек.

undo C
undo B
undo A

Зачем обратный процесс? Рассмотрим плагин, который запускается вот так.

1. open database
2. start service using database
3. start agent using service

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

close database
stop service
stop agent

Безопасный порядок — это противоположность.

stop agent
stop service
close database

Это принцип «последний вошел — первый вышел».

Last In
First Out

Cordis встроил такое поведение в механизм управления жизненным циклом компонентов.

Одного обратного очищения недостаточно

Здесь статья становится более интересной. Предположим, плагин A изменяет общую переменную, затем плагин B изменяет ту же переменную, после чего A пытается восстановить её первоначальное значение. Это может стереть изменения, внесённые B.

Initial: x = 10

Plugin A: x = 20

Plugin B: x = 30

Plugin A unloads: restore x = 10

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

Plugin A registers tool "search"
Plugin B registers tool "calculator"

Замена той же конфигурации, вероятно, не поможет.

Plugin A replaces configuration X
Plugin B also replaces configuration X

Это различие снова всплывает позже, когда речь заходит о системе контекста Cordis.

Пространственная композиционность: понимание потребностей плагина

Временная композиционность касается вопроса о том, можно ли безопасно удалить компонент. Пространственная композиционность касается вопроса о том, понимает ли система, от чего зависит компонент. Представьте себе этот плагин.

CodingAgent

Для этого нужны три вещи.

LLM
ToolRegistry
SessionStore

Традиционный код может обращаться к глобальным переменным.

global.llm
global.tools
global.sessions

В таком случае архитектура не обладает реальным пониманием зависимостей. Cordis делает их явными. Концептуально плагин указывает, что он вставляет.

inject: [
    "llm",
    "tools",
    "sessions"
]

Теперь среда выполнения может видеть требования плагина в виде дерева.

CodingAgent
    ├── requires LLM
    ├── requires ToolRegistry
    └── requires SessionStore

Это позволяет системе реагировать на изменения в этих сервисах.

Реактивные зависимости

Возможно, это лучшая идея в Cordis. Предположим, компоненту нужен LLM.

LLM

Сначала его нет.

LLM unavailable

Поэтому компонент не может стать активным. Позже загружается плагин-провайдер, который предоставляет такой компонент.

OpenAI Plugin loads
      ↓
provides LLM
      ↓
dependency becomes satisfied
      ↓
component activates

Если этот поставщик будет устранён, соответствующая функциональность исчезнет вместе с ним.

OpenAI Plugin unloads
      ↓
LLM disappears
      ↓
dependency becomes unsatisfied
      ↓
dependent component unloads

Когда загружается другой поставщик, функциональность восстанавливается.

DeepSeek Plugin
      ↓
provides LLM
      ↓
component becomes active again

Зависимости, следовательно, не проверяются один раз при запуске. Они реактивны, и именно поэтому в статье говорится о реактивных коэффектах.

Эффекты против коэффектов

Терминология может показаться сложной, но различие простое. Эффект описывает то, что изменяет компонент, поступая из плагина в среду.

Plugin → Environment

Примерами являются эти действия.

register tool
open database
subscribe to event
start timer

Коэффект описывает то, что компонент требует от своей среды, протекая в обратном направлении.

Environment → Plugin

Типичными примерами являются эти потребности.

need an LLM
need a logger
need session storage
need a tool registry

Соединив их вместе, требования будут двигаться в одном направлении.

requirements
Environment ───────────────────> Plugin

пока эффекты возвращаются обратно.

Environment <─────────────────── Plugin
                    effects

Вот основная идея Cordis. Компонент указывает, что ему нужно, что он предоставляет и какие обратимые эффекты он осуществляет.

I NEED these services.
I PROVIDE these services.
I PERFORM these reversible effects.

Затем среда выполнения координирует жизненный цикл.

Откуда появилось понятие «пространственно-временное»

Теперь название статьи становится понятным. Пространственная композиционность касается взаимосвязей между компонентами.

A depends on B
B provides X
C depends on X

Временная композиционность касается того, как компоненты движутся во времени.

load
activate
replace
deactivate
unload
reload

Вместе они составляют всю философию.

Spatiotemporal composability = dependency-aware composition + reversible lifecycle changes

Объект контекста

DeepSeek Harness не передаёт десятки сервисов вручную через конструкторы. Плагины взаимодействуют через общий контекст, который обычно называется именно так.

ctx

Концептуально он отображает основные сервисы.

ctx
├── llm
├── tools
├── sessions
├── agents
├── agentLoop
├── logger
└── ...

Однако ctx — это не просто объект JavaScript, заполненный глобальными переменными. Благодаря ему плагины находят свои зависимости, предоставляют услуги, регистрируют эффекты, прослушивают события, изолируют ресурсы, перехватывают доступ к услугам и координируют жизненные циклы, именно поэтому Cordis представляет контекст как единую абстракцию.

От теории к реальному проекту

DeepSeek Harness обеспечивает доступ к своим основным подсистемам через этот общий контекст.

ctx.sessions
ctx.systemPrompt
ctx.tools
ctx.agents
ctx.agentLoop
ctx.llm

Обратите внимание на нечто необычное: даже цикл агентов представляет собой всего лишь сервис.

ctx.agentLoop

Следовательно, этот цикл можно заменить, и он не является священным кодом фреймворка. Это приводит к основному принципу проектирования: не существует привилегированного ядра, которое каждая функция обязана модифицировать.

Почему цикл в виде плагина имеет значение

Большинство фреймворков агентов содержат центральный цикл, похожий на этот.

while not finished:
response = model(history)
    if response.tool_call:
        result = execute_tool(response.tool_call)
        history.append(result)
    else:
        return response

Затем каждая продвинутая функция начинает её изменять. Подтверждение перед выполнением команд? Нужно исправить цикл. Отслеживание? Тоже нужно исправить цикл. Повторные попытки, делегирование задач множеству агентов, другой движок инференса? Всё равно нужно исправить цикл. В итоге получается хаб, к которому привязаны инструменты, модели и память.

                    Agent Loop
                   /    |    \
                  /     |     \
             tools    models   memory
             /          |        \
        approvals     retries    tracing

Цикл превращается в «боговский объект» приложения. DeepSeek Harness избегает этой проблемы, позволяя циклу использовать ту же архитектуру плагинов, что и все остальные компоненты.

Структура одного цикла агента

По сути, взаимодействие проходит через этапы, примерно соответствующие следующим.

turn/start
    ↓
claim incoming user input
    ↓
assemble prompt + available tools
    ↓
agent/pre-step
    ↓
step/start
    ↓
record user message
    ↓
reconstruct conversation history
    ↓
send model request
    ↓
stream assistant response
    ↓
tool call?
   │
   ├── yes → execute tool
   │          record result
   │          continue another step
   │
   └── no  → finish
    ↓
step/end
    ↓
turn/end

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

События в режиме водопада как промежуточное решение

Cordis поддерживает несколько режимов выполнения событий. Один из удобных режимов — водопадный, который функционирует как промежуточное решение. Представьте запрос, проходящий через цепочку операций.

request
   ↓
Plugin A
   ↓
Plugin B
   ↓
Plugin C
   ↓
  LLM

Плагин B может обернуть выполнение обработчиком, который принимает следующий шаг.

async function handler(next) {
    console.log("before")
    const result = await next()
    console.log("after")
    return result
}

Выполнение происходит иерархически, причем каждый плагин действует до и после внутреннего вызова.

Plugin A before
    Plugin B before
        Plugin C before
            LLM
        Plugin C after
    Plugin B after
Plugin A after

Это включает разрешения, перезапись запросов, телеметрию, кэширование, маршрутизацию моделей, проверки безопасности и вставку контекста — ничто из этого не требует прямой интеграции в адаптер модели.

Модель находится за границей возможностей

Инструментарий также абстрагирует LLM, поэтому агенту не нужно понимать каждый SDK поставщика; он взаимодействует с одним сервисом.

Agent
  ↓
ctx.llm
  ↓
Model Adapter
  ↓
Provider API

Один из поставщиков может реализовать его для API DeepSeek.

DeepSeek API

Другая статья посвящена OpenAI.

OpenAI

Третий раздел посвящён Anthropic.

Anthropic

Остальная часть архитектуры агента обеспечивает реализацию той же функциональности больших языковых моделей. В документации Harness это иногда называют «швом функциональности», состоящим из определения сервиса и поставщика сервиса.

Service Definition
   ↓
Service Provider
   ↓
Consumer

Для ЯИИ эта цепочка идёт от интерфейса до конкретного поставщика.

LLM interface
     ↓
OpenAI provider
     ↓
Agent loop

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

Сессии, основанные на событиях

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

turn/start
user/message
assistant/chunk
assistant/chunk
assistant/message
tool/call
tool/result
assistant/message
turn/end

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

Session log = source of truth

Это заменяет обычную альтернативу.

Mutable chat history = source of truth

Почему агенты выигрывают от использования источника событий

Агенты стали настолько сложными, что хранение простого списка сообщений зачастую бывает недостаточным.

[
  {"role": "user", "content": "..."},
  {"role": "assistant", "content": "..."}
]

Для отладки может потребоваться знание того, какой инструмент был использован и какой вызван, какая модель сгенерировала ответ, какой системный промпт был применён, где началась запросная операция, где закончился этап обработки, какая конфигурация была активна, повторялся ли вызов и какой потоковый вывод был получен. Система записывает структурированные события сессии, что позволяет воссоздать всё, что могла увидеть модель. Один из принципов её проектирования гласит, что всё, что видит модель, должно быть восстановимо из журнала. Вместо того чтобы гадать, почему агент поступил определённым образом, можно воссоздать сам запрос, лежащий в его основе.

Волокна и состояние жизненного цикла

Cordis представляет запущенные компоненты с помощью волокон. Это не имеет никакого отношения к волокнам операционной системы. Волокно Cordis — это экземпляр компонента во время выполнения, и оно проходит через такие состояния.

PENDING
   ↓
LOADING
   ↓
ACTIVE
   ↓
UNLOADING
   ↓
DISPOSED

Существуют также состояния сбоя. Что ещё важнее, волокно хранит информацию о себе в нескольких аспектах.

what dependencies I need
what providers currently satisfy them
what effects I have created
what cleanup functions belong to me

Когда изменяются зависимости, фибра может обновить свой жизненный цикл.

Почему важна идентичность поставщика

Предположим, компонент зависит от сервиса базы данных.

database

В настоящее время его предоставляет один поставщик.

DatabaseProvider A

Во время горячей замены он заменяется на другой.

DatabaseProvider B

Даже когда оба возвращают эквивалентные объекты JavaScript, Cordis может различать идентичности поставщиков. Причина в том, что понятие зависимости означает не просто наличие значения.

"value exists"

Это также может означать, что значение поступило из другой инстанции компонента.

"this value came from a different component instance"

Таким образом, смена поставщика может заставить зависимости корректно перезагрузиться, что позволяет избежать большого числа ошибок, связанных с устаревшими ссылками.

Сброс загрузки в порядке зависимостей

Рассмотрим цепочку, в которой один плагин обеспечивает доступ к базе данных.

Plugin A provides database

Второй плагин зависит от базы данных, а третий — от второго.

Plugin B depends on databasePlugin C depends on Plugin B

Цепочка зависимостей выглядит следующим образом.

A
↓
B
↓
C

Теперь первый удаляется. Наивная система выполнения может сразу же закрыть базу данных, хотя две остальные могут всё ещё выполняться. Вместо этого Cordis координирует граф зависимостей. Начинается выгрузка.

A begins unloading

Затем зависимые элементы обрабатываются по порядку до того, как исходный элемент завершит свою очистку.

↓ mark A unavailableB notices dependency disappeared↓ B unloadsC notices B disappeared↓ C unloadsthenA completes cleanup

Порядок имеет огромное значение, поскольку он предотвращает использование зависимыми компонентами чего-то, что уже наполовину разрушено.

Изоляция: одно название, отдельные миры

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

Agent A → Database A
Agent B → Database B

Оба по-прежнему просят одно и то же.

database

Cordis поддерживает изоляцию, поэтому разрешение проблем с сервисами происходит в парном режиме.

service name + isolation realm

и не только по имени.

service name

Концептуально каждая сфера приводит одно и то же имя к своему собственному экземпляру.

Realm A: database → DB_A
Realm B: database → DB_B

Таким образом, одна и та же логическая зависимость может решаться по-разному в зависимости от контекста, что полезно для систем с несколькими арендаторами, нескольких агентов, сред с тестирования, плагинов в изолированных средах и отдельных рабочих пространств.

Перехват

Cordis также может формировать доступ к сервисам с использованием метаданных. Рассмотрим реестр инструментов, где административный агент может видеть эти инструменты.

shell
browser
filesystem
deploy

в то время как агент с ограниченными правами видит меньший набор.

browser
filesystem-readonly

Вместо создания отдельного реестра доступ можно перехватывать в зависимости от контекста.

ctx + metadata
      ↓
service resolution
      ↓
modified view of capability

Это сильный подход для систем политик.

Более безопасная замена горячих модулей

Горячая перезагрузка кажется простой.

file changed
    ↓
reload module

Во время работы плагина ситуация становится сложной. Что произойдёт, если новый модуль содержит ошибку, и что станет с прежней рабочей версией? Загрузчик Cordis поддерживает режим перезагрузки, который функционирует как транзакция.

  working plugin
        ↓
    code changes
        ↓
  attempt new import
        ↓
     success?
 ┌───────┴───────┐
yes               no
 ↓                 ↓
replace         rollback
plugin          old module

Это естественным образом сочетается с обратимыми эффектами. Плагин с четким жизненным циклом, набором зависимостей и процедурой очистки гораздо менее опасен для замены.

Пример из реальной жизни

Cordis был создан не только для DeepSeek Harness. В статье рассматривается Koishi — фреймворк чат-ботов с открытым исходным кодом, построенный на нем, с сообщественной экосистемой, включающей тысячи плагинов, как указывают авторы. Настоящая экосистема делает динамическое составление гораздо более привлекательным, чем десять ручно созданных модулей. Однако авторы проявляют осторожность и не утверждают, что контролируемые тесты показали значительное улучшение производительности или эффективности. Требуется дополнительная оценка.

Не всё можно отменить

Здесь теория встречается с реальностью. Некоторые эффекты во время выполнения действительно обратимы, например открытие и закрытие файла.

open file
→ close file

Другие тоже хорошо сочетаются попарно.

allocate memory
→ free memorystart worker
→ terminate workerregister event listener
→ unregister listener

Затем идет отправка электронного письма.

send email

Какова будет его обратная величина?

unsend email?

Обычно это невозможно, и то же самое касается группы других действий.

send HTTP request
transfer money
publish message
delete external data

Когда что-то влияет на внешний мир, настоящего обратного эффекта может и не быть. Лучшим возможным решением является компенсация.

payment → refund
message → follow-up correction
database mutation → compensating transaction

Компенсация не является тем же, что математическое обратное преобразование. В документе прямо указывается на это различие, и Cordis наилучшим образом справляется с эффектами, которые среда выполнения действительно может контролировать и восстанавливать.

Cordis доверяет вашей обработке завершения

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

ctx.effect(() => {
    startServer()
    return () => {
        // supposedly cleanup
    }
}))

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

effect + cleanup

Это не автоматическая формальная верификация, и это важное отличие.

Почему это подходит для ИИ-агентов

Традиционные приложения остаются довольно стабильными после запуска. Агенты развиваются в противоположном направлении. Будущие системы агентов могут постоянно выполнять подобные операции.

install tool
remove tool
change model
spawn agent
kill agent
load skill
reload code
switch permissions
connect service
disconnect service
modify environment

Представьте агента, который решает, что ему нужна поддержка GitHub, загружает соответствующую функциональность, а затем удаляет её, когда она больше не нужна, или заменяет несработавшую реализацию. Такой системе требуются гораздо более строгие семантики композиции во время выполнения, чем предлагает обычный инжектор зависимостей. Без них агент, работающий длительное время, может накапливать лишние компоненты.

orphan listeners
stale tools
dangling processes
broken dependencies
zombie services
duplicated handlers

Cordis стремится сделать композицию во время выполнения первоклассным концептом программного обеспечения.

Почему дизайн кажется изящным

Благодаря тому, что Cordis обрабатывает процесс композиции, DeepSeek Harness может моделировать практически всё одинаковым способом.

Model provider     → plugin
Tool               → plugin
Agent loop         → plugin
Session store      → plugin
UI                 → plugin
Telemetry          → plugin
Approval system    → plugin
Sandbox            → plugin
Credential store   → plugin

Новые функции не становятся особыми случаями внутри фреймворка. Они превращаются в дополнительные участники единой системы композиции.

Профили и пакеты

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

Base Bundle
├── model adapters
├── tools
├── sessions
├── sandbox
├── approvals
├── credentials
├── settings
└── telemetry

Другой пакет может включать веб-приложение.

Web Application

Другой вариант может создать агента без головы.

Headless Agent

Архитектура остается модульной, не усложняя повседневного использования.

Пять идей, которые стоит запомнить

Если всё остальное уйдёт на второй план, именно эти пять моментов следует запомнить.

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

change + inverse

Второй тип — реактивные совместные действия. Компоненты указывают, что им нужно, а среда выполнения реагирует, когда появляются, исчезают или меняются зависимости.

dependency available → activate
dependency gone      → deactivate

Третьим является контекст. Эффекты, зависимости и доступ к сервисам находятся внутри единого контекста выполнения.

ctx

Четвертым является динамический калькул компонентов, который описывает компонент через то, что ему нужно, что он предоставляет и что он изменяет, обеспечивая системе во время выполнения достаточную структуру для анализа процессов загрузки и выгрузки.

Dependencies + Provisions + Effects

Пятым является пространственно-временная композиционность, которая объединяет пространственные и временные аспекты.

spatial:
who depends on whom?
+
temporal:
how can components safely enter and leave?

Если сформулировать кратко, это обратимые изменения в сочетании с реактивной зависимостью.

Почему это важно не только для одного проекта

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

discover a capability
install it
use it
upgrade it
replace it
remove it
continue running

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

Более глубокий урок

Архитектура программного обеспечения обычно касается композиции в определённый момент времени: вы собираете компоненты и запускаете программу.

A + B + C

Cordis задаёт более сложные вопросы.

What if A disappears?
What if B is replaced?
What if C suddenly gains a dependency?
What if another implementation of A appears?
What if all of this happens while the system is running?

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

Основной вывод

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

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