Глава 19

Handoff передает доказанный контекст, а не мнение модели

Передача оператору нужна при конфликтной политике, недостатке данных, повторной ошибке tool, высокой цене решения или прямой просьбе пользователя. И передавать надо не "мнение модели", а доказанный контекст: черновик handoff состоит из проверенных фактов и ссылок на события, а не из догадок и пересказа.

TypeScript
type HandoffDraft = {
  id: string;
  category: "refund" | "delivery" | "policy" | "other";
  userQuestion: string;
  verifiedOrderId: string | null;
  verifiedFacts: Array<{ label: string; value: string }>;
  sourceIds: string[];
  toolErrors: string[];
};

async function handoffPrepare(raw: unknown, context: TrustedToolContext) {
  const input = handoffInput.parse(raw);
  return handoffs.createDraft({
    actorId: context.actorId,
    conversationId: input.conversation_id,
    category: input.category
  });
}

Что класть в черновик, а что нет - вопрос и безопасности, и уважения к оператору.

Добавлять · Не добавлять

  • Исходный вопрос пользователя - Скрытый reasoning
  • Проверенный order id - Предположение, что пользователь "мошенничает"
  • Sources и tool results - Сырые персональные поля
  • Что уже пробовали и какая ошибка возникла - Выдуманную срочность

Добавляют исходный вопрос, проверенный order id, sources и tool results, что уже пробовали и какая ошибка возникла. Не добавляют скрытый reasoning, предположение "пользователь мошенничает", сырые персональные поля и выдуманную срочность. Оператор должен получить факты, а не интерпретацию.

И оговорка про сам тикет.

Создание тикета тоже side effect. Если продукт создаёт тикет автоматически, явно сообщите об этом пользователю и обеспечьте deduplication. Для чувствительных каналов сначала покажите подготовленный handoff и получите согласие.

Все части примера готовы по отдельности. Соберём их в один runtime вокруг registry - и увидим, как contract, tools и провайдер стыкуются на сервере.

Ссылки