PythonでLangChainを使ってもいいのですが、Rustを使いたい!と思ったので、RustでAI Agentを作ってみました。
Tech Stack
- Rust
- Ollama
- Rig
- wttr.in(API)
Difficulty
久しぶりにRustを使ったので、Rustに手間取るかなーと思いましたが、ClaudeCodeを使えば問題なしでしたね。
あとは、LangChainのようなライブラリの調査ですね。2つ候補がありました。
今回は、今も開発が継続されている Rig を選びました。
-
langchain-rust
最終更新が1年以上前でメンテが止まっている -
Rig
Agent・RAG・VectorStoreに対応したモダンなライブラリ
2024年から活発に開発中
Sample example
リモートPCのOllamaを使っているコードです。
Code
src/main.rs
use rig::client::{Nothing, CompletionClient};
use rig::completion::Prompt;
use rig::providers::ollama;
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let client = ollama::Client::builder()
.api_key(Nothing)
.base_url("http://192.168.0.11:11434")
.build()?;
let agent = client
.agent("gpt-oss:20b")
.preamble("あなたは親切なアシスタントです。")
.build();
let response = agent.prompt("自己紹介してください").await?;
println!("{response}");
Ok(())
}
Output
PS C:\Users\mniyk\Study\RigTestLab> cargo run
Compiling RigTestLab v0.1.0 (C:\Users\mniyk\Study\RigTestLab)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.17s
Running `target\debug\RigTestLab.exe`
こんにちは!
私はChatGPT、OpenAI が開発した対話型 AI です。
- **自然言語での会話**を得意としており、質問や相談に親切に答えます。
- **幅広いトピック**(技術、文化、趣味、学習サポートなど)に対応できます。
- **日本語でのコミュニケーション**に力を入れていますので、分かりやすく丁寧にお話しします。
もし何か知りたいことや相談したいことがあれば、遠慮なくどうぞ!😊
AI Agent Code
簡単な天気予報を取得して、回答するだけのエージェントとしました。
Code
Cargo.toml
[package]
name = "RigTestLab"
version = "0.1.0"
edition = "2024"
[dependencies]
rig-core = "0.34.0"
tokio = { version = "1", features = ["full"] }
anyhow = "1"
reqwest = { version = "0.11", features = ["json"] }
urlencoding = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
src/main.rs
use rig::client::{Nothing, CompletionClient};
use rig::completion::Prompt;
use rig::providers::ollama;
use rig::tool::Tool;
use rig::completion::ToolDefinition;
use serde::{Deserialize, Serialize};
use serde_json::json;
use reqwest::Client;
#[derive(Debug)]
struct ToolError(String);
impl std::fmt::Display for ToolError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for ToolError {}
#[derive(Deserialize)]
struct WeatherArgs {
city: String,
}
#[derive(Deserialize, Serialize)]
struct WeatherAgent;
impl Tool for WeatherAgent {
const NAME: &'static str = "get_weather";
type Error = ToolError;
type Args = WeatherArgs;
type Output = String;
async fn definition(&self, _prompt: String) -> ToolDefinition {
ToolDefinition {
name: "get_weather".to_string(),
description: "指定した都市の現在の天気を取得します".to_string(),
parameters: json!({
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "都市名(例: Kagoshima, Tokyo)"
}
},
"required": ["city"]
}),
}
}
async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
let url = format!("https://wttr.in/{}?format=4", urlencoding::encode(&args.city));
let result = Client::new()
.get(&url)
.header("User-Agent", "curl/7.0")
.send()
.await
.map_err(|e| ToolError(e.to_string()))?
.text()
.await
.map_err(|e| ToolError(e.to_string()))?;
println!("[get_weather] {}", result.trim());
Ok(result)
}
}
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let client = ollama::Client::builder()
.api_key(Nothing)
.base_url("http://192.168.0.11:11434")
.build()?;
let agent = client
.agent("gpt-oss:20b")
.preamble("あなたは親切なアシスタントです。天気を聞かれたら必ずget_weatherツールを使ってください。")
.tool(WeatherAgent)
.default_max_turns(5)
.build();
let response = agent.prompt("今日の鹿児島の天気を教えてください。").await?;
println!("{response}");
Ok(())
}
Output
PS C:\Users\mniyk\Study\RigTestLab> cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.27s
Running `target\debug\RigTestLab.exe`
[get_weather] 鹿児島: ⛅ 🌡️+19°C 🌬️↖19km/h
今日の鹿児島の天気はこんな感じです👇
「鹿児島: ⛅ 🌡️+19°C 🌬️↖19km/h」
気温はちょうどよく、雲も少しあるみたいです。外出の際は軽いジャケットや傘を持っておくと安心かもしれませんね。天気が変わるときはまたお知らせします!
Wrap-up
今回の調査で、RustとOllamaで、エージェントが作れることはわかりました。
TauriとOllamaを使って、自分のAI秘書でも作ってみようかなー。