パターン 5: スタンドアローンメモリ(バッチ)
会話が終わってから 1 回だけ呼び出します。完全なトランスクリプトを /process(または messages を渡した sessions.end)に送るだけで、Sonzai が背景でファクト・ムード・パーソナリティ・習慣を抽出します。
会話の所有権はあなたにあります。Sonzai はリアルタイムには介入しません。 通話終了、サポートケースのクローズ、ジャーナリングセッションの完了など、 会話が終わったタイミングでトランスクリプトを 1 回だけ POST すれば、 Sonzai の抽出器がそれをファクト、ムード更新、パーソナリティのドリフト、 習慣検出、プロアクティブな連絡シグナルへ変えます。チューター、フィットネス、 CRM、音声通話、ジャーナリングなど、Sonzai がホットパスにいることが 許容されない/不可能なフローに最適です。
使うべき時
- レイテンシ予算がターンごとの
/turnラウンドトリップに耐えられない。 - すでにトランスクリプトが存在する(録音、Gong/Zoom のエクスポート、 ジャーナルのエントリ)。
- 事後にバッチで取り込みたい — ログのリプレイ、ユーザー移行、エージェント 品質のベンチマーク。
切り替えるべき時
- ターンごとに新鮮なコンテキストが必要 — パターン 4: スタンドアローン・リアルタイム。
- LLM 呼び出しまで Sonzai に任せられる — パターン 1: マネージドランタイム。
アーキテクチャ
┌─────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Your App │ │ Sonzai API │ │ Your LLM │
└──────┬──────┘ └────────┬─────────┘ └──────┬───────┘
│ │ │
│ GET /context │ │
│────────────────────>│ (optional pre-session │
│ <── user profile ──│ personalization) │
│ │ │
│ ══ Your conversation (Sonzai not involved) ═════════│
│ │ │ │
│ Chat ──────────────┼──────────────────────>│ │
│ <── reply ─────────┼───────────────────────│ │
│ [N turns, your loop, your tools] │ │
│ │ │ │
│ ════════════════════════════════════════════════════════│
│ │ │
│ /process or sessions.end({ messages }) │
│────────────────────>│── extract facts, │
│ (full transcript) │ personality, mood, │
│ │ habits, interests │
│ <── extractions ───│ (Sonzai LLM) │
│ │ │
│ Use insights │ │
│ (push notif, │ │
│ dashboard, │ │
│ exercises, …) │ │
└─────────────────────┴───────────────────────┘
エンドツーエンドの例
もっとも簡単な経路は /process:1 回の呼び出しで自動的にセッションを作成し、
生成された session_id を相関付けに使えます。セッションスコープのツール、
通話時間、非同期ポーリングが必要な場合は、明示的な
sessions.start → end({ messages }) ライフサイクルを使います。
import { Sonzai } from "@sonzai-labs/agents";
const sonzai = new Sonzai({ apiKey: process.env.SONZAI_API_KEY! });
async function ingestTranscript(
agentId: string,
userId: string,
transcript: { role: "user" | "assistant" | "tool"; content: string; tool_calls?: any[] }[],
) {
// One call. Auto-creates a session. Tool messages allowed.
const result = await sonzai.agents.process(agentId, {
userId,
messages: transcript,
provider: "gemini", // optional override
model: "gemini-3.1-flash-lite-preview", // optional override
});
// result.session_id is the auto-created session id.
// Pull extractions from the read endpoints when ready:
const memory = await sonzai.agents.memory.list(agentId, { userId });
const mood = await sonzai.agents.getMood(agentId, { userId });
return { sessionId: result.session_id, memory, mood };
}トリガーは 1 つだけにする
/process と sessions.end({ messages }) はバッチ取り込みとして等価で、
どちらもトランスクリプト全体からファクトと副作用をインラインに抽出します。
同じトランスクリプトに対して両方は呼ばないこと — 抽出が二度走ります。
「1 呼び出しでシンプルにしたい」なら /process、明示的なライフサイクル、
非同期ポーリング、セッションスコープのツールが欲しいなら
sessions.start + sessions.end({ messages }) を使います。
いつ何が走るか
/process と sessions.end は意図的に軽量に設計されています:呼び出し
ごとにファクトとセッションサマリーを抽出するだけ(チャンクごとに 1 回の
LLM 呼び出し)。重いクロスセッション処理(重複排除、クラスタリング、
ダイアリー、減衰)はプラットフォームが自動スケジュールで実行するので、
毎回呼んでも追加で課金されることはありません。