トラック A · タスク A4
エージェントトレース エクスプローラー
AI エージェントが出力する JSON はリリースごとに構造が変わります。VARIANT に保存し、通常の列のようにクエリします。
- 60~120 分
- 中級
- 言語自由 · CLI、ノートブック、Web
- AI ツールの利用歓迎
困ったときは? 質問はこちら: #dev 参加先: Apache Doris Slack。メンテナーやほかの参加者がサポートします。
環境を準備
何を作るか、Doris ならどう簡単になるかを学び、クラスターを起動します。
作成するもの
エージェントの不揃いな JSON も、そのままクエリ。
LLM 呼び出し、ツール呼び出し、エラー、最終回答。それぞれに独自のフィールドがあり、リリースごとに新しいフィールドも増えます。Doris の VARIANT は JSON を型付きの列に自動変換するため、通常の SQL でフィルター、検索、集約できます。スキーマ移行は不要です。
次を対象にしたトレースエクスプローラー: 1,000 件の AI エージェントセッション(約 20,000 イベント):
- 検索用の セッション一覧 (イベント数、エラー、トークン数、レイテンシを表示)、
- 検索用の セッションのタイムライン:セッションをクリックすると、エージェントの動作を順に再現、
- ツールとモデルの統計:p95 レイテンシ、エラー率、トークン使用量、
- JSON 内の検索:「timeout」を含むツールエラーをすべて検索します。
そして次に答えます: 13:00 にデプロイされたエージェント v2 によって、状況は改善しましたか、それとも悪化しましたか?
概略図はコードパネルの上部にあります
Doris で取り組む利点
スキーマ定義不要の書き込み時スキーマ処理。 VARIANT は JSON の各パスの型を推論し、よく使うパスを実際の列指向サブカラムとして保存します。そのため、
payload['latency_ms']は全ドキュメントを解析せず、1 列を読むだけで済みます。新しいフィールドは自動で現れます。 v2 のイベントが次を追加すると、
cost_usd、次のロードで新しいパスがサブカラムとして現れます。次の操作は不要です:ALTER TABLE.JSON 内を検索。 VARIANT 列の転置インデックスにより、すべてのテキストパスを次で検索できます:
MATCH_*.
パネル:テーブル定義のインデックス行
始める前に
docker pull apache/doris:all-in-one-4.1.3docker run -d --name doris -p 9030:9030 -p 8030:8030 -p 8040:8040 apache/doris:all-in-one-4.1.3docker exec -it doris mysql -uroot -h127.0.0.1 -P9030curl -LO https://github.com/morningman/demo-env/releases/download/for-hackathon/doris-hackathon-glasgow-2026.zip && unzip doris-hackathon-glasgow-2026.zip && cd doris-hackathon-glasgow-2026
- ホスト
- 127.0.0.1
- ポート
- 9030
- ユーザー
- rootパスワードなし
- データベース
- hackathon
データ
hackathon.agent_events :エージェントのイベントごとに 1 行を保存し、イベント本体を VARIANT 列に保持します:
CREATE TABLE agent_events ( session_id VARCHAR(40) NOT NULL, ts DATETIME(3) NOT NULL, event_id BIGINT NOT NULL, event_type VARCHAR(32) NOT NULL, -- user_message / llm_call / tool_call / error / final_answer payload VARIANT NOT NULL, INDEX idx_payload (payload) USING INVERTED PROPERTIES ("parser" = "english"))DUPLICATE KEY(session_id, ts)DISTRIBUTED BY HASH(session_id) BUCKETS 1PROPERTIES ("replication_num" = "1", "storage_format" = "V3");ペイロード例:構造の違いに注目してください:
{"text": "Why did checkout fail at 11:40?", "lang": "en", "agent_version": "v1"}{"model": "model-large", "usage": {"input_tokens": 812, "output_tokens": 96}, "latency_ms": 1430, "agent_version": "v1"}{"tool": "sql_query", "args": {"sql": "SELECT ..."}, "latency_ms": 37, "status": "ok", "agent_version": "v1"}{"tool": "http_get", "args": {"url": "..."}, "latency_ms": 3012, "status": "error", "agent_version": "v1", "error": {"type": "Timeout", "message": "read timeout after 3000 ms calling https://api.internal/orders"}}13:00 以降に始まるセッションは次を実行します: エージェント v2。ペイロードには次が含まれ、 "agent_version": "v2"、v2 の LLM 呼び出しには次のフラグが追加されます: cache_hit 。マイルストーン 5 では、テーブルにまだ存在しないフィールドを持つイベントをロードします。
パネル → テーブル:テーブル定義の全体
AI を使って作る
AI コーディングエージェントとの共同作業を推奨しています。 Doris 4.x の検索機能と AI 機能は、多くのモデルの学習データより新しいため、SQL を書かせる前に適切な情報を渡してください:
次の コンテキストプロンプト をエージェントに貼り付けます。
参照先として次を指定: このページに掲載した参考資料 および
AGENTS.md(スターターキット内)。多くのコーディングエージェントはこのファイルを自動で読み込みます。コードに組み込む前に、すべての SQL 文を実際のクラスターで実行させてください。
さらに、次を接続すると便利です: Doris MCP Server (参照: タスク A2)。エージェント自身でスキーマを確認し、クエリをテストできるようになります。
I'm building an agent trace explorer on Apache Doris 4.1 for a hackathon.Connection: MySQL protocol, 127.0.0.1:9030, user root, empty password, database `hackathon`.Use a plain MySQL driver and raw SQL.Table `agent_events`: session_id, ts DATETIME(3), event_id, event_type(user_message / llm_call / tool_call / error / final_answer), payload VARIANT(inverted index, english parser). Payload shapes differ by event_type. Every payload hasagent_version: "v1" before 13:00, "v2" from 13:00; v2 llm_calls add cache_hit.Doris SQL rules:1. Read JSON paths as payload['a']['b']. CAST to a concrete type before comparing, sorting or aggregating: CAST(payload['latency_ms'] AS DOUBLE).2. VARIANT cannot be a key, a sort key or a join key.3. Text search inside JSON: payload['error']['message'] MATCH_ANY 'timeout'. Never LIKE.4. Percentiles: percentile_approx(expr, 0.95).5. `SET describe_extend_variant_column = true; DESC agent_events;` lists inferred subcolumns.6. To insert JSON yourself, CAST the text: CAST('{"a": 1}' AS JSON).Build: sessions list, session timeline, tool/model stats, and JSON search.Run every SQL statement against the live cluster first.AI エージェントが陥りやすい Doris の落とし穴
| Trap | What to do instead |
|---|---|
| キャストせずに VARIANT のパスを比較する | CAST(payload['latency_ms'] AS INT)。VARIANT はキー列や結合列にできません |
次に期待すること: DESC による JSON パスの一覧表示 | 実行: SET describe_extend_variant_column = true; を先に実行します。その後、 DESC に推論されたすべてのサブカラムと型が表示されます |
次の使用: LIKE '%term%' によるテキスト検索 | col MATCH_ANY 'a b' (OR)、 MATCH_ALL (AND)、 MATCH_PHRASE 'a b' 。これらは転置インデックスを使います |
| ORM を使う | 通常の MySQL ドライバーと生の SQL を推奨します。ORM は Doris がサポートしない文を生成する場合があります |
実装する
6 マイルストーン、 M0 → M5。パネルは読んでいるステップに追従します。
ロードして調べる
スターターキットのフォルダー内で実行:
M0 · ロードbashdocker exec -i doris mysql -uroot -h127.0.0.1 -P9030 < seed/a4_agent_events.sql続いて SQL シェルで実行:
M0 · 調査sqlUSE hackathon;SET describe_extend_variant_column = true;DESC agent_events; -- see the subcolumns Doris inferred: payload.tool, payload.usage.input_tokens, ...確認ポイントロード結果の表示: 1,000 セッション、20,401 イベント;
DESCには約 20 個のpayload.*パスが、それぞれ推論された型とともに表示されます。JSON パスをクエリ
M1 · JSON パスをクエリsqlSELECT CAST(payload['tool'] AS STRING) AS tool, COUNT(*) AS callsFROM agent_eventsWHERE event_type = 'tool_call'GROUP BY toolORDER BY calls DESC;確認ポイントツールは 5 つあり、
sql_queryが最も多く呼び出されています(3,506 回)。推論されたサブカラムを集約
M2 · 推論されたサブカラムを集約sqlSELECT CAST(payload['tool'] AS STRING) AS tool, COUNT(*) AS calls, percentile_approx(CAST(payload['latency_ms'] AS DOUBLE), 0.95) AS p95_ms, SUM(CASE WHEN CAST(payload['status'] AS STRING) = 'error' THEN 1 ELSE 0 END) AS errorsFROM agent_eventsWHERE event_type = 'tool_call'GROUP BY toolORDER BY p95_ms DESC;確認ポイントpython_execの p95 が最も悪く(約 2.1 秒)、http_getの失敗が最も多い(425 エラー)。JSON 内を検索
M3 · JSON 内を検索sqlSELECT session_id, ts, CAST(payload['error']['message'] AS STRING) AS error_messageFROM agent_eventsWHERE payload['error']['message'] MATCH_ANY 'timeout'ORDER BY tsLIMIT 20;確認ポイント合計 398 イベントに timeout が含まれます。時間ごとに集計すると、v2 に関する最初の手掛かりが得られます。
セッションのタイムライン
M4 · セッションのタイムラインsqlSELECT ts, event_type, CAST(payload['tool'] AS STRING) AS tool, CAST(payload['status'] AS STRING) AS status, CAST(payload['latency_ms'] AS INT) AS latency_ms, CAST(payload['text'] AS STRING) AS textFROM agent_eventsWHERE session_id = 's-0042'ORDER BY ts;これらのクエリを使って、セッション一覧 → タイムライン → 統計の UI を作ります。
確認ポイントセッション
s-0042には 25 イベントがあります。質問、LLM とツールの呼び出し(1 回失敗したsql_queryは再試行)、最終回答で構成されています。スキーマの変化を観察
M5 · スキーマ変更バッチをロードbashdocker exec -i doris mysql -uroot -h127.0.0.1 -P9030 < a4/drift_batch.sql # events with new fieldsM5 · 新しいフィールドをクエリsqlSELECT CAST(payload['agent_version'] AS STRING) AS version, COUNT(*) AS llm_calls, ROUND(SUM(CAST(payload['cost_usd'] AS DOUBLE)), 2) AS cost_usdFROM agent_eventsWHERE event_type = 'llm_call'GROUP BY versionORDER BY version;実行:
DESC agent_eventsを再実行すると、新しいパスが表示されます。次の操作はALTER TABLE実行していません。確認ポイント第 3 のバージョンが現れます:
v2.1。そのバージョンの LLM 呼び出しだけに次が含まれます:cost_usd、かつDESCに次が表示されます:payload.cost_usdおよびpayload.retries.
完成させる
チェックを済ませ、成果を共有し、バッジを獲得しましょう。
完了条件
チェックリスト提出してバッジを獲得
参加 → 提出 → バッジを獲得。
成果物は次の名前のフォルダーにまとめてください: ご自身の GitHub ID。コードと README を含め、README に内容、実行方法、スクリーンショットまたは GIF 1 点、使用した Doris の機能を記載します。
プルリクエストを作成 次の場所に追加してください: morningman/demo-env 配置先:
doris-hackathon-glasgow-2026/<your-github-id>/。フォークして push するか、GitHub の次の操作を使ってください: Add file → Upload files。ほかに入力する項目はありません。共有する 共有先:
#dev参加先: Apache Doris Slack:プルリクエストまたはリポジトリへのリンクと、スクリーンショットまたは短いデモを共有します。質問、提出、バッジの案内はすべてこちらで行います。
タスクに参加した方全員に次のバッジを贈ります: Apache Doris Contributor バッジ。Doris 本体へのプルリクエストがマージされている必要はありません。締め切りはないので、ご自身のペースで進めてください。チーム参加も可能ですが必須ではありません。全員の GitHub ID を次に記載してください: README.
追加の挑戦
自分のトレースを使う。 ご自身の AI コーディングエージェントのローカルセッションログ(JSONL)をエクスポートし、1 行に 1 つの
CAST('…' AS JSON)をロードします。データはローカルの Doris インスタンスに保存されます。Schema Template。 よく使うパスを次で固定します:
VARIANT<'latency_ms': INT, 'tool': STRING>(テーブルのコピーで実行)。次の結果とDESCクエリの挙動を比較します。データの投入方法:INSERT … SELECT …, CAST(payload AS JSON):VARIANT はテンプレート付きの VARIANT に直接キャストできません。アシスタントに探索させる。 Doris MCP Server を接続し(タスク A2)、最も問題のあるセッションを探すようアシスタントに依頼します。
SQL でエラーを分類 (API キーはご自身で用意):
AI_CLASSIFY(CAST(payload['error']['message'] AS STRING), ['timeout', 'auth', 'bad input', 'other'])。参照: LLM SQL 関数.
トラブルシューティングと参考資料
| Symptom | Fix |
|---|---|
docker: command not found (macOS) | Docker Desktop を起動してください。起動済みなら CLI へのリンクを作成します: sudo ln -s /Applications/Docker.app/Contents/Resources/bin/docker /usr/local/bin/docker |
error getting credentials (イメージ取得時) | 削除する項目: credsStore のフィールドを次から削除: ~/.docker/config.json (ローカル開発環境のみ) |
port is already allocated | 別のプロセス(多くは別の Doris)が 9030、8030、8040 のいずれかを使っています。実行中のコンテナーを確認してください(docker ps)。または別のホストポートを公開します。例: -p 19030:9030。その場合は 19030 に接続してください。 |
The container name "/doris" is already in use | 以前に起動したことがあります: docker start doris。最初からやり直すには、 docker rm -f doris (データが削除されます) |
コンテナーが終了する、または状態が変わらない: (healthy) | 確認: docker logs doris。多くはメモリが原因です。Docker Desktop に 6 GB 以上を割り当ててください(Settings → Resources)。Apple Silicon では次を追加しないでください: --platform linux/amd64 |
permission denied: ./doris.sh | 解凍ツールによって実行権限が失われています: chmod +x doris.sh、または次を実行: bash doris.sh start |
Current database is not set | 実行: USE hackathon; を先に実行するか、次で接続します: -Dhackathon |
score() function requires WHERE clause with MATCH function, ORDER BY and LIMIT | 次を追加: MATCH_* の述語、 ORDER BY score() DESC および LIMIT、さらに次は score() を式で包まないでください(上記の落とし穴を参照) |
| 10 分以上解決できない場合 | 投稿先: #dev 参加先: Apache Doris Slack |
参考資料
Apache Doris Hackathon
