Bump llm-worker to 0.2.1
This commit is contained in:
parent
1fd7a4c698
commit
6d87da90d1
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -708,7 +708,7 @@ checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
|||
|
||||
[[package]]
|
||||
name = "llm-worker"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"clap",
|
||||
|
|
|
|||
|
|
@ -31,41 +31,48 @@ graph TD
|
|||
|
||||
Workerは以下のループ(ターン)を実行します。
|
||||
|
||||
1. **Start Turn**: `Worker::run(messages)` 呼び出し
|
||||
2. **Hook: OnMessageSend**:
|
||||
* ユーザーメッセージの改変、バリデーション、キャンセルが可能。
|
||||
* コンテキストへのシステムプロンプト注入などもここで行う想定。
|
||||
3. **Request & Stream**:
|
||||
* LLMへリクエスト送信。イベントストリーム開始。
|
||||
* `Timeline`によるイベント処理。
|
||||
4. **Tool Handling (Parallel)**:
|
||||
* レスポンス内に含まれる全てのTool Callを収集。
|
||||
* 各Toolに対して **Hook: BeforeToolCall** を実行(実行可否、引数改変)。
|
||||
* 許可されたToolを**並列実行 (`join_all`)**。
|
||||
* 各Tool実行後に **Hook: AfterToolCall** を実行(結果の確認、加工)。
|
||||
5. **Next Request Decision**:
|
||||
* Tool実行結果がある場合 -> 結果をMessageとしてContextに追加し、**Step 3へ戻る** (自動ループ)。
|
||||
* Tool実行がない場合 -> Step 6へ。
|
||||
6. **Hook: OnTurnEnd**:
|
||||
* 最終的な応答に対するチェック(Lint/Fmt)。
|
||||
* エラーがある場合、エラーメッセージをContextに追加して **Step 3へ戻る** ことで自己修正を促せる。
|
||||
* 問題なければターン終了。
|
||||
1. **Start Turn**: `Worker::run(messages)` 呼び出し
|
||||
2. **Hook: OnMessageSend**:
|
||||
- ユーザーメッセージの改変、バリデーション、キャンセルが可能。
|
||||
- コンテキストへのシステムプロンプト注入などもここで行う想定。
|
||||
3. **Request & Stream**:
|
||||
- LLMへリクエスト送信。イベントストリーム開始。
|
||||
- `Timeline`によるイベント処理。
|
||||
4. **Tool Handling (Parallel)**:
|
||||
- レスポンス内に含まれる全てのTool Callを収集。
|
||||
- 各Toolに対して **Hook: BeforeToolCall** を実行(実行可否、引数改変)。
|
||||
- 許可されたToolを**並列実行 (`join_all`)**。
|
||||
- 各Tool実行後に **Hook: AfterToolCall** を実行(結果の確認、加工)。
|
||||
5. **Next Request Decision**:
|
||||
- Tool実行結果がある場合 -> 結果をMessageとしてContextに追加し、**Step
|
||||
3へ戻る** (自動ループ)。
|
||||
- Tool実行がない場合 -> Step 6へ。
|
||||
6. **Hook: OnTurnEnd**:
|
||||
- 最終的な応答に対するチェック(Lint/Fmt)。
|
||||
- エラーがある場合、エラーメッセージをContextに追加して **Step 3へ戻る**
|
||||
ことで自己修正を促せる。
|
||||
- 問題なければターン終了。
|
||||
|
||||
## Tool 設計
|
||||
|
||||
### アーキテクチャ概要
|
||||
|
||||
Rustの静的型付けシステムとLLMの動的なツール呼び出し(文字列による指定)を、**Trait Object** と **動的ディスパッチ** を用いて接続します。
|
||||
Rustの静的型付けシステムとLLMの動的なツール呼び出し(文字列による指定)を、**Trait
|
||||
Object** と **動的ディスパッチ** を用いて接続します。
|
||||
|
||||
1. **共通インターフェース (`Tool` Trait)**: 全てのツールが実装すべき共通の振る舞い(メタデータ取得と実行)を定義します。
|
||||
2. **ラッパー生成 (`#[tool]` Macro)**: ユーザー定義のメソッドをラップし、`Tool` Traitを実装した構造体を自動生成します。
|
||||
3. **レジストリ (`HashMap`)**: Workerは動的ディスパッチ用に `HashMap<String, Box<dyn Tool>>` でツールを管理します。
|
||||
1. **共通インターフェース (`Tool` Trait)**:
|
||||
全てのツールが実装すべき共通の振る舞い(メタデータ取得と実行)を定義します。
|
||||
2. **ラッパー生成 (`#[tool]` Macro)**: ユーザー定義のメソッドをラップし、`Tool`
|
||||
Traitを実装した構造体を自動生成します。
|
||||
3. **レジストリ (`HashMap`)**: Workerは動的ディスパッチ用に
|
||||
`HashMap<String, Box<dyn Tool>>` でツールを管理します。
|
||||
|
||||
この仕組みにより、「名前からツールを探し、JSON引数を型変換して関数を実行する」フローを安全に実現します。
|
||||
|
||||
### 1. Tool Trait 定義
|
||||
|
||||
ツールが最低限持つべきインターフェースです。`Send + Sync` を必須とし、マルチスレッド(並列実行)に対応します。
|
||||
ツールが最低限持つべきインターフェースです。`Send + Sync`
|
||||
を必須とし、マルチスレッド(並列実行)に対応します。
|
||||
|
||||
```rust
|
||||
#[async_trait]
|
||||
|
|
@ -113,7 +120,8 @@ impl MyApp {
|
|||
|
||||
**マクロ展開後のイメージ (擬似コード):**
|
||||
|
||||
マクロは、元のメソッドに対応する**ラッパー構造体**を生成します。このラッパーが `Tool` Trait を実装します。
|
||||
マクロは、元のメソッドに対応する**ラッパー構造体**を生成します。このラッパーが
|
||||
`Tool` Trait を実装します。
|
||||
|
||||
```rust
|
||||
// 1. 引数をデシリアライズ用の中間構造体に変換
|
||||
|
|
@ -155,15 +163,18 @@ impl Tool for GetUserTool {
|
|||
|
||||
### 3. Workerによる実行フロー
|
||||
|
||||
Workerは生成されたラッパー構造体を `Box<dyn Tool>` として保持し、以下のフローで実行します。
|
||||
Workerは生成されたラッパー構造体を `Box<dyn Tool>`
|
||||
として保持し、以下のフローで実行します。
|
||||
|
||||
1. **登録**: アプリケーション開始時、コンテキスト(`MyApp`)から各ツールのラッパー(`GetUserTool`)を生成し、WorkerのMapに登録。
|
||||
2. **解決**: LLMからのレスポンスに含まれる `ToolUse { name: "get_user", ... }` を受け取る。
|
||||
3. **検索**: `name` をキーに Map から `Box<dyn Tool>` を取得。
|
||||
4. **実行**:
|
||||
* `tool.execute(json)` を呼び出す。
|
||||
* 内部で `serde_json` による型変換とメソッド実行が行われる。
|
||||
* 結果が返る。
|
||||
1. **登録**:
|
||||
アプリケーション開始時、コンテキスト(`MyApp`)から各ツールのラッパー(`GetUserTool`)を生成し、WorkerのMapに登録。
|
||||
2. **解決**: LLMからのレスポンスに含まれる `ToolUse { name: "get_user", ... }`
|
||||
を受け取る。
|
||||
3. **検索**: `name` をキーに Map から `Box<dyn Tool>` を取得。
|
||||
4. **実行**:
|
||||
- `tool.execute(json)` を呼び出す。
|
||||
- 内部で `serde_json` による型変換とメソッド実行が行われる。
|
||||
- 結果が返る。
|
||||
|
||||
これにより、型安全性を保ちつつ、動的なツール実行が可能になります。
|
||||
|
||||
|
|
@ -171,8 +182,9 @@ Workerは生成されたラッパー構造体を `Box<dyn Tool>` として保持
|
|||
|
||||
### コンセプト
|
||||
|
||||
* **制御の介入**: ターンの進行、メッセージの内容、ツールの実行に対して介入します。
|
||||
* **Contextへのアクセス**: メッセージ履歴(Context)を読み書きできます。
|
||||
- **制御の介入**:
|
||||
ターンの進行、メッセージの内容、ツールの実行に対して介入します。
|
||||
- **Contextへのアクセス**: メッセージ履歴(Context)を読み書きできます。
|
||||
|
||||
### Hook Trait
|
||||
|
||||
|
|
@ -219,7 +231,8 @@ pub enum OnTurnEndResult {
|
|||
|
||||
### Tool Call Context
|
||||
|
||||
`before_tool_call` / `after_tool_call` は、ツール実行の文脈を含む入力を受け取る。
|
||||
`before_tool_call` / `after_tool_call`
|
||||
は、ツール実行の文脈を含む入力を受け取る。
|
||||
|
||||
```rust
|
||||
pub struct ToolCallContext {
|
||||
|
|
@ -237,17 +250,20 @@ pub struct ToolResultContext {
|
|||
|
||||
## 実装方針
|
||||
|
||||
1. **Worker Struct**:
|
||||
* `Timeline`を所有。
|
||||
* `Handler`として「ToolCallCollector」をTimelineに登録。
|
||||
* `stream`終了後に収集したToolCallを処理するロジックを持つ。
|
||||
1. **Worker Struct**:
|
||||
- `Timeline`を所有。
|
||||
- `Handler`として「ToolCallCollector」をTimelineに登録。
|
||||
- `stream`終了後に収集したToolCallを処理するロジックを持つ。
|
||||
- **履歴管理**: `set_history`, `with_messages`, `history_mut`
|
||||
等を通じて、会話履歴の注入や編集を可能にする。
|
||||
|
||||
2. **Tool Executor Handler**:
|
||||
* Timeline上ではツール実行を行わず、あくまで「ToolCallブロックの収集」に徹する(Toolの実行は非同期かつ並列で、ストリーム終了後あるいはブロック確定後に行うため)。
|
||||
* ただし、リアルタイム性を重視する場合(ストリーミング中にToolを実行開始等)は将来的な拡張とするが、現状は「結果が揃うのを待って」という要件に従い、収集フェーズと実行フェーズを分ける。
|
||||
2. **Tool Executor Handler**:
|
||||
- Timeline上ではツール実行を行わず、あくまで「ToolCallブロックの収集」に徹する(Toolの実行は非同期かつ並列で、ストリーム終了後あるいはブロック確定後に行うため)。
|
||||
- ただし、リアルタイム性を重視する場合(ストリーミング中にToolを実行開始等)は将来的な拡張とするが、現状は「結果が揃うのを待って」という要件に従い、収集フェーズと実行フェーズを分ける。
|
||||
|
||||
3. **worker-macros**:
|
||||
* `syn`, `quote` を用いて、関数定義から `Tool` トレイト実装と `InputSchema` (schemars利用) を生成。
|
||||
3. **worker-macros**:
|
||||
- `syn`, `quote` を用いて、関数定義から `Tool` トレイト実装と `InputSchema`
|
||||
(schemars利用) を生成。
|
||||
|
||||
## Worker Event API 設計
|
||||
|
||||
|
|
@ -256,6 +272,7 @@ pub struct ToolResultContext {
|
|||
Workerは内部でイベントを処理し結果を返しますが、UIへのストリーミング表示やリアルタイムフィードバックには、イベントを外部に公開する仕組みが必要です。
|
||||
|
||||
**要件**:
|
||||
|
||||
1. テキストデルタをリアルタイムでUIに表示
|
||||
2. ツール呼び出しの進行状況を表示
|
||||
3. ブロック完了時に累積結果を受け取る
|
||||
|
|
@ -264,10 +281,10 @@ Workerは内部でイベントを処理し結果を返しますが、UIへのス
|
|||
|
||||
Worker APIは **Timeline層のHandler機構の薄いラッパー** として設計します。
|
||||
|
||||
| 層 | 目的 | 提供するもの |
|
||||
|---|------|-------------|
|
||||
| **Handler (Timeline層)** | 内部実装、役割分離 | スコープ管理 + Deltaイベント |
|
||||
| **Worker Event API** | ユーザー向け利便性 | Handler露出 + Completeイベント追加 |
|
||||
| 層 | 目的 | 提供するもの |
|
||||
| ------------------------ | ------------------ | ---------------------------------- |
|
||||
| **Handler (Timeline層)** | 内部実装、役割分離 | スコープ管理 + Deltaイベント |
|
||||
| **Worker Event API** | ユーザー向け利便性 | Handler露出 + Completeイベント追加 |
|
||||
|
||||
Handlerのスコープ管理パターン(Start→Delta→End)をそのまま活かしつつ、累積済みのCompleteイベントも追加提供します。
|
||||
|
||||
|
|
@ -448,7 +465,8 @@ impl<C: LlmClient> Worker<C> {
|
|||
### 設計上のポイント
|
||||
|
||||
1. **Handlerの再利用**: 既存のHandler traitをそのまま活用
|
||||
2. **スコープ管理の維持**: ブロックイベントはStart→Delta→Endのライフサイクルを保持
|
||||
2. **スコープ管理の維持**:
|
||||
ブロックイベントはStart→Delta→Endのライフサイクルを保持
|
||||
3. **選択的購読**: on_*で必要なイベントだけ、またはSubscriberで一括
|
||||
4. **累積イベントの追加**: Worker層でComplete系イベントを追加提供
|
||||
5. **後方互換性**: 従来の`run()`も引き続き使用可能
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "llm-worker"
|
||||
description = "A library for building autonomous LLM-powered systems"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
publish.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user