Convex Agents Streaming について
Convex Agents Streaming は、Convex エージェントアプリに非同期の段階的なテキスト出力を加えるスキルです。ストリーム差分の保存・取得と React での表示を扱います。
主な機能
- 01非同期テキストストリーミング
- 02分割とスロットリングの設定
- 03ストリーム差分の永続化
- 04ストリーム状態の処理
- 05useSmoothText による React 表示
活用シーン
- 01チャットのリアルタイム更新
- 02長い応答の段階的な表示
- 031 回の生成結果を複数クライアントへ配信
- 04バックグラウンド Action でのストリーミング
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ sstobo/ convex-skills --skill convex-agents-streamingインストール後、Claude Code で/convex-agents-streamingを入力して読み込まれたか確認します。
詳細
目的
ストリーミングを使うと、応答をリアルタイムで1文字ずつ表示でき、UXと体感速度が向上します。非同期ストリーミングと複数のクライアントに対応しています。
このスキルを使う場面
- リアルタイムで更新されるチャットインターフェースを構築する
- 段階的に表示すると効果的な長い応答を生成する
- 1回の生成から複数のクライアントにストリーミングする
- バックグラウンドアクションで非同期ストリーミングを使う
- 滑らかなテキストアニメーションを実装する
基本的な非同期ストリーミング
差分をストリーミングしてデータベースに保存します。
export const streamResponse = action({
args: { threadId: v.string(), prompt: v.string() },
handler: async (ctx, { threadId, prompt }) => {
const { thread } = await myAgent.continueThread(ctx, { threadId });
await thread.streamText(
{ prompt },
{ saveStreamDeltas: true }
);
return { success: true };
},
});
ストリームのチャンク化を設定する
await thread.streamText(
{ prompt },
{
saveStreamDeltas: {
chunking: "line", // "word" | "line" | regex | function
throttleMs: 500, // Save deltas every 500ms
},
}
);
ストリームの差分を取得する
import { vStreamArgs, syncStreams } from "@convex-dev/agent";
export const listMessagesWithStreams = query({
args: {
threadId: v.string(),
paginationOpts: paginationOptsValidator,
streamArgs: vStreamArgs,
},
handler: async (ctx, { threadId, paginationOpts, streamArgs }) => {
const messages = await listUIMessages(ctx, components.agent, {
threadId,
paginationOpts,
});
const streams = await syncStreams(ctx, components.agent, {
threadId,
streamArgs,
});
return { ...messages, streams };
},
});
React でストリーミングを表示する
import { useUIMessages, useSmoothText } from "@convex-dev/agent/react";
function ChatStreaming({ threadId }: { threadId: string }) {
const { results } = useUIMessages(
api.streaming.listMessages,
{ threadId },
{ initialNumItems: 20, stream: true }
);
return (
<div>
{results?.map((message) => (
<StreamingMessage key={message.key} message={message} />
))}
</div>
);
}
function StreamingMessage({ message }: { message: UIMessage }) {
const [visibleText] = useSmoothText(message.text, {
startStreaming: message.status === "streaming",
});
return <div>{visibleText}</div>;
}
重要な原則
- 非同期ストリーミング:バックグラウンドでの生成に最適です
- 差分のスロットリング:応答性と書き込み量のバランスを取ります
- ストリームのステータス:
message.status === "streaming"を確認します - 滑らかなアニメーション:テキストの更新に
useSmoothTextを使います - 永続化:差分はページを再読み込みしても保持されます
次のステップ
- メッセージ管理については、messages を参照してください
- エージェントのセットアップについては、fundamentals を参照してください
- ストリーミングに対応したコンテキストについては、context を参照してください
コメント
Markdown 対応