0
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?

Strands AgentsとGradioでツール付きAIチャットを構築する

Posted at

AWSが開発するAIエージェントフレームワーク Strands Agents と、HuggingFaceが提供するお手軽なWeb UIライブラリ Gradio を組み合わせて、独自ツールを実行できるシンプルなAIチャットを作ってみます。

Strands Agentsとは

Strands Agents は、AIエージェントを構築するためのPython製フレームワークです。AWSによってオープンソースとして開発・公開されています。

Strandsの特徴

  • コードファーストで軽量、シンプル
  • 特定のAIプロバイダーに依存しない
  • 可観測性 (Observability) 対応など、本番運用も考慮している

数行のコードで基本的なAIエージェントを作成でき、拡張もサクサクできます。シンプルながら必要な機能が一通り備わっており、他のフレームワークと比べても「ちょうどいい」感じがします。
また、AWSがバックにいるため安心感もあります🤗

エージェントの例

以下はエージェントのサンプルです。Ollama のローカルAIモデルに接続し、いくつかのツール(Python関数)を利用できるように設定しています。

from strands import Agent
from strands.models.ollama import OllamaModel
from strands_tools import current_time  # Strandsに付属するツール
import tools as my_tools  # 自作のツール

# AIモデルを定義
#   Ollama (ローカルのAIサーバ) と接続し、gpt-ossモデルを使用する
model = OllamaModel(model_id="gpt-oss:20b", host="http://localhost:11434")
# モデルをエージェント化する。ツールとプロンプトを設定
agent = Agent(
    model=model, tools=[current_time, my_tools],
    system_prompt="あなたは有能なアシスタントです。"
)

このエージェントに指示を与えてみます。

# エージェントに指示
agent("いま何時?")
agent("tools/__init__.py内の関数を教えて")

すると、以下のような応答が返ってきます。使用したツール名とユーザーへのメッセージが出力されます。

「いま何時?」 の応答例:

Tool #1: current_time

現在は 2025‑09‑15 01:51:44 (UTC)です。  
もし日本時間(JST)など別のタイムゾーンでの時刻が知りたい場合は、タイムゾーンを教えてくださいね。

ここでは current_time ツールを呼び出して、現在時刻を取得してから回答しています。

また、次の応答例では、複数のツールを組み合わせて必要な情報を集めています。

tools/__init__.py内の関数を教えて」 の応答例:

Tool #2: list_files
Tool #3: read_file

`tools/__init__.py` に定義されている関数は以下の3つです。
- `get_timezone`
- `read_file`
- `list_files`

対象のファイルを探してから内容を読み込み、関数名を抽出して回答しているようです。
かしこい!

Gradioとは

Gradio(グレーディオ)は、簡易的なWeb UIを構築できるPythonフレームワークです。HuggingFace がオープンソースで開発しており、生成AIのデモなどで広く利用されています。

Pythonコードから直接UI部品を呼び出すだけで、そのままWeb UIを組み立てられる手軽さが特徴です。 Streamlit に似ていますが、Gradioの方がAIツールのプロトタイピングに向いている印象があります。特に2024年にリリースされたバージョン5ではパフォーマンスが大幅に改善され、UIも洗練されてかなり垢抜けました。

Gradioは豊富なUIコンポーネントが標準で用意されています。また、任意の処理をキュー化できるため、GPU依存の重いタスクも扱いやすいです。さらに、3Dモデルの表示にも対応しているため、AWSの 3D Gaussian Splat パイプライン でもUIとして使われています。

Pythonで簡易Web UIが欲しくなったら、とりあえずGradioを試すと間違いない🤗と思います。

StrandsとGradioの連携

概要

今回はStrands AgentsとGradioを組み合わせて、シンプルなAIチャットを実装します。

Gradioでチャット用のWeb UIを立ち上げ、AIエージェントの管理はStrands Agentsに任せます。手順は以下の通りです。

  1. エージェント用のツールを作成
  2. エージェントを作成 (Strands Agents)
  3. チャットUIを作成 (Gradio)
  4. チャットUIとエージェントを連携させる
  5. Gradioアプリとして起動する🚀

これだけで実現できます。

準備

まず、Pythonのパッケージ管理ツールからStrands AgentsとGradioをインストールします。

以下の例では pip を利用していますが、実用上は uv での管理をおすすめします。

pip install strands-agents gradio

実装

1. エージェント用のツールを作成

任意のPythonの関数にStrandsの @tool デコレータを付けると、エージェントが関数を利用できるようになります。エージェントは関数のコメント(docstring)を読み取り、処理内容を理解して必要に応じてツールを呼び出します。

以下はサイコロを転がすだけの、シンプルなツールの例です。

import random
from strands import tool

@tool
def roll_dice(num_dice: int) -> list[int]:
    """
    サイコロを転がして出た目の数を返します。

    Args:
        num_dice (int): サイコロの数

    Returns:
        list[int]: それぞれのサイコロの出た目の値
    """
    return [random.randint(1, 6) for _ in range(num_dice)]

ただの関数に @tool が付いているだけです。

2. エージェントを作成

次にエージェントを作成します。
以下の例ではClaudeを利用していますが、OpenAIやOllamaなど他のモデルも利用できます。関数定義にしているのは、あとでUIから設定を変更した際に、エージェントを再作成できるようにするためです。

from typing import Any
from strands import Agent
from strands.models.anthropic import AnthropicModel
from strands.session.file_session_manager import FileSessionManager
from strands_tools import calculator, current_time

def create_agent(system_prompt: str, session_id: str) -> tuple[Agent, list[dict]]:
    """エージェントを作成し、セッションIDに基づいてチャットの履歴を復元"""
    # モデルの定義
    # 今回はAnthoropicのAPIを利用 (APIキーが必要)
    model = AnthropicModel(
        model_id="claude-sonnet-4-0",
        max_tokens=8192,
        client_args={"api_key": os.environ["ANTHROPIC_API_KEY"]},
    )

    # ローカルファイルベースのセッション管理
    # "./sessions" の下にセッションIDのフォルダが作られて、チャット履歴が記録される
    session = FileSessionManager(session_id=session_id, storage_dir="./sessions")

    # エージェントを作成
    agent = Agent(
        model=model,
        session_manager=session,
        tools=[calculator, current_time, roll_dice],  # ツールを登録
        system_prompt=system_prompt,
    )

    # チャットの履歴から本文だけを取り出し
    # 元の履歴にはツール呼出しなどの情報も記録されており、GradioのチャットUIとは互換性がない
    # ここでつじつま合わせをする
    chat_history = []
    for message in agent.messages:
        # チャットの本文("text" コンテンツの中身)だけ取り出す
        contents = message.get("content", [])
        text_items = (x["text"] for x in contents if x.get("text"))
        text = next(text_items, None)
        if text:
            chat_history.append({"role": message.get("role"), "content": text})

    return agent, chat_history

戻り値として、エージェント本体とチャット履歴(Gradio用に整形したもの)を返しています。チャット履歴は FileSessionManager というセッション管理クラスを利用してローカルに自動保存させています。

3. チャットUIを作成

Gradioには gradio.ChatInterface というシンプルなチャットUIが用意されています。以下のようにメッセージ処理関数を指定するだけで、すぐにチャットができるようになります。

import gradio as gr

def handle_chat(message, history):
    """引数のユーザーメッセージに対して返答する"""
    return "さすが鋭いですね!確かに '" + message + "' と思います!!"

chat = gr.ChatInterface(handle_chat, type="messages")
chat.launch()

chatif_ss.png

今回はこのチャットUIをベースに、いくつか設定をカスタマイズできるように拡張します。開閉パネル gr.Accordion を設定パネルとしてチャットの上部に設置し、システムプロンプトやセッションIDを切り替え可能にします。

import gradio as gr
            
with gr.Blocks(fill_height=True) as demo:
    # 設定パネル
    with gr.Accordion("🛠️ 設定", open=False):
        system_prompt = gr.Textbox(
            value="あなたは有能なアシスタントです。",
            label="システムプロンプト",
        )
        session_id = gr.Dropdown(
            choices=get_available_session_names(),  # セッション一覧を取得 (実装は省略)
            value="default",
            label="セッションID",
            allow_custom_value=True,
        )

    # エージェント格納用の入れ物
    agent_state = gr.State(None)
    # メインのチャットUI
    chat = gr.ChatInterface(
        handle_chat,  # ※後述
        type="messages", additional_inputs=[agent_state]
    )

    # エージェントを作成
    gr.on(
        # 起動時、設定パネルの内容変更時に呼び出し
        [chat.load, system_prompt.blur, session_id.blur],
        create_agent,
        inputs=[system_prompt, session_id],
        outputs=[agent_state, chat.chatbot_value],
    )

真ん中あたりにある agent_state 変数は、 gr.State を利用してエージェントの参照を保持します。また、最後の gr.on はイベントハンドラとしてUI操作とエージェント作成処理を紐づけています。

4. チャットUIとエージェントを連携させる

チャットUIのメッセージ処理関数 handle_chat() を実装します。
以下のように、引数のメッセージをStrandsのエージェントに渡し、応答をyield文でチャットUIに返します。

async def handle_chat(message, _history, agent: Agent):
    """引数のユーザーメッセージに対して返答する"""
    chunks = []
    async for event in agent.stream_async(message):
        if "data" in event:
            chunks.append(event["data"])
            yield "".join(chunks)

引数の agent には、 ChatInterfaceadditional_inputs で指定したエージェントが渡されます。

5. Gradioアプリとして起動する🚀

最後にGradioアプリを起動します。

demo.launch()

これらのコードを my_chat_app.py として保存し、実行します。

$ python my_chat_app.py
* Running on local URL:  http://127.0.0.1:7860
* To create a public link, set `share=True` in `launch()`.

ブラウザで http://localhost:7860/ にアクセスすると、チャットUIが表示され、AIと会話が可能になります。

chat_ss.png

まとめ

Strands AgentsとGradioを組み合わせることで、簡単にツール実行機能付きのAIチャットアプリを構築できました。

この実装をベースに、ツールを増やしたり、複数のAIモデルを切り替えたりと、さまざまなカスタマイズが可能です。Strandsのユーザガイドの目次には、MCPの利用やOpenTelemetry連携、マルチエージェント構成など、さらに発展的な機能も載っています。

今後のさらなる進化に期待です!!

おまけ: 他のエージェントフレームワークの印象

他のエージェントフレームワークもいくつか調べたので、軽く印象をまとめます:

これらと比べると、Strandsは中庸でいいバランスなのかなと思います。 ただ、基本的にはどのフレームワークでも同じことが実現可能だと思います。つまりバイブス🤞で選んでオッケーってことですね。

おまけ: 全コード

0
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
0
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?