1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Ollama × Rust × Rig】AI Agentを作ってみる

1
Posted at

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秘書でも作ってみようかなー。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?