コンテンツにスキップ
Subako Docs
日本語
Esc
↑↓移動↵開く⌘Jプレビュー
このページの内容

Rust

Rust 用の SDK。

subako-function-sdk は、普通の Rust の関数を Tool にします。関数名が Tool の名前に、doc コメントがモデルの読む説明になります。入力と出力の型には JsonSchema を derive し、それが Tool の Schema になります。

Package を始める

Rust テンプレートを使うと、crate、ツールチェーン、Bundle をビルドするスクリプトがそろいます。

rustup target add wasm32-wasip1
cargo install cargo-generate
cargo generate subako-ai/subako-function-template-rust --name orders

自分の crate に SDK を追加することもできます。

[dependencies]
schemars = "1"
serde = { version = "1", features = ["derive"] }
subako-function-sdk = "0.2"

[profile.release]
opt-level = "s"
lto = true

Tool

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use subako_function_sdk::{ToolError, function, package};

#[derive(Deserialize, JsonSchema)]
struct LookupInput {
    /// The order's number, such as 1042.
    order: u32,
}

#[derive(Serialize, JsonSchema)]
struct Order {
    status: String,
    total_cents: u64,
}

/// Look an order up by its number.
#[function]
fn lookup(input: LookupInput) -> Result<Order, ToolError> {
    if input.order == 0 {
        return Err(ToolError::new("order numbers start at 1"));
    }
    Ok(Order { status: "shipped".into(), total_cents: 12_900 })
}

/// Cancel an order that has not shipped.
#[function]
fn cancel(input: LookupInput) -> Result<Order, ToolError> {
    Err(ToolError::new(format!("order {} has already shipped", input.order)))
}

package! {
    name: "orders",
    description: "Looks orders up, and cancels them.",
    functions: [lookup, cancel],
}
  • #[function] を付けた関数には、必ず doc コメントを書きます。これがモデルの読む説明になり、doc コメントがないとビルドが失敗します。
  • 関数は Deserialize + JsonSchema を満たす引数を 1 つ取り、Result<O, E> を返します。O は Serialize + JsonSchema を満たし、E は ToolError に変換できる型です。
  • フィールドの doc コメントは、Schema のプロパティの説明になります。モデルは何を渡せばよいかをここから知るので、モデルに向けて書いてください。
  • package! では Package の名前と含める関数を指定します。main はこのマクロが生成します。

エラー

ToolError::new は、モデルが読むエラーを作ります。String、&str、std::io::Error、SDK の HttpError から変換できるので、? を使えば失敗の理由がそのままモデルに渡ります。Schema に合わない入力には、関数を実行する前にエラーが返されます。

panic させずにエラーを返してください。panic はクラッシュになり、モデルには Function が止まったことしか伝わりません。

ファイル

Volume と Asset は std::fs で読み書きします。

let csv = std::fs::read_to_string("/volume/tmp/export.csv")?;
std::fs::create_dir_all("/volume/data/reports")?;
std::fs::write("/volume/data/reports/q3.md", summary)?;
let template = std::fs::read_to_string("/package/templates/report.md")?;

HTTP

http::request は、Subako を通してリクエストを送ります。Grant のネットワークと Credential の設定が適用されます。

use subako_function_sdk::http::{self, Request, RequestBody, ResponseBody, ResponseOutput};

/// Fetch a page's text.
#[function]
fn fetch(input: FetchInput) -> Result<Page, ToolError> {
    let response = http::request(&Request::get(input.url))?;
    match response.body {
        ResponseBody::Inline { text } => Ok(Page { status: response.status, text }),
        ResponseBody::File { .. } => Err(ToolError::new("the body was saved to a file")),
    }
}

レスポンスの本文は、http::INLINE_MAX_BYTES までならテキストとしてインラインで返ります。それより大きい本文やバイナリの本文は、リクエストの output を ResponseOutput::File { path } にすれば Volume に直接書き出せます。逆に Volume のファイルを本文として送るには、RequestBody::File { path } を使います。

画像

Answer を返すと、値に加えて Volume の画像をモデルに見せられます。

use subako_function_sdk::{Answer, ToolError, function};

/// Plot a chart and show it.
#[function]
fn plot(input: PlotInput) -> Result<Answer<Plot>, ToolError> {
    let path = "/volume/tmp/chart.png".to_string();
    // ... `path` にグラフを書き出します ...
    Ok(Answer::new(Plot { path: path.clone() }).with_image_file(path))
}

ビルドとテスト

cargo test                                         # Tool は普通の Rust として実行されます
cargo build --release --target wasm32-wasip1       # target/wasm32-wasip1/release/orders.wasm
cargo run -- --subako-manifest > subako-package.json

手元のマシン向けにビルドした crate は、--subako-manifest を付けて実行すると subako-package.json を出力します。Manifest をコードから生成するので、両者が食い違うことはありません。テンプレートの package.sh はこの 3 つをまとめて実行し、そのままアップロードできる dist/<name>.tar.gz を作ります。

API リファレンスは docs.rs にあります。

このページは役に立ちましたか?