RAGは「知識をAIに読ませて、ユーザーが何か聞いたら答えてくれる仕組み」と思われがちです。そこまではあっています。問題は、「ユーザーが打った文章をそのまま検索クエリとして流す」という実装のしかたにあります。
それで動くことも、あります。でも会話が複数ターンになると、たいていどこかで崩れます。
採用面接AIを作ったときの詰まり所
候補者の「本当の動機」を引き出したい、というニーズがありました。採用や自己分析の場面で、表面的な答えではなく、根源にある欲求まで会話で掘り下げていく。それをAIがやる、という仕組みです。
Difyでワークフローを組み、Knowledge(RAGの知識ベース)に質問設計のための情報を入れました。最初の実装は、ユーザーの回答をそのまま検索クエリとして投げるものでした。
動きません。正確には、「動くときもあるけど、精度が安定しない」状態です。
ユーザーが打ってくる文章は、検索クエリとして設計されていません。「うーん、なんとなく人の役に立ちたいというか…」という入力から、次に何を聞くべき質問を引き出そうとしても、検索がノイズだらけになります。
ユーザー入力と検索クエリは、別物
ここが誤解されやすいところです。
RAGの検索は、クエリと文書の類似度で動きます。ユーザーの発言がそのままクエリになると、感情語や助詞、言いよどみが混じって、本当に引き出したい情報とずれた文書を拾います。
加えて、会話は「今どの段階にいるか」で必要な情報が変わります。最初の「自己紹介を聞く」フェーズと、「動機を深掘りする」フェーズと、「まとめに入る」フェーズでは、Knowledge から引いてくべき内容がまったく違う。
それなのにユーザーの最新発言だけをクエリにすると、フェーズを無視した検索になります。
フェーズを判定して、クエリを固定する
私がAIに頼んでたどり着いた設計は、こうです。
まずワークフロー内のCodeブロックで、会話がどのフェーズにあるかを判定します。「何ターン目か」「どのトピックまで終わったか」を条件にして、現在地を決める。
そのフェーズに応じて、検索クエリを固定します。ユーザーの入力を直接クエリにするのではなく、「このフェーズならこの問い」という対応表をあらかじめ作っておいて、そこから決まったクエリを投げる。
AIへの頼み方はだいたいこんなかたちでした。
会話フェーズを「導入」「掘り下げ」「まとめ」の3段階に分けて、現在のフェーズをCodeブロックで判定してほしい。
- 判定したフェーズに応じて、Knowledgeへの検索クエリを固定で渡す(ユーザーの発言を直接クエリにしない)
- 検索で引いた内容をもとに、「共感」→「要約」→「次の質問」の順で1問ずつ応答する
- 会話の記憶はMemoryに持たせて、何ターン目でも文脈が引き継がれるようにする
この設計に変えると、精度が安定しました。ユーザーが何を打ってきても、AIは「今はここを聞く段階だ」という軸を持ったまま動きます。
プロンプトが1/30になった
もう一つ変えたことがあります。プロンプトの量です。
最初は「こういう人物像のユーザーに対して、こういう観点で、こういう掘り下げ方をして…」と長い指示を書いていました。それをMemoryとフェーズ判定に任せて短くしたところ、トークンが従来比1/30になりました。
プロンプトを詰め込めば精度が上がる、とは限らないです。むしろフレームワーク(フェーズ管理・Memoryの役割分担)を整理することで、AIが「今何をすべきか」を短い指示でも正しく判断できるようになる。
長いプロンプトが必要なのは、構造が整理されていないサインかもしれません。
