本記事は体験談であり、記載内容は自分の環境で検証済みのものではありません。公式ドキュメントに基づく一般的な情報として参考にしてください。
エグゼクティブサマリ
Databricks上で複雑なジョブを開発する際、GitHub CopilotとDatabricks側のコーディングエージェントを併用しているが、「ジョブを直接実行し、失敗したらエージェントに調べさせて編集する」というループが繰り返し発生し、技術的負債のように積み上がっていた。具体的には次の3つのつまずきが解消できずにいた。
- Delta Lakeテーブルへのアップサート処理(MERGE INTO)実行時に、コンピュートのメモリが枯渇する
- テーブルのカラム定義(DDL)の「今の正しい状態」がDatabricksのカタログ内にしか存在せず、変更を追跡できない
- 単純なPythonのimportエラーが繰り返し発生する
どのエージェントを使っても解決しなかったが、公式ドキュメントを調べたところ、3つの症状はいずれもコードのテキストだけでは見えないコンテキスト(テーブルの物理設計・カタログの現在状態・プラットフォーム固有の実行規則)がエージェントに渡っていなかったことが原因だと分かった。
同じようにAIコーディングエージェントを使ってDatabricksの複雑なジョブ開発をしていて、原因不明の失敗を繰り返している人に向けて、何を疑えばいいかの具体的なチェックポイントをまとめる。
背景
業務でDatabricks上に、多岐にわたるファイル・テーブルを扱う複雑なジョブを開発している。コーディングエージェントとしてGitHub CopilotとDatabricks側のコーディングエージェントの両方を利用している。
ジョブの管理自体はすでに実践できていた。具体的には次の通り。
- 宣言型オートメーションバンドル(旧称Databricks Asset Bundles)でジョブ定義をコードとして管理
- pytestによるユニットテストと
bundle validateを開発フローに組み込み済み
つまり、一般的に言われる「ジョブをコード管理する」という土台はすでに整っていた。にもかかわらず、日々の実装作業は「ジョブを直接実行して確かめ、失敗したらエージェントに調べさせて編集させる」という運用になっており、このギャップが後の課題につながっていく。
課題認識
「ジョブを直接実行し、失敗したらエージェントで直す」というループを繰り返すうちに、自分の技術理解が浅いのか、それとも別の何かなのか判断がつかないまま、技術的負債(あるいは理解負債)のようなものが積み上がっていく感覚があった。毎回失敗すること自体は見えているのに、一気に改善することができない、というのが当時の実感だった。
具体的には次の3つのつまずきが繰り返し発生していた。
1. MERGE INTO実行時のメモリ枯渇
Delta Lakeテーブルへのアップサート処理(MERGE INTO)を実行すると、コンピュートのメモリが枯渇して処理が完了しない。エージェントに実装を何度直させても、どのエージェントを使っても同じようにリソース不足に陥る。
2. DDLの「原本」がカタログ内にしか存在しない
テーブルのカラム定義についてエージェントとやりとりしながら変更していたが、変更後の「今の正しい状態」がDatabricksのカタログ内にしか存在せず、DDL自体も十分にコード管理できていなかった。結果、何が正しい状態なのかを後から観測できなくなっていた。
3. 単純なPythonのimportエラー
ModuleNotFoundErrorなどの単純なimportエラーが繰り返し発生していた。
この3点が、どんなにエージェントに指示を与えても、途中で情報が欠落しているのかハルシネーションを起こしているのか、というように見えていた。
調べて分かったこと
公式ドキュメント(Databricksの開発者ベストプラクティス、Delta Lakeのパフォーマンスに関するナレッジベース、ワークスペースファイルのインポートに関するドキュメント)を確認したところ、3つの症状はそれぞれ以下のような技術的な原因と対策が公式に示されていた。
| 症状 | 公式が示す主な原因 | 公式が示す対策 |
|---|---|---|
| MERGE INTOでメモリ枯渇 | ON句にパーティション列の条件が含まれていないと、全パーティションをスキャン・シャッフルしてしまう | ON句にパーティション列の条件を含める、小さいソースはbroadcastする、shuffle partition数を調整する、joinキーでZ-ORDER/Liquid Clusteringを設定する |
| DDLがカタログ内にしかない | スキーマ変更がコード経由でのみ反映されるという前提が崩れている | テーブル・列のコメントを.sqlファイルとしてバンドル定義と一緒に保持し、専用のメタデータジョブ経由でデプロイする |
| importエラー | Databricksワークスペース特有のパス解決ルールを一般的なPythonの作法では把握していない | 別ディレクトリのモジュールはsys.path.append()で明示的に追加する、Gitフォルダーから読む場合はパスの先頭に/Workspace/を付ける |
この表は公式ドキュメントに基づく一般的な情報であり、自分の環境でまだ検証済みというわけではない。以下、それぞれをもう少し詳しく見る。
MERGE INTOのメモリ枯渇について
Databricksのナレッジベースでは、MERGE INTOのパフォーマンス問題の最も一般的な原因はON句にパーティション列の条件が含まれていないことだと説明されている。その条件がないと、Sparkはテーブルの全パーティションをスキャンしてしまい、対象データが実際はごく一部でもリソース消費が大きくなる。さらにDatabricks Runtime 10.4以降はLow Shuffle Mergeがデフォルトで有効になっており、変更のない行の再配置コストを押さえる仕組みも用意されている。
DDLをコードとして扱うことについて
公式ベストプラクティスでは、テーブルと列のコメントをコードの一部として扱い、宣言型オートメーションバンドルの定義と一緒に.sqlファイルとして保持し、専用のメタデータジョブを通してデプロイすることが推奨されている。つまり、カタログへのスキーマ変更は「常にコード経由でのみ反映される」状態を作ることが前提とされている。UIやエージェントに直接ALTER TABLEさせる運用は、この前提が崩れた状態だと言えそうだと感じた。
importエラーについて
Databricks Runtime 11.3 LTS以降では、ノートブックのカレントディレクトリが自動的にPythonパスに追加され、Gitフォルダーを使っている場合はリポジトリのルートディレクトリが自動追加される、という仕様がある。別ディレクトリのモジュールをインポートする場合はsys.path.append(os.path.abspath(...))で明示的に追加が必要で、Gitフォルダーから読み込む場合はパスの先頭に/Workspace/を付ける必要があり、これを省略するとエラーになるという具体的な仕様がある。一般的なPython知識だけでは知らない、Databricks特有の落とし穴だと感じた。
気づき
3つの症状を並べてみると、共通しているのは「コードのテキストだけを見ていても分からない、コードの外側にある情報」が原因になっているという点だと私は受け取った。
- MERGE INTOでのメモリ枯渇 → テーブルの物理設計(パーティション/クラスタリング)
- DDLが観測できない → カタログの「今の状態」の正本がコードにない
- importエラー → Databricksワークスペース特有のパス解決ルール
これはエージェントの性能やプロンプトの工夫の問題ではなく、そもそもエージェントに「見えている情報」の範囲の外側に原因があった、と捉えると自分の中で腑に落ちた。どんなにエージェントに教え込んでも解決しなかったのは、ハルシネーションではなく、その情報自体が渡っていなかったからだったというのが、現時点での自分の判断である。
逆に言えば、対策の方向性は共通している。この「見えないコンテキスト」をDDLファイルや明示的なパス指定、パーティション定義など、いつでも参照できるコードとして外部化することが、今回の状況に対する現時点での自分の結論だ。
今後の対応
ここまでは調べて分かったことと自分の整理であり、実際に手を入れて検証した結果はまだこれからである。現時点では次の3つを実践しようとしている。
- テーブルのDDL(CREATE TABLE / ALTER TABLE / COMMENT ON COLUMN、パーティション定義を含む)を.sqlファイルとして書き出し、専用のメタデータジョブ経由でのみカタログに反映する運用に変える
- MERGE INTOを書く際は、対象テーブルのパーティション列を必ずON句に含めるルールを徹底する
- Pythonモジュールのimportについては、Databricksワークスペース特有のパス規則をエージェントへの指示に明記する、またはwheelパッケージ化を検討する
これらを実践した結果、実際に三つのつまずきが解消するのかは、正直なところまだ分からない。進捗があれば別記事で報告する予定。
まとめ
AIコーディングエージェントを使ってDatabricksの複雑なジョブ開発をしていて、原因不明の失敗を繰り返している人には、エージェントの限界を疑う前に、コードの外側にあるコンテキスト(テーブルの物理設計、カタログの現在状態、プラットフォーム固有の実行規則)がエージェントに渡っているかを疑ってみることをお勧めしたい。
次の記事では、実際にDDLのコード化・メタデータジョブ化を行った結果を報告する予定。