連載「Genie Codeと学ぶDatabricks」
- 入門編: 作らせて読む学習法
- Unity Catalog編: 3階層名前空間を体で覚える
- Delta Lake編: わざと事故を起こして、タイムトラベルで戻す
- Lakeflow編: DesignerとSDPは同じパイプラインの表と裏だった
- AI/BIダッシュボード編: 作らせて、確かめて、整えて、届ける
- エージェント開発編: Genie Codeに、エージェントそのものを作らせる (本記事・最終回)
はじめに
連載「Genie Codeと学ぶDatabricks」、今回が最終回です。
この連載では一貫して、Genie Codeというコーディングエージェントに作らせて、生成物を読み解いて学んできました。ノートブック、パイプライン、ダッシュボード。最終回で作らせるのは、AIエージェントそのものです。コーディングエージェントにエージェントのコードを書かせて、その中身を読み解く。AIに作らせて学んできた連載の締めくくりとして、これ以上の題材はないと思います。
材料はDatabricksのモデルサービングエンドポイント (基盤モデルAPI) と、この連載で作ってきた月別受注データです。第5回で「想定外の質問を受けるのはGenieエージェントの仕事」と線を引きましたが、今回はそのGenieエージェントのようなもののミニチュアを自分の手で作って、中で何が起きているのかを理解します。
環境はDatabricks Free Editionです。
エージェントの正体は、ループである
作る前に、エージェントとは何かを一言で言っておきます。LLMと、ツールと、ループです。
LLMは言葉を生成することしかできません。SQLを実行する手も、ファイルを読む目もありません。そこで人間側のコードが、LLMに「使ってよい道具のリスト」を渡します。LLMは質問を受けると、答えるために道具が必要なら「この道具をこの引数で使いたい」と言葉で返してくる。人間側のコードがそれを実行して結果を渡すと、LLMは結果を踏まえて次を考える。必要がなくなるまでこれを繰り返し、最後に答えを言う。このループがエージェントです。
第5回まで使ってきたGenie Codeも、質問に答えたGenieエージェントも、本質はこの構造です。今日はこれを最小構成で作ります。
材料: モデルサービングエンドポイント
エージェントの頭脳になるLLMは、Databricksのモデルサービングエンドポイントから調達します。基盤モデルAPIとして主要なモデルがワークスペースにホストされた状態で提供されており、外部サービスとの契約もAPIキーの管理も不要で、エンドポイント名を指定するだけで呼べます。
APIキーを配らずにLLMを呼べるというのは、さらっと書きましたが実務ではかなり大きな話です。キーの発行、配布、ローテーション、漏洩対応という一連の管理業務が丸ごと消え、アクセス制御はワークスペースの権限管理に一元化されます。
ここで注意が2つあります。1つ目、ドキュメントの一覧にあるモデルがすべての環境で使えるとは限りません。自分の環境で使えるモデルは、AI Playgroundのモデル一覧で確認してください。私のFree Edition環境ではClaude系は使えず、オープンウェイトモデルが提供されていたので、その中からMetaのLlama 3.3 70B Instructを使います。ツール呼び出しに対応しており、70Bクラスなら「ツールを使うべきか」の判断も安定するので、エージェントの頭脳が務まります。
2つ目、モデルの名前は2種類あります。カタログ上では system.ai.meta-llama-3-3-70b-instruct と表示されますが、これはUnity Catalog上の登録名で、コードから呼ぶサービングエンドポイント名は databricks-meta-llama-3-3-70b-instruct です。system.aiの方の名前をクライアントに渡すと404で怒られます。地味ですが確実につまずくポイントなので、先にお伝えしておきます。
作らせる
いつも通り、フルページ型のGenie Codeに仕様を渡します。
月別受注データについて日本語の質問に答えるミニエージェントを、
ノートブックとして実装してください。
- LLMは基盤モデルAPIのdatabricks-meta-llama-3-3-70b-instructエンドポイントを使う
- workspace.tpch_learning.monthly_order_totalsに対してSELECT文を
実行するツールを1つ持たせる (SELECT以外の文は実行を拒否する)
- 質問を受け取り、必要ならツールを呼び、結果を踏まえて回答する
ループを実装する
- 「1998年で受注金額が最も多かった月はいつ?」という質問でテストする
- エージェントの仕組みが分かるよう、各部にコメントで解説を付ける
仕様の2行目に注目してください。「SELECT以外の文は実行を拒否する」。エージェントに渡す道具には、能力だけでなく制限を設計します。第3回で「破壊的操作の最終判断はAIに委ねない」と書きましたが、自作エージェントではそれをコードのレベルで強制できるわけです。
読み解く: エージェントは「仕様書の塊」だった
生成されたノートブックを読み解きます。中心になる構造はおそらくこの3つです (実際の生成コードに合わせて読み替えてください)。
1つ目、ツール定義。LLMに渡す道具のリストは、こういう形のスキーマで書かれます。
tools = [{
"type": "function",
"function": {
"name": "run_sql",
"description": "月別受注データ (monthly_order_totals) に対して"
"SELECT文を実行し、結果を返す",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "実行するSELECT文"}
},
"required": ["query"]
}
}
}]
これを見て気づくことがあります。ツール定義とは、道具の仕様の明文化です。名前、何をするものか、引数は何か。この連載でずっとやってきた「仕様を明文化してAIに渡す」が、エージェントの内部ではデータ構造として埋め込まれている。私たちがGenie Codeに書いてきたプロンプトと、エージェントが持つツール定義は、同じ行為の2つの姿です。
2つ目、ループ。
while True:
response = client.chat.completions.create(
model="databricks-meta-llama-3-3-70b-instruct",
messages=messages,
tools=tools,
)
msg = response.choices[0].message
if not msg.tool_calls:
break # ツールが不要になったら、それが最終回答
for call in msg.tool_calls:
result = run_sql(call) # 人間側のコードがSQLを実行
messages.append(ツールの実行結果)
LLMが「ツールをこのクエリで呼びたい」と言い、コードが実行して結果を返し、LLMが次を考える。実際にテスト質問を流したときのログが興味深いものでした。最初のループでLLMは month という存在しない列名でSQLを発行し、実行はエラーになります。そのエラーがツール結果としてLLMに返ると、次のループで自分で列名を order_month に直して再クエリし、答えに到達しました。エラーを隠さずそのまま返せば、数十行のループでも自己修正が起きる。第3回でGenie Codeが見せたエラー自己修正と同じ挙動が、この最小構成でも現れたわけです。
なお、このエージェントにチャット画面はありません。生成されたコードではループが ask_agent のような関数にまとまっていて、質問はノートブックのセルから関数の引数として渡します。
ask_agent("1998年で受注金額が最も多かった月はいつ?")
チャットUIを付けたくなったらDatabricks Appsの領域ですが、エージェントの本体がただの関数だと分かること自体が、今回の学びの1つです。
3つ目、システムプロンプト。エージェントの行動方針を決める文章です。これが単なる飾りでないことは、実測ですぐに分かりました。私の環境では、回答に「不过」と中国語が混ざることがあったのです。オープンウェイトモデルではときどき起きる現象で、対処はシステムプロンプトに「回答は必ず日本語のみで書いてください」と1行足すだけ。モデルの素の挙動と、こちらの要件との差分を埋める場所がシステムプロンプトだ、ということが小さく体験できます。
ここから先: 測って、見張る世界
今回作ったのは最小構成のミニチュアです。本番のエージェント開発では、この先に「評価」と「観測」が待っています。回答品質をデータセットで測るAgent Evaluation、応答の裏側のツール呼び出しを追跡するMLflow Tracing。DatabricksはこれらをAgent Bricksとしてスイート化しており、フレームワークで書いたエージェントもその土俵に載せられます。
ミニチュアを自作して中身を理解した今なら、これらの道具が何を測り、何を見張っているのかも解像度高く読めるはずです。興味のある方は、今回のノートブックを足がかりに進んでみてください。
まとめ: 連載を終えて
最終回のまとめと、連載全体の締めです。
- エージェントの正体はLLMとツールとループ。魔法ではなく、読めるサイズのコードに還元できる
- モデルサービングエンドポイント (基盤モデルAPI) を使えば、APIキー管理なしでLLMをコードから呼べる
- ツール定義は道具の仕様の明文化。システムプロンプトは行動方針の明文化。エージェント開発とは、仕様を書く仕事の集積
- ツールには能力だけでなく制限 (SELECTのみ) を設計する。ガードレールはコードで強制できる
- ツールのエラーは隠さずそのまま返す。それだけで、最小構成のループでも列名間違いの自己修正が起きた
- オープンウェイトモデルでは回答に他言語が混ざることがある。システムプロンプトの1行で直す
連載全体を振り返ると、6回でやってきたことは一貫していました。仕様を明文化してAIに渡す。生成されたものの裏側を読む。AIが知らない文脈を人間が補う。対象はノートブックからパイプライン、ダッシュボード、そして最後はエージェント自身へと変わりましたが、使う筋肉はずっと同じでした。そしてこの筋肉は、Databricksに限らず、AIと働くすべての場面で効きます。
2026年の今からDatabricksを学ぶ人へ、第1回で書いたことをもう一度。文法から積み上げる必要はありません。Free Editionで、AIに作らせて、読み解きながら学んでください。この連載がその最初の伴走になれば幸いです。

