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

Contextual Retrievalをやってみた

moritalous
October 28, 2024
130

Contextual Retrievalをやってみた

【生成AI/LLM LT大会】今注目している技術や最新動向を共有!
https://blueish.connpass.com/event/333518/

で発表した資料です。

moritalous

October 28, 2024
Tweet

Transcript

  1. 自己紹介 森田 和明 富士ソフト株式会社 主任 / フェロー(アーキテクト・エバンジェリスト) AWS Ambassador(2023~) AWS Top

    Engineer(2020~) AWS All Certifications Engineer(2024) AWS Community Builder(2024) 生成AIに限らず、AWS関係のアーキテクトとエバンジェリストをやってます Java Webアプリ開発出身 新しいもの好き X / Qiita / GitHub : @moritalous 2 「Jumping deer with japanese temple」 Amazon Titan Image Generatorにて生成
  2. 従来のRAGの概要① 5 • 生成AI単体では、最新情報や専門分野に関する知識がないため誤った回答を 生成をしてしまう • RAG(Retrieval-Augmented Generation:検索拡張生成)という手法を 使用することで回答精度を向上させることができる •

    RAGでは一般的に以下のような処理を行う ◦ ドキュメント小さなチャンクに分割する(通常は数百トークン程度) ◦ 埋め込みモデルを使用してチャンクをベクトルに変換する ◦ ベクトルをデータベースに登録し、類似のチャンクを検索する(セマンティッ ク検索)
  3. 従来のRAGの課題 7 • チャンクに分割することによりコンテキスト(文脈)がなくなってしまう • 財務情報を対象にチャンク分割を行うと以下のようなチャンクが発生してしま う • この課題の解決法として「Contextual Retrieval」が紹介されています

    ****株式会社の2024年の決算について報告します。 会社の収益は前四半期より 3% 増加しました。 この業界では**の影響をうけた結果となりました。 チャンク→ 会社の収益は前四半期より 3% 増加しました。 どこの会社? 何年度?? 原因は??
  4. 手順 12 1. HTMLを取得し整形しMarkdown化 2. LangChainのDocument Loaderで500トークンごとにチャンク分け import requests from

    bs4 import BeautifulSoup from markdownify import markdownify as md url = "https://ja.wikipedia.org/wiki/進撃の巨人" response = requests.get(url) soup = BeautifulSoup(response.text) body = soup.find("div", id="bodyContent") for target in ["style", "script", "noscript"]: tags = body.find_all(target) for t in tags: t.clear() md_contents = md(body.decode_contents(),   strip=["a", "head", "script", "style"]).strip() print(md_contents) from langchain_core.documents import Document from langchain_text_splitters import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=30, ) documents = [Document(page_content=md_contents, metadata={"source": url})] documents = text_splitter.split_documents(documents)
  5. チャンクの例 13 • 単純に分割したチャンク 圧倒的な力を発揮する「獣の巨人」に対し、エルヴィンは自らと新兵たちの特攻を囮にした奇襲作戦を実行する。エルヴィ ンと新兵たちは「獣の巨人」の投石によって無惨にも散っていった。そして作戦通りに、リヴァイは「獣の巨人」がエル ヴィン達の特攻に気を取られているうちに「獣の巨人」に接近して奇襲を仕掛け、「獣の巨人」との戦闘になる。リヴァイ の圧倒的な力の前に「獣の巨人」は為す術もなく切り刻まれ、遂に本体であるジークを巨人の体の中から引きずり出し、捕 らえることに成功する。 リヴァイは、エルヴィンに渡されていた「注射薬」によって生き残りの兵士に「獣の巨人」の力を継承させようと、周りを

    見渡して生き残りを探すが、その直後、突然現れた「四足歩行型の巨人」によってジークは救出されてしまう。更に、「鎧 の巨人」もミカサの雷槍により倒されるが、ライナーもまた「四足歩行型の巨人」に救出され、ベルトルト以外の壁外勢力 3人は撤退する。 • 生成した「チャンクの文脈を説明する短文」 「ウォール・マリア最終奪還作戦」に関する記述。 チャンクの文内では「ウォール・マリア最終 奪還作戦」とは触れられていない (前後のチャンクには存在)
  6. 出来上がったチャンク 14 • 組み合わせてできたチャンク 「ウォール・マリア最終奪還作戦」に関する記述。 圧倒的な力を発揮する「獣の巨人」に対し、エルヴィンは自らと新兵たちの特攻を囮にした奇襲作戦を実行する。エルヴィ ンと新兵たちは「獣の巨人」の投石によって無惨にも散っていった。そして作戦通りに、リヴァイは「獣の巨人」がエル ヴィン達の特攻に気を取られているうちに「獣の巨人」に接近して奇襲を仕掛け、「獣の巨人」との戦闘になる。リヴァイ の圧倒的な力の前に「獣の巨人」は為す術もなく切り刻まれ、遂に本体であるジークを巨人の体の中から引きずり出し、捕 らえることに成功する。

    リヴァイは、エルヴィンに渡されていた「注射薬」によって生き残りの兵士に「獣の巨人」の力を継承させようと、周りを 見渡して生き残りを探すが、その直後、突然現れた「四足歩行型の巨人」によってジークは救出されてしまう。更に、「鎧 の巨人」もミカサの雷槍により倒されるが、ライナーもまた「四足歩行型の巨人」に救出され、ベルトルト以外の壁外勢力 3人は撤退する。 なるほど これだと検索精度が良くなりそうだ だがしかし
  7. コストが気になる 16 • 毎回ドキュメント全体を含めて「チャンクの文脈を説明する短文」を作成させて いる 入力トークン:136,150トークン $0.03404 出力トークン:36トークン $0.00005 合計:$0.03408

    / 1チャンク 「ウォール・マリア最終奪還作戦」に関する記述。 1ドキュメント(383チャンク)だと$13.05 高い... ←ここに毎回ドキュメント全体を含めている 入力プロンプト 出力プロンプト
  8. そんなあなたに「プロンプトキャッシュ」 17 • Claudeではベータ機能として「プロンプトキャッシュ」が提供されています (AWSのAmazon Bedrockでは未提供) • キャッシュへの登録はちょっとだけ割高だけど、キャッシュからの取得は激安 message =

    client.beta.messages.create( max_tokens=1024, messages=[ { "role": "user", "content": [ { "type": "text", "text": TEMPLATE_1.replace("{WHOLE_DOCUMENT}", md_contents), "cache_control": {"type": "ephemeral"}, }, { "type": "text", "text": TEMPLATE_2.replace( "{CHUNK_CONTENT}", document.page_content ), }, ], } ], model=model, ) from anthropic import Anthropic client = Anthropic( api_key=api_key, default_headers={ "anthropic-beta": "prompt-caching-2024-07-31" }, ) プロンプトキャッシュを使えば 1ドキュメント$1.66 87%割安!!
  9. • 最大10,000メッセージまたは最大32MBを上限に送信し、バッチで処理を実 行 • コストはリアルタイム推論の50%! • キャッシュとバッチは同時利用が可能 • 24時間以内に処理が完了する •

    気長に待つのかと思いきや、爆速でした。。 (ベータ版だからかもですが、50チャンク分を1分以内に処理できました) • 金額算出は間に合いませんでしたが、十分に利用価値はありそう!! 10/8にバッチAPIが登場しました!(ベータ版) 21
  10. コード例 22 batches_response = client.beta.messages.batches.create( betas=["prompt-caching-2024-07-31"], requests=[ { "custom_id": f"id_{n}",

    "params": { "model": model, "max_tokens": 1024, "messages": [ { "role": "user", "content": [ { "type": "text", "text": TEMPLATE_1.replace( "{WHOLE_DOCUMENT}", md_contents ), "cache_control": {"type": "ephemeral"}, }, { "type": "text", "text": TEMPLATE_2.replace( "{CHUNK_CONTENT}", doc.page_content ), }, ], } ], }, } for n, doc in enumerate(batch_doc) ], )