DifyのRAG精度が低い?GenSparkとGeminiで高精度チャットボットを自作する方法【コード付】

1. DifyのRAG精度に限界を感じていませんか?

「企業サイトのチャットボットって、なぜあんなに的外れな回答ばかりなのか?」

自身で開発したコミュニティアプリに「ジェンスパーク(GenSpark)」のサポートボットを導入しようとした際、私はこの疑問にぶつかりました。「FAQのリンクを貼るだけなら検索でいい」「知りたいのはそこじゃない」——そんなユーザー体験を避けるため、「本当に納得できる精度のチャットボット」を自作することにしました。

2. Difyのナレッジベース構築で直面した「3つの壁」

当初は、人気のローコード開発ツール「Dify」を使用してRAG(検索拡張生成)システムを構築しました。ブログ記事をインポートし、自動でベクトル化してくれる便利な機能です。

しかし、3日間かけてチューニングを行いましたが、以下の問題が解決しませんでした。

  • 情報の断片化:記事の一部だけが検索され、文脈が無視される。
  • ハルシネーション:似た単語に引っ張られ、無関係な記事を元に嘘をつく。
  • 「分かりません」の連発:検索スコアの閾値を上げると、今度は何も答えなくなる。

ここで私は仮説を立てました。「検索(Retrieval)に頼るRAGという仕組み自体が、今回の規模感には合っていないのではないか?」と。

3. 解決策:GenSparkナレッジ × Geminiロングコンテキスト

そこで、アプローチを「検索」から「全読ませ」に切り替えました。以下の3ステップ構成です。

  1. GenSpark (データ生成):ブログ記事をAIに読ませ、「完璧なQ&Aリスト」を生成させる。
  2. Cloudflare Workers (実行環境):生成したナレッジをKVに保存し、API化する。
  3. Gemini 1.5 Flash (頭脳):ナレッジ全文をプロンプトに含めて回答させる。
重要な提言:Gemini Flashのような「ロングコンテキスト(長文入力)」対応モデルが安価になった今、小〜中規模のドキュメントなら無理にRAGを使わず、全部AIに読ませる方が圧倒的に精度が出ます。

4. 実装コード解説:Cloudflare Workers + Hono

実際に2時間で組み上げたバックエンドのコード(抜粋)を公開します。フレームワークには軽量なHonoを使用しています。

コアロジック:ナレッジ全渡しとNO_ANSWER制御

このコードのポイントは、KVから取得したナレッジをそのままGeminiに投げている点と、ボットが適当なことを言わないための制御です。

import { Hono } from 'hono'
import { cors } from 'hono/cors'

const app = new Hono()
app.use('/*', cors())

// メインの返信エンドポイント
app.post('/api/reply', async (c) => {
  try {
    const body = await c.req.json()
    const { content } = body // ユーザーの投稿内容
    
    // 1. ナレッジベース(KV)から全テキストを取得
    // RAG(検索)はせず、ここですべて読み込む
    const knowledge = await c.env.KV.get('kb:all', 'text')
    
    if (!knowledge) {
      return c.json({ error: 'Knowledge base error' }, 500)
    }
    
    // 2. Gemini APIで回答生成
    const answer = await generateAnswer(content, knowledge, c.env.GEMINI_API_KEY)
    
    // 3. ナレッジ外の質問なら無視する(重要!)
    // コミュニティのノイズにならないよう、分からないことは答えない
    if (answer === 'NO_ANSWER' || answer.trim() === 'NO_ANSWER') {
      console.log('[BOT] ナレッジベース外のためスキップ')
      return c.json({
        status: 'no_answer',
        message: '該当情報なし'
      })
    }
    
    // ... (以下、投稿処理へ続く)
    
    return c.json({ status: 'success', answer })
    
  } catch (error) {
    return c.json({ error: error.message }, 500)
  }
})

export default app

実際の動作画面

以下は、コミュニティアプリで実際に稼働しているボットの様子です。ユーザーから「Thinkingループ」について質問があり、ボットが適切に回答している場面です。

コミュニティアプリでのボット回答画面

図:GenSparkボットがユーザーの質問に回答している様子

この画面からも分かるように、ボットは「Thinkingループが発生した場合」という具体的な対処法を、ナレッジベースから正確に抽出して回答しています。DifyのRAGでは難しかった、この「文脈を理解した的確な回答」が実現できています。

5. ボットの性格を決めるプロンプト設計のコツ

Geminiに渡すプロンプト(指示書)も重要です。単に答えるだけでなく、「コミュニティボットとしての立ち振る舞い」を制御しています。

async function generateAnswer(question, knowledge, apiKey) {
  const prompt = `あなたはGensparkコミュニティのサポートボットです。

【重要なルール】
1. 以下のナレッジベースに記載されている情報のみを使用してください
2. ナレッジベースに該当する情報がない場合は「NO_ANSWER」とだけ返してください
3. 不具合について謝罪しないでください(あなたは公式ではなく、有志のツールです)
4. 挨拶や前置きは最小限にし、結論から答えてください
5. 雑談には付き合わず「NO_ANSWER」としてください

ナレッジベース:
${knowledge}

ユーザーの質問: ${question}

回答:`
  
  // ... (Gemini API呼び出し処理)
}
成功の鍵:
特に「謝罪禁止」の指示が効果的です。AIはすぐに「ご不便をおかけして申し訳ありません」と言いたがりますが、非公式ボットがこれをやるとユーザーが混乱します。この制御により、非常に「役に立つ」ボットになりました。

6. まとめ:適材適所のAI開発を

Difyで3日間悩んだ開発が、構成を変えるだけでわずか2時間で完了しました。 稼働後のテストでも、私の嫌いだった「ズレた回答」は一度も発生していません。

もしあなたが今、DifyやLangChainでのRAG構築、精度の低さに疲弊しているなら、一度立ち止まって考えてみてください。 「そのドキュメント、今のAIなら全部読めるのでは?」

GenSparkで整理し、Geminiで読む。 このシンプルな構成こそが、個人開発における最強のソリューションになるかもしれません。

使用ツール・リンク:
- Cloudflare Workers
- Gemini API (Google AI Studio)
- Hono framework