2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Agno】 Agentic RAGで強化するF1データ分析 【Agno SQL F1 sample】

Posted at

本記事では、**F1(Formula 1)データを対象にした「テキスト→SQL変換エージェント」の動作概要や、エージェントが参照するナレッジベース(Knowledge Base)**の詳細を解説します。さらに、実際のStreamlitアプリでの実行結果ログも交えて、エージェントがどのようにSQLを生成・実行し、どのような回答を返すのかを示します。

プロジェクト概要

このサンプルプロジェクトの目的は、自然言語での質問を自動的にSQLクエリへ変換し、F1データ(1950年~2020年)に対して実行→結果を返すというエージェントを構築することです。
具体的には以下のような特徴があります。

  1. F1の歴史的データ
    1950年~2020年までのレース結果やドライバー情報、チーム(コンストラクターズ)情報、最速ラップなどを一括管理。

  2. Agentic RAG
    エージェントが自身でナレッジベースに問い合わせ、テーブルのメタデータやサンプルクエリを参照する仕組み。より正確なSQLクエリを生成できるようになります。

  3. Streamlit + Docker Compose

    • StreamlitによるUI(チャット形式のインターフェース)。
    • Docker Composeでpgvector(PostgreSQL拡張)とアプリが同時起動。
    • 簡単にローカル環境で試せます。

ディレクトリ構成と主なファイル

リポジトリのディレクトリ構成はざっくり以下の通りです。

├── agents.py                <-- エージェントの定義・設定
├── app.py                   <-- Streamlitアプリ(UI部)
├── docker-compose.yml       <-- DBとアプリの起動設定
├── Dockerfile               <-- コンテナのビルド設定
├── load_f1_data.py          <-- CSVをPostgreSQLにロード
├── load_knowledge.py        <-- ナレッジベースをベクトルDBにロード
├── knowledge/               <-- テーブルメタデータやサンプルSQL, JSONファイル
└── utils.py                 <-- Streamlit用ユーティリティ等

2.1 agents.py

  • Agnoの Agent クラスを継承し、「SQLエージェント」を実装。
  • LLM(OpenAI GPT-4など)を選択し、SQLツールファイル操作ツールを追加。
  • ナレッジベース(後述)やセッション管理(PostgresAgentStorage)を設定し、エージェントの「振る舞いのルール」(instructions)を詳細に記述。

2.2 app.py

  • Streamlitでチャット形式のUIを作成。
  • agents.py のエージェントを呼び出し、ユーザーからの質問を受け取り、エージェントが生成する回答やSQLをリアルタイム表示。

2.3 load_f1_data.py / load_knowledge.py

  • load_f1_data.py: F1データ(CSV形式)をS3からダウンロード → pandas で読み込み → PostgreSQLにテーブルとして保存。
  • load_knowledge.py: knowledge/ ディレクトリのファイル(テーブルJSONやサンプルSQL)をベクトルDB(pgvector)に取り込み、エージェントの検索用ナレッジベースを構築。

2.4 knowledge/

  • テーブル構造を記したJSONファイル (例: drivers_championship.jsonrace_wins.json など)
  • サンプルクエリが書かれたSQLファイル (例: sample_queries.sql)
  • このフォルダに入っている情報がエージェントの問い合わせ元となる。

ナレッジベースの詳細

本プロジェクトが特に特徴的なのは、「Agentic RAGを活用し、エージェントがナレッジベースを随時検索して適切なSQLを組み立てる」という点です。

3.1 ナレッジベースの構成

  1. テーブルのメタデータ (JSON)

    • 各テーブルのカラム名・型・意味を記載。
    • 例: race_wins.json
      {
        "table_name": "race_wins",
        "table_description": "...",
        "table_columns": [
          { "name": "index", "type": "int", ... },
          { "name": "venue", "type": "text", ... },
          ...
        ]
      }
      
  2. サンプルSQL (sample_queries.sql)

    • よくある分析例(「チャンピオンが何回優勝したか」「コンストラクターの順位とレース勝利数の比較」など)をクエリ例として記載。
  3. 補足情報(テキストベース)

    • たとえば「date 列は DD Mon YYYY フォーマットなので TO_DATE 関数を使うと良い」といった注意事項。

3.2 読み込みと活用フロー

  1. CombinedKnowledgeBase
    TextKnowledgeBaseJSONKnowledgeBase をまとめた複合KBで、ファイル内容を全て取り込みます。

  2. PgVector
    取り込んだテキストをベクトルとして変換し、pgvectorテーブルに格納。

    • ユーザー質問の意図に合うテーブルやサンプルクエリをベクトル検索で素早く見つけ出す。
  3. エージェントのツール呼び出し

    • search_knowledge_base(table_name): エージェントが、自分でこのツールを呼び出し、対象テーブルやルールを検索。
    • describe_table(table_name): データベース側の実テーブル定義を確認。
  4. サンプルクエリを参考にSQL組み立て

    • 例: date 列から年を抽出する場合 → EXTRACT(YEAR FROM TO_DATE(date, 'DD Mon YYYY')) を流用。

実行手順

4.1 環境変数の設定

.env ファイル内にOpenAIのAPIキーなどを記載します(例: OPENAI_API_KEY="sk-...")。

4.2 Docker Composeで起動

docker compose up -d
  • 初回起動時、load_f1_data.pyload_knowledge.py が自動実行され、F1データとナレッジベースがDBに取り込まれます。
  • 数分かかる場合があるので完了を待ちます。

4.3 アプリにアクセス

ブラウザで http://localhost:8509 を開くと、StreamlitチャットUIが表示されます。
自然言語で質問すると、エージェントが最適なSQLを組み立てて実行→結果を返すフローを体験できます。

4.4 停止

docker compose down

永続化ボリュームを含め完全削除したい場合は docker compose down -v を使います。

実際の処理ログ(一例)

以下は、Streamlitアプリ上で行われたユーザーとのやりとりの抜粋です。
(ログには「どのテーブルをdescribeしたか」「実行したSQL」「結果」が表示されています。)

5.1 テーブル一覧を問い合わせる

利用可能なテーブルを教えてください

エージェントの回答例:

以下のテーブルが利用可能です:
constructors_championship ...
drivers_championship ...
fastest_laps ...
race_results ...
race_wins ...

5.2 各テーブルのカラム詳細を取得

これらのテーブルについて詳しく説明してください

エージェントは search_knowledge_base および describe_table を呼び出し、メタデータをまとめて表示します。
ログのツール呼び出し例:

🛠️ Describe Table
Arguments:
{
  "table_name":"drivers_championship"
}
Results:
[ "index: BIGINT()", "year: BIGINT()", "position: TEXT()", ... ]

5.3 「最も多くレースに勝ったドライバーは?」

最も多くのレースに優勝したドライバーは誰ですか?

エージェントが自動生成したSQLの例(ログより):

SELECT name, COUNT(*) AS win_count
FROM race_wins
GROUP BY name
ORDER BY win_count DESC
LIMIT 1

結果:
「ルイス・ハミルトン」 95回の優勝

5.4 「年間のレース数の推移を表示して」

race_wins テーブルには「year」列がないため、date列から年を抽出する必要があると判断。
エージェントはサンプルSQLを検索して TO_DATE(date, 'DD Mon YYYY') を活用し、年ごとのレース数をカウント。
結果として、1950年に7レース、2019年に21レースなど、年ごとの増減が一覧表示されます。

5.5 「2010年以降、最も多くのレースに勝利したドライバーとチームの順位は?」

以下のように、driversチャンピオンシップrace_winsを結合しながら、さらにconstructors_championshipの順位を取得する複雑なクエリを作成。ログにはツール呼び出し(knowledge base検索やSQL実行)が順次記録されています。

最終表示例:

ドライバー チーム 勝利数 チーム順位
2010 Fernando Alonso Ferrari 5 2
2011 Sebastian Vettel Red Bull Racing Renault 11 1
2012 Sebastian Vettel Red Bull Racing Renault 5 1
2013 Sebastian Vettel Red Bull Racing Renault 13 1
2014 Lewis Hamilton Mercedes 11 1
2015 Lewis Hamilton Mercedes 10 1
2016 Lewis Hamilton Mercedes 10 2
2017 Lewis Hamilton Mercedes 9 1
2018 Lewis Hamilton Mercedes 11 1
2019 Lewis Hamilton Mercedes 11 1
2020 Lewis Hamilton Mercedes 11 1

まとめと応用

  1. ナレッジベース

    • テーブルのメタデータ・サンプルSQL・日付フォーマット注意点などを格納し、エージェントは質問に応じて必要な情報を検索・取得。
    • これにより、ユーザーが「年ごとの推移が見たい」と要望したとき、自動的に適切なクエリを組み立てられます。
  2. エージェントの流れ

    1. ユーザー質問を受け取り
    2. ナレッジベースからテーブル定義・ルールを参照
    3. クエリを生成しSQLを実行
    4. 結果を整形して返す
  3. 拡張・応用

    • F1以外のデータも、同じ形式(JSONでテーブル情報、サンプルSQL)でナレッジベースを整備すれば、同じ仕組みで動かせます。
    • 質問例やサンプルクエリが豊富になるほど、エージェントの回答精度は高まります。

おわりに

本記事では、Docker Composeで動くSQLエージェントAgentic RAGを通じてナレッジベースから情報を取得し、F1データを自由に分析できるしくみをまとめました。
実際のログにある通り、ユーザーは自然言語で「最も多く優勝したドライバーは?」「2010年以降で一番勝ったドライバーは?」などと尋ねるだけで、エージェントが適切なクエリを組み立てて結果を返します。

もし本プロジェクトを試してみたい場合は、手元でリポジトリを**git clone**し、.envに自分のAPIキーをセット → docker compose up -d すればすぐにF1データの分析を始められます。ぜひご活用ください。

リポジトリ

2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?