ステート、ツール、ユーザーナレッジ
エージェントに状態をアタッチし、LLMが推論中に呼び出せるカスタムツールを定義し、最初の会話前にユーザーにナレッジをプライミングします。
カスタムステート
チャット時にLLMコンテキストに注入される柔軟なキーバリューストレージです。環境状態・タスク進捗・リソース・その他のアプリケーションデータをすべてのAI応答に直接渡すために使用します。
スコーピングモデル
インスタンス
すべてのステートは instanceId——エージェントのデプロイメントコンテキスト(ワークスペースや環境など)——にスコープされます。デフォルトインスタンスを使用するには instanceId を省略します。複数のコンテキストを管理するにはインスタンスを参照してください。
ステートの作成
import { Sonzai } from "@sonzai-labs/agents";
const client = new Sonzai({ apiKey: "sk-..." });
// グローバルステート(すべてのユーザー間で共有)
await client.agents.customStates.create("agent-id", {
key: "current_status",
value: "Processing requests",
scope: "global",
contentType: "text",
instanceId: "workspace-1", // デフォルトインスタンスを使用する場合は省略
});
// ユーザーごとのステート
await client.agents.customStates.create("agent-id", {
key: "assigned_tasks",
value: { reports: 1, reviews: 3 },
scope: "user",
contentType: "json",
userId: "user-123",
instanceId: "workspace-1",
});アップサート(作成または更新)
upsert はキーが存在しない場合はステートを作成し、存在する場合は値を更新します。べき等——更新サイクルのたびに呼び出しても安全です。
await client.agents.customStates.upsert("agent-id", {
key: "workflow_stage",
value: "review_started",
scope: "user",
userId: "user-123",
});キーで取得
複合キーで特定のステートを取得します。
const state = await client.agents.customStates.getByKey("agent-id", {
key: "assigned_tasks",
scope: "user",
userId: "user-123",
});
console.log(state.value); // { reports: 1, reviews: 3 }
console.log(state.updatedAt); // ISOタイムスタンプステートの一覧表示
// インスタンスのすべてのグローバルステート
const globals = await client.agents.customStates.list("agent-id", {
scope: "global",
instanceId: "workspace-1",
});
// 特定ユーザーのすべてのユーザーごとステート
const userStates = await client.agents.customStates.list("agent-id", {
scope: "user",
userId: "user-123",
});キーで削除
await client.agents.customStates.deleteByKey("agent-id", {
key: "assigned_tasks",
scope: "user",
userId: "user-123",
});ツール
ツールによってLLMは推論中に関数を呼び出せます。Sonzaiは sonzai_ プレフィックスの組み込みツールを処理します。カスタムツールはあなたが定義し、バックエンドで実行します——Sonzaiは呼び出しをサイドエフェクトとして表示します。
独自のLLMを使用していますか?
スタンドアロンメモリモード(BYO-LLM)を使用する場合、Sonzaiはエージェントフレームワーク(LangChain・Vercel AI SDK・Gemini function callingなど)に組み込めるツールスキーマを公開します。詳細はツール統合ガイドを参照してください。
組み込みツール(機能)
エージェントごとにプラットフォーム管理の機能を切り替えます。エージェント作成時に有効化するか、機能APIで更新します。
sonzai_memory_recall(常時オン)
推論中に保存されたメモリを検索します。コンテキストに自動注入されます。
sonzai_remember_name(切り替え可能)
今後の会話のためにユーザーの名前を保持します。デフォルトでオン。
sonzai_web_search(切り替え可能)
Google経由のライブウェブ検索。デフォルトでオン。
sonzai_inventory(切り替え可能)
ユーザーリソースアイテムを読み取り、ナレッジベースデータと結合します。
// エージェント作成時に機能を設定
const agent = await client.agents.create({
agentId: "your-stable-uuid", // 推奨——作成をべき等にします
name: "Luna",
big5: { openness: 0.75, conscientiousness: 0.6, extraversion: 0.8,
agreeableness: 0.7, neuroticism: 0.3 },
toolCapabilities: {
webSearch: true,
rememberName: true,
imageGeneration: false,
inventory: true,
},
});
// または既存エージェントの機能を更新
await client.agents.update("agent-id", {
toolCapabilities: {
webSearch: false,
inventory: true,
},
});予約済みプレフィックス
sonzai_ プレフィックスは予約済みです。カスタムツールにはこれを使用しないでください——APIで拒否されます。
カスタムツール(エージェントレベル)
エージェントに保存され、セッションやインスタンスに関係なくすべてのチャットで利用できる永続ツールです。
// カスタムツールを作成
await client.agents.createCustomTool("agent-id", {
name: "check_inventory",
description: "Check the user's current tasks and their statuses",
parameters: {
type: "object",
properties: {
item_type: {
type: "string",
description: "Filter by category: active, pending, completed",
},
},
},
});
// すべてのカスタムツールを一覧表示
const tools = await client.agents.listCustomTools("agent-id");
// ツールの説明またはパラメータを更新
await client.agents.updateCustomTool("agent-id", "check_inventory", {
description: "Check and summarize the user's tasks by category",
});
// ツールを削除
await client.agents.deleteCustomTool("agent-id", "check_inventory");セッションレベルツール(一時的)
特定のセッションのためにツールを動的に注入します。セッションツールはエージェントレベルツールとマージされます——同名のセッションツールが優先されます。セッション終了時に破棄されます。
オプション1——既存セッションに設定
await client.agents.sessions.setTools("agent-id", "session-id", [
{
name: "execute_action",
description: "Execute an action from the agent's capabilities",
parameters: {
type: "object",
properties: {
action_name: { type: "string" },
target: { type: "string" },
},
required: ["action_name"],
},
},
]);オプション2——チャット呼び出しにインラインで渡す
for await (const event of client.agents.chatStream({
agent: "agent-id",
messages: [{ role: "user", content: "Check my tools" }],
userId: "user-123",
toolDefinitions: [
{
name: "check_inventory",
description: "List the agent's active tools",
parameters: { type: "object", properties: {} },
},
],
})) {
// イベントを処理...
}ツール呼び出しの処理
LLMがカスタムツールを呼び出すと、SSEストリームのサイドエフェクトとして現れます。バックエンドがツールを実行し、次のメッセージで結果を返します。
1. ツール呼び出しを受信
const toolCalls: { name: string; arguments: Record<string, unknown> }[] = [];
for await (const event of client.agents.chatStream({
agent: "agent-id",
messages: [{ role: "user", content: "What tasks do I have?" }],
userId: "user-123",
})) {
// コンテンツをユーザーにストリーム
const content = event.choices?.[0]?.delta?.content;
if (content) process.stdout.write(content);
// サイドエフェクトからツール呼び出しを収集
const calls = event.sideEffects?.externalToolCalls ?? [];
toolCalls.push(...calls);
}2. 実行して結果を返す
// バックエンドでツール呼び出しを実行
const toolResults: string[] = [];
for (const call of toolCalls) {
const result = await myBackend.executeTool(call.name, call.arguments);
toolResults.push(result);
}
// 次のチャットメッセージで結果を返す
for await (const event of client.agents.chatStream({
agent: "agent-id",
userId: "user-123",
messages: [
{ role: "user", content: "What tasks do I have?" },
{ role: "tool", content: toolResults.join("\n") },
],
})) {
process.stdout.write(event.choices?.[0]?.delta?.content ?? "");
}ツールスコーピングまとめ
| タイプ | スコープ | 永続性 | 管理方法 |
|---|---|---|---|
組み込み(sonzai_) | すべてのインスタンス | プラットフォーム管理 | SDK機能・ダッシュボード |
| エージェントレベルカスタム | すべてのインスタンス | 永続的 | SDK・ダッシュボード |
| セッションレベル | セッションごと | 一時的 | SDK(インラインまたはsetTools) |
ユーザースコープナレッジ(プライミング)
最初の会話前にエージェントがユーザーについて知っていることをシードします。CRMデータ・ユーザープロファイル・過去の購入履歴・その他のユーザー固有のナレッジを最初から利用可能にするために使用します。
ユーザーのプライミング
primeUser はユーザーに関する事実を非同期でシードします。抽出が完了したことを確認するためにポーリングできるジョブIDを返します。
const job = await client.agents.priming.primeUser(
"agent-id",
"user-123",
{
display_name: "Jane Smith",
metadata: {
company: "Acme Corp",
title: "Product Manager",
email: "[email protected]",
custom: { tier: "premium", region: "us-west" },
},
content: [
{
type: "text",
content: "Jane joined in 2024 and prefers concise answers. She focuses on mobile growth.",
},
],
source: "crm_import",
},
);
// プライミング完了を確認
const status = await client.agents.priming.getPrimeStatus(
"agent-id", "user-123", job.jobId
);
console.log(status.status); // "pending" | "processing" | "completed" | "failed"ユーザーメタデータの取得と更新
// ユーザーの保存されたメタデータを取得
const meta = await client.agents.priming.getMetadata("agent-id", "user-123");
console.log(meta.displayName, meta.company, meta.customFields);
// メタデータを更新(部分更新——未指定のフィールドは保持されます)
await client.agents.priming.updateMetadata("agent-id", "user-123", {
custom: { tier: "enterprise", lastContact: "2026-03-28" },
});バッチインポート(複数ユーザー)
複数のユーザーを一括でインポートします。進捗を追跡するためのジョブIDを返します。
const job = await client.agents.priming.batchImport("agent-id", {
users: [
{
userId: "user-1",
displayName: "Alice",
metadata: { company: "Acme", custom: { tier: "pro" } },
content: [{ type: "text", content: "Alice is a power user." }],
},
{
userId: "user-2",
displayName: "Bob",
metadata: { company: "Globex" },
},
],
source: "bulk_crm_sync",
});
// インポートステータスをポーリング
const status = await client.agents.priming.getImportStatus(
"agent-id", job.jobId
);
console.log(status.processed, status.total, status.failed);
// 最近のインポートジョブを一覧表示
const jobs = await client.agents.priming.listImportJobs("agent-id", 10);実践ガイド
カスタムステートとツールはすべてのユースケースにおける2つの主要な拡張ポイントですが、何を保存するか、何をツールとして公開するかは大きく異なります。
ステートはシーンとワールドレイヤーのデータです。 チャット間で持続し、世界を駆動するものを保存します:クエスト進捗・アンロック可能なコンテンツフラグ・シーン状態・キャラクターが持つワールド内アイテムのインベントリ。
ツールは表現的なアクションです。 キャラクターがアプリ内でできること——エモート・衣装変更・別のシーンへの移動・ギフトを渡す。LLMが自然に呼び出せるよう説明を生き生きとしたものにします。
await client.agents.sessions.setTools("agent-id", {
userId: "user-123",
tools: [
{
name: "change_scene",
description: "Move to a new location in the story. Use when the scene has run its course or a new chapter begins.",
parameters: { type: "object", properties: { location: { type: "string" } }, required: ["location"] },
},
],
});ハンドオフツールを含めないでください。 コンパニオンは人間に引き渡すべきではありません——関係性こそがプロダクトです。