Архитектура интеллектуального агента с нуля (AGI или не AGI?). Часть 1

Когда-то всё начиналось с одной строчки кода и вопроса: «А что, если он сам поймёт, что делать?»
Я не строю сверхразум и не собираюсь перевернуть мир. Просто много лет в своей тихой лаборатории (читай: за обычным столом у компьютера) проектирую кусочки алгоритмов, как детали конструктора. Иногда они щёлкают и начинают жить — и это самый крутой момент.
Этот цикл статей — не манифест и не доказательство. Это мой личный черновик, дневник исследователя-одиночки, где я раскладываю по полочкам то, что накопил. Пишу простыми словами, чтобы даже ребёнок, заглянув через плечо, понял: вот тут агент «смотрит», тут он «думает», а тут — «делает».
Пишу для себя, чтобы не забыть, и для истории — чтобы кто-то потом мог посмотреть и сказать: «Ага, вот тут он ошибся, а вот тут догадался». И для вас — чтобы вместе разобрать, как устроена архитектура интеллектуального агента, простыми словами, без пафоса, но с уважением к сложности задачи. И да, это импровизация: каждая статья — это разговор с собой вслух, попытка объяснить сложное так, чтобы самому стало яснее. Если тебе интересно заглянуть в эту лабораторию — добро пожаловать. Будем собирать агента с нуля, шаг за шагом.
Эта статья — первая в цикле, где я делюсь тем, что накопил: простыми словами, с примерами и без претензий на истину. Только опыт, наблюдения. Тема — архитектура интеллектуального агента с нуля. И вопрос, который будет висеть над каждой статьёй: это уже AGI… или ещё нет? Поехали разбираться.
Правила игры, или почему я не буду сравнивать агента с кошкой
Представьте: вы смотрите на робота, который бродит по комнате и пытается найти выключатель. Вы говорите: «Смотри, он ищет — как человек!». Ваш друг возражает: «Нет, он просто крутится — как мотылёк!». На самом деле он не похож ни на человека, ни на мотылька. Он похож на алгоритм, который крутится в пространстве состояний. И это нормально.
Я программирую на C#. Весь код в этой статье — на нём. И у меня есть одно жёсткое правило: сравнивать поведение агента с любыми живыми существами и критиковать его за непохожесть на человека или животное — недопустимо. Не потому что это «обидно для агента», а потому что это сбивает с мысли. Вы начинаете думать «а как бы кошка решила эту задачу?» — а агент не кошка. У него другие данные, другие инструменты, другая архитектура.
Оценивайте то, что есть - не то, что вы хотели бы увидеть.
Три пары глаз на одного агента
Когда я проектирую агента, я смотрю на него с трёх точек зрения. Не потому что я мнительный, а потому что без этого получается каша — непонятно, где абстракция, где код, а где моя фантазия.
1. Сторонний наблюдатель
Человек сидит в кресле, смотрит на экран и видит, что делает агент. Здесь можно философствовать сколько угодно: «агент умный, он сам включил лампочку» или «агент тупой, он тычется в стену». Это субъективная оценка интеллектуальности. Она важна — именно так мы, люди, оцениваем друг друга и других существ. Но это только одна из трёх точек зрения, и на ней одной далеко не уедешь.
2. Программная реализация
Это код. Здесь агент — классы, объекты, списки, методы. На этом уровне я как программист связываю реальный мир с абстрактным миром агента: программирую тело (данные и инструменты, доступные телу) и мозг (набор алгоритмов). Можно использовать любые известные подходы — от простых переключателей до сложных архитектур.
3. Абстрактная архитектура
А вот это — самое интересное. Это вся информация и все инструменты, доступные агенту и алгоритмам, которые в нём работают. Ключевой момент: алгоритмы могут оперировать только символами из архитектуры агента и тем функционалом, который заложен в этих символах. Они ничего не знают о том, что это за информация. Для алгоритма «включено» — это не про электричество. Это просто символ. Точка. И у этого символа есть какой-то функционал — например, «проверить, целевое ли это состояние». Но что за этим стоит — алгоритм не знает. Эта третья точка зрения — самая важная. Именно она отделяет «как агент видит мир» от «как мир устроен на самом деле». И именно она позволяет рассуждать об интеллектуальности агента, не приписывая ему человеческих черт и не сравнивая с тем, как мыслил бы человек.

Моя главная задача
Разработать максимально универсальную архитектуру агента, данных которой достаточно для всех алгоритмов, которые я когда-либо захочу поместить в мозг агента. Не «достаточно для текущей версии» — а достаточно для всех.
Амбициозно? Да. Возможно ли? Я собираюсь узнать.
Архитектуру я буду развивать от простого к сложному. Цикл разработки такой:
Определяюсь, для чего мне нужен агент и какие у него требования.
Разрабатываю агента с учётом требований: создаю тело, подключаю приток внешних данных и воздействие на внешнюю среду, наполняю мозг алгоритмами.
Провожу симуляцию — выявляю изменение интеллектуальности агента с точки зрения наблюдателя.
Дорабатываю требования и повторяю циклы 2–4.
Звучит просто? Отлично. Значит, пора усложнить.
Китайская комната, или как представить себе абстрактную архитектуру
Чтобы описать абстрактную архитектуру агента, мне нужны понятные образы. Я использую два подхода. Первый — схематический, понятными словами из человеческой жизни: агент состоит из тела (поставляет данные из внешнего мира и воздействует на внешний мир) и мозга (содержит набор интеллектуальных алгоритмов). Просто и ясно, но не хватает глубины. Второй — образ китайской комнаты, тот самый мысленный эксперимент Сёрла, который я буду наполнять недостающим и необходимым функционалом. Итак, агент — это китайская комната. В комнате есть:
Лампочки — это символы (состояния) из внешнего мира. Каждая лампочка показывает какое-то состояние рецептора. В один момент горит только одна — текущее наблюдаемое состояние.
Кнопки — для воздействия на внешний мир. Кнопки — это действия эффекторов. Для каждого эффектора можно нажать только одну кнопку.
Приборная панель — на ней размещены все лампочки и все кнопки. Это интерфейс между комнатой и миром.
Общие правила поведения — помогают жителям ориентироваться в комнате. Например: «горящая лампочка показывает текущее состояние рецептора», «кнопку можно нажимать».
Чтобы у китайской комнаты появилась интеллектуальность, нужны жители — интеллектуальные алгоритмы, помещённые в мозг. Житель просыпается, смотрит на лампочки, думает и (возможно) нажимает кнопку. Потом засыпает. Просыпается следующий.
Базовая архитектура, или с чего всё начинается
Представьте, что вы архитектор. Но не обычный — вы проектируете не здание, а существо. Существо, которое должно жить в мире, воспринимать его и действовать в нём. С чего вы начнёте? С фундамента. С того минимума, без которого ничего не работает.
У меня этот минимум выглядит так: Агент состоит из тела и мозга. Тело — это связь с миром. Мозг — это то, что внутри. Всё. Больше ничего не нужно для старта. Но давайте заглянем глубже.

Тело состоит из двух списков.
Первый список — рецепторы. Рецептор поставляет данные откуда-то — из внешнего мира, из симуляции, из чего угодно. Нам пока неважно откуда. Важно, что у рецептора есть список доступных (известных, выученных) состояний. Ключевое правило: в один момент может быть активно только одно состояние из его списка. Не два. Не три. Одно. Как лампочка на приборной панели — горит только одна.
Второй список — эффекторы. Эффектор даёт возможность воздействовать на что-то — опять же, на что именно, нам пока неважно. У эффектора есть список доступных действий. И правило то же: в один момент можно выполнить только одно действие из его списка. Одна кнопка — одно нажатие.
Мозг: коллекция алгоритмов
Мозг — это коллекция алгоритмов. Интеллектуальных и не только. Алгоритмы — это те самые жители китайской комнаты. Каждый житель просыпается, смотрит на лампочки (состояния рецепторов), думает и, возможно, нажимает кнопку (помещает действие в эффектор). Потом засыпает. Просыпается следующий.
Пока в мозге пусто — никакого интеллекта нет. Архитектура есть, а ума нет. Как компьютер без операционной системы: железо работает, а сделать ничего не может.
Звучит просто? Почти примитивно? Отлично. Значит, пора проверить это на практике.
Первый агент: интеллектуальная лампочка
Теперь попробую создать самого простого агента и проверить как будет работать текущая архитектура.
Я люблю начинать с самого простого. Не с робота, который ходит по лабиринту. Не с дрона, который облетает препятствия. А с лампочки. Обычной лампочки, которая должна сама уметь включаться и выключаться.
Почему именно лампочка? Потому что это минимальный агент, на котором можно проверить архитектуру. Если архитектура не работает на лампочке — она не заработает ни на чём. А если работает — можно усложнять.

У агента будет:
один рецептор с двумя состояниями, показывающими, включена ли лампочка (включено / выключено);
один эффектор с одним действием — выполнение действия инвертирует состояние лампочки: если включена — выключает, если выключена — включает.
Мозг у лампочки пуст. Ни одного алгоритма. Ни одного жителя в китайской комнате. Лампочка просто горит или не горит — и ничего сама не делает. С точки зрения наблюдателя — это просто лампочка с выключателем. Нажал — горит. Нажал ещё раз — не горит. Никакой интеллектуальности не наблюдается. И не будет — пока мозг пуст.
Взгляд изнутри китайской комнаты
Теперь посмотрим на агента с точки зрения абстрактной архитектуры. Представим, что агент — это китайская комната. Внутри — приборная панель, на которой представлены все доступные состояния рецептора в виде лампочек. Сейчас их две, и что они означают — нам недоступно. Всегда горит одна лампочка — это текущее наблюдаемое состояние. На панели есть кнопки — все доступные кнопки эффектора. Сейчас кнопка одна. Можно нажать только одну из доступных кнопок для каждого эффектора.
Чтобы у китайской комнаты появилась интеллектуальность, нужно добавить в комнату жителей, которые будут нажимать на кнопки. С точки зрения наблюдателя это будет выглядеть так, будто лампочка сама включается и выключается по своему желанию.
Для начала, чтобы понять, что к чему, представим, что я стал жителем китайской комнаты. Я вижу две лампочки на приборной панели (одна из них светится) и одну кнопку. Больше никакой информации нет. Даже я, как человек, сейчас не понимаю, что мне делать. В правилах поведения комнаты указано, что светящаяся лампочка показывает текущее состояние рецептора, а кнопку можно нажимать.
Но что дальше? Что мне это даёт? Ничего.
Я стою перед панелью с двумя лампочками и одной кнопкой, и у меня нет ни малейшей причины нажать эту кнопку. Нет мотивации. Нет смысла. А нет смысла — потому что нет цели.
Цель: зачем жителю китайской комнаты нажимать на кнопку
Ты стоишь в этой комнате. Перед тобой панель: одна лампочка горит, вторая — нет. И одна кнопка. Ты знаешь правила: горящая лампочка — текущее состояние, кнопку можно нажимать. Но ты не знаешь главного — зачем.
Это и есть проблема. Без цели нажатие кнопки — просто щелчок. С точки зрения наблюдателя лампочка мигнёт. С точки зрения жителя — ты просто сделал движение. Никакой интеллектуальности.
А теперь представь, что тебе шепнули на ухо: «Твоя задача — чтобы горела вторая лампочка на приборной панели». Всё. Теперь у тебя есть цель. Ты смотришь на панель и думаешь: «Сейчас горит первая. Вторая — нет. Значит, надо что-то сделать». И ты нажимаешь кнопку. Вот в этот момент и появляется интеллектуальность — не из-за того, что ты нажал кнопку, а из-за того, что ты понял: текущее состояние не совпадает с целевым, и попытался это исправить.
Китайская комната должна предоставить информацию о какой-то цели, которую будут достигать жители — достигаторы цели, воздействующие на кнопки. Теперь нужно подумать, как предоставить таким жителям информацию о цели и что из себя будет представлять цель.
Понятие цели очень многосторонне, и программно реализовать его можно разными способами (со своими плюсами и минусами). Но я хочу универсальную архитектуру, чтобы цель предоставляла исчерпывающую информацию, которая может понадобиться жителю для её достижения. На данный момент у меня уже есть универсальная реализация функционала цели, но начнём с нуля и на примерах будем разбираться, чего не хватает и как это реализовать.
Цель с точки зрения наблюдателя
Представьте, что вы дистанционно управляете агентом, которого выбросили с вертолёта в самый центр густого леса радиусом в 1000 километров. Вам доступна только та информация, что доступна агенту. У агента энергии на 1 день, и больше ничего нет. Рецептор агента показывает координаты текущего местонахождения. Агенту доступны только действия передвижения (вперёд, назад, влево, вправо).
Если ничего не делать — через 1 день агент выключится. Если бродить по такому большому лесу — всё равно через 1 день агент выключится.
Чтобы сдвинуться с мёртвой точки, нужна цель. Цель — добраться до деревни, которая находится на некотором расстоянии от агента.
Как дать агенту понять, что он достиг цели? Скажу сразу, забегая вперёд: я пробовал разные варианты размещения данных о цели в китайской комнате — на отдельной приборной панели, отдельно от рецепторов и эффекторов, и в других местах. В итоге пришёл к следующей архитектуре: понятие цели добавляется в сам рецептор.
Как спрятать цель внутрь архитектуры
Теперь давайте уберём наше «шёпотом на ухо» и положим цель внутрь самой архитектуры — так, чтобы любой житель, попав в комнату, сразу видел: «Ага, вот какое состояние считается целевым».
Я решил поместить цель в сам рецептор. Это удобно: рецептор уже знает все свои состояния, значит, он может знать и то, какое из них — целевое. Для этого я добавил в рецептор метод:
bool? IsTarget(T value)Он возвращает:
true— если состояние целевое;false— если не целевое;null— если цели вообще нет.
Почему null, а не просто false? Потому что false означает «цель есть, но мы её не достигли». А если цели нет, агент не должен пытаться её достичь. Если мы вернём false, агент подумает: «Цель есть, я её не достиг, надо действовать». А цели-то нет! Поэтому null — это честный сигнал: «Не парься, цели нет». Давайте посмотрим, как это выглядит на нашей лампочке.
public class LightReceptor : IReceptor<bool>
{
private bool? _targetState;
public bool? IsTarget(bool value) =>
_targetState == value ? true : (_targetState.HasValue ? false : null);
public void SetTarget(bool target) => _targetState = target;
}
Снаружи кто-то (например, наблюдатель или другой модуль) ставит цель:
lightReceptor.SetTarget(true); // хотим, чтобы лампочка горелаТеперь житель китайской комнаты может спросить у текущего состояния:
if (currentState.IsTarget() == false)
{
// цель не достигнута — надо действовать
}И это уже работает. Но… есть подвох.
Подвох: знать, что цель не достигнута, — мало
Представьте, что вас снова выбросили с вертолёта — на этот раз в тот самый лес радиусом 1000 км. У вас энергии на день. Рецептор показывает координаты. Эффектор даёт кнопки «вперёд, назад, влево, вправо». Цель — добраться до деревни. Вы едете вперёд и спрашиваете с интервалом, допустим, в 1 секунду у текущего состояния: «Ты целевое?» — оно отвечает «нет». Что дальше? Вы нажимаете «вперёд». Через секунду снова спрашиваете: «Ты целевое?» — опять «нет». И через час оно наконец выдаёт «да».
С точки зрения наблюдателя робот ехал вперёд на север, добрался до деревни, которая там была, и остановился — его спасли и зарядили аккумулятор.
Но что если деревня была бы не впереди, а сзади? Робот удалился бы от цели, даже не подозревая об этом. Так очень легко заблудиться в лесу и не найти деревни за 1 день. В этом сценарии вы действуете вслепую. Вы знаете только: «ещё не там». Но не знаете: «приближаюсь или удаляюсь». Значит, кроме «это цель или нет», агенту нужно ещё одно знание: насколько он близок к цели.
Расстояние до цели: как понять, что ты идёшь в нужную сторону
Чтобы агент мог понимать, приближается он к цели или отдаляется, я добавил в рецептор ещё один метод:
float? Distance(T value1, T value2)Он возвращает расстояние между двумя состояниями. Или null, если посчитать нельзя или функционал не поддерживается.
На лампочке это не нужно — там всего два состояния, и «расстояние» между ними особого смысла не имеет. Но на координатах — критично.
Теперь, перемещая робота, можно наблюдать, приближается ли он к цели или отдаляется, и в зависимости от этого менять направление движения, чтобы каждое следующее состояние уменьшало дистанцию до целевого. Пример для координат:
public class PositionReceptor : IReceptor<(float x, float y)>
{
private (float x, float y)? _targetPosition;
public float? Distance((float x, float y) v1, (float x, float y) v2)
{
var dx = v1.x - v2.x;
var dy = v1.y - v2.y;
return (float?)Math.Sqrt(dx * dx + dy * dy);
}
public bool? IsTarget((float x, float y) value)
{
if (!_targetPosition.HasValue) return null;
var target = _targetPosition.Value;
// можно сравнивать с небольшим допуском, но для простоты — точное совпадение
return value.Equals(target);
}
public void SetTarget((float x, float y) target) => _targetPosition = target;
}Теперь агент может делать то, что раньше не мог: оценивать направление.
var current = positionReceptor.ObservedState;
var target = positionReceptor.TargetState; // где-то хранится
var distance = positionReceptor.Distance(current, target);
// делаем пробное действие, получаем newState
var distanceNew = positionReceptor.Distance(newState, target);
if (distanceNew < distance)
{
// мы приблизились — хорошо, оставляем действие
}
else
{
// мы удалились — пробуем другое направление
}Вот это уже похоже на интеллектуальное поведение. Агент не просто тыкает кнопки. Он оценивает последствия своих действий и выбирает те, которые уменьшают расстояние до цели.
Возвращаемся к лампочке: что это ей даёт
У лампочки всего два состояния: true и false. Расстояние между ними формально можно считать, но смысла мало. Однако сама идея остаётся той же: агент должен уметь оценивать, становится ли ситуация лучше или хуже. Для лампочки «лучше» — это когда текущее состояние совпадает с целевым. Поэтому для неё мы используем только IsTarget(). Но архитектура уже готова и для более сложных случаев — где расстояние реально помогает.
Что у нас теперь есть в китайской комнате
Давайте соберём всё вместе и посмотрим на приборную панель с точки зрения жителя:
Лампочки (состояния рецепторов) — показывают, что сейчас происходит.
Кнопка (действие эффектора) — инструмент, чтобы что-то поменять.
Знания о цели — спрятаны в самих рецепторах: у каждого состояния можно спросить «ты целевое?» и «насколько ты далёк от цели?».
Житель (алгоритм) — смотрит на лампочки, проверяет цель и расстояние, решает, нажимать ли кнопку. Теперь у жителя есть причина нажать кнопку. Не просто «надо что-то делать», а «я вижу, что текущее состояние не целевое, и я могу попробовать его изменить».
Продолжаем проектировать агента-лампочку
Нужно добавить рецептору функционал цели и текущего состояния. В рецептор добавляю именованные ячейки, в которых будут храниться состояния. Каждая ячейка отвечает за свой тип состояния, и в каждую ячейку можно поместить только одно состояние. Добавляю: ячейка для наблюдаемого состояния — Observed.

Добавляем для рецептора методы:
bool? IsTarget(bool value)
float? Distance(bool value1, bool value2) // вернёт null — для лампочки этот функционал не нуженНа данном этапе цель для рецептора можно установить только внешне — человеком. С точки зрения реализации агента я как программист вывожу установку цели для рецептора на внешний дисплей, и человек может выбрать одно из двух значений: включить или выключить.
С точки зрения абстрактной архитектуры я нахожусь в китайской комнате в качестве жителя-достигатора цели. Смотрю на текущее состояние рецептора (Observed) и спрашиваю у него: «Ты целевое?» — а оно отвечает: «Нет». Значит, цель не достигнута, и нужно, нажимая на кнопки, добиться того, чтобы активное состояние стало целевым. Но у меня ещё не заложен абстрактный функционал нажатия на кнопки эффектора.
В эффектор добавляю именованные ячейки, в которых будут храниться действия. Каждая ячейка отвечает за свой тип действия, и в каждую ячейку можно поместить только одно действие. Добавляю: ячейка для действия на выполнение — Execute.

Теперь единственное, что я могу сделать, чтобы повлиять на внешний мир, — нажать на единственную кнопку (с точки зрения реализации алгоритма это выглядит как «поместить кнопку в ячейку эффектора Execute»). Так я и делаю: нажимаю на единственную кнопку. Эта кнопка должна включить лампочку, но это нужно реализовать в коде.
Нужно для агента придумать жизненный цикл — на примере китайской комнаты, где агент и есть само помещение.
Ритм жизни: тик-так, тик-так
У агента есть свой «пульс» — интервал между пробуждениями. Допустим, мы поставили одну секунду. Каждую секунду комната делает один полный цикл:
Просыпается.
Смотрит на мир.
Думает.
Действует.
Засыпает.
И снова по кругу. Ровно как будильник: дзынь — и ты снова в деле. Давайте пройдёмся по каждому шагу так, будто мы стоим внутри комнаты и сами проживаем этот цикл.
Шаг 1. Просыпание: комната открывает «глаза»
Комната просыпается. Это не значит, что внутри кто-то потягивается и зевает. Это значит, что система запускает новый такт работы. Всё готово к приёму данных, к вычислениям и к действию. В коде это может быть просто вызов метода Tick() или Step(). Но для жителя комнаты — это момент, когда всё становится актуальным. Старые данные уходят в прошлое, начинается новый отсчёт.
Шаг 2. Сбор данных: что сейчас происходит в мире?
Теперь комната «смотрит». Рецепторы обновляют свои состояния. То, что было актуально секунду назад, может уже устареть.
Для лампочки это просто: рецептор берёт текущее состояние — горит или не горит — и кладёт его в ячейку Observed. Но представьте, что это не лампочка, а агент в лесу. Тогда рецептор координат берёт свежие данные: «Ты сейчас в точке (10.15, 3.23)». И это значение становится тем самым «сейчас», от которого агент будет отталкиваться.
Важно: на этом шаге агент только наблюдает. Он не делает выводов, не нажимает кнопок. Он просто фиксирует факты. Как фотограф, который щёлкает кадр: «Вот что есть прямо сейчас».
Шаг 3. Мышление: жители просыпаются и принимают решения
Вот тут начинается магия. Просыпаются жители — алгоритмы мозга. Каждый из них смотрит на панель, на лампочки, на кнопки, на цель — и решает, что делать. У каждого жителя своя логика:
Один может быть «случайным достигателем»: если цель не достигнута — тыкаю любую кнопку.
Другой — «аналитиком»: смотрит на расстояние до цели и выбирает направление, которое сокращает дистанцию.
Третий — «осторожным»: ничего не делает, пока не уверен.
Они могут работать по очереди или параллельно. В нашей простой версии — по очереди. Первый житель просыпается, думает, помещает действие в ячейку Execute. Потом второй, третий… При этом никто из них ещё ничего не делает в мире. Они только предлагают действия. Как будто в комнате несколько советников, и каждый говорит: «Я бы нажал вот эту кнопку».
Шаг 4. Действие: комната нажимает кнопку
Теперь наступает момент истины. То, что лежит в ячейке Execute эффектора, выполняется. Если в ячейке лежит действие «инвертировать состояние», оно срабатывает. Лампочка меняет состояние: была выключена — стала включена. Или наоборот. После выполнения ячейка Execute очищается. Это важно: мы не хотим, чтобы действие выполнялось дважды. Один тик — одно действие.
Шаг 5. Сон: комната отдыхает и готовится к следующему такту
Комната засыпает. Это не значит, что всё останавливается. Просто активный цикл завершён. Данные сохранены, состояние зафиксировано, действия выполнены. В это время жители могут засыпать, а могут выполнять какие-то фоновые операции, не связанные с рецепторами и эффекторами.
А потом — снова пробуждение. И новый цикл.
Интервал, через который комната проснётся после засыпания, устанавливается как настройка для комнаты (настройка для агента) — программистом или пользователем.
Жизненный цикл в действии
Теперь я буду руководствоваться жизненным циклом комнаты. Установим интервал цикла в 1 секунду.
Сценарий 1: пользователь хочет включить лампочку.
Цикл 1:
Комната просыпается.
Рецептор обновляет состояние: лампочка выключена.
Житель просыпается, смотрит: текущее состояние не целевое. Он нажимает единственную кнопку — действие «инвертировать».
Действие выполняется: лампочка включается.
Комната засыпает.
Цикл 2:
Комната просыпается.
Рецептор обновляет состояние: лампочка включена.
Житель просыпается, проверяет: текущее состояние целевое. Ничего делать не нужно.
Ячейка
Executeпуста — действий нет.Комната засыпает.
С точки зрения наблюдателя: он нажал на дисплее кнопку включения, и лампочка загорелась. Вроде бы житель умный и достигает цели, но выглядит это так, будто произошло простое замыкание выключателем и лампочка загорелась — то есть выглядит не интеллектуально.
Сценарий 2: лампочка включена, пользователь нажимает кнопку выключения.
Цикл 1:
Комната просыпается.
Рецептор обновляет состояние: лампочка включена.
Житель просыпается, смотрит: текущее состояние не целевое. Он нажимает единственную кнопку — действие «инвертировать».
Действие выполняется: лампочка выключается.
Комната засыпает.
Цикл 2:
Комната просыпается.
Рецептор обновляет состояние: лампочка выключена.
Житель просыпается, проверяет: текущее состояние целевое. Ничего делать не нужно.
Ячейка
Executeпуста — действий нет.Комната засыпает.
Так как интервал работы комнаты — 1 секунда, с точки зрения наблюдателя после нажатия на кнопку выключения лампочка иногда включается или выключается не сразу, а через 1 секунду (это зависит от того, в какой момент наблюдателем была нажата кнопка: когда комната только заснула или прямо перед тем, как она просыпается).
Чтобы реакция на нажатие кнопки пользователем была быстрой, достаточно уменьшить интервал работы комнаты — пусть она просыпается 10 раз в секунду.
Почему ритм важен?
Ритм — это то, что делает агента предсказуемым и управляемым. Можно менять интервал:
Раз в секунду — для простых задач.
Десять раз в секунду — если нужна быстрая реакция.
Раз в минуту — если агент работает медленно и обдумывает каждый шаг.
Это как настройка темпа в музыке: быстрый ритм — для динамики, медленный — для размышлений.
Итог: первый интеллектуальный агент
Так как у лампочки только один рецептор и у него цель — только включение или выключение, больше ничего делать не нужно. Интеллектуальность по достижению цели достигнута. Осталось только те действия, которые я делал в мыслительной симуляции как житель китайской комнаты, перенести на программную реализацию жителя — а точнее, это будет один-единственный алгоритм в списке алгоритмов мозга агента.
Роль этого жителя может быть такой: если цель на случайном рецепторе не достигнута, нажимаем случайную кнопку на случайном эффекторе. Это случайный достигатель случайных целей.
В реальном коде это прекрасно работает у агента уровня лампочки с одним рецептором и одним эффектором с одним действием. Если цель не достигнута — он просто будет нажимать на кнопки, пока цель не будет достигнута.
Что это даёт для архитектуры
Жизненный цикл — это каркас, на который мы будем навешивать всё остальное: память, обучение, конкуренцию алгоритмов. Без него агент был бы просто набором функций, которые срабатывают непонятно когда. А с ним — это существо, которое живёт во времени, шаг за шагом.
Сейчас цикл очень простой. Но именно в эту структуру мы позже встроим и «тетрадку» жителя с памятью, и проверку дистанции, и многое другое.
В абстрактной архитектуре агента на его интеллектуальность можно влиять, модифицируя следующие три блока: рецепторы, эффекторы, алгоритмы мозга.
Жизненный цикл в коде: как комната оживает на 'C#'
Слова — это хорошо, но код — это где магия становится реальностью. Давайте посмотрим, как весь этот цикл — просыпание, сбор данных, мышление, действие, сон — выглядит в реальном коде на C#. Я буду показывать по частям и каждую часть объяснять. Не кусок сухого кода, а живой организм, где каждый метод имеет смысл.
Интерфейсы: язык, на котором говорят все части комнаты
Прежде чем показывать цикл, нужно определить, как части комнаты общаются друг с другом. Каждый житель, каждая лампочка, каждая кнопка говорят на общем языке — через интерфейсы.
Рецептор — поставщик состояний:
public interface IReceptor
{
// Обновить состояние из внешнего мира
void Observe();
// Текущее наблюдаемое состояние
IState Observed { get; }
}
public interface IState
{
IReceptor Receptor { get; }
// Это целевое состояние?
bool? IsTarget();
// Расстояние до другого состояния (или null)
float? DistanceTo(IState other);
}Observe() — это момент, когда рецептор «смотрит» наружу и забирает свежие данные. Observed — то, что он увидел. Каждая лампочка на панели знает две вещи: является ли она целью и насколько далеко от другой лампочки.
Эффектор — кнопка на панели:
public interface IEffector
{
// Ячейка для действия на выполнение
IAction Execute { get; }
// Выполнить то, что лежит в Execute
void Act(IAction action);
}
public interface IAction
{
IEffector Effector;
}У эффектора есть ячейка Execute — «что нажать в этом такте». Одна кнопка — одно действие. Нажал — что-то произошло.
Алгоритмы — жители комнаты:
public interface IBrain
{
// Мозг выполняет все алгоритмы, которые в него заложены
// (будет на работу всех жителей китайской комнаты)
void UpdateBrain(IAgent agent);
}Всё. Один метод. Мозг получает доступ ко всей комнате — рецепторам, эффекторам — и решает, что делать.
Каркас агента: китайская комната
Сначала — сама комната. Контейнер, в котором живёт всё остальное:
/// <summary>
/// Контракт агента — связующее звено между мозгом (обработка) и телом (ввод/вывод).
/// </summary>
public interface IAgent
{
/// <summary>Мозг агента: обрабатывает данные тела и формирует команды.</summary>
IBrain Brain { get; }
/// <summary>Сенсоры и исполнительные механизмы.</summary>
List<IReceptor> Receptors { get; }
List<IEffector> Effectors { get; }
void InitAgent(object context = null);
/// <summary>Единый шаг агента: наблюдение → обработка → действие.</summary>
void UpdateAgent();
}
public class Agent : IAgent
{
public List<IReceptor> Receptors { get; set; } = new();
public List<IEffector> Effectors { get; set; } = new();
public IBrain Brain { get; set; } = new();
// Интервал между циклами — «пульс» агента
public float TickInterval { get; set; } = 1.0f;
// Сколько тактов прошло с момента рождения
public long TickCount { get; private set; } = 0;
public virtual void InitAgent(object context = null) {}
public void UpdateAgent()
{
// ── Шаг 1. Комната просыпается ──────────────────
TickCount++;
// ── Шаг 2. Сбор данных: рецепторы смотрят на мир ─
foreach (var receptor in Receptors)
{
receptor.Observe();
}
// ── Шаг 3. Мышление: жители просыпаются ──────────
Brain.UpdateBrain(this); // Обработка и планирование (мозг)
// ── Шаг 4. Действие: эффекторы нажимают кнопки ───
foreach (var effector in Effectors)
{
// Выполняем то, что жители положили в Execute
effector.Act(effector.Execute);
// Очищаем Execute — новый цикл, новые решения
effector.Execute = null;
}
// ── Шаг 5. Комната засыпает ──────────────────────
// Ничего не делаем. Просто ждём следующего тика.
}
}Здесь всё просто: тело — это рецепторы и эффекторы, мозг — список алгоритмов. TickInterval — это тот самый ритм, который мы настраиваем. Одна секунда, десять раз в секунду, раз в минуту — как захотим.
Разбор цикла по шагам
Шаг 1. Просыпание
TickCount++;Одна строчка, но она важна. TickCount — это возраст агента в тактах. Сколько циклов он прожил. Позже это понадобится: жители смогут использовать его, чтобы понимать «сколько я уже тут живу» или «как давно я в последний раз менял состояние».
Шаг 2. Сбор данных
foreach (var receptor in Receptors)
{
receptor.Observe();
}Каждый рецептор «смотрит» наружу. У лампочки — проверяет, горит ли она. У робота в лесу — читает координаты. У агента с камерой — делает снимок. Результат попадает в Observed. Важно: на этом шаге никто не думает и никто не действует. Только наблюдение. Чистый кадр реальности.
Шаг 3. Мышление
Brain.UpdateBrain(this);Это самый интересный шаг. Каждый алгоритм-житель получает доступ ко всей комнате: к рецепторам (лампочкам), к эффекторам (кнопкам). И каждый решает: «нажать кнопку или нет». Житель не выполняет действие напрямую. Он помещает его в ячейку Execute эффектора — как будто пишет записку: «Я предлагаю нажать вот эту кнопку». А кто в итоге нажмёт — решит эффектор на следующем шаге. Сейчас жители работают по очереди, в том порядке, в котором я их добавил в список мозга.
Шаг 4. Действие
foreach (var effector in Effectors)
{
effector.Act(effector.Execute);
effector.Execute = null;
}Эффектор берёт то, что лежит в Execute, и выполняет. Если в ячейке пусто — ничего не происходит. Если там действие «инвертировать» — лампочка переключается. После выполнения очищаем Execute — чистый лист для нового цикла.
Шаг 5. Сон
В коде это просто конец метода UpdateAgent(). Никаких операций. Комната ждёт, пока её не разбудят снова. А кто будит? Снаружи — например, игровой цикл Unity:
public class AgentRunner : MonoBehaviour
{
public Agent agent;
private float timer = 0f;
void Update()
{
timer += Time.deltaTime;
if (timer >= agent.TickInterval)
{
timer = 0f;
agent.UpdateAgent();
}
}
}Вот и всё. Unity каждый кадр прибавляет время к таймеру, и когда накопится достаточно — вызывает UpdateAgent(). Одна секунда — один цикл. Десять раз в секунду — десять циклов. Комната живёт.
Пожалуй хватит, итоги первой части
Мы собрали агента-лампочку. Он видит цель, он тянется к ней, он делает шаг — и мир чуть-чуть меняется. Это не магия. Это архитектура. И в этой простоте — вся интрига.
Сейчас он кажется почти наивным: один рецептор, один эффектор, один алгоритм. Будто ребёнок, который только научился тянуться к игрушке. Но именно в этой ясности — сила: здесь нет ничего лишнего, и потому видно, как рождается самое главное — способность действовать не по команде, а по смыслу.
И вот тут начинается самое интересное. Потому что архитектура, которая работает для лампочки, не обязана останавливаться на ней. Она готова расти — тихо, по кирпичику, без громких обещаний. Что получится, когда мы начнём надстраивать её дальше — не знаю даже я. Каждая следующая статья будет импровизацией: попыткой понять, где заканчивается «просто работающий код» и начинается что-то большее.
Вопрос «AGI или не AGI?». Честный ответ: конечно, нет. Пока рано. Наш агент-лампочка — это даже не муравей. Это лампочка. Но архитектура, на которой он держится, не запрещает расти. И в этом вся суть: я не доказываю, что собрал AGI. Я показываю, как строить фундамент, на котором AGI — пусть крошечный, пусть далёкий — становится не случайностью, а следствием архитектуры.
Вопрос «AGI или не AGI?» останется висеть над каждой статьёй. Мы будем возвращаться к нему снова и снова — и каждый раз отвечать честно. Но он уже не кажется абстрактным — он висит прямо над нашей комнатой, над лампочками и кнопками, над каждым тиком цикла. И с каждым новым шагом он будет звучать всё острее.
Так что не спешите закрывать вкладку. Впереди — не план, а путь. Путь, на котором мы будем снова и снова проверять: становится ли агент умнее, или мы просто добавляем ему кнопок.
Следующая часть — это следующий шаг. И он обязательно будет неожиданным. Оставайтесь рядом — будет интересно.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
0%рецептор0
0%эффектор0
0%мозг (алгоритмы)0
0%наблюдатель0
0%не знаю0
Никто еще не голосовал. Воздержался 1 пользователь.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
0%цель не достигнута0
0%цели нет вообще0
0%ошибка0
0%не знаю0
Никто еще не голосовал. Воздержавшихся нет.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
0%отлично, понял всё0
0%хорошо, но местами сложно0
0%скорее непонятно0
0%совсем не понял0
Никто еще не голосовал. Воздержавшихся нет.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.