Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RAGをテーマに考える、LLMの認知アーキテクチャとソフトウェア設計

takuya kikuchi
June 17, 2024
920

 RAGをテーマに考える、LLMの認知アーキテクチャとソフトウェア設計

2024-06-19 LLM Night〜生成AIソフトウェアアーキテクチャ〜 のLT資料です

takuya kikuchi

June 17, 2024
Tweet

More Decks by takuya kikuchi

Transcript

  1. RAGとは • 外部のデータベースや知識をもとにした回答を⼤規模⾔語モデルに⽣成させ る技術 © 2024 Algomatic Inc. 8 Algomatic

    社内 ドキュメント 経費申請 どうしたらいい? ⼀般的にはこうだよ! 経費申請 どうしたらいい? このフォームから必要事 項を記⼊して送ってね! 検索 検索結果 RAGなし RAGあり
  2. © 2024 Algomatic Inc. 11 まずはピュアに実装してみる async function answer( //

    ユーザー入力 message: Message, // チャット履歴 history: Message[]) { // ナレッジベースから知識を取得 const knowledge = await knowledgeBase.search(message); // LLMを呼び出して回答を生成し、回答 return await llm.call(message, history, knowledge); }
  3. © 2024 Algomatic Inc. 13 精度評価結果から、改善案を考える 検索精度に課題が⼤きいことがわかったので、そこを⾼める⼯夫をする 1. 検索⽤のクエリ改善 2.

    質問への仮回答⽂を⽣成し、それをクエリに検索する(HyDE) async function answer2(message: Message, history: Message[], useHyDE: boolean) { // 検索精度を高めるためにクエリを整形する const refinedMessage = await refineQuery(message, history); // HyDEモードの場合、HyDEを使ってクエリを生成する const searchQuery = useHyDE ? await hydeQuery(refinedMessage) : refinedMessage; // ナレッジベースから知識を取得 const knowledge = await knowledgeBase.search(searchQuery); // LLMを呼び出して回答を生成 return await llm.call(message, history, knowledge); }
  4. © 2024 Algomatic Inc. 14 まだまだ改善は続く RefineQuery →  良い感じ。採⽤。 HyDE →  精度向上はあるものの回答にかかる時間が⻑くなり、体験悪化。オ

    プション式にする。 検索精度は依然として課題 → 検索空間を狭めるために「カテゴリ」という概念を導⼊してみる
  5. © 2024 Algomatic Inc. 15 「カテゴリ推定」、「ユーザーに逆質問」という遷移が追加 async function answer3(message: Message,

    history: Message[], useHyDE: boolean) { // 検索精度を高めるためにクエリを整形する const refinedMessage = await refineQuery(message, history); // カテゴリを推定する const estimatedCategory = await decideCategory(refinedMessage); // カテゴリが推定できなかった場合、質問内容をもう少し詳しく教えるように促す if (!estimatedCategory) { return "質問内容について、もう少し詳しく教えてください。 "; } // HyDEモードの場合、HyDEを使ってクエリを生成する const searchQuery = useHyDE ? await hydeQuery(refinedMessage) : refinedMessage; // ナレッジベースから知識を取得 const knowledge = await knowledgeBase.search(searchQuery); // LLMを呼び出して回答を生成 return await llm.call(message, history, knowledge); }
  6. © 2024 Algomatic Inc. RAGシステムの複雑さを考える これまでの実装で複雑なところは... • 各ノードの実⾏処理 ◦ プロンプトエンジニアリング

    ◦ ナレッジ検索精度 • 判断と状態遷移 ◦ こんなとき、ユーザーに聞き返すべき? ◦ こうなったらもう回答を⽣成すべき? 17
  7. © 2024 Algomatic Inc. RAGシステムの複雑さを考える これまでの実装で複雑なところは... • 各ノードの実⾏処理 ◦ プロンプトエンジニアリング

    ◦ ナレッジ検索精度 • 判断と状態遷移 ◦ こんなとき、ユーザーに聞き返すべき? ◦ こうなったらもう回答を⽣成すべき? 18
  8. © 2024 Algomatic Inc. RAGシステムの複雑さを考える これまでの実装で複雑なところは... • 各ノードの実⾏処理 ◦ プロンプトエンジニアリング

    ◦ ナレッジ検索精度 • 判断と状態遷移 ◦ こんなとき、ユーザーに聞き返すべき? ◦ こうなったらもう回答を⽣成すべき? 19
  9. © 2024 Algomatic Inc. 宣⾔的に記述してみた 21 “実⾏” と “判断” を宣⾔的に記述するようにしてみる

    class EstimateCategoryNode implements Node { process(state: AgentState) { // カテゴリ推定する機能を実装 } plan(state: AgentState) { // カテゴリ判定に成功したかどうかを判定し、次の遷 移先を決定 if (state.推定成功()) { return nodeOf("ナレッジ検索"); } else { return nodeOf("ユーザーに逆質問 "); } } } class RAG { ... async run() { while (true) { const node = this.currentNode; node.process(); this.currentNode = node.plan(); if(currentNode === END) { return state; } } } } const rag = new RAG([ new EstimateCategoryNode(), new RetrieveKnowledgeNode(), ...]) const result = await rag.run(); 実⾏と遷移の定義 ノードを取りまとめるクラス RAG機能の呼び出し
  10. © 2024 Algomatic Inc. どうだった? かなり実装および改善がしやすくなった • 「実⾏」と「遷移」が明確に分離されることで開発およびテストが容易に なった ◦

    「検索処理を新しいバージョンに⼊れ替えて試してみるか」 などの実験も容易に • 状態遷移図がそのまま実装されているので、開発メンバー以外との仕様に 関するディスカッションもしやすくなった 22
  11. © 2024 Algomatic Inc. 認知アーキテクチャ OpenAI's Bet on a Cognitive

    Architecture - LangChain Blog https://blog.langchain.dev/openais-bet-on-a-cognitive-architecture/ 24 AIがどのように情報を処理し、理解し、⾏動を決定するかという根本的なフ レームワーク
  12. © 2024 Algomatic Inc. 認知アーキテクチャ 25 種別 処理のアウト プット 次の処理選択

    利用可能なシー ケンス Code コードで記述 コードで記述 コードで記述 LLM Call LLMによる応答 (単一呼び出し) コードで記述 コードで記述 Chain LLMによる応答 (複数呼び出し) コードで記述 コードで記述 Router LLMによる応答 LLMによる選択 (ただしループはしない) コードで記述 StateMachine LLMによる応答 LLMによる選択 (ループあり) コードで記述 Agent LLMによる応答 LLMによる選択 LLMによる定義
  13. © 2024 Algomatic Inc. 認知アーキテクチャ 26 種別 処理のアウト プット 次の処理選択

    利用可能なシー ケンス Code コードで記述 コードで記述 コードで記述 LLM Call LLMによる応答 (単一呼び出し) コードで記述 コードで記述 Chain LLMによる応答 (複数呼び出し) コードで記述 コードで記述 Router LLMによる応答 LLMによる選択 (ただしループはしない) コードで記述 StateMachine LLMによる応答 LLMによる選択 (ループあり) コードで記述 Agent LLMによる応答 LLMによる選択 LLMによる定義 LLMを使わないアプ リケーション Assistant API / GPTs
  14. © 2024 Algomatic Inc. 認知アーキテクチャ 27 種別 処理のアウト プット 次の処理選択

    利用可能なシー ケンス Code コードで記述 コードで記述 コードで記述 LLM Call LLMによる応答 (単一呼び出し) コードで記述 コードで記述 Chain LLMによる応答 (複数呼び出し) コードで記述 コードで記述 Router LLMによる応答 LLMによる選択 (ただしループはしない) コードで記述 StateMachine LLMによる応答 LLMによる選択 (ループあり) コードで記述 Agent LLMによる応答 LLMによる選択 LLMによる定義 RAGは現状これ が多い
  15. © 2024 Algomatic Inc. LangGraph 認知アーキテクチャにおける、StateMachineを実装するためのライブラリ NodeとEdge、およびStateを 定義することで、宣⾔的に StateMachineを実装できる 28

    const workflow = new StateGraph({ channels: graphState }); workflow.addNode("カテゴリ推定", (state: AgentState) => { // カテゴリ推定処理を記述 }); workflow.addNode("ナレッジ検索", (state: AgentState) => { // ナレッジ検索処理を記述 }); workflow.addEdge(START, "カテゴリ推定"); workflow.addConditionalEdges("カテゴリ推定", (state: AgentState) => { if (state.カテゴリ推定成功 ()) { return "ナレッジ検索"; } return "再質問"; });
  16. © 2024 Algomatic Inc. まとめ RAGシステム、最初はシンプルだが、やがて複雑なアプリケーションに変貌して いく。 • 「アクション」と「状態遷移」そのものが関⼼ごと ◦

    それらを変更しやすいアーキテクチャを⽬指そう これらはRAGに限らず、LLMを活⽤する場合によく直⾯する • LLMは「動かしてみないとわからない」ことが多い ◦ 状態遷移やアクションは頻繁に変更したくなる ◦ ⾼速な試⾏錯誤がプロダクトの優位性にもつながる 30