Архитектура · Протокол

Протокол FSS — набросок спецификации

Рабочий черновик спецификации протокола. Финальная версия будет RFC-подобным документом ~30 страниц; здесь — основные абстракции и форматы сообщений, чтобы оценить архитектуру.

Статус документа

Это набросок v0.1, а не финальная спецификация. Имена полей, форматы сообщений, и даже базовые абстракции могут измениться в фазе 1-2 реализации. Не используйте как reference для имплементации.

Узлы и идентификация

Каждый узел FSS — это независимый актор с уникальным идентификатором WebID. WebID — это HTTPS URL, который dereferenceable и возвращает JSON-LD документ с публичным ключом узла и метаданными (имя, описание, поддерживаемые онтологии). Это та же модель, что в Solid, с одним отличием: WebID в FSS указывает не на pod-хранилище, а на FSS-эндпоинт.

{
  "@context": "https://fss.example/ns/v0.1",
  "@id": "https://alice.example/fss-node",
  "@type": "FSSNode",
  "name": "Alice Knowledge Graph",
  "publicKey": {
    "@id": "https://alice.example/fss-node#key",
    "@type": "Ed25519Key",
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n..."
  },
  "inbox": "https://alice.example/fss/inbox",
  "outbox": "https://alice.example/fss/outbox",
  "digests": "https://alice.example/fss/digests",
  "ontologies": ["https://fss.example/ontologies/personal-films/v1"]
}

Узел может быть приватным (WebID не публикуется, обмен только по прямому приглашению) или публичным (WebID в каталоге узлов). По умолчанию — приватный, публикация — явное действие пользователя.

Семантический дайджест

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

{
  "@context": "https://fss.example/ns/v0.1",
  "@type": "FSSDigest",
  "node": "https://alice.example/fss-node",
  "generatedAt": "2026-08-03T12:00:00Z",
  "entityCounts": {
    "Person": 247,
    "Film": 89,
    "Book": 134
  },
  "predicates": [
    "watched", "rated", "read_in", "wrote", "directed_by",
    "influenced_by", "similar_to"
  ],
  "ontologies": ["personal-films/v1", "common-books/v2"],
  "sampleQueries": [
    "films directed by Hitchcock",
    "books read in 2024"
  ],
  "signature": "..."
}

Поле sampleQueries — это примеры запросов, на которые узел готов отвечать. LLM-посредник использует их, чтобы понять, имеет ли смысл обращаться к этому узлу по конкретной теме. Если узел А имеет 0 фильмов в дайджесте, нет смысла спрашивать его про Хичкока.

Структура триплета

Триплет в FSS — это расширение классического RDF-триплета с обязательным provenance. Без provenance триплет считается анонимным и имеет confidence 0.0, что делает его непригодным для federated ответов (но пригодным для локального использования как черновик).

{
  "@context": "https://fss.example/ns/v0.1",
  "@type": "FSSTriple",
  "subject": "fss-local:note-187",
  "predicate": "rated",
  "object": { "@value": 8, "@type": "xsd:integer" },
  "subjectLabel": "Birdman (2014)",
  "predicateLabel": "оценил(а) на",
  "provenance": {
    "source": "fss-local:note-187",
    "author": "https://alice.example/fss-node",
    "extractedAt": "2026-08-03T11:42:00Z",
    "extractedBy": "qwen2.5:14b",
    "confidence": 0.92,
    "signature": "..."
  }
}

Поля subjectLabel и predicateLabel — это человекочитаемые подписи, которые LLM-агент использует при сборке ответа. Технически они избыточны (можно вывести из онтологии), но без них ответы читаются как «fss-local:note-187 rated 8» вместо «Birdman (2014) оценил(а) на 8».

Federated запрос

Запрос от узла А к узлу B проходит через LLM-посредник на стороне А, который формирует запрос на естественном языке + указывает нужные онтологии и ожидаемые типы. Узел B принимает запрос, локальный LLM-агент B переводит его в SPARQL к своему графу (с учётом маппинга онтологий), выполняет, возвращает ответ.

// Запрос от Alice к Bob
POST https://bob.example/fss/query
Content-Type: application/json
Authorization: Bearer <capability-token>
X-FSS-Signature: ...

{
  "@context": "https://fss.example/ns/v0.1",
  "@type": "FSSQuery",
  "from": "https://alice.example/fss-node",
  "query": "films directed by Hitchcock rated above 7 by you",
  "expectedPredicates": ["directed_by", "rated"],
  "ontologies": ["personal-films/v1"],
  "maxResults": 10,
  "includeProvenance": true
}

Ответ содержит массив триплетов с provenance и указанием confidence каждого. LLM-агент Alice собирает финальный ответ пользователю, явно показывая источник каждого утверждения. Если confidence низкий или маппинг онтологий неуверенный, пользователь видит предупреждение.

{
  "@type": "FSSQueryResponse",
  "queryId": "q-2026-08-03-001",
  "results": [
    {
      "subject": "Vertigo (1958)",
      "predicate": "rated",
      "object": 9,
      "provenance": {
        "author": "https://bob.example/fss-node",
        "confidence": 0.95,
        "ontologyMapping": "rated → rated (direct match)"
      }
    }
  ],
  "mappingsUsed": [
    { "from": "rated", "to": "rated", "confidence": 1.0 }
  ],
  "partial": false
}

Маппинги онтологий

Маппинг — это двустороннее соответствие между предикатами двух онтологий. Маппинги бывают трёх типов: эквивалентность (1:1, confidence 1.0), частичное соответствие (confidence 0.5-0.9, есть нюансы), отсутствие маппинга (0.0, предикаты несравнимы). Все маппинги кэшируются на обеих сторонах и обновляются при изменении онтологий.

{
  "@type": "FSSMapping",
  "nodeA": "https://alice.example/fss-node",
  "nodeB": "https://bob.example/fss-node",
  "predicateA": "написан_в",
  "predicateB": "year_published",
  "confidence": 0.85,
  "notes": "Алиса использует написан_в для даты рукописи и публикации; Боб только для публикации",
  "verifiedAt": "2026-08-03T12:00:00Z",
  "verifiedBy": "qwen2.5:14b + alice-confirmation",
  "expiresAt": "2026-11-03T12:00:00Z"
}

Маппинги — самая инновационная часть протокола. Они не статичны: LLM-посредник регулярно перероверяет их через тестовые запросы («отвечают ли оба узла одинаково на запрос X?»). Если ответы расходятся, confidence снижается, и при следующем federated запросе пользователь видит предупреждение.

Подписи и доверие

Каждое сообщение в FSS подписывается Ed25519-ключом отправителя. Подпись покрывает канонизированный JSON-LD (через Universal RDF Dataset Canonicalization). Это даёт две гарантии: авторство (сообщение действительно от того, кто указан в from) и целостность (сообщение не было изменено в пути).

Доверие — отдельный слой, не встроенный в протокол. Узел может вести белый список доверенных узлов, чьи утверждения принимаются с confidence 1.0. Узлы вне белого списка принимаются с понижающим коэффициентом (например, 0.5), если у них есть валидная подпись, и игнорируются, если подписи нет. Репутация строится как социальный граф доверия: если Алиса доверяет Бобу, а Боб — Кэрол, то Алиса может принять утверждение Кэрол с коэффициентом 0.7.

Жизненный цикл взаимодействия

  1. Обнаружение: узел А находит WebID узла B через каталог или прямое приглашение
  2. Знакомство: А запрашивает дайджест B, LLM-посредник сравнивает онтологии, предлагает маппинги
  3. Подтверждение маппингов: пользователь А подтверждает (или отклоняет) предложенные маппинги
  4. Запрос: при необходимости А делает federated запрос к B
  5. Ответ: B возвращает триплеты с provenance, А собирает ответ пользователю
  6. Кэширование: A кэширует полученные триплеты с указанием source = B, до истечения TTL
  7. Переоверка: периодически A переоверяет маппинги через тестовые запросы

Открытые вопросы

Несколько вопросов пока не решены и требуют экспериментов в фазе 1-2. Как обрабатывать конфликты триплетов от разных узлов? Если Алиса говорит «фильм вышел в 1958», а Боб — «в 1959», что показывать пользователю? Текущая идея — показывать оба с указанием источников и confidence, но UX этого неочевиден. Как предотвратить утечку приватных данных через federated ответы? Если узел случайно публикует в дайджесте предикат medical_condition, это уже утечка. Нужны явные redaction-политики. Как версионировать онтологии? Если Алиса обновляет personal-films/v1 до v2, что происходит с маппингами, основанными на v1?

Эти вопросы — нормальная часть проектирования протокола. Часть из них будет решена в фазе 1 (прототип), часть — в фазе 2 (протокол), часть потребует реального опыта использования и будет дорабатываться в фазе 3-4. Главное — не пытаться решить всё заранее, но и не закрывать глаза на реальные проблемы.

Документ: protocol.html · Версия: v0.1 · Обновлён: 2026-08-03