「CSV を渡して、欲しい集計とグラフを日本語で指示するだけで返ってくる」— そんなエージェントを社内で使い始めたとき、Excel で30分かけていた月次レポートが3分で終わるようになりました。Antigravity のエージェント機能と pandas を組み合わせると、この体験は驚くほど少ないコードで実現できます。ただし素朴に組むと、空のデータフレームで例外を吐いたり、数値と文字列が混在した列で黙って誤集計したりと、現場で痛い目に遭います。ここでは私が実際に使っている CSV 分析エージェントの構成と、最初の数週間で気づいた落とし穴をまとめてお伝えします。
なぜ Antigravity エージェントが CSV 分析に向いているのか
CSV 分析は「指示の曖昧さを、その場で解消しながら進める」作業です。たとえば「売上の推移を出して」と言われたとき、日次なのか週次なのか、店舗別で分けるのか、欠損値はどう扱うのか — 人間なら手を動かす前に何回か確認します。Antigravity のエージェントは、この「対話しながらコードを書き、実行して結果を見せ、必要ならやり直す」ループがエディタ内で完結する点で、Jupyter やスクリプトを単体で使うより明らかに速いです。
私はもともと pandas を直接叩く派でしたが、社内の非エンジニアにも使ってもらうには敷居が高すぎました。エージェントに任せると、コードを書けない人でも自然言語で同じ出力を得られます。
最小構成のエージェントスケルトン
まずは土台です。プロジェクト直下に agents/csv_analyst/ を作り、依存ライブラリを固定します。
# 依存インストール(requirements.txt に保存しておく)
pip install pandas==2.2.2 matplotlib==3.9.0 japanize-matplotlib==1.1.3次に、エージェントに渡す実行関数(tool)を定義します。Antigravity の Agent Manager からこの Python 関数を呼び出してもらう構成です。
# agents/csv_analyst/tools.py
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib # 日本語フォント対応(import するだけで有効)
from pathlib import Path
OUTPUT_DIR = Path("output")
OUTPUT_DIR.mkdir(exist_ok=True)
def load_csv(path: str) -> dict:
"""CSV を読み込み、基本情報を返す。エージェントが構造を理解するための最初のステップ。"""
df = pd.read_csv(path)
return {
"columns": list(df.columns),
"dtypes": {c: str(df[c].dtype) for c in df.columns},
"rows": len(df),
"head": df.head(5).to_dict(orient="records"),
}
def aggregate_and_plot(path: str, group_by: str, value: str, output_name: str) -> str:
"""group_by 列で集計し、棒グラフを PNG で保存する。戻り値は保存先パス。"""
df = pd.read_csv(path)
# 数値変換できない行は落とす(エージェントに警告を返すため件数を保持)
df[value] = pd.to_numeric(df[value], errors="coerce")
dropped = df[value].isna().sum()
df = df.dropna(subset=[value])
agg = df.groupby(group_by)[value].sum().sort_values(ascending=False)
fig, ax = plt.subplots(figsize=(10, 6))
agg.plot(kind="bar", ax=ax)
ax.set_title(f"{group_by} 別の {value} 合計")
ax.set_ylabel(value)
plt.tight_layout()
out = OUTPUT_DIR / f"{output_name}.png"
fig.savefig(out, dpi=150)
plt.close(fig)
return f"saved={out} dropped_rows={dropped}"ポイントは dropped_rows を戻り値に含めていることです。数値列に文字が混ざっていた場合に何件落としたかをエージェントに返すと、次のターンで「30件落ちていますが確認しますか?」のように人間側に戻してくれます。無言で削られるのが一番怖いパターンなので、ここは必ず明示します。
エージェントへの指示ファイル(system prompt)
Antigravity では AGENTS.md をプロジェクト直下に置くと、エージェント全体の振る舞いを規定できます。CSV 分析用には以下のような骨子を置いています。
# CSV Analyst Agent
## あなたの役割
ユーザーから受け取った CSV ファイルを pandas で読み込み、指示に従って
集計・可視化を行います。結果は必ず以下の順序で提示してください。
1. load_csv ツールで列と型を確認する
2. 曖昧な指示があれば、コード実行前に1度だけ確認する
3. aggregate_and_plot を呼び出し、PNG を保存する
4. 保存先パスと、落とした行数を報告する
## 禁止事項
- 元の CSV ファイルを書き換えない(常に読み取り専用で扱う)
- 列名を勝手に変更しない
- 欠損値の扱いを変えたら必ずユーザーに報告する「曖昧な指示があれば1度だけ確認する」のバランスが肝心です。毎回聞き返すと UX が悪化し、黙って進めると誤集計のリスクが上がります。私は「閾値:3つ以上の解釈候補がある場合のみ確認」をルールにしたら、体感で最もストレスが少なくなりました。
ありがちな落とし穴と対処
運用を始めて2週間ほどで、いくつか定番のトラブルに遭遇しました。
文字コードが Shift_JIS の CSV を読めない — Excel からエクスポートした CSV は今でも Shift_JIS が多く、pd.read_csv(path) のデフォルトだと UnicodeDecodeError が出ます。load_csv 関数の先頭で chardet や charset-normalizer を使って自動判定させるか、最悪 encoding="cp932" を明示的に試すフォールバックを入れておくと安心です。
日付列が文字列として解釈される — ISO 8601 形式なら parse_dates=["日付"] で済みますが、「2026/4/23」のようなスラッシュ区切りだと失敗することがあります。エージェントに「集計前に dtype を確認する」ステップを必ず踏ませるのは、これが理由です。
グラフの日本語が豆腐になる — japanize-matplotlib を import するだけで解決しますが、import 位置が重要です。matplotlib.pyplot より後にimportするとフォント設定が上書きされないケースがあります。私は tools.py の先頭で読み込むようにしています。
「月別に出して」で年を無視される — df["日付"].dt.month だけでグルーピングすると、2025年4月と2026年4月が合算されます。指示文に年が含まれていない場合、エージェントに「年月で集計しますか?月のみで集計しますか?」と確認させるルールを AGENTS.md に加えました。
セキュリティとデータ境界
社内データを扱う場合、CSV にそのまま個人情報が含まれていることがあります。私は以下を守っています。
- CSV は
/tmp/csv_analyst/などの作業ディレクトリにコピーしてから処理し、処理後に削除する - エージェントのログには列の中身を含めない(
headの戻り値もマスクする関数を挟む) - Gemini にデータを送信する必要があるときは、サンプルの数行のみに限定する
Antigravity の Python 連携を本格運用する前段階として、Antigravity の Python API を本番投入するためのセーフガード で扱っている鍵管理・タイムアウト・リトライの設計も合わせて整えておくと、夜間の自動実行まで安心して任せられます。
次の一歩
まずは手元の月次売上 CSV で load_csv → aggregate_and_plot の往復を1回試してみてください。うまく動いたら、次は複数 CSV を結合する merge_csv ツール、さらに時系列予測を足した forecast ツールへと拡張できます。同じ土台の上に、ウェブスクレイピングで収集したデータをそのまま分析に回すエージェント を組み合わせると、収集から可視化までを一本のチャットで回せるようになります。
Antigravity のエージェント機能は、pandas のような「道具」を渡された瞬間から本領を発揮します。コードを書ける人にとっては時短、コードが書けない人にとっては新しい入口 — 両方を同時に提供できるのがこの組み合わせの面白いところだと感じています。