yoi/crates/llm-worker/docs/tool-output-design.md

133 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ツール出力の遅延読み込み設計
## 課題
ツール実行結果(ファイル内容、検索結果等)は サイズが予測不能 で、
全量を `Item::ToolResult { output: String }` として LLM コンテキストに
載せると、トークン消費が爆発する。
## 方針
- ツール出力に **Inline / Stored** の区別を導入する
- Stored な出力は **BlobStore** に保存し、履歴には要約のみ載せる
- LLM が詳細を見たい場合は **inspect ツール** で部分取得する
## データ型
### ToolOutputllm-worker 側)
```rust
pub enum ToolOutput {
/// 小さな結果: そのまま history に載る
Inline(String),
/// 大きな結果: summary だけ history に載り、全体は BlobStore に保存される
Stored {
summary: String,
content: Content,
},
}
pub enum Content {
Text(String),
Structured(serde_json::Value),
}
```
- `Tool::execute()` の戻り値は `Result<String, ToolError>` のまま据え置き
- `From<String> for ToolOutput` で閾値ベースの自動昇格を行う
- ツール実装者が明示的に `ToolOutput` を返したい場合は別トレイトメソッドを用意
### BlobStorellm-worker-persistence 側)
```rust
pub type BlobId = uuid::Uuid; // UUID v7
pub trait BlobStore: Send + Sync {
fn store(&self, content: &Content) -> impl Future<Output = Result<BlobId, BlobStoreError>> + Send;
fn load(&self, id: BlobId) -> impl Future<Output = Result<Content, BlobStoreError>> + Send;
fn exists(&self, id: BlobId) -> impl Future<Output = Result<bool, BlobStoreError>> + Send;
}
```
### FsBlobStore レイアウト
```
blobs/
├── {blob_id}.txt # Content::Text
└── {blob_id}.json # Content::Structured
```
セッションとは独立したフラットなストア。セッションとの紐付けは
ログ側の参照summary 内の `[blob:<id>]`)で行う。
## 自動サマリ
`From<String>` による自動昇格時のサマリ生成ルール:
| 項目 | 値 |
|---|---|
| Inline 閾値 | 800 bytes |
| サマリ上限 | 400 bytes |
| 先頭行数 | 5 行 |
| 末尾行数 | 3 行 |
### Text のサマリ形式
```
[blob:<id>] text | {N} lines
── head ──
{先頭5行}
── tail ──
{末尾3行}
```
### Structured (JSON Array) のサマリ形式
```
[blob:<id>] json_array | {N} entries
── schema ──
{最初の要素のキー: 型}
── head ──
{先頭2要素}
```
### Structured (JSON Object) のサマリ形式
```
[blob:<id>] json_object | {N} keys
── keys ──
{キー一覧と各値の型/サイズ}
```
## Worker への統合
```
Tool::execute() → Result<String, ToolError>
▼ From<String> for ToolOutput
ToolOutput::Inline(s) ← len ≤ 800
ToolOutput::Stored { .. } ← len > 800
▼ Worker が BlobStore に保存
Item::ToolResult { output: summary } ← history に載る
▼ LLM が詳細を見たい場合
inspect(blob_id, selector?) → 部分取得
```
Worker はオプショナルに `BlobStore` を保持する。
BlobStore が未設定の場合は従来通り全量 Inline として扱う。
## inspect ツール
Worker に BlobStore が設定されている場合、自動的に登録される組み込みツール。
```
inspect(blob_id, selector?)
```
- selector 省略: メタ情報 + 先頭部分
- `lines:20-50`: 行範囲Text 用)
- `slice:3..8`: インデックス範囲Array 用)
- `key:results`: キー指定Object 用)