はじめに
前回の記事では、ONNX Runtime を Crystal から動かせるようになった話を紹介しました。
ONNX Runtime が動かせるなら、llama.cpp
も動かせるのでは?と思い、試してみたところ、あっさりと動いてしまいました。しかも、CLINE + Claude にとっては llama.cpp
の方が ONNX Runtime よりも簡単だったようで、特に初速の立ち上がりがすごかったです。
AIもメモリの扱いが苦手
しかし調子に乗って関数や機能をどんどん追加していくと、次第にエラーが発生するようになりました。
セグメンテーション違反(Segmentation Fault)が出るようになり、しかもなかなか修正してくれません。しばらくは改修をどんどん指示していたのですが、改善の兆しが見えなかったため、gdb
などを使ってメモリリークの発生箇所を特定し、バックトレースをAIに渡したりもしました。しかし、それでもなかなか直らなかったので、自分でソースコードを見てみると……。
私の目にも明らかに「これはダメだな」とわかるような状態になっていました。
私は職業エンジニアではなく、半ば趣味でプログラミングをしている人間です。仕事で静的型付き言語を本格的に使ったこともありませんし、スキルが高いとはとても言えません。Ruby や Crystal の C ライブラリ向けバインディングを作っているので、C言語はほんの少しだけ読めるようになりましたが、自分で書けるわけではありません。
そんな私でもわかる程度に、コードにはアドホックなワークアラウンドがたくさん存在していました。
「AIって意外とメモリ管理が苦手なんだな」と思いました。
CrystalでCバインディングを作成するときの一般原則
Crystal における C バインディングのメモリ管理が難しい最大の理由は、Crystal 側で確保したメモリは主に GC によって管理されるため、「どのタイミングで解放されるのか分からない」という点にあります。
最もよくないパターンは、同じ構造体について、Crystal 側で malloc
により確保するケースと、C 言語側の関数で確保するケースが混在することです。Crystal の malloc
は libgc
のそれなので、私たちの知らないタイミングでメモリが解放されます。一方、C 側の関数で確保された構造体は、対応する C の関数を使って手動で解放する必要があります。
つまり、同じ構造体に対して、Crystal と C の両方でメモリ確保が行われる場合がある状態になると、Crystal 側で確保した場合であっても finalize
メソッドが呼び出され、二重解放が発生してしまうのです。
そのため、ベストプラクティス(あくまで私がそう考えているだけかもしれませんが)は、以下のとおりです:
- 各構造体ごとに、Crystal 側でメモリを確保すべきか、C 側で確保すべきかを事前に決めておく
- どうしても混在が避けられない場合は、フラグなどで管理し、メモリの確保方法に応じて解放方法も変える
こうした大原則はドキュメントとしてあまり整備されておらず、Crystal でいくつかバインディングを作ってみないと身につかない知識です。そのため、AI もまだ十分には理解していないのではないかと感じました。
このような基本が伝わっていなかったため、gdb
のバックトレースなどを渡しても、どこで二重解放が起きているのかを特定できたとしても、問題解決にはつながらず、アドホックな対応ばかりが増えてしまいました。
AIとは「話し合い」が重要
問題の所在が明らかになったので、CLINE の ACT
を停止し、PLAN
に切り替えて、Crystal のメモリ管理について AI に説明しました。
また、AI 側から「llama.cpp
のコードを読みたい」というリクエストがあったので、コード全体を渡しました。すると Claude は、「llama.cpp
の初期化処理が良くない」と言ってきました。まあ、確かにそうかもしれませんし、C++ ではよくあるスタイルなのかもしれません。
特に印象的だったのは、「AIは、アップストリームのリポジトリにプルリクエストを送って修正提案をする」といった発想はあまり持っていないのだな、ということです。
まとめ
AI エージェントの力は素晴らしく、短時間で llama.cpp
のバインディングを作成してくれました。
私は LLM についてほとんど理解していないにもかかわらず、ダウンロードした GGFU ファイルを使って、PC 上で英語の文章を生成できるようになりました。
一方で、AI を使ったプログラミングには、いくつかの課題も見えてきました。
- Crystal における C バインディングの慣習など、学習資料が少ない分野では、AI も正しい結論にたどり着きにくい
- AI は「アップストリームのライブラリ自体を修正する」という発想に乏しい
- プロジェクトの立ち上げは簡単だが、どうメンテナンスするかという視点はまだ不十分
- 現状では、まだまだコストがかかる
また、人間とプログラミングの関係性そのものも、大きく変わってきていると感じます。
これまで私は、Ruby や Crystal を好んで使ってきました。これは、それらの書き心地が好きだったからであり、趣味であるがゆえに、自分の好きな言語を選べたからです。
しかし、AI エージェントの時代では、やり取りする「日本語」や「自然言語」こそが、真のプログラミング言語になりつつあります。
これまで人間が人間に対して行ってきたような「間接的なプロジェクト管理」こそが、今後は AI に対して求められる役割になっていくのではないかと感じています。
この記事は以上です。
本記事は、ChatGPTによる日本語の編集・校正を行っていますが、本文の内容は人間である私が全て書きました。