DeepSeek-R1で「思考するRAG」を構築!深い思考で精度向上

DeepSeek-R1で「思考するRAG」を構築!深い思考で精度向上

DeepSeek-R1は、OpenAI o1モデルのように高度な推論能力を活かした「深い思考プロセス」を強みとしています。

RAGにDeepSeek-R1を組み込むことで、深い思考を活かした精度の高い生成ができるようになります。

この記事では、DeepSeek-R1を使って「思考するRAG」を構築する方法を紹介します。

ざっくり言うと

  • DeepSeek-R1の深い思考プロセスを通じて、精度の高いRAG生成ができる
  • DeepSeek-R1とLangChainを使ってRAGを構築する
  • サイバーエージェントが公開したDeepSeek-R1の日本語モデルを使用

2/25開催の無料ウェビナー!

目次

DeepSeek-R1で構築する「思考するRAG」とは?

見出し画像

DeepSeek-R1は、OpenAIのo1モデルに匹敵する性能を持つ最高級のオープンソースLLMです。

o1モデルのように高度な推論能力を活かした「深い思考プロセス」を強みとしています。

RAGにDeepSeek-R1を組み込むことで、深い思考を活かした精度の高い生成ができるようになります。

DeepSeek-R1の高度な推論能力とは?

DeepSeek-R1は日本語で使える?

DeepSeek-R1 RAGの環境構築

見出し画像

この記事で用意した実行環境は以下のとおりです。

  • GPU:NVIDIA A100 80GB
  • GPUメモリ(VRAM):80GB
  • OS :Ubuntu 22.04
  • Docker

Dockerで環境構築

Dockerを使用してRAGの環境を構築をします

Dockerの使い方は?

STEP
Dockerfileの作成

Ubuntuのコマンドラインで、Dockerfileを作成します。

mkdir deepseekr1_rag
cd deepseekr1_rag
nano Dockerfile

Dockerfileに以下の記述を貼り付けます。

# ベースイメージ(CUDA)の指定
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y python3-pip python3-venv git nano curl

RUN curl -fsSL https://ollama.com/install.sh | sh

# 作業ディレクトリを設定
WORKDIR /app

# アプリケーションコードをコピー
COPY . /app

# Python仮想環境の作成
RUN python3 -m venv /app/.venv

# 仮想環境をアクティベートするコマンドを.bashrcに追加
RUN echo "source /app/.venv/bin/activate" >> /root/.bashrc

# JupyterLabのインストール
RUN /app/.venv/bin/pip install Jupyter jupyterlab

# LangChain関連のインストール
RUN /app/.venv/bin/pip install ollama==0.4.4 langchain-ollama langchain langsmith langchain-chroma faiss-gpu langchain-community langchain_huggingface langchain_core tiktoken

# コンテナの起動時にbashを実行
CMD ["/bin/bash"]

[Ctrl + S]キーで変更内容を保存し、[Ctrl + X]キーで編集モードから抜けます。

コマンドの説明
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04

CUDA12.1のベースイメージを指定しています。

RUN apt-get update && apt-get install -y python3-pip python3-venv git nano curl

Python関連のパッケージをインストールしています。

RUN curl -fsSL https://ollama.com/install.sh | sh

Linux用のOllamaをインストールします。

RUN /app/.venv/bin/pip install ollama==0.4.4 langchain-ollama langchain langsmith langchain-chroma faiss-gpu langchain-community langchain_huggingface langchain_core tiktoken

Python用のOllamaとLangChain関連のパッケージをインストールします。

LLMはOllamaのライブラリを使って動かしますので、PyTorchやTransformerは別途インストール不要です。

STEP
docker-compose.ymlファイルの作成

docker-compose.ymlを使用してDockerコンテナの設定をします。

docker-compose.ymlのYAMLファイルを作成して開きます。

nano docker-compose.yml

以下のコードをコピーして、YAMLファイルに貼り付けます。

services:
  deepseekr1_rag:
    build:
      context: .
      dockerfile: Dockerfile
    image: deepseekr1_rag
    runtime: nvidia
    container_name: deepseekr1_rag
    ports:
      - "8888:8888"
    volumes:
      - .:/app/deepseekr1_rag
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
    command: >
      bash -c '/usr/local/bin/ollama serve & /app/.venv/bin/jupyter lab --ip="*" --port=8888 --NotebookApp.token="" --NotebookApp.password="" --no-browser --allow-root'

[Ctrl + S]キーで変更内容を保存し、[Ctrl + X]キーで編集モードから抜けます。

コマンドの説明
bash -c '/usr/local/bin/ollama serve

Ollama Serverを起動しています。

PythonのOllamaを使用する際に、Ollama Serverを起動しておく必要がありますので、ご注意ください。

& /app/.venv/bin/jupyter lab --ip="*" --port=8888 --NotebookApp.token="" --NotebookApp.password="" --no-browser --allow-root'

Jupyter Labを8888番ポートで起動しています。

STEP
Dockerコンテナを起動

Dockerfileからビルドしてコンテナを起動します。   

docker compose up

 

Dockerの起動後にブラウザの検索窓に”localhost:8888″を入力すると、Jupyter Labをブラウザで表示できます。

localhost:8888

DeepSeek-R1 RAGの実装

見出し画像

Dockerコンテナで起動したJupyter Lab上でRAGの実装をします。

LangChainを使ったRAGの実装方法は?

STEP
環境変数の設定

LangChainに関する環境変数を設定します。

import os
from uuid import uuid4

unique_id = uuid4().hex[0:8]

os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = f"deepseekr1_rag - {unique_id}"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "***************"
コードの説明
unique_id = uuid4().hex[0:8]

8桁のランダムな一意の識別子を生成しています。

os.environ["LANGCHAIN_TRACING_V2"] = "true"

この設定により、LangChainのトレースが可能になります。

os.environ["LANGCHAIN_PROJECT"] = f"deepseekr1_rag - {unique_id}"

LangChainプロジェクトの名前を設定しています。

ここでは、生成したunique_idを使用してプロジェクト名を「langchainrag – {unique_id}」の形式で一意にしています。

os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"

LangsmithのAPIエンドポイントを指定しています。

os.environ["LANGCHAIN_API_KEY"] = "***************"

LangChain APIを利用するためのAPIキーを設定しています。

STEP
LLMの設定

HuggingFaceから「mmnga/cyberagent-DeepSeek-R1-Distill-Qwen-32B-Japanese-gguf」をダウンロードします。

サイバーエージェントが公開したDeepSeek-R1の日本語モデルです。

!curl -L -o cyberagent-DeepSeek-R1-Distill-Qwen-32B-Japanese-Q4_K_M.gguf "https://huggingface.co/mmnga/cyberagent-DeepSeek-R1-Distill-Qwen-32B-Japanese-gguf/resolve/main/cyberagent-DeepSeek-R1-Distill-Qwen-32B-Japanese-Q4_K_M.gguf?download=true"

DeepSeek-R1の他のモデルは?

ダウンロードしたモデルをOllamaで使えるように設定します。

import ollama
from langchain_ollama.chat_models import ChatOllama

modelfile='''
FROM ./cyberagent-DeepSeek-R1-Distill-Qwen-32B-Japanese-Q4_K_M.gguf
TEMPLATE """{{- if .System }}{{ .System }}{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1}}
{{- if eq .Role "user" }}<|User|>{{ .Content }}
{{- else if eq .Role "assistant" }}<|Assistant|>{{ .Content }}{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- if and $last (ne .Role "assistant") }}<|Assistant|>{{- end }}
{{- end }}"""
PARAMETER stop <|begin▁of▁sentence|>
PARAMETER stop <|end▁of▁sentence|>
PARAMETER stop <|User|>
PARAMETER stop <|Assistant|>
'''
ollama.create(model='deepseekr1-32b-jpn', modelfile=modelfile)

llm = ChatOllama(model='deepseekr1-32b-jpn', temperature=0)
コードの説明
modelfile='''

モデルファイルを定義します。

モデルファイルは、Ollamaでカスタムモデルを設定するためのスクリプトです。

FROM ./cyberagent-DeepSeek-R1-Distill-Qwen-32B-Japanese-Q4_K_M.gguf

ダウンロードしたモデルのパスが入ります。

TEMPLATE """{{- if .System }}{{ .System }}{{ end }}...

モデルで使用するプロンプトテンプレートが入ります。

プロンプトテンプレートはモデルによって異なりますので、ご注意ください。

ollama.create(model='deepseekr1-32b-jpn', modelfile=modelfile)

モデルとプロンプトテンプレートを使ってOllama用のモデルを作成します。

modelにはOllamaで呼び出す際に使用する名前をつけられます。

ChatOllama(model='deepseekr1-32b-jpn', temperature=0)

LangChainでモデルを実行できる状態にしています。

ollama.createのエラー「invalid digest format」の解消方法

Ollamaの詳しい使い方は?

STEP
Wikipediaからテキストを抽出

Wikipediaからテキストデータを抽出して、読み込みます。

Wikipediaの『葬送のフリーレン』からテキストを抽出しています。

from langchain_community.document_loaders import WebBaseLoader

urls = [
"https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3"
]

docs = [WebBaseLoader(url).load() for url in urls]
docs_list = [item for sublist in docs for item in sublist]
コードの説明
WebBaseLoader(url).load()

指定したWebページのHTMLを取得・解析し、使いやすいデータ構造に変換して読み込みます。

STEP
テキストをチャンクに分割

読み込んだデータをチャンクに分割します。

データベースの検索精度の向上や効率的な処理のためにチャンク分割が必要になります。

from langchain.text_splitter import CharacterTextSplitter

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    separator = "\n",
    chunk_size= 1000,
    chunk_overlap=100,
)

doc_splits = text_splitter.split_documents(docs_list)
doc_splits[12:15]
コードの説明
CharacterTextSplitter.from_tiktoken_encoder...

テキストを指定された条件でチャンクに分割しています。

separator = "\n"

チャンクを分割する際の区切り文字を「\n」として指定します。

chunk_size= 1000

各チャンクが1000文字を超えないように分割されます。

chunk_overlap=100

各チャンクが100文字分重複するように設定しています。

確認のため、分割したチャンクを3つ表示しています。

[Document(metadata={'source': 'https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3', 'title': '葬送のフリーレン - Wikipedia', 'language': 'ja'}, page_content='これからのフリーレンの人生を「想像もできないほど、長いものになる」といい、後日の再会を約束するも、彼女が次に訪れたのは自身の晩年である50年後だった。「たった10年一緒に旅をしただけ」の彼の死がフリーレンに与えた影響は大きく、彼のことを知ろうとしなかったことで大きな後悔の念を抱かせることとなる。\n初対面時からフリーレンの強さを直感で見抜き、自身のパーティーに勧誘した。魔族の本質を知らなかったために、フリーレンの忠告を無視して人を食った魔族の少女を見逃したことがあるが、のちに彼女がまた人を殺めたと言う苦い経験をしている。勇者のみが抜ける「勇者の剣」がある里で剣を抜こうと挑戦して失敗したが、「偽物の勇者でもかまわない、魔王を倒せば偽物でも本物でも関係ない」と話して実際にそれを成し遂げ、フリーレンからも「あんな剣が無くてもヒンメルは本物の勇者」だと評され、剣が抜けなかったという一件は秘匿された[注 8]。'),
 Document(metadata={'source': 'https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3', 'title': '葬送のフリーレン - Wikipedia', 'language': 'ja'}, page_content='困った人を決して見捨てない性格で、その生涯をかけて人助けに奔走したようである。死後も作中での存在感は大きく、「ヒンメルならどうしたか」がフリーレンを始めとする元勇者パーティーメンバーの行動基準のひとつであり続けており、フリーレンの回想中にも、たびたびその勇者ぶりが振り返られる。かつてフリーレンに恋心を抱いていたと思わせるようなエピソードも多い。幼いころに森で道に迷ったときにフリーレンと出会っており、花畑の魔法を見せてもらったことがある。エルフであるがゆえにはるかに長命であるフリーレンの未来をおもんぱかって銅像に細かく注文をしたり、故郷を魔族に奪われて孤独に生きてきた彼女を思いやったりと、何かと気にかけていた。女神の石碑に触れて過去に戻ったフリーレンと出会った際は、彼女が未来から来たという事実を素直に受け入れている。\nハイター (Heiter)\n声 - 東地宏樹[15]\n人間出身の僧侶。戦災孤児で、ヒンメルとは同郷の幼なじみ。魔王討伐後は聖都の司教となり、偉大な僧侶として人々の尊敬を集めた。穏やかで明るい性格だが、お酒が大好きな生臭坊主。大酒飲みであったにも関わらず、ヒンメルの死後も20年以上に渡り生き続けるなど人間としてはかなりの長寿を保った。ただし、晩年は体調を崩したこともあって酒を絶った様子である。'),
 Document(metadata={'source': 'https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3', 'title': '葬送のフリーレン - Wikipedia', 'language': 'ja'}, page_content='最晩年、戦災孤児であるフェルンを引き取り、訪ねてきたフリーレンにちょっとした計略をしかけてフェルンを彼女の弟子として託すことで、自分の死後の悩みを解決した。かつては自身が孤児だったことから、孤児院の復興資金をみずから捻出したこともあった。その存在は、フェルンにとって「育ての親」として死後も大切なものとなっている。ザインからも、ハイターは自分と違って優しく頼りがいのある理想的な大人だったと評される。\nアイゼン (Eisen)\n声 - 上田燿司[15]\nドワーフ族出身の戦士。エルフほどではないが人間よりははるかに長命で、ヒンメルやハイターの死後も容姿の変化があまり見られない。非常に頑強な肉体をもち、過去に竜を昏倒させるほどの猛毒の矢を受けても平気でいたり、自由落下程度ならどんな高さから落ちても無傷な姿を見せた際はハイターを驚かせた。魔族からも「人類最強の戦士」として名を知られるほどだが、本人は「俺より強いやつが皆先に死んだだけ」と自らを評する。フリーレンとの再会時も超人ぶりを発揮する一方で、肉体は着実に細く老化しつつあり、ヒンメルの死後にフリーレンから再度同行を請われた際は「もう斧を振れる歳じゃない」と拒否する。')]
STEP
埋め込みモデルの設定

テキストをベクトル表現に変換する埋め込みモデルを読み込みます。

日本語性能が高く、無料で使える埋め込みモデル「intfloat/multilingual-e5-large」を指定しています。

from langchain_huggingface import HuggingFaceEmbeddings

embedding = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large")
STEP
リトリーバー設定

リトリーバーとは、クエリをもとにベクトルデータベースから関連情報を検索・取得する機能です。

リトリーバーの実装には、GPUを活用した高速ベクトル検索が可能な「FAISS」ライブラリを使用しています。

from langchain.vectorstores import FAISS

vectorstore = FAISS.from_documents(doc_splits, embedding)
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 3})
question = "フリーレンとは"
retriever.invoke(question)
コードの説明
FAISS.from_documents(splits, embedding)

ベクトルストアを作成しています。

ベクトルストアは、テキストデータなどベクトル化して格納し、意味的検索や類似検索を行うためのデータベースです。

retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 3})

リトリーバーを作成しています。

リトリーバーは、ユーザーの質問に関連する情報をベクトルストアから検索して抽出する機能です。

search_type="similarity":検索の方法として「類似度検索」を指定しています。

search_kwargs={"k": 3}:検索結果として上位3件の類似ドキュメントを返す設定です。

retriever.invoke(question)

検索クエリをリトリーバーに渡し、類似したドキュメントを検索します。

「フリーレンとは」というクエリに対して、リトリーバーが返した結果

[Document(id='bd6a0798-bda1-4776-9d0b-150005fb4c6d', metadata={'source': 'https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3', 'title': '葬送のフリーレン - Wikipedia', 'language': 'ja'}, page_content='葬送のフリーレン - Wikipedia\nコンテンツにスキップ\nメインメニュー\nメインメニュー\nサイドバーに移動\n非表示\n\t\t案内\n\t\nメインページコミュニティ・ポータル最近の出来事新しいページ最近の更新おまかせ表示練習用ページアップロード (ウィキメディア・コモンズ)特別ページ\n\t\tヘルプ\n\t\nヘルプ井戸端お知らせバグの報告ウィキペディアに関するお問い合わせ\n検索\n検索\n表示\n寄付\nアカウント作成\nログイン\n個人用ツール\n寄付 アカウント作成 ログイン\n\t\tログアウトした編集者のページ もっと詳しく\n投稿記録トーク\n目次\nサイドバーに移動\n非表示\nページ先頭\n1\n概要\n2\nあらすじ\n3\n登場人物\n登場人物サブセクションを切り替えます\n3.1\n主要人物(フリーレン一行)\n3.2\n勇者パーティー(ヒンメル一行)\n3.3\n北側諸国\n3.4\n一級試験受験者\n3.5\n大陸魔法協会\n3.6\n帝国領\n3.7\n魔族\n3.8\nその他\n4\n魔法\n魔法サブセクションを切り替えます\n4.1\n民間魔法\n4.2\n魔族の魔法\n4.3\n女神様の魔法\n5\n魔物\n6\n用語\n用語サブセクションを切り替えます\n6.1\n世界観\n6.2\n国家・組織\n6.3\n地名・施設\n6.4\n種族・生物\n6.5\n魔族関連\n6.6\nその他の用語\n7\n社会的評価・受賞\n8\n書誌情報\n書誌情報サブセクションを切り替えます\n8.1\n単行本\n8.2\n関連書籍\n9\nテレビアニメ\nテレビアニメサブセクションを切り替えます\n9.1\n制作\n9.1.1\n企画・スタッフィング\n9.1.2\n演出\n9.1.3\n音楽\n9.1.4\nキャスティング\n9.1.5\nプロモーション\n9.2\nスタッフ(テレビアニメ)\n9.3\n主題歌\n9.4'),
 Document(id='9b93cec0-a77e-48ae-9559-e31aa7c02963', metadata={'source': 'https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3', 'title': '葬送のフリーレン - Wikipedia', 'language': 'ja'}, page_content='2020年22・23合併号 -\n発表期間\n2020年4月28日[1] -\n巻数\n既刊13巻(2024年4月現在)\nアニメ\n原作\n山田鐘人、アベツカサ\n監督\n斎藤圭一郎\nシリーズ構成\n鈴木智尋\n脚本\n鈴木智尋\nキャラクターデザイン\n長澤礼子\n音楽\nEvan Call\nアニメーション制作\nマッドハウス\n製作\n「葬送のフリーレン」製作委員会\n放送局\n日本テレビ系列ほか\n放送期間\n第1期:2023年9月29日 - 2024年3月22日\n話数\n第1期:全28話\nその他\n第1話 - 第4話は『金曜ロードショー』で放送\nアニメ:葬送のフリーレン 〜●●の魔法〜\n原作\n山田鐘人、アベツカサ\nキャラクターデザイン\nめばち\n音楽\nEvan Call\nアニメーション制作\nTOHO animation STUDIO\n製作\n「葬送のフリーレン」製作委員会\n配信サイト\nYouTubeほか\n配信期間\n2023年10月11日 -\nテンプレート - ノート\nプロジェクト\n漫画・アニメ\nポータル\n漫画・アニメ\n『葬送のフリーレン』(そうそうのフリーレン)は、山田鐘人(原作)、アベツカサ(作画)による日本の漫画。『週刊少年サンデー』(小学館)にて、2020年22・23合併号より連載中[1]。\n2021年に第14回マンガ大賞および第25回手塚治虫文化賞新生賞を、2023年に第69回小学館漫画賞、2024年に第48回講談社漫画賞受賞。\n概要\n魔王を倒した勇者一行の後日譚を描くファンタジー[1]。'),
 Document(id='11e138ba-5b49-4834-b113-468ac8ff6564', metadata={'source': 'https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3', 'title': '葬送のフリーレン - Wikipedia', 'language': 'ja'}, page_content='概要\n魔王を倒した勇者一行の後日譚を描くファンタジー[1]。\n原作担当の山田の前作である『ぼっち博士とロボット少女の絶望的ユートピア』の連載終了後、いくつかの読切のネームを描くもうまくいかず、担当編集者から、最初の受賞作が勇者・魔王物のコメディーだったことから、その方向でギャグを描いてみてはと提案したところ、いきなり『葬送のフリーレン』の第1話のネームが上がってきた[2][3]。その後、作画担当をつけることになり、同じく担当していたアベにネームを見せたところ「描いてみたい」と反応があり、フリーレンのキャラ絵を描いてもらったところ、山田からも「この方ならお願いしたい」と返答をもらったため、アベが作画担当になった[2][3]。ちなみにマンガ大賞を受賞した2021年3月現在、山田とアベは一度も会ったことがないという[2]。\n本作のタイトルの由来は、山田が考えたタイトル案がありながら、編集部でも検討をし、編集部会議で「いいタイトルが決まったら自腹で賞金1万円出します」と担当編集者が募ったところ、副編集長が出したタイトル案の中に「葬送のフリーレン」があり、最終的に山田、アベに決めてもらい現在の題名となった[4]。\n2022年にテレビアニメ化が発表された[5][6]。第1期は2023年9月から2024年3月まで、日本テレビ系列ほかにて連続2クールで放送された[7]。第2期の制作が決定している[8]。\nあらすじ')]
STEP
プロンプトテンプレートの設定

プロンプトに使用する構文(プロンプトテンプレート)を設定しています。

from langchain_core.prompts import PromptTemplate

prompt = PromptTemplate(
    template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> 
    与えられた参考情報をもとに質問に回答してください。
    <|eot_id|><|start_header_id|>user<|end_header_id|>
    質問: {question} 
    参考情報: {context} 
    回答: <|eot_id|><|start_header_id|>assistant<|end_header_id|>""",
    input_variables=["question", "context"],
)
コードの説明
PromptTemplate()

プロンプトのテンプレートを定義するために使用されるクラスです。

テンプレート内で、指定された変数に動的に値を埋め込み、LLMに指示を与えるプロンプトを生成します。

template には、LLMに対してどのような指示を与えるかを記述します。

<|begin_of_text|><|start_header_id|>system<|end_header_id|> ...<|eot_id|>には、システムプロンプトが入ります。

<|start_header_id|>user<|end_header_id|>...<|eot_id|>には、ユーザーの質問が入ります。

<|start_header_id|>assistant<|end_header_id|>...には、LLMの回答が入ります。

input_variables では、テンプレート内で動的に置き換えられる変数名をリストで指定します。

この場合、questioncontextの2つの変数が指定されています。

STEP
RAGチェーンの構築

ユーザーからの質問とリトリーバーからの取得情報をもとにプロンプトを作成し、モデルに渡すRAGチェーンを構築します。

from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

rag_chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llm | StrOutputParser()
コードの説明
{"context": retriever, "question": RunnablePassthrough()} | prompt | llm | StrOutputParser()

プロンプトの生成、LLMによる回答生成、文字列形式での出力までを、一連の処理として統合したチェーンを構築しています。

"context": retrieverユーザーの質問から関連する情報をリトリーバーで検索・取得し、その情報を”context”としてプロンプトに渡します。

"question": RunnablePassthrough()ユーザーの質問を変換せずにそのまま”question”としてプロンプトに渡します。

| prompt

定義したテンプレートに”context”と”question”を挿入してプロンプトを作成し、LLMに渡します。

| llm

渡されたプロンプトをもとにLLMがテキストを生成します。

| StrOutputParser()

出力形式を文字列として扱うパーサーです。

DeepSeek-R1 RAGに『葬送のフリーレン』について聞いてみる

見出し画像

DeepSeek-R1 RAGを使って、『葬送のフリーレン』について質問してみます。

質問(1)

response = rag_chain.invoke("フリーレンの性格を教えて下さい。")
print(response)

フリーレンの性格を教えて下さい。

回答

<think>
まず、ユーザーがフリーレンの性格を知りたいと質問しています。提供された参考情報は3つのドキュメントで、それぞれ異なる側面からフリーレンについて説明されています。

最初のドキュメントでは、フリーレンの性格を「ドライで厳しいが普段は優しく面倒見がある」と述べています。表情に乏しく淡々としているが、大好きな魔導書や食い意地、朝の弱さなど、感情表現が豊かになる場面があるとあります。また、エルフであるため人間の思考に鈍感でコミュニケーションが不器用な点も指摘されています。さらに、魔族への憎悪が深く、敵対する魔族に対しては問答無用で葬り去ろうとする姿勢があるようです。

次のドキュメントでは、フリーレンのダンジョン攻略に関する知識や宝箱に対する異常な興味について触れています。判別魔法でミミックと判断しても宝箱を開け、結果として上半身を噛まれる場面が繰り返されるというエピソードがあります。これは彼女の冒険心やリスクを恐れない性格を示していると考えられます。

3つ目のドキュメントはフェルンについての情報で、フリーレンの弟子であるフェルンの性格や行動が記載されています。ただし、このドキュメントは直接フリーレンの性格に関する情報ではないため、回答には含めない方が良いでしょう。

これらの情報を整理すると、フリーレンの性格は以下の特徴にまとめられます:
1. ドライで厳しいが優しく面倒見がある。
2. 表情に乏しく淡々とした態度だが、特定のことに感情を表す。
3. 人間の思考に鈍感でコミュニケーションが不器用。
4. 魔族への憎悪が強く、敵対する魔族に対しては容赦ない。
5. ダンジョン攻略に詳しいが、宝箱に対する異常な興味とリスクを恐れない性格。

これらのポイントを過不足なく回答に反映させる必要があります。また、情報の重複や矛盾がないか確認し、適切にまとめることが重要です。
</think>

フリーレンの性格は以下の特徴で構成されています:

1. **感情表現の二面性**  
   - 普段は表情に乏しく淡々とした態度だが、大好きな魔導書や食い意地、朝の弱さなど特定の場面では感情を豊かに表す。
   - 人間の思考・思想には鈍感でコミュニケーションが不器用な一方、魔族への憎悪は深く、敵対する魔族に対しては「問答無用で葬る」という強い意思を持つ。

2. **価値観と行動原理**  
   - 富や地位、名声には興味を示さないが、目的(例:魔導書の手に入れ)があれば無茶をすることも。
   - エルフとして長命ゆえに「人間の言葉で人間を欺く猛獣」という魔族の本質を理解し、彼らへの対応は冷徹。

3. **冒険心とリスクテイク**  
   - 「歴史上で最もダンジョンを攻略したパーティーの魔法使い」と自称するほどダンジョン知識が豊富。
   - 宝箱を開ける際には判別魔法で99%ミミックと判断しても1%の可能性に賭け、結果として上半身を噛まれる場面も繰り返される。

4. **周囲への影響**  
   - フェルン(弟子)からは「時間感覚が人間とかけ離れている」と辟易されつつも尊敬されている。
   - 甘い食べ物や飲酒に寛容な姿勢を示すなど、非冒険的な側面でも存在感を放つ。

これらの要素から、フリーレンは「冷徹さと優しさが共存し、リスクを恐れず目的に突き進む矛盾した性格」であると言えます。

Wkipediaのデータから必要な情報を抽出しながら、しっかり思考できています!

質問(2)

response = rag_chain.invoke("ヒンメルの性格を教えて下さい。")
print(response)

ヒンメルの性格を教えて下さい。

回答

<think>
まず、ユーザーがヒンメルの性格を尋ねているので、提供された参考情報から関連する部分を探します。各ドキュメントを見ると、ヒンメルに関する記述は主に最初の2つの文書にあります。

最初のドキュメントでは、フリーレンの回想の中でヒンメルが「困った人を決して見捨てない性格で、その生涯をかけて人助けに奔走した」と述べられています。また、フリーレンへの恋心や幼少期の出会い、エルフであるフリーレンの未来を気にかけるエピソードが挙げられています。

次のドキュメントでは、ハイター(ヒンメル)について「穏やかで明るい性格だが、お酒が大好き」とあり、人間としては長寿だったと書かれています。ただし、ここでの名前がハイターとなっている点に注意が必要です。もしかすると、ヒンメルとハイターは同じ人物なのか、あるいは別のキャラクターかもしれません。しかし、一般的な知識として「葬送のフリーレン」の主要キャラクターであるヒンメル(Heiter)は僧侶で、ハイターという名前が正しい可能性があります。この場合、回答ではハイターとヒンメルを同一人物として扱う必要があります。

さらに、3つ目のドキュメントにはフェルンに関する記述があり、ヒンメルの情報はありません。したがって、ヒンメルの性格は最初の2つの文書からまとめます。

重要なポイントは、「困った人を見捨てない」「人助けに奔走」「フリーレンへの恋心」「エルフの未来を気にかける」などです。また、ハイターとしての性格は穏やかで明るいが酒好きという点も含めると良いでしょう。

ただし、名前の不一致(ヒンメル vs ハイター)に注意が必要です。もしハイターがヒンメルの正しい名前であれば、回答ではそのように統一します。逆に、ヒンメルとハイターが別のキャラクターなら問題ですが、この作品ではハイターがヒンメルの本名である可能性が高いです。

最終的に、ヒンメル(ハイター)の性格を「困った人を見捨てず、人助けに尽力し、フリーレンへの深い愛情を持ち、穏やかで明るいが酒好き」とまとめます。
</think>

ヒンメル(Heiter)は、以下の特徴的な性格と行動様式を持つキャラクターです:

1. **利他主義的で献身的**  
   「困った人を決して見捨てない」信念を持ち、生涯を通じて人々の救済に尽力。フリーレンへの深い愛情や、エルフである彼女の未来を心配する姿勢がその典型です。

2. **穏やかで明るい性格**  
   幼少期から同郷のフリーレンと親交し、戦災孤児として育った経験にも関わらず、人間らしい温かみを持ちます。酒好きという生臭坊主的な一面も、その素直さを象徴しています。

3. **エルフへの特別な関心**  
   フリーレンの長命性や故郷の魔族侵攻を気にかけ、銅像に細かい注文をつけるなど、人間としての視点でエルフの存在を深く理解しています。

4. **時間的矛盾への冷静さ**  
   魔法で過去に戻ったフリーレンと出会った際も、「未来から来た」という事実を素直に受け入れる理性を持ちます。

5. **人間としての限界を超えた長寿**  
   20年以上生き続けるなど、人間としては異例な長寿を保ちつつも、晩年は体調不良で酒を断つなど、現実的な側面も併せ持ちます。

これらの要素が、ヒンメルの「人間らしさ」と「エルフへの特別な関与」を両立させる複雑な性格を形成しています。

取得したドキュメントの取捨選択にDeepSeek-R1の思考が効いています!

質問(3)

response = rag_chain.invoke("ファルンの好きな食べ物は?")
print(response)

ファルンの好きな食べ物は?

回答

<think>
まず、ユーザーからの質問は「ファルンの好きな食べ物は?」です。参考情報として提供された3つのドキュメントを確認します。

最初のドキュメント(ID:4e17a0c0-...)には、「甘い食べ物が好きで、フリーレンと一緒に結構な量の菓子を食す場面も多い」という記述があります。ここで「フェルン」が師匠であるフリーレンと共に菓子を食べる様子が述べられています。

次のドキュメント(ID:5a54adc1-...)では、フェルンについての情報はなく、主にフリーレンの性格や行動に関する記述があります。特に食べ物に関する言及はありません。

3つ目のドキュメント(ID:675e1fc7-...)もまた、フェルンではなくフリーレンの背景や能力について説明されており、食べ物に関する情報は含まれていません。

したがって、フェルンの好きな食べ物に関する直接的な記述は最初のドキュメントのみに存在します。ここで「甘い食べ物」が好きであることが明確に述べられているため、これが回答の根拠となります。
</think>

<|start_header_id|>assistant<|end_header_id|>  
フェルン(Fern)は**甘い食べ物**が好きです。特に菓子を大量に消費する場面が描かれており、師匠であるフリーレンと共に菓子を楽しむ様子が作品内で頻繁に登場します。この嗜好性は、フェルンの性格や行動パターンを反映した特徴的な描写となっています。

思考の過程が見えるのでわかりやすいです!

生成AI・LLMのコストでお困りなら

GPUのスペック不足で生成AIの開発が思うように進まないことはありませんか?

そんなときには、高性能なGPUをリーズナブルな価格で使えるGPUクラウドサービスがおすすめです!

GPUSOROBAN
GPUSOROBAN

GPUSOROBANは、高性能GPU「NVIDIA H200」を業界最安級の料金で使用することができます。

NVIDIA H200は、生成AI・LLMの計算にかかる時間を大幅に短縮することが可能です。

クラウドで使えるため、大規模な設備投資の必要がなく、煩雑なサーバー管理からも解放されます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
EdgeHUBロゴ

メールマガジン登録

Stable Diffusion・LLM・RAGに関する最新情報をいち早くお届けします。

無料メルマガの配信をご希望の方は、下記フォームよりご登録ください。

    EdgeHUB編集部からのお知らせ

    無料ウェビナーのお知らせ

    ウェビナー

    業界を震撼させた革新的LLM「DeepSeek-R1」の使い方を解説する無料ウェビナー!

    開催日時:
    2025年2月25日(火) 11:00~12:00

    内容:

    • DeepSeek-R1のローカル環境での使い方、日本語モデルの解説
    • 業界最安級GPUクラウド「GPUSOROBAN」の紹介・使い方デモ

    このウェビナーでは、「DeepSeek-R1」のデモを交えてGPUクラウドの使い方を紹介します。

    生成AIに関心のある方、AI技術をビジネスに活かしたい方は、ぜひこの貴重な機会にご参加ください!

    こんな方におすすめ!

    • DeepSeek-R1の安全性に不安を感じている方
    • DeepSeek-R1の日本語モデルを使いたい方
    • DeepSeek-R1を使ったRAGの構築方法を知りたい方
    • GPUのコスト、リソースに課題を感じている方

    希望者にはデモで使用したソースコードをプレゼント!

    \簡単30秒で申し込み!/

    この記事を書いた人

    EdgeHUBは、NVIDIAクラウドパートナーである株式会社ハイレゾが運営しています。「AIと共にある未来へ繋ぐ」をテーマに、画像生成AI、文章生成AI、動画生成AI、機械学習・LLM、Stable Diffusionなど、最先端の生成AI技術の使い方をわかりやすく紹介します。

    目次