Skip to content

Instantly share code, notes, and snippets.

@chottokun
Created April 14, 2025 15:00
Show Gist options
  • Save chottokun/8d5e05fddcb31e8e18d686ac5ea13c14 to your computer and use it in GitHub Desktop.
Save chottokun/8d5e05fddcb31e8e18d686ac5ea13c14 to your computer and use it in GitHub Desktop.
cl-nagoya-ruri-v3.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"gpuType": "T4",
"authorship_tag": "ABX9TyMXDOz0c4I3LTexw1WTWaVD",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/chottokun/8d5e05fddcb31e8e18d686ac5ea13c14/cl-nagoya-ruri-v3.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"id": "vN3Z4_Yq_T9U"
},
"outputs": [],
"source": [
"!pip install -q langchain_community sentence_transformers langchain_core langchain chromadb\n",
"!pip install -q unidic_lite fugashi"
]
},
{
"cell_type": "code",
"source": [
"from typing import List, Dict, Any, Optional\n",
"from langchain_core.embeddings import Embeddings\n",
"from sentence_transformers import SentenceTransformer\n",
"\n",
"class PrefixEmbeddings(Embeddings):\n",
" \"\"\"\n",
" LangChain用のPrefixEmbeddings埋め込みモデルラッパークラス\n",
" \"\"\"\n",
"\n",
" def __init__(\n",
" self,\n",
" model_name: str = \"l-nagoya/ruri-v3-310m\",\n",
" query_prompt_name: str = \"検索クエリ: \",\n",
" document_prompt_name: str = \"検索文章: \",\n",
" cache_folder: Optional[str] = None,\n",
" model_kwargs: Optional[Dict[str, Any]] = None,\n",
" encode_kwargs: Optional[Dict[str, Any]] = None,\n",
" ):\n",
" \"\"\"\n",
" 初期化メソッド\n",
"\n",
" Args:\n",
" model_name: Hugging Faceモデル名\n",
" query_prompt_name: クエリエンコード時のプロンプト名\n",
" document_prompt_name: ドキュメントエンコード時のプロンプト名\n",
" cache_folder: モデルキャッシュディレクトリ\n",
" model_kwargs: SentenceTransformerモデル初期化用の追加引数\n",
" encode_kwargs: encode関数用の追加引数\n",
" \"\"\"\n",
" self.model_name = model_name\n",
" self.query_prompt_name = query_prompt_name\n",
" self.document_prompt_name = document_prompt_name\n",
" self.cache_folder = cache_folder\n",
" self.model_kwargs = model_kwargs or {}\n",
" self.encode_kwargs = encode_kwargs or {}\n",
"\n",
" # SentenceTransformerモデルの初期化\n",
" self._model = SentenceTransformer(\n",
" model_name_or_path=model_name,\n",
" cache_folder=cache_folder,\n",
" prompts={\n",
" query_prompt_name: query_prompt_name,\n",
" document_prompt_name: document_prompt_name,\n",
" },\n",
" **self.model_kwargs\n",
" )\n",
"\n",
" def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
" \"\"\"\n",
" ドキュメントテキストをベクトル埋め込みに変換\n",
"\n",
" Args:\n",
" texts: 埋め込むドキュメントのリスト\n",
"\n",
" Returns:\n",
" 埋め込みベクトルのリスト\n",
" \"\"\"\n",
" # ドキュメント用プロンプトを使用してエンコード\n",
" encode_kwargs = {**self.encode_kwargs, \"prompt_name\": self.document_prompt_name}\n",
" embeddings = self._model.encode(texts, **encode_kwargs)\n",
" return embeddings.tolist()\n",
"\n",
" def embed_query(self, text: str) -> List[float]:\n",
" \"\"\"\n",
" クエリテキストをベクトル埋め込みに変換\n",
"\n",
" Args:\n",
" text: 埋め込むクエリテキスト\n",
"\n",
" Returns:\n",
" クエリの埋め込みベクトル\n",
" \"\"\"\n",
" # クエリ用プロンプトを使用してエンコード\n",
" encode_kwargs = {**self.encode_kwargs, \"prompt_name\": self.query_prompt_name}\n",
" embedding = self._model.encode(text, **encode_kwargs)\n",
" return embedding.tolist()\n"
],
"metadata": {
"id": "tCIKCjXmAMbt"
},
"execution_count": 2,
"outputs": []
},
{
"cell_type": "code",
"source": [
"from langchain_community.vectorstores import Chroma\n",
"from langchain_community.document_loaders import TextLoader\n",
"from langchain.text_splitter import CharacterTextSplitter\n",
"\n",
"# カスタムAMBER埋め込みモデルのインスタンス化\n",
"embeddings = PrefixEmbeddings(\n",
" model_name=\"cl-nagoya/ruri-large-v2\",\n",
" model_kwargs={\"device\": \"cuda\"},\n",
" query_prompt_name=\"検索クエリ: \",\n",
" document_prompt_name=\"検索文章: \"\n",
")\n",
"\n",
"# ドキュメントのロードと分割\n",
"loader = TextLoader(\"japanese_documents.txt\")\n",
"documents = loader.load()\n",
"text_splitter = CharacterTextSplitter(\n",
" separator = \"\", # セパレータ\n",
" chunk_size=4000,\n",
" chunk_overlap=0)\n",
"docs = text_splitter.split_documents(documents)\n",
"\n",
"# ChromaDBベクトルストアの作成\n",
"vectordb = Chroma.from_documents(\n",
" documents=docs,\n",
" embedding=embeddings,\n",
" persist_directory=\"vectorstore\"\n",
")\n",
"\n",
"# クエリの実行\n",
"query = \"劉備と曹操について教えてください\"\n",
"results = vectordb.similarity_search(query, k=1)\n",
"\n",
"# 結果の表示\n",
"for doc in results:\n",
" print(doc.page_content)\n",
" print(\"---\")\n"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "OV_ShAgeANrJ",
"outputId": "d88e620b-4c67-4f90-d4d4-30c0ccc01385"
},
"execution_count": 3,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"「これは県楼桑村の生れで、それがしとは幼少からの朋友です。劉備字は玄徳といって、つい先頃までは、平原県の令を勤めていた者です。どうかよろしく」\n",
"曹操は、眼をみはって、\n",
"---\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"%%time\n",
"\n",
"# クエリの実行\n",
"query = \"孔明はいつ劉備と会いましたか?\"\n",
"results = vectordb.similarity_search(query, k=10)\n",
"\n",
"# 結果の表示\n",
"for doc in results:\n",
" print(doc.page_content)\n",
" print(\"---\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qUbL33SAD3IQ",
"outputId": "d96ecb30-8057-4d7b-9b2d-caba1348c883"
},
"execution_count": 4,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"このとき孔明は二十七歳、劉備玄徳は四十七であった。\n",
"新野に帰ってからも、ふたりは寝るにも、室を共にし、食事をするにも、卓をべつにしたことがない。\n",
"---\n",
"「いま呼んでおひきあわせ致そうと考えていたところだ。誰か、孔明を召し連れてこい」\n",
"玄徳の命にひとりが立ち去って行くと、やがて孔明もここへ姿をあらわして、物やわらかに席に着いた。\n",
"---\n",
"孟建などが噂するせいか、襄陽の名士のあいだには、いつか、孔明の存在とその人物は、無言のうちに認められていた。\n",
"---\n",
"次の日の早朝、魯粛は、孔明をその客館へ誘いに行った。前の夜から報らせがあったので、孔明は斎戒沐浴して、はや身支度をととのえていた。\n",
"---\n",
"「そうだ隆中へ立寄っても、さして廻り道にはならぬ。別辞かたがた孔明にもちょっと会って行こう。そして主君玄徳の懇望があったら、ぜひ召しに応じてくれるよう、自分からもよく頼んでおこう」\n",
"---\n",
"そこへ、半年ほどいるうち、叔父の玄は、劉表の縁故があるので、荊州へゆくことになった。\n",
"孔明と、弟の均とは、叔父の家族とともに、荊州へ移住したがそれを機に、長男瑾は別れを告げて、\n",
"---\n",
"「よろしい。ともかく、孔明と会ってみよう。柴桑城へ伺うのは、孔明の肚を訊ねてみてからでも決して遅くはあるまいからともかく彼をつれて来給え。それまで登城をのばして待っているから」\n",
"---\n",
"孔明だった。\n",
"ほかの船には、孫乾も乗っていた。一体どうしてここへは?人々が怪しんで問うと、孔明は微笑して、\n",
"「およそこの辺にいたら、各と落合えるであろうかと、夏口の兵を少し募って、お待ちしていただけです」と、あまり多くを語らなかった。\n",
"危急に迫って、援軍をたのんでも、援軍の間に合う場合は少ないものであるが、それの間に合ったのは、やはり孔明自身行って、関羽や劉をよく動かしたからであろう。\n",
"しかし、それをつぶさに語るとなると、自分の口から自分の功を誇るようなものになるので、孔明は、\n",
"「さし当って、次の策こそ肝腎です。夏口(漢口附近)の地は要害で水利の便もありますから、ひとまず彼処の城にお入りあって、曹操の大軍に対し、堅守して時節を待たれ、また劉君にも江夏の城へお帰りあって、わが君と首尾相助けながら、共に武具兵船の再軍備にお励みあるが万全の計でしょう」と、まず将来の方針を示した。\n",
"劉は、同意したが、\n",
"「それよりも、もっと安全なのは、ひとまず玄徳どのを、私の江夏城へおつれして、充分に装備をしてから、夏口へお渡りあっては如何ですか。いきなり夏口へ入られるよりもそのほうが危険がないと思われますが」と、一応自分の考えも述べた。\n",
"玄徳も孔明も、\n",
"「それこそ、然るべし」と、意見は一致し、関羽に手勢五千をつけて、先に江夏の城へやった。そして何らの異変もないと確かめて後、玄徳や孔明、劉などは前後して入城した。\n",
"こうして、すでに長蛇を逸し去った曹操は、ぜひなく途中に軍の行動を停止して、各地に散開した追撃軍を漢水の畔に糾合したが、\n",
"「他日、玄徳が江陵に入っては一大事である」\n",
"と、さらに湖南へ下ってそこを奪い、一部の兵を留めて、すぐ荊州へ引っ返してきた。\n",
"荊州には、義とか劉先などという旧臣が守っていたが、もう幼主劉は殺され、襄陽はおち、軍民すべて曹操の下に服してしまっているので、\n",
"「もはや誰のために戦おう」と、城門をひらいてことごとく曹操に降服してしまった。\n",
"曹操は荊州に居すわって、いよいよ対呉政策に乗り出した。\n",
"呉を如何にするか。\n",
"これは多年の懸案である。しかもこの対策に成功しなければ、絶対に統一の覇業は完成しないのである。\n",
"「檄文を作れ」\n",
"荀攸に命じて、檄を書かせた。もちろんそれは呉へ送るものである。\n",
"いま、玄徳、孔明の輩は、その余命をわずかに江夏、夏口に拠せて、なお不逞な乱を企ておる。予、三軍をひきいて、疾くこれに游漁す。君も呉軍をひきいて、この快游を共にし給わずや。漁網の魚は、これを採って一盞の卓にのぼせ、地は割譲て、ながく好誼をむすぶ引出物としようではないか。\n",
"という意味のものだった。\n",
"ただし曹操としても、こんな一片の文書だけで、呉が降参してこようなどとは決して期待していない。いかなる外交もその外交辞令の手もとに、\n",
"(これがお嫌なら、またべつなご挨拶を以て)といえる「実力」が要る。彼は呉へ檄を送ると同時に、その実力を水陸から南方へ展開した。\n",
"総勢八十三万の兵を、号して百万ととなえ、西は荊陜から東は黄にわたる三百里のあいだ、烟火連々と陣線をひいて、呉の境を威圧した。\n",
"この時、呉主孫権も、隣境の変に万一あるをおそれて、柴桑城(廬山、陽湖の東南方)まで来ていたが、事態いよいよただならぬ形勢となったので、\n",
"「今こそ、呉の態度を迫られる時が来た。曹操についたが得策か、玄徳と結んだがよいか。ここの大方針は呉の興亡を決するものだ。乞う、そちの信じるところを忌憚なく聞かしてくれい」\n",
"呉の大賢といわるる魯粛は、孫権から直々にこう問われた。\n",
"魯粛は慎重に、孫権の諮問にこたえた。\n",
"「劉表の喪を弔うという名目をもって、私が荊州へお使いに立ちましょう」\n",
"「そして?」\n",
"「帰途ひそかに江夏へおもむき、玄徳と対面して、よく利害を説き、彼に援助を与える密約をむすんで来ます」\n",
"「玄徳を援助したら、曹操は怒って、いよいよ鋭鋒を呉へ向けてくるだろう」\n",
"「いや、ちがいます。玄徳の勢いが衰退したので、曹操はたちまち呉へ大軍を転じて来たものです。故に、玄徳が強力となれば、背後の憂いがありますから、曹操は決して、思い切った侵攻を呉へ試みることはできません」\n",
"魯粛は、なお説いて、\n",
"「私がお使いに立てば、それらの大策の決定は後日に譲るまでも、とにかく荊州から江夏にわたる曹操、玄徳、両方の実状をしかとこの眼で見てくるつもりです。それも重要な前提ですから」\n",
"と、いった。\n",
"呉の国のうごきは今、呉自身の浮沈を決する時であると共に、曹操の大軍にも、江夏の玄徳の運命にも、こうして重大な鍵をもっていた。\n",
"江夏の城中にあっても、その事について、度々、評議するところがあったが、孔明はいつも、\n",
"「呉は遠く、曹は近く、結局われわれの抱く天下三分の理想すなわち三国鼎立の実現を期するには、あくまで遠い呉をして近い曹操と争わせなければなりません。両大国を相搏たせて、その力を相殺させ、わが内容を拡充する。真の大策を行うのはそれからでしょう」\n",
"と、至極、穏当な論を述べていた。\n",
"「だが、そううまく、こちらの望みどおりにゆけばよいが?」\n",
"と、これは、玄徳だけの懐疑ではない。誰しも一応はそう考える。\n",
"これに対して、孔明は、\n",
"「ごらんなさい。今にきっと呉から使者が来るにちがいありません。然るときは、わたくし自身、一帆の風にまかせて、呉国へ下り、三寸不爛の舌をふるって、孫権と曹操を戦わせ、しかも江夏の味方は、そのいずれにも拠らず、一方のやぶれるのを見てから、遠大にしてなお万全な大計の道をおとりになるようにして見せます。戦わば必ず勝つ戦いを戦うこと、三歳の児童も知る兵法の初学です」\n",
"こう聞いても、人々はなお釈然となれなかった。むしろ不安にさえなった。\n",
"「孔明は何か非常な奇蹟でもあらわれるのをそらだのみにして、あんな言を吐いているのではないか」\n",
"そう思われる節がないでもないからである。\n",
"ところが、その奇蹟は、数日の後、ほんとうに江夏を訪れて来た。\n",
"「呉主孫権の名代として、故劉表の喪を弔うと称し、重臣魯粛と申される方の船が、いま江頭に着きました」と、いう知らせが、江岸の守備兵から城中へ通達されてきたのである。\n",
"「どうして軍師には、この事あるを、ああはやくからお分りになっておられたのか?」\n",
"ざわめく人々の問いに、孔明は、\n",
"「いかに強大な呉国でも、常勝軍と誇る曹兵百万が、南下するに会っては、戦慄せざるを得ないにきまっている。加うるに呉は富強ではあるが実戦の体験が少ない。境外の兵備の進歩やその実力をはかり知っておらぬ。で、ひとまずは、使者を派して、君玄徳を説きつけ、あくまで曹操の背後を衝かせておくの策を考えるものと私は観た」と語りまた劉をかえりみて、呉の孫策が死んだ時、荊州から弔問の使者が会葬に行ったか否かをたずねて、がその事なしと答えると、\n",
"「それごらんなさい。呉と荊州とは、累代の仇。今それをも捨てて使者をよこしたのは、喪を弔うの使いではなく、実は虚実をさぐるための公然たる密命大使であることが、その一事でも明らかでしょう」と、笑って説明した。\n",
"やがて魯粛は賓閣へ迎えられた。彼は、劉に弔慰を述べ、玄徳には礼物を贈って、\n",
"「呉主孫権からも、くれぐれよろしく申されました」\n",
"と、まずは型の如き使節ぶりを見せた。\n",
"後、後堂で酒宴となり、こんどは玄徳から遠来の労をねぎらった。\n",
"魯粛は、酔い大いに発すると、玄徳へ向ってずけずけ訊ね出した。\n",
"「あなたは年来、曹操から眼の仇にされて、彼と戦いをくり返しておいでだから、よくご存じであろうがいったい曹操という者は、天下統一の大野心を抱いているのでしょうか、それとも慾心はただ自己の繁栄に止まっている程度でありましょうか」\n",
"「さあ?どうであろう」\n",
"「彼の帷幕ではいま、誰と誰とが、もっとも曹操に用いられておりましょうな」\n",
"「よく知らぬが」\n",
"「では」と、魯粛はたたみかけて、\n",
"「曹操の持つ総兵力というものは、実際のところ、どのくらいでしょう」\n",
"「その辺も、よくわきまえぬ」\n",
"何を問われても、玄徳は空とぼけていた。これは孔明の忠告によるものだった。\n",
"魯粛は少し色をなして、\n",
"「新野、当陽そのほか諸所において、曹操と戦ってきたあなたが、敵について、何の知識もないわけはないでしょう」と、詰問ると、玄徳はなお茫漠たる面をして、\n",
"「いや、いつの戦いでも、こちらは、曹操来ると聞けば、逃げ走ってばかりいたので、くわしいことはまったく不明です。ただ孔明なら少しは心得ているであろうが」\n",
"「諸葛亮はどこにおられますか」\n",
"「いま呼んでおひきあわせ致そうと考えていたところだ。誰か、孔明を召し連れてこい」\n",
"玄徳の命にひとりが立ち去って行くと、やがて孔明もここへ姿をあらわして、物やわらかに席に着いた。\n",
"「亮先生。自分は先生の実兄とは、年来の親友ですが」と魯粛は、個人的な親しさを示しながら、彼に話しかけた。\n",
"「ほ。兄の瑾をよくご存じですか」と、孔明もなつかしげに瞳を細めた。\n",
"「されば、このたびの門出にも、お会いしてきました。何やらお言伝でも承って参りたいと存じたが、公のお使い、わざと差し控えてきましたが」\n",
"「いや、余事はおいて、時に、わが主玄徳におかれては、かねてより呉の君臣に交友を求め、相たずさえて曹操を討たんと欲しられていますが、貴下のお考えでは如何であろうか」\n",
"「さあ、重大ですな」\n",
"「自惚れではありませんが、呉もまたわれわれと結ばなければ、存立にかかわりましょう。もしわが主玄徳が、一朝に意気地を捨てて、曹操につけば、これ自己の保身としては、最善でしょうが、呉にとっては脅威でしょう。南下の圧力は倍加するわけですから」\n",
"ことばは鄭重だがその言外に大国の使臣を強迫しているのである。魯\n",
"---\n",
"と、型のごとく、酒宴にうつり、重礼厚遇、至らざるなしであった。\n",
"その日まで、孔明は何も知らなかったが、ふと、江岸の兵から、今日のお客は、夏口の劉皇叔であると聞いて、\n",
"「さては?」\n",
"---\n",
"が、何ぶんにも、千七百余年も前のことである。孔明の家系やその周囲については、正確にわからない点も多分にある。\n",
"---\n",
"CPU times: user 30.9 ms, sys: 998 µs, total: 31.8 ms\n",
"Wall time: 31.4 ms\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"%%time\n",
"\n",
"# クエリの実行\n",
"query = \"曹操の愛馬の名前は?\"\n",
"results = vectordb.similarity_search(query, k=10)\n",
"\n",
"# 結果の表示\n",
"for doc in results:\n",
" print(doc.page_content)\n",
" print(\"---\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ukAA9u4C7KYF",
"outputId": "6ad6010b-2777-40b7-8d20-b88e41776be0"
},
"execution_count": 5,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"「馬を見給え」と促すと、曹操は、\n",
"「はっ、有難く拝領いたします」\n",
"と、急いで庭上へ出て、呂布がひいて来た駿馬の鬣をなでながら、\n",
"---\n",
"曹操は急に、侍臣をどこかへ走らせて、一頭の馬を、そこへ曳かせた。\n",
"見ると、全身の毛は、炎のように赤く、眼は、二つの鑾鈴をはめこんだようだった。\n",
"「美髯公、君はこの馬に見おぼえはないかね」\n",
"---\n",
"などと、警蹕のあいだにも、ささやく声が流れる。\n",
"この日。\n",
"曹操は、「爪黄飛電」と名づける名馬にまたがって、狩装束も華やかに、ひたと天子のお側に寄り添っていた。\n",
"---\n",
"「召しのお使いをうけたので、すぐ拝領のこれに乗って、快足を試してきました」\n",
"馬の鞍を叩きながら云った。\n",
"曹操はここ数日の惨敗を、ことばも飾らず彼に告げて、\n",
"「ともかく、戦場を一望してくれ給え」\n",
"---\n",
"洛陽の都をあとに、黄馬に鞭をつづけ、日夜をわかたず、南へ南へと風の如く逃げてきた曹操は、早くも中牟県(河南省中牟・開封鄭州の中間)の附近までかかっていた。\n",
"「待てっ」\n",
"「馬をおりろ」\n",
"---\n",
"朝門を辞して帰る折、曹操はまた、彼がみすぼらしい痩馬を用いているのを見て、\n",
"「なぜもっと良い飼糧をやって、充分に馬を肥やさせないのか」と、武人のたしなみを咎めた。\n",
"---\n",
"武将が良士を熱愛する度を云い現わすことばとしてこの国の古くからの馬にのれば金を与え、馬を降れば銀を贈るというたとえがあるが、曹操の態度は、それどころでなかった。\n",
"都の内でも、選りすぐった美女十人に、\n",
"---\n",
"「や。今のは兄の愛馬の声ではないか」と、馳けつけてきて、月明りにすかしてみると、今しも兄の曹操はわずかな雑兵輩の自由になって、高手小手に縛められようとしている様子である。\n",
"「くそッ」\n",
"---\n",
"帝が急きこんで叫ばれると、曹操はつと馳け寄って、帝の御手から弓矢を取り、それをつがえながら爪黄馬を走らすかと見る間に、ぶんと弦鳴りさせて射放った。\n",
"---\n",
"「つい今しがた、その曹操は、黄毛の駿馬にまたがって、飛ぶが如く東門を乗打ちして行ったので、番兵がまた馬でそれを追いかけ、ようやく城外へ出る関門でとらえて詰問したところ、曹操がいうには我は丞相の急命を帯びてにわかに使いに立つなり。汝ら、我をはばめて大事の急用を遅滞さすからには、後に董相国よりいかなるお咎めがあらんも知れぬぞとのことなので、誰も疑う者なく、曹操はそのまま鞭を上げて関門を越え、行方のほども相知れぬ由にござります」\n",
"---\n",
"CPU times: user 30.7 ms, sys: 1.95 ms, total: 32.7 ms\n",
"Wall time: 32.6 ms\n"
]
}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment