llm-worker-rs/worker/README.md

6.3 KiB
Raw Blame History

worker クレート

worker クレートは、大規模言語モデル (LLM) を利用したアプリケーションのバックエンド機能を提供するコアコンポーネントです。LLMプロバイダーの抽象化、ツール利用、柔軟なプロンプト管理、フックシステムなど、高度な機能をカプセル化し、アプリケーション開発を簡素化します。

主な機能

  • マルチプロバイダー対応: Gemini, Claude, OpenAI, Ollama, XAIなど、複数のLLMプロバイダーを統一されたインターフェースで利用できます。
  • ツール利用 (Function Calling): LLMが外部ツールを呼び出す機能をサポートします。独自のツールを簡単に定義して Worker に登録できます。
  • ストリーミング処理: LLMの応答やツール実行結果を StreamEvent として非同期に受け取ることができます。これにより、リアルタイムなUI更新が可能になります。
  • フックシステム: Worker の処理フローの特定のタイミング(例: メッセージ送信前、ツール使用後)にカスタムロジックを介入させることができます。
  • セッション管理: 会話履歴やワークスペースの状態を管理し、永続化する機能を提供します。
  • 柔軟なプロンプト管理: 設定ファイルを用いて、ロールやコンテキストに応じたシステムプロンプトを動的に構築します。

主な概念

Worker

このクレートの中心的な構造体です。LLMとの対話、ツールの登録と実行、セッション管理など、すべての主要な機能を担当します。

LlmProvider

サポートしているLLMプロバイダーGemini, Claude, OpenAI などを表すenumです。

Tool トレイト

Worker が利用できるツールを定義するためのインターフェースです。このトレイトを実装することで、任意の機能をツールとして Worker に追加できます。

pub trait Tool: Send + Sync {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn parameters_schema(&self) -> serde_json::Value;
    async fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, crate::WorkerError>;
}

WorkerHook トレイト

Worker のライフサイクルイベントに介入するためのフックを定義するインターフェースです。特定のイベント(例: OnMessageSend, PostToolUse)に対して処理を追加できます。

StreamEvent

Worker の処理結果を非同期ストリームで受け取るためのenumです。LLMの応答チャンク、ツール呼び出し、エラーなど、さまざまなイベントを表します。

アプリケーションへの組み込み方法

1. Workerの初期化

まず、Worker のインスタンスを作成します。これには LlmProvider、モデル名、APIキーが必要です。

use worker::{Worker, LlmProvider};
use std::collections::HashMap;

// APIキーを準備
let mut api_keys = HashMap::new();
api_keys.insert("openai".to_string(), "your_openai_api_key".to_string());
api_keys.insert("claude".to_string(), "your_claude_api_key".to_string());

// Workerを作成
let mut worker = Worker::new(
    LlmProvider::OpenAI,
    "gpt-4o",
    &api_keys,
    None // RoleConfigはオプション
).expect("Workerの作成に失敗しました");

2. ツールの定義と登録

Tool トレイトを実装してカスタムツールを作成し、Worker に登録します。

use worker::{Tool, ToolResult};
use worker::schemars::{self, JsonSchema};
use worker::serde_json::{self, json, Value};
use async_trait::async_trait;

// ツールの引数を定義
#[derive(Debug, serde::Deserialize, JsonSchema)]
struct FileSystemToolArgs {
    path: String,
}

// カスタムツールを定義
struct ListFilesTool;

#[async_trait]
impl Tool for ListFilesTool {
    fn name(&self) -> &str { "list_files" }
    fn description(&self) -> &str { "指定されたパスのファイル一覧を表示します" }

    fn parameters_schema(&self) -> Value {
        serde_json::to_value(schemars::schema_for!(FileSystemToolArgs)).unwrap()
    }

    async fn execute(&self, args: Value) -> ToolResult<Value> {
        let tool_args: FileSystemToolArgs = serde_json::from_value(args)?;
        // ここで実際のファイル一覧取得処理を実装
        let files = vec!["file1.txt", "file2.txt"];
        Ok(json!({ "files": files }))
    }
}

// 作成したツールをWorkerに登録
worker.register_tool(Box::new(ListFilesTool)).unwrap();

3. 対話処理の実行

process_task_with_history メソッドを呼び出して、ユーザーメッセージを処理します。このメソッドはイベントのストリームを返します。

use futures_util::StreamExt;

let user_message = "カレントディレクトリのファイルを教えて".to_string();

let mut stream = worker.process_task_with_history(user_message, None).await;

while let Some(event_result) = stream.next().await {
    match event_result {
        Ok(event) => {
            // StreamEventに応じた処理
            match event {
                worker::StreamEvent::Chunk(chunk) => {
                    print!("{}", chunk);
                }
                worker::StreamEvent::ToolCall(tool_call) => {
                    println!("\n[Tool Call: {} with args {}]", tool_call.name, tool_call.arguments);
                }
                worker::StreamEvent::ToolResult { tool_name, result } => {
                    println!("\n[Tool Result: {} -> {:?}]", tool_name, result);
                }
                _ => {}
            }
        }
        Err(e) => {
            eprintln!("\n[Error: {}]", e);
            break;
        }
    }
}

4. (オプション) フックの登録

WorkerHook トレイトを実装してカスタムフックを作成し、Worker に登録することで、処理フローをカスタマイズできます。

// (WorkerHookの実装は省略)
// let my_hook = MyCustomHook::new();
// worker.register_hook(Box::new(my_hook));

これで、アプリケーションの要件に応じて Worker を中心とした強力なLLM連携機能を構築できます。