8.6 KiB
llm-worker
LLMを用いた自律的なワーカーを構築するためのライブラリ。
ツールの定義・呼び出し、コンテキスト管理、ストリーミングイベント処理、フック制御などを責務にもつ。
ワークスペース insomnia に属し、以下の3クレートで構成される:
| クレート | 概要 |
|---|---|
insomnia |
アプリケーション本体 |
llm-worker |
LLMワーカーライブラリ (本クレート) |
llm-worker-macros |
#[tool_registry] / #[tool] 手続きマクロ |
用語定義
- Item:
会話の基本単位。Open Responses仕様に準じた列挙型で、
Message・FunctionCall・FunctionCallOutput・Reasoningの4バリアントを持つ。従来のメッセージベースAPIと異なり、ツール呼び出しや思考をファーストクラスのItemとして扱う。 - ContentPart:
Message Item内のコンテンツ要素。
InputText(ユーザー入力)・OutputText(アシスタント出力)・Refusal(拒否)を区別する。 - ブロック (Block):
モデルが「開始→デルタ→終了」で囲む一塊の出力。OpenAIの
response.output_itemやAnthropicのcontent_block、Geminiのcandidates[].content.partsなどが該当する。BlockTypeとしてText・Thinking・ToolUse・ToolResultが定義されている。 - メタイベント (Meta Event):
Ping・Usage・Status・Errorなど、ブロックに属さない補助イベント群。ステータス更新やハートビートとして処理される。 - Event:
LLMからのストリーミングレスポンスを表現する統一型。メタイベントとブロックイベント(
BlockStart・BlockDelta・BlockStop・BlockAbort)から成る。llm_client層とeventモジュールの双方に定義が存在する。 - Worker: LLMとのインタラクションを管理する中心コンポーネント。ツール実行ループ、フック呼び出し、ストリーミングイベントのディスパッチを統括する。
以降の仕様では「ブロック」を上記の生成・ツール単位の総称として扱う。
アーキテクチャ
モジュール構成概念図:
llm-worker
├── worker # Workerコア (実行ループ、状態管理)
├── state # Type-stateパターン (Mutable / CacheLocked)
├── tool # Tool trait, ToolMeta, ToolDefinition
├── tool_server # ToolServer (ツールのレジストリと実行)
├── hook # Hook trait, HookRegistry (10種のフックポイント)
├── handler # Kind/Handler trait (イベントディスパッチ)
├── subscriber # WorkerSubscriber trait (UI向けイベント購読)
├── event # Worker層の公開Event型
├── message # Item/ContentPart/Roleのre-export
├── timeline # イベントストリームの状態管理とHandlerディスパッチ
│ ├── event # Timeline内部イベント型
│ ├── timeline # Timelineコア
│ ├── text_block_collector # テキスト収集Handler
│ └── tool_call_collector # ツール呼び出し収集Handler
└── llm_client # LLMクライアント層
├── client # LlmClient trait
├── event # llm_client層のEvent型
├── error # ClientError
├── types # Item, ContentPart, Role, Request, RequestConfig, ToolDefinition
├── scheme # APIスキーマ変換
│ ├── openai # OpenAI Chat Completions API
│ ├── anthropic # Anthropic Messages API
│ └── gemini # Google Gemini API
└── providers # プロバイダ固有クライアント
├── openai # OpenAI
├── anthropic # Anthropic
├── gemini # Google Gemini
└── ollama # Ollama (ローカルLLM)
OpenAI互換のプロバイダでスキーマを使い回せるよう、schemeとprovidersモジュールは分離されている。
scheme層
単純な変換を責務とするスキーマを定義する。
- リクエスト変換:
Request(SystemPrompt + Items + Tools + RequestConfig) → プロバイダ固有のリクエストJSON - レスポンス変換: SSEイベント → 型付き
Event構造体のストリーム
各APIスキーマ(OpenAI / Anthropic / Gemini)ごとに実装を持ち、APIスキーマに準じたパース・バリデーションを行う。
llm_client (providers) 層
LlmClient traitを実装する各プロバイダクライアントがリクエストを送信し、差異が吸収され統一されたEventストリームを出力する。
ストリーミング中のバッファリング(ToolArguments の累積等)もこの層で行う。
ConfigWarningにより、プロバイダがサポートしない設定オプションを警告として通知する仕組みを持つ。
timeline層
llm_clientからのイベントストリームを受信し、登録されたHandlerにディスパッチする。
Kind traitがイベント型を定義し、Handler<K: Kind> traitがScope(ブロックのライフサイクルに対応する状態)を持つイベント処理を行う。組み込みHandlerとしてTextBlockCollectorとToolCallCollectorが提供される。
worker層
WorkerはType-stateパターンによりMutable状態とCacheLocked状態を持つ。
- Mutable: システムプロンプトの設定変更、メッセージ履歴の編集、ツール・フックの登録が可能
- CacheLocked:
Worker::lock()で遷移。LLM APIのKVキャッシュヒット率を最大化するため、既存履歴の変更を制限する
WorkerSubscriber traitにより、テキスト生成やツール呼び出しのストリーミングイベントをUI等に配信できる。
Tools
各種プロバイダのLLMのAPI仕様として存在するTool CallやFunction CallingをTool traitとして統一的に扱う。
ToolMeta: ツール名・説明・入力スキーマ(JSON Schema)を保持する不変のメタ情報。Worker登録後は変更されない。ToolDefinition:Fn() -> (ToolMeta, Arc<dyn Tool>)型のファクトリ。Worker登録時に一度呼び出され、メタ情報とインスタンスがセッションスコープでキャッシュされる。Tooltrait:async fn call(&self, arguments: Value) -> Result<String, ToolError>を持つ非同期trait。セッション中に状態を保持できる。ToolServer: 登録済みツールのレジストリと実行を管理するインメモリサーバー。
llm-worker-macrosクレートが提供する#[tool_registry] / #[tool]手続きマクロにより、implブロック上のメソッドからTool trait実装を自動生成する。
Hooks
Claude Codeに存在するようなHooksと同様のターン制御・介入機構を搭載する。
以下の10種のフックポイントが定義されている:
| フックポイント | タイミング | 戻り値による制御 |
|---|---|---|
OnPromptSubmit |
プロンプト送信時 | Continue / Cancel |
PreLlmRequest |
LLMリクエスト直前 | Continue / Cancel |
PreToolCall |
ツール実行直前 | Continue / Skip / Abort / Pause |
PostToolCall |
ツール実行直後 | Continue / Abort |
OnTurnEnd |
ターン終了時 | Finish / ContinueWithMessages / Paused |
OnAbort |
中断時 | (通知のみ) |
OnTextDelta |
テキストデルタ受信時 | (ストリーミング) |
OnToolCallDelta |
ツール引数デルタ受信時 | (ストリーミング) |
OnStreamChunk |
ストリームチャンク受信時 | (ストリーミング) |
OnStreamComplete |
ストリーム完了時 | (ストリーミング) |
フックはHook traitとして表現され、HookRegistryで管理される。
ストリーミングイベント処理
イベントストリームを扱う設計目標として、Text / InputJSON / Thinkingのデルタと、細粒度ツールストリーミングを含む、デルタの低遅延・リアルタイム処理がある。
ブロックのライフサイクル: BlockStart → BlockDelta(複数回) → BlockStop / BlockAbort
DeltaContentの種別:
Text(String)- テキスト生成のデルタThinking(String)- 思考(Extended Thinking等)のデルタInputJson(String)- ツール引数JSONの部分文字列デルタ