kubell Advent Calendar 2025 の投稿です。
プロダクト戦略ユニットの山本です。 今回は、AI エージェント開発におけるルールベースと LLM の効果的な使い分けについて考察します。
TL;DR
AI エージェント開発では、ハルシネーション対策として「決定論」と「非決定論」の使い分けが重要です。例外的なケースはルールベースで処理し、HITL(Human in the Loop)は高精度モデルとアプリケーション側の制御で強制します。プロンプトだけに頼らず、ルールベースと LLM を適切に組み合わせることで、効率性と信頼性を両立できます。
はじめに
AI エージェントを開発していると、ルールベースで実現すべきか、それとも LLM(大規模言語モデル)に任せるべきかという判断に直面します。 その代表的なテーマの 1 つが「ハルシネーション(幻覚)」への対策です。
ハルシネーションを回避しつつ、どのように LLM の良さを活かすべきか——これはある意味「とんち」に近い問題だと思います。 プロンプトの工夫だけでハルシネーションを抑え込もうとすると、プロンプトがどんどん膨れ上がり、最終的にはメンテナンスが難しいものになってしまいます。 では、どうすればよいのでしょうか。ここではいくつかの例を紹介します。
例1: 存在しないデータを勝手に埋める
これはハルシネーションでよく見られるパターンです。 特定の例外的なケースに対応しようとしても、完全に回避するのは難しいものです。 では、そのような場合にエージェント化を諦めるべきでしょうか?
graph LR
A[画像入力] --> B[LLM 処理]
B --> C{JSON 出力}
C --> D[正常なデータ<br/>name: 田中太郎<br/>age: 30<br/>email: [email protected]<br/>phone:]
C --> E[ハルシネーション発生<br/>name: 田中太郎<br/>age: 30<br/>email: [email protected]<br/>phone: 090-XXXX-XXXX ⚠️]
style E fill:#ffcccc
style D fill:#ccffcc
上図のように、画像から構造化データを抽出する際、LLM が存在しないフィールド(例: phone)を勝手に推測して埋めてしまうケースがあります。
ここでの「とんち」は、例外的なケースのみをルールベースで扱うという選択です。 具体的には、読み取り処理の後に例外的な部分を切り落とすようにします。
graph LR
A[画像入力] --> B[LLM 処理]
B --> C[JSON 出力<br/>ハルシネーション含む]
C --> D[ルールベース処理<br/>スキーマバリデーション]
D --> E[正常な JSON<br/>name: 田中太郎<br/>age: 30<br/>email: [email protected]<br/>phone:]
style A fill:#e3f2fd
style B fill:#fff9c4
style C fill:#ffcccc
style D fill:#c8e6c9
style E fill:#ccffcc
このように、LLM による読み取り処理の後に、スキーマに存在しないフィールドをルールベースで削除する仕組みを導入します。 これにより、ルール化されたプロセスとして安定した動作を実現しつつ、LLM の良さも活かせるようになります。
例2 :HITL(Human in the Loop)を無視する
これも LLM でよく起きる課題の 1 つです。 プロンプトをどれだけ工夫しても解決が難しい場合が多く、対応には 2 つの手段が必要になることがあります。 それは、高精度なモデルを利用することと、アプリケーション側で制御を強制することです。
モデルの精度を上げる方法としては、たとえば Gemini 2.0 から Gemini 2.5 へとアップデートすることで理解精度が大きく変わります。 これは誰もが想像しやすい、わかりやすい対処法です。
# Basic pay update specialized agent basic_pay_update_agent = Agent( model="gemini-2.5-pro", # 高精度モデルを指定 name="BasicPayUpdateAgent", description=BASIC_PAY_UPDATE_AGENT_DESCRIPTION, instruction=BASIC_PAY_UPDATE_AGENT_INSTRUCTION, tools=[update_basic_pay], )
もう 1 つの「アプリケーションでの強制」は少し複雑です。 なぜなら、エージェントと UI の両方で対処が必要になるからです。 具体的には、ツール呼び出し後に必ず承認を経るルートを設けることが有効です。
# From agent.py root_agent = Agent( ... tools=[ # Set require_confirmation to True to require user confirmation # for the tool call. FunctionTool(reimburse, require_confirmation=True), ], ...
こうすることで、エージェントが人間の確認を無視して勝手に処理を進めることを防止できます。
問題は UI 側でも同様の対策が必要になることです。 たとえば、UI 側でツール呼び出し後に確認ダイアログを表示する仕組みが必要になります。しかし、この承認フロー専用の「Tool Confirmation Flow」に対応した UI を開発する必要があります。また、Gemini Enterprise の場合、Tool Confirmation Flow は、私が確認した時点(2025年11月2日)ではまだサポートされていませんでした。
まとめ:決定論と非決定論のバランスを取る
このような課題は他にもさまざまありますが、重要なのは「決定論」と「非決定論」の使い分けを意識することだと思います。 AI エージェントの導入を諦めるのではなく、ユーザーに誠実に価値を届けるために、どこでソフトウェアエンジニアとしての知恵を使うべきかを見極めることが大切だと思います。
ソフトウェアエンジニアとして、効率性と信頼性の両立を目指し、「怠惰(よい意味での自動化志向)」を活かしていくことが、現状の AI エージェント開発のプラクティスではないでしょうか。
記事は以上です。
今後も AI エージェント開発に関する発信する予定です。BPaaS 戦略に興味をお持ちでしたら、ぜひお気軽にお問い合わせください。
この投稿をみていただい方はいいねをお願いします。
それでは次回のアドカレでお会いしましょう👋