Перейти к содержанию

🧠 Слой 7: Output Layer (Речевые зоны + Моторная кора)

Подробное описание архитектуры и работы

Статус: 🟡 Частично реализовано (Этап G) · 106+7 тестов ✅ trace_builder.py — OutputTraceBuilder (ExplainabilityTrace, цепочки причинности) ✅ response_validator.py — ResponseValidator (4 проверки: полнота, согласованность, уверенность, длина) ✅ dialogue_responder.py — DialogueResponder (hedging, шаблоны, RU/EN) ✅ OutputPipeline — оркестратор (trace → validate → respond) ⬜ ActionProposer — не реализован (Post-MVP) ⬜ Проверка безопасности / language mismatch в ResponseValidator — Post-MVP


Что такое Output Layer в биологии

В человеческом мозге выходной слой — это несколько специализированных зон:

Биологическая структура Функция Аналог
Зона Брока Формирование речи, грамматика DialogueResponder
Моторная кора Управление действиями ActionProposer
Передняя поясная кора Мониторинг ошибок в ответе ResponseValidator
Угловая извилина Интеграция смысла в слова TraceBuilder

Output Layer — это последний шаг: взять результат рассуждения и превратить его в понятный, объяснимый, проверенный ответ.


Роль в искусственном мозге

CognitiveResult от Cognitive Core
┌─────────────────────────────────────────────────────────────┐
│                    OUTPUT LAYER                             │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              TraceBuilder                            │   │
│  │  собирает полную цепочку причинности:                │   │
│  │  источники → факты → рассуждение → решение           │   │
│  └──────────────────────┬───────────────────────────────┘   │
│                         │                                   │
│  ┌──────────────────────▼───────────────────────────────┐   │
│  │              ResponseValidator                       │   │
│  │  проверяет ответ перед отправкой:                    │   │
│  │  полнота, согласованность, безопасность              │   │
│  └──────────────────────┬───────────────────────────────┘   │
│                         │                                   │
│  ┌──────────────────────▼───────────────────────────────┐   │
│  │              DialogueResponder                       │   │
│  │  формирует текстовый ответ с учётом:                 │   │
│  │  confidence, стиля, языка, контекста диалога         │   │
│  └──────────────────────┬───────────────────────────────┘   │
│                         │                                   │
│  ┌──────────────────────▼───────────────────────────────┐   │
│  │              ActionProposer                          │   │
│  │  предлагает действия (не только текст):              │   │
│  │  сохранить файл, запросить данные, обновить факт     │   │
│  └──────────────────────┬───────────────────────────────┘   │
└─────────────────────────┼───────────────────────────────────┘
                  BrainOutput
    {text_response, actions, trace, confidence, digest}
                          ├──► Пользователь (текст)
                          ├──► Learning Loop (обратная связь)
                          └──► Логгер (JSONL + digest)

Компонент 1: TraceBuilder — Построитель трассировки

Файл: brain/output/trace_builder.py
Аналог: Угловая извилина — интеграция всех источников в единый смысл

Принцип работы

CognitiveResult содержит:
  - memory_refs:    ["semantic:нейрон", "episodic:ep_001"]
  - source_refs:    ["docs/нейрон.pdf#p1", "user_input"]
  - reasoning_trace: [шаг_1, шаг_2, шаг_3]
  - contradictions: []
  - uncertainty:    UncertaintyReport(level="medium")
TraceBuilder.build(cognitive_result)
ExplainabilityTrace(
    input_sources=[...],      # откуда пришли данные
    memory_facts=[...],       # какие факты использованы
    reasoning_chain=[...],    # как рассуждал
    decision=[...],           # почему выбрано это действие
    confidence=0.78,          # итоговая уверенность
    uncertainty_sources=[...] # почему не 1.0
)

Структура ExplainabilityTrace

@dataclass
class ExplainabilityTrace:
    trace_id: str                      # "trace_a1b2c3"
    session_id: str
    cycle_id: str

    # Входные данные
    input_query: str                   # исходный вопрос
    input_modalities: List[str]        # ["text", "image"]

    # Источники
    input_sources: List[SourceRef]     # откуда пришли данные
    memory_facts: List[FactRef]        # какие факты из памяти использованы
    modal_evidence: List[ModalRef]     # кросс-модальные доказательства

    # Рассуждение
    reasoning_type: str                # "associative" | "causal" | ...
    reasoning_chain: List[str]         # ["нейрон", "→", "клетка", "→", "организм"]
    key_inferences: List[str]          # ключевые умозаключения

    # Решение
    action_taken: str                  # "respond_hedged"
    action_reason: str                 # почему выбрано это действие
    alternatives_considered: List[str] # другие рассмотренные варианты

    # Качество
    confidence: float                  # итоговая уверенность
    uncertainty_level: str             # "high" | "medium" | "low" | "very_low"
    uncertainty_reasons: List[str]     # причины неопределённости
    contradictions_found: List[str]    # найденные противоречия

    # Метаданные
    total_duration_ms: float
    created_at: str

Форматы трассировки

Machine format (JSONL):

{
  "ts": "2026-03-19T12:00:00.123Z",
  "level": "INFO",
  "module": "output_layer",
  "event": "response_generated",
  "session_id": "sess_01",
  "cycle_id": "cycle_4521",
  "trace_id": "trace_9fa",
  "input_ref": ["user_input", "semantic:нейрон"],
  "state": {"goal": "answer_question", "cpu_pct": 45, "ram_mb": 3800},
  "decision": {"action": "respond_hedged", "confidence": 0.78},
  "reasoning": ["нейрон", "→", "клетка", "→", "нервная система"],
  "latency_ms": 142,
  "notes": "medium confidence, hedging applied"
}

Human digest format:

Cycle 4521
  Query:        "Что такое нейрон?"
  Goal:         answer_question
  Memory used:  semantic:нейрон (conf=0.87), episodic:ep_001
  Sources:      docs/нейробиология.pdf (trust=0.87)
  Reasoning:    associative [нейрон → клетка → нервная система]
  Contradiction: none
  Confidence:   0.78 (medium) → hedged response
  Action:       respond_hedged
  Duration:     142ms | CPU: 45% | RAM: 3.8 GB

Компонент 2: ResponseValidator — Валидатор ответа

Файл: brain/output/response_validator.py
Аналог: Передняя поясная кора — мониторинг ошибок перед выводом

Проверки перед отправкой ответа

Сформированный ответ R
ResponseValidator.validate(R, cognitive_result)
    ├── 1. Проверка полноты:
    │       ответ не пустой?
    │       ответ отвечает на вопрос?
    │       → если нет → INCOMPLETE → запросить повторное рассуждение
    ├── 2. Проверка согласованности:
    │       ответ не противоречит фактам в памяти?
    │       → если противоречит → INCONSISTENT → добавить оговорку
    ├── 3. Проверка уверенности:
    │       confidence соответствует тону ответа?
    │       confidence=0.4 но ответ звучит уверенно → MISMATCH
    │       → добавить hedging phrases
    ├── 4. Проверка безопасности:
    │       нет ли в ответе приватных данных?
    │       нет ли потенциально вредного контента?
    │       → если есть → REDACT → удалить/заменить
    └── 5. Проверка языка:
            язык ответа соответствует языку вопроса?
            → если нет → LANGUAGE_MISMATCH → перевести

Структура ValidationResult

@dataclass
class ValidationResult:
    is_valid: bool                     # прошёл ли ответ все проверки
    issues: List[ValidationIssue]      # найденные проблемы
    corrected_response: str            # исправленный ответ (если нужно)
    applied_corrections: List[str]     # что было исправлено

@dataclass
class ValidationIssue:
    issue_type: str    # "incomplete" | "inconsistent" | "mismatch" | "unsafe" | "language"
    severity: str      # "critical" | "warning" | "info"
    description: str   # описание проблемы
    correction: str    # как исправлено

Компонент 3: DialogueResponder — Формирователь ответа

Файл: brain/output/dialogue_responder.py
Аналог: Зона Брока — формирование речи

Принцип работы

CognitiveResult + ExplainabilityTrace + ValidationResult
DialogueResponder.generate(...)
    ├── 1. Выбрать шаблон ответа по action_type:
    │   RESPOND_DIRECT:
    │     "{conclusion}"
    │   RESPOND_HEDGED (confidence 0.6–0.85):
    │     "Вероятно, {conclusion}. Уверенность: {confidence:.0%}."
    │   RESPOND_LOW_CONFIDENCE (confidence < 0.6):
    │     "Я не уверен, но возможно {conclusion}. "
    │     "Рекомендую проверить в источнике: {source}."
    │   ASK_CLARIFICATION:
    │     "Уточните, пожалуйста: {clarification_question}"
    │   REFUSE:
    │     "У меня недостаточно данных для ответа на этот вопрос."
    │     "Пробел в знаниях: {missing_concepts}"
    ├── 2. Добавить контекст из трассировки (опционально):
    │     "Источник: {source_ref} | Уверенность: {confidence:.0%}"
    └── 3. Адаптировать под язык:
          язык вопроса = "ru" → ответ на русском
          язык вопроса = "en" → ответ на английском
          язык вопроса = "mixed" → ответ на языке большинства

Hedging phrases (фразы неопределённости)

HEDGING_BY_CONFIDENCE = {
    (0.75, 1.00): [],                                    # без оговорок
    (0.60, 0.75): ["Вероятно,", "Скорее всего,"],
    (0.45, 0.60): ["Возможно,", "Я думаю,", "Мне кажется,"],
    (0.30, 0.45): ["Не уверен, но,", "Предположительно,"],
    (0.00, 0.30): ["Очень неуверенно:", "Это лишь предположение:"],
}

HEDGING_BY_CONFIDENCE_EN = {
    (0.75, 1.00): [],
    (0.60, 0.75): ["Probably,", "Most likely,"],
    (0.45, 0.60): ["Perhaps,", "I think,", "It seems,"],
    (0.30, 0.45): ["I'm not sure, but,", "Presumably,"],
    (0.00, 0.30): ["Very uncertain:", "This is just a guess:"],
}

Примеры ответов

Вопрос: "Что такое нейрон?"
confidence=0.87 → RESPOND_DIRECT:
  "Нейрон — это основная клетка нервной системы, которая
   передаёт электрические сигналы."

confidence=0.65 → RESPOND_HEDGED:
  "Вероятно, нейрон — это клетка нервной системы.
   [Уверенность: 65% | Источник: нейробиология.pdf]"

confidence=0.35 → RESPOND_LOW_CONFIDENCE:
  "Я не уверен, но возможно нейрон связан с нервной системой.
   Рекомендую проверить в источнике: нейробиология.pdf, стр. 12."

confidence=0.15 → REFUSE:
  "У меня недостаточно данных для точного ответа.
   Пробел в знаниях: 'нейрон'. Могу поискать дополнительную информацию."

Компонент 4: ActionProposer — Предложение действий

Файл: brain/output/action_proposer.py
Аналог: Моторная кора — инициация действий

Типы предлагаемых действий

class ProposedAction:
    """Действие, которое мозг предлагает выполнить."""

    action_type: str    # тип действия
    description: str    # описание
    params: Dict        # параметры
    priority: float     # приоритет 0.0–1.0
    reason: str         # почему предлагается

Каталог действий

MEMORY_ACTIONS:
  save_fact(concept, description)     — сохранить новый факт
  update_fact(concept, new_desc)      — обновить существующий факт
  delete_fact(concept)                — удалить устаревший факт
  add_association(A, B, weight)       — добавить ассоциацию

FILE_ACTIONS:
  read_file(path)                     — прочитать файл
  write_file(path, content)           — записать файл
  index_directory(path)               — проиндексировать директорию

DIALOGUE_ACTIONS:
  ask_user(question)                  — задать вопрос пользователю
  confirm_fact(concept)               — попросить подтвердить факт
  request_source(concept)             — попросить источник

LEARNING_ACTIONS:
  trigger_replay()                    — запустить replay
  verify_hypothesis(hyp_id)           — проверить гипотезу
  close_gap(concept)                  — устранить пробел в знаниях

SYSTEM_ACTIONS:
  save_memory()                       — сохранить память на диск
  report_status()                     — отчёт о состоянии
  adjust_confidence(concept, delta)   — скорректировать уверенность

Пример предложения действий

# После ответа на вопрос о нейронах:
proposed_actions = [
    ProposedAction(
        action_type="save_fact",
        description="Сохранить факт о нейроне",
        params={"concept": "нейрон", "description": "клетка нервной системы"},
        priority=0.8,
        reason="Новый факт с высокой уверенностью"
    ),
    ProposedAction(
        action_type="add_association",
        description="Связать нейрон и синапс",
        params={"A": "нейрон", "B": "синапс", "weight": 0.85},
        priority=0.6,
        reason="Часто встречаются вместе в контексте"
    ),
    ProposedAction(
        action_type="close_gap",
        description="Изучить подробнее: аксон",
        params={"concept": "аксон"},
        priority=0.4,
        reason="Связан с нейроном, но confidence=0.3"
    ),
]

Выходной формат: BrainOutput

@dataclass
class BrainOutput:
    # Идентификаторы
    output_id: str              # "out_a1b2c3"
    session_id: str
    cycle_id: str
    trace_id: str

    # Основной ответ
    text_response: str          # текстовый ответ пользователю
    response_language: str      # "ru" | "en"
    confidence: float           # итоговая уверенность 0.0–1.0
    uncertainty_level: str      # "high" | "medium" | "low" | "very_low"

    # Объяснимость
    trace: ExplainabilityTrace  # полная цепочка причинности
    digest: str                 # человекочитаемый digest

    # Действия
    proposed_actions: List[ProposedAction]  # предлагаемые действия

    # Метаданные
    action_taken: str           # "respond_direct" | "respond_hedged" | ...
    validation_passed: bool     # прошёл ли валидацию
    corrections_applied: List[str]  # что было исправлено

    # Производительность
    total_duration_ms: float    # общее время от вопроса до ответа
    created_at: str             # ISO timestamp

Полный пример вывода

brain_output = BrainOutput(
    text_response="Вероятно, нейрон — это основная клетка нервной системы, "
                  "которая передаёт электрические сигналы между клетками мозга.",
    confidence=0.78,
    uncertainty_level="medium",

    trace=ExplainabilityTrace(
        input_query="Что такое нейрон?",
        input_sources=[SourceRef("user_input", trust=0.8)],
        memory_facts=[
            FactRef("semantic:нейрон", "клетка нервной системы", conf=0.87),
        ],
        reasoning_chain=["нейрон", "→", "клетка", "→", "нервная система"],
        action_taken="respond_hedged",
        action_reason="confidence=0.78 → medium → hedging applied",
        confidence=0.78,
        uncertainty_reasons=["single_source", "no_cross_modal_evidence"],
        total_duration_ms=142.3,
    ),

    digest="""
Cycle 4521
  Query:        "Что такое нейрон?"
  Memory used:  semantic:нейрон (conf=0.87)
  Sources:      user_input (trust=0.80)
  Reasoning:    associative [нейрон → клетка → нервная система]
  Confidence:   0.78 (medium) → hedged
  Duration:     142ms | CPU: 45% | RAM: 3.8 GB
    """,

    proposed_actions=[
        ProposedAction("save_fact", priority=0.8, ...),
        ProposedAction("close_gap", params={"concept": "синапс"}, priority=0.4, ...),
    ],

    total_duration_ms=142.3,
)

Поток данных: от вопроса до ответа (полный путь)

Пользователь: "Что такое нейрон?"
      ▼  [Слой 1: Таламус]
PerceptEvent(text, "Что такое нейрон?", source="user_input")
      ▼  [Слой 2: Сенсорная кора]
EncodedPercept(vector=768d, keywords=["нейрон"], type="question")
      ▼  [Слой 3: Ассоциативная кора]
FusedPercept(unified_vector=512d, confidence=0.8, entity_clusters=[])
      ▼  [Слой 4: Memory System]
MemorySearchResult(semantic=[нейрон→клетка], episodic=[ep_001])
      ▼  [Слой 5: Cognitive Core]
CognitiveResult(action=respond_hedged, confidence=0.78,
                reasoning=[нейрон→клетка→нервная система])
      ▼  [Слой 6: Learning Loop]
OnlineLearningUpdate(associations_updated=[нейрон↔клетка])
      ▼  [Слой 7: Output Layer]
BrainOutput(
  text="Вероятно, нейрон — это основная клетка нервной системы...",
  confidence=0.78,
  trace=ExplainabilityTrace(...),
  digest="Cycle 4521 | 142ms | CPU: 45%"
)
Пользователь получает ответ
Логгер записывает JSONL
Learning Loop получает обратную связь

Наблюдаемость (Observability)

Output Layer — единственное место, где формируются все логи:

brain/logs/
    ├── brain.jsonl          — все события (machine format)
    ├── cognitive.jsonl      — только cognitive events
    ├── memory.jsonl         — только memory events
    ├── errors.jsonl         — только ошибки
    └── digests/
        ├── 2026-03-19.txt   — человекочитаемые дайджесты по дням
        └── session_01.txt   — дайджест по сессии

Ротация логов: - brain.jsonl → ротация при > 100 MB - Архив: brain_2026-03-19.jsonl.gz - Хранение: последние 30 дней


Ресурсный бюджет (CPU-only, 32 GB RAM)

Компонент RAM CPU Время/запрос
TraceBuilder ~2 MB 1 поток ~5–10 мс
ResponseValidator ~1 MB 1 поток ~2–5 мс
DialogueResponder ~1 MB 1 поток ~1–3 мс
ActionProposer ~1 MB 1 поток ~1–2 мс
Logger (JSONL) ~5 MB 1 поток ~1 мс
Итого ~10 MB 1–2 потока ~10–20 мс

Статус реализации

Компонент Статус Файл
ExplainabilityTrace dataclass ✅ Реализовано (Этап G) brain/output/trace_builder.py
BrainOutput dataclass ✅ Реализовано (Этап G) brain/output/__init__.py
OutputTraceBuilder ✅ Реализовано (Этап G) brain/output/trace_builder.py
ResponseValidator ✅ Реализовано (Этап G, 4 проверки) brain/output/response_validator.py
DialogueResponder ✅ Реализовано (Этап G) brain/output/dialogue_responder.py
OutputPipeline ✅ Реализовано (Этап G) brain/output/__init__.py
ActionProposer ⬜ Post-MVP brain/output/action_proposer.py
BrainLogger (JSONL) ✅ Реализовано (Этап C) brain/logging/brain_logger.py

Итог: место Output Layer в системе

Learning Loop → [OUTPUT LAYER] → Пользователь
                     │           Логгер
                     │           Learning Loop (обратная связь)
                     ├── TraceBuilder:      "почему я так решил"
                     ├── ResponseValidator: "правильно ли я отвечаю"
                     ├── DialogueResponder: "как это сказать"
                     └── ActionProposer:    "что ещё нужно сделать"

Output Layer — это голос мозга. Он не просто выдаёт ответ, он объясняет его, проверяет его и предлагает следующие шаги. Никаких "магических" ответов без trace chain.