reSpeaker Clip AI チャットシステムアーキテクチャ
reSpeaker Clip AI エージェントチャットシステムの動作を説明する平易なガイドです。ここに書かれている内容はすべて README と backend/ 内の実際のコードに基づいています。

1. 概要
このシステムは Flask + LangGraph + Groq 上に構築された音声ファーストの AI アシスタントです。あなたが音声またはテキストでメッセージを送ると、エージェントが処理方法を判断し、必要に応じてツールを呼び出し、回答を生成し、その返信を音声で話します。
パイプラインの概要は次のとおりです:

この仕組みを成り立たせているのは次の 3 つの考え方です:
- ルーターがすべてのリクエストを 3 つのパスのいずれかに分類します。
- それぞれのパス上のエージェントはツール(ウェブ検索、電卓、Notion、過去会話検索)を呼び出すことができます。
- ベクターストア + メモリレイヤーにより、エージェントはあなたの過去の会話や長期的な事実を想起できます。
2. システムアーキテクチャ図

各コンポーネントは次のように組み合わさります:
- Flask は API の表面(チャット、ストリーミング、音声、TTS)です。
- LangGraph はリクエストをルーティングし、選択されたノードを実行するステートマシンです。
- Groq は LLM、音声認識(Whisper)、音声合成(Orpheus)を提供します。
- Mem0 が長期メモリを提供し、Pinecone + ローカル埋め込みが過去会話検索を提供します。
- Supabase(SQLite フォールバック付き)が会話、メッセージ、要約を保存します。
3. 3 つのルーティングパス
すべてのリクエストは必ず 3 つのノードのうち 1 つにルーティングされます。コードは backend/graph/graph.py 内でルート文字列をノードにマッピングします:
simple — コンテキストなしチャット
- 素の LLM 応答です。ツールも特別な人格もありません。
- 一般的な質問、説明、通常の会話に使用されます。
- ノード:
simple_node(backend/graph/nodes/simple.py)、LLM = メインの Groq モデル。
context — エージェント(ツール対応)
- リクエストに外部情報やツール(ウェブ、数学、Notion、過去会話)が必要になる場合があります。
- このノードは
create_agentで LangChain エージェントを構築し、モデルがループ内でツールを呼び出せるようにします。 - ノード:
agentic_node(backend/graph/nodes/agentic.py)、LLM = ツール呼び出し専用モデル(gpt-oss-20b)。
persona — スタイル付き
- ユーザーが明示的にスタイル、人格、役割、教え方などを求めた場合です。
- 仕組みは
simpleと同じですが、システムプロンプトが異なり、モデルに口調を適応させるよう指示します。 - ノード:
persona_node(backend/graph/nodes/persona.py)、LLM = メインの Groq モデル。
4. 分類ロジック
ルーティングは router_node(backend/graph/router.py)で行われ、キーワードの事前チェックの後に LLM 分類が続きます。
-
キーワード事前チェック(高速パス)。書き起こしテキストをツール用キーワードでスキャンします。どれかが一致した場合、ルートは強制的に
contextとなり、LLM は完全にスキップされます:notion, to-do, todo, task list, to do list, calendar,
schedule, reminder, note down, create a task, add a task例:「add a task to my to-do list」は分類器に送られることすらありません。
-
LLM 分類。それ以外の場合、リクエストは
ROUTER_PROMPTとともにメインの Groq モデルに送られます。これはちょうど 1 語だけを返す分類プロンプトです:ルート トリガーとなる入力 simple一般的な質問、説明、通常の会話。ツールや persona は不要 context外部情報/ツールが必要になる可能性があるもの、データ管理(Notion/カレンダー)、ユーザーのデバイス/ファイル/保存情報に関する質問 personaユーザーが明示的にスタイル、人格、教え方、役割や振る舞いを要求する場合 -
フォールバック。出力は小文字化され、前後の空白が削除されます。
{simple, context, persona}に含まれないものはすべてsimpleにフォールバックします。
5. エージェント型ツールシステム
ツール呼び出しの仕組み
context パスは LangChain の create_agent(backend/graph/nodes/agentic.py)を使用します。ループは次のようになります:

注目すべき詳細:
- エージェントはキャッシュされ、ツールシグネチャが変わった場合にのみ再構築されます(
_get_agent)。 - リトライロジック:最大
MAX_RETRIES = 3回試行し、一時的なtool_use_failedエラーは 1 秒スリープを挟んで再試行します。 - ガードレール:再帰は
MAX_AGENT_ITERATIONS = 10に制限されています。上限に達した場合、エージェントはクラッシュする代わりに固定の「上限に達しました…」メッセージを返します。 - システムプロンプトは、モデルに対してツール呼び出し回数を最小限にし、十分な情報が得られたらすぐに回答するよう指示します。
- SSE ストリーミング中は、各ツール呼び出しが
thinkingイベント({"tool": "web_search"})として UI に表示されます。
利用可能なツール
get_available_tools()(backend/tools/registry.py)は、エージェントが呼び出せるすべてのツールを返します:
| ツール | バックエンドサービス | 目的 | 設定キー |
|---|---|---|---|
calculator | ローカル、安全な AST 評価 | ホワイトリスト化された + - * / ** % 評価器による数学計算 | —(常に利用可能) |
search_conversations | Pinecone + ローカル埋め込み | ユーザー自身の過去会話を関連度で検索 | PINECONE_API_KEY |
composio_search | Composio | 自然言語リクエストに一致する Composio アプリツールを検索 | COMPOSIO_API_KEY |
composio_execute | Composio | 一致したツールをスラッグと JSON 引数で実行 | 同上 |
composio_connect | Composio | Connect Link を通じてツールキット(例:github)を認可 | 同上 |
web_search | Tavily | ライブ/最新のウェブ情報(ニュース、ファームウェア、製品詳細) | TAVILY_API_KEY |
add_todo | Notion | To-do リストにタスクを追加 | NOTION_API_KEY / NOTION_DATABASE_ID |
list_todos | Notion | ステータス付きでタスクを一覧表示 | 同上 |
complete_todo | Notion | タスクを完了済みにする(名前/キーワードで一致) | 同上 |
delete_todo | Notion | タスクを削除(名前/キーワードで一致) | 同上 |
- Notion ツールは、Notion が設定されている場合にのみ追加されます。
- 未設定のツールは(「Web search is unavailable…」のような)フレンドリーなメッセージを返すため、システムは優雅に機能低下します。
設定済みツール

6. ベクター検索の詳細
設定

すべてのベクター設定は config.py / .env にあります:
| 設定 | デフォルト | 意味 |
|---|---|---|
PINECONE_API_KEY | — | ベクター検索を有効化 |
PINECONE_INDEX_NAME | conversations | Pinecone インデックス名 |
PINECONE_CLOUD | aws | サーバーレスのクラウドプロバイダ |
PINECONE_REGION | us-east-1 | サーバーレスリージョン |
EMBEDDING_MODEL | all-MiniLM-L6-v2 | ローカル sentence-transformers モデル |
EMBEDDING_DIM | 384 | ベクター次元(インデックスと一致している必要あり) |
起動時に、init_index() が Pinecone インデックスを自動作成します(存在しない場合、次元 384、メトリック cosine、サーバーレス)。
埋め込み対象とメタデータとして保存されるもの
設計としてはベクターを小さく保ち、それ以外をメタデータに入れます:
- 埋め込み(ベクター):
"<title>\n\n<overview>"— 会話の短い意味的要約。 - メタデータ:
user_id、conversation_id、title、created_at。 - ベクターストアには一切入れないもの:完全な書き起こし。実際の会話ターンは Supabase/SQLite に保存され、一致後に id で取得されます。
ベクター id は "{user_id}-{conversation_id}" であり、ユーザーごとの会話ごとに安定しています。
ベクター作成(書き込みパス)
すべてのチャット/音声ターンの後に、システムはバックグラウンドスレッド(index_conversation_async → summarize_and_index in backend/services/conversation_service.py)を起動します:
詳細:
MIN_TURNS = 2未満のターン数しかない会話はスキップされます。- タイトル/概要は、メインの Groq LLM が 2 行のプロンプト(
Title:/Overview:)を使って生成します。 - 埋め込みは正規化されます(cosine に適した形)。
- これらはすべて非同期(デーモンスレッド)で行われるため、ユーザーへの応答がインデックス作成でブロックされることはありません。
ベクタークエリ(読み取りパス)
エージェントが search_conversations を呼び出すとき、フローは次のようになります:
重要なポイント:
- クエリは同じローカルモデルで埋め込まれ、その後
user_idフィルタ付きで検索されるため、ユーザーは自分自身の会話しか見ることができません。 - 一致結果として id + スコア + メタデータが返され、完全な要約はリレーショナルストアから id で取得されます。
- 一致結果は類似度スコア付きで整形されるため、エージェントは関連度を判断できます。
7. メモリシステム
長期メモリには Mem0 を使用し、単一ユーザー(MEM0_USER_ID、デフォルトは user-1)にスコープされています。
メモリカテゴリ
コード内にハードコードされたバケットはなく、その代わりに MEM0_CUSTOM_INSTRUCTIONS が、どの永続的事実を優先順で抽出するかを Mem0 に指示します:
- 健康上の制約とアレルギー — 特に医師から助言された内容(ユーザーに適用されるものとして解釈)。
- スケジュール — 会議、予定、リマインダー。
- 嗜好や個人的な詳細。
明示的に除外されるもの:アシスタント自身の応答/レシピ/説明、および一時的な単発リクエスト。
チャットにおけるメモリ検索
プロアクティブなリコールは、ルーティングの前にすべてのリクエストで行われます(backend/routes/chat.py の recall(text)):
-
受信メッセージが Mem0 のセマンティック検索(
top_k = 5)に送られます。 -
結果はスコア内訳に対する 2 段階の関連度チェックでフィルタされます:
semantic ≥ 0.28→ 採用、またはsemantic ≥ 0.24かつbm25 > 0.01(キーワードでブーストされたヒット)→ 採用。
-
残ったメモリは
created_at(新しいものが先)でソートされ、次の形式で整形されます:Relevant context from your past conversations:
- <memory text> (created 2026-08-30) -
そのブロックは、任意のノードに到達する前にユーザーメッセージの前に付加されます — そのため LLM はそれをコンテキストとして認識しますが、トピックに直接関連する場合にのみ使用するよう指示されます。
書き込みはすべてのやり取りの後(save_exchange)に行われます:ユーザー/アシスタントのペアがカスタムインストラクションとともに Mem0 に送信されます。Mem0 キーが存在しない場合、メモリの保存と呼び出しはどちらも正常に失敗(ログに記録され、無視)します。
8. チャットセッションとコンテキスト
セッション構造
「セッション」とは、リレーショナルに保存された会話(Supabase PostgreSQL、または SQLite フォールバック)を指します。スキーマは次のとおりです:
users—id,email(単一ユーザー、user-1をシード)。conversations—id,user_id,title,overview,action_items, timestamps.messages/turns—conversation_id,role(user/assistant),content, timestamp.
1 ターンのフロー:
- 会話を作成(または再利用)し、
conversation_idを取得します。 - コンテキストを読み込みます:
recall()によるメモリ +get_recent_messages(conversation_id, 10)による履歴。 AgentStateを構築し、LangGraph に通します。- 応答後:両方のターンを保存し、やり取りを Mem0 に保存し、非同期のベクトルインデックス作成を開始します。
コンテキストウィンドウ
LLM 用に組み立てられるコンテキストは、意図的に小さくレイヤー化されています:
| コンポーネント | ソース | サイズ |
|---|---|---|
| システムプロンプト | パスごとの定数(simple/persona/agent SYSTEM_PROMPT) | 固定 |
| 会話履歴 | get_recent_messages(conversation_id, 10) | 直近 10 ターン(ユーザー 10 件 + アシスタント 10 件)、時系列順 |
| 呼び出されたメモリ | Mem0 recall()、上位 5 件、フィルタ済み | 最大 5 件のメモリ |
| 現在のユーザーメッセージ | format_memories(...) + transcript | リクエスト |

注意:
- 履歴はベクトルストアではなくリレーショナルストアから取得されます(ベクトルストアにはターンではなく要約が保存されます)。
- メモリはユーザーメッセージにインラインで挿入されるため、モデルはそれらを「過去の会話からの関連コンテキスト」として扱います。
- エージェントパスはメッセージを
[history..., ("user", memories + transcript)]として構築し、ツールを用いたエージェントループを行います。
9. システムプロンプト構造
システムプロンプトは 4 種類あります:
| プロンプト | 場所 | 使用者 | 役割 |
|---|---|---|---|
ROUTER_PROMPT | backend/graph/router.py | ルーター分類 | 1 語で返答:simple / context / persona |
SIMPLE_PROMPT (simple.py) | backend/graph/nodes/simple.py | simple_node | シンプルなチャット用の親切な音声アシスタント |
PERSONA_PROMPT (persona.py) | backend/graph/nodes/persona.py | persona_node | simple と同様だが、ユーザーのリクエストに合わせてスタイル/教え方を調整 |
SYSTEM_PROMPT (agentic) | backend/graph/nodes/agentic.py | agent | ツール対応アシスタント;各ツールとその使用タイミングを説明 |
simple、persona、agentic の各プロンプトは、共通のハウススタイルの末尾を共有します:
- 最大 2〜3 文の短い文章で回答します。
- プレーンテキストのみ — markdown、アスタリスク、絵文字は禁止。
- 呼び出されたメモリは、トピックに直接関連する場合にのみ使用します(スケジュールと食事の分離は明示的に強制されます)。
- 矛盾がある場合は、最も最近作成されたメモリを信頼します。
- ユーザーが新しい事実を述べた場合、その事実のみに言及し、無関係なメモリを反復しないでください。
agentic プロンプトはさらに次のことを行います:
- ツールに名前を付けます(
web_search,calculator,search_conversations, Notion ツール)。 - ツール呼び出しを最小限にするよう指示し、十分な情報が集まったら停止します。
- 短くプレーンテキストの回答形式を維持します。
10. 使用している LLM モデル
すべてのモデルは Groq 上で動作します。backend/llm/client.py、config.py、groq_client.py で定義されています:
| 役割 | 環境変数 | デフォルトモデル | Temperature | 備考 |
|---|---|---|---|---|
| メイン LLM(router、simple、persona、要約) | GROQ_LLM_MODEL | qwen/qwen3.6-27b | 0.7 | ChatGroq インスタンス llm |
| エージェント / ツール呼び出し用 LLM | GROQ_AGENT_MODEL | openai/gpt-oss-20b | 0.0 | ChatGroq インスタンス agent_llm、create_agent で使用 |
| 音声認識(Speech-to-text) | GROQ_STT_MODEL | whisper-large-v3 | 0.0 | Whisper 文字起こし |
| 音声合成(Text-to-speech) | GROQ_TTS_MODEL | canopylabs/orpheus-v1-english | — | Voice = TTS_VOICE(autumn) |
| 埋め込み(ローカル、Groq ではない) | EMBEDDING_MODEL | all-MiniLM-L6-v2 | — | sentence-transformers、384 次元、正規化済み |
LLM 推論のデフォルト値(groq_client.chat 経由):max_completion_tokens = 2048、top_p = 1.0、temperature は上書き可能です。
11. エージェント呼び出しデモ
メールを読む

カレンダーを追加

技術サポート & 製品ディスカッション
当社の製品をお選びいただきありがとうございます。私たちは、製品をできるだけスムーズにご利用いただけるよう、さまざまなサポートを提供しています。お好みやニーズに応じて選べる、複数のコミュニケーションチャネルをご用意しています。