Open in Colab

Indexes#

indexesとは、LLMがドキュメントと最適なやり取りができるように、ドキュメントを構造化する方法です。

indexesを使用する最も一般的な方法は、「検索」ステップです。このステップは、ユーザーのクエリを受け取り、最も関連性の高いドキュメントを返すことを意味します。

Document Loaders#

言語モデルと独自のテキストデータを組み合わせることは、言語モデルを差別化するための強力な方法です。そのための最初のステップは、データをdocumentsに読み込むことです。documentsとは、いくつかのテキストのピースを指します。

LangChainにはさまざまなDocument Loaderが提供されています。

https://python.langchain.com/en/latest/modules/indexes/document_loaders.html

JSON Files#

ここでは JSONLoader を使ってJSONファイルを扱います。

import json
from urllib import request

with request.urlopen("https://connpass.com/api/v1/event/?event_id=281632") as res:
    data = json.load(res)
    with open("event.json", "w") as f:
        json.dump(data, f)

data
{'results_start': 1,
 'results_returned': 1,
 'results_available': 1,
 'events': [{'event_id': 281632,
   'title': 'ChatGPTのAPIを使ってみよう',
   'catch': 'ついでにLangChainをさわってみよう',
   'description': '<h1>概要</h1>\n<p>本イベントでは、初めてChatGPTのAPIを利用する方を対象に、APIの使い方を学び、実際に操作します。従来、Web UIから利用していた方でも、APIを使うことでより高度な文章を扱え、APIの利点を知るきっかけになるかもしれません。</p>\n<p>ハンズオンではプロンプトに複数の長い文章をまとめて入力して、要約した内容を生成します。</p>\n<h1>参加条件</h1>\n<p>下記の準備をしておいてください</p>\n<ol>\n<li>OpenAIのアカウント</li>\n<li>利用できるAPIキー(無料プランの場合、1ヶ月で利用できる制限があります)</li>\n<li>Python環境</li>\n</ol>\n<h1>タイムテーブル</h1>\n<ol>\n<li>オープニング</li>\n<li>ハンズオン</li>\n<li>フリータイム(実際に動かしてみる)</li>\n<li>成果共有</li>\n<li>クロージング</li>\n</ol>\n<h1>免責事項</h1>\n<ul>\n<li>本イベントは法務、会計、税務、経営、投資その他に係る助言を構成するものではありません</li>\n<li>本イベント から生じたいかなる損害に関して、イベントの参加者およびコミュニティは一切の責任を負うものではありません</li>\n</ul>',
   'event_url': 'https://fin-py.connpass.com/event/281632/',
   'started_at': '2023-05-12T19:00:00+09:00',
   'ended_at': '2023-05-12T21:00:00+09:00',
   'limit': None,
   'hash_tag': '',
   'event_type': 'participation',
   'accepted': 55,
   'waiting': 0,
   'updated_at': '2023-05-12T07:52:09+09:00',
   'owner_id': 36417,
   'owner_nickname': 'driller',
   'owner_display_name': 'driller',
   'place': 'オンライン(Brave Talk)',
   'address': '',
   'lat': None,
   'lon': None,
   'series': {'id': 3056,
    'title': 'fin-py',
    'url': 'https://fin-py.connpass.com/'}}]}

JSONLoader の引数 jq_schema には jq のフィルタ記法が利用できます。

from langchain.document_loaders import JSONLoader

loader = JSONLoader(
    file_path="event.json",
    jq_schema=".events[].description"
)
loader.load()
[Document(page_content='<h1>概要</h1>\n<p>本イベントでは、初めてChatGPTのAPIを利用する方を対象に、APIの使い方を学び、実際に操作します。従来、Web UIから利用していた方でも、APIを使うことでより高度な文章を扱え、APIの利点を知るきっかけになるかもしれません。</p>\n<p>ハンズオンではプロンプトに複数の長い文章をまとめて入力して、要約した内容を生成します。</p>\n<h1>参加条件</h1>\n<p>下記の準備をしておいてください</p>\n<ol>\n<li>OpenAIのアカウント</li>\n<li>利用できるAPIキー(無料プランの場合、1ヶ月で利用できる制限があります)</li>\n<li>Python環境</li>\n</ol>\n<h1>タイムテーブル</h1>\n<ol>\n<li>オープニング</li>\n<li>ハンズオン</li>\n<li>フリータイム(実際に動かしてみる)</li>\n<li>成果共有</li>\n<li>クロージング</li>\n</ol>\n<h1>免責事項</h1>\n<ul>\n<li>本イベントは法務、会計、税務、経営、投資その他に係る助言を構成するものではありません</li>\n<li>本イベント から生じたいかなる損害に関して、イベントの参加者およびコミュニティは一切の責任を負うものではありません</li>\n</ul>', metadata={'source': '/home/driller/repo/chatgpt-api-hands-on/docs/event.json', 'seq_num': 1})]

Text Splitters#

大きなテキストデータを扱う場合はそのテキストを分割する必要があります。

Character Text Splitter#

CharacterTextSplitter は文字列を指定したチャンクサイズで分割します。

text = """\
我々は一人の英雄を失った。しかし、これは敗北を意味するのか?否!始まりなのだ!
地球連邦に比べ、我がジオンの国力は30分の1以下である。
にもかかわらず今日まで戦い抜いてこられたのは何故か?
諸君!我がジオン公国の戦争目的が正義だからだ。これは諸君らが一番知っている。
我々は地球を追われ、宇宙移民者にさせられた。
そして、一握りのエリートらが宇宙にまで膨れ上がった地球連邦を支配して50余年、
宇宙に住む我々が自由を要求して何度踏みにじられたか。
ジオン公国の掲げる人類一人一人の自由のための戦いを神が見捨てるはずはない。
私の弟!諸君らが愛してくれたガルマ・ザビは死んだ。
何故だ!?
新しい時代の覇権を選ばれた国民が得るは、歴史の必然である。
ならば、我らは襟を正し、この戦局を打開しなければならぬ。
我々は過酷な宇宙空間を生活の場としながらも共に苦悩し、錬磨して今日の文化を築き上げてきた。
かつて、ジオン・ダイクンは人類の革新は宇宙の民たる我々から始まると言った。
しかしながら地球連邦のモグラ共は、自分たちが人類の支配権を有すると増長し我々に抗戦する。
諸君の父も、子もその連邦の無思慮な抵抗の前に死んでいったのだ!
この悲しみも怒りも忘れてはならない!それを、ガルマは!死をもって我々に示してくれた!
我々は今、この怒りを結集し、連邦軍に叩きつけて、初めて真の勝利を得ることができる。
この勝利こそ、戦死者全てへの最大の慰めとなる。
国民よ立て!悲しみを怒りに変えて、立てよ!国民よ!
我らジオン国国民こそ選ばれた民であることを忘れないでほしいのだ。
優良種である我らこそ人類を救い得るのである。ジーク・ジオン!\
"""
from langchain.text_splitter import CharacterTextSplitter

text_splitter = CharacterTextSplitter(        
    separator = "\n",
    chunk_size = 200,
    chunk_overlap  = 10,
    length_function = len,
)
texts = text_splitter.create_documents([text])
texts[0]
Document(page_content='我々は一人の英雄を失った。しかし、これは敗北を意味するのか?否!始まりなのだ!\n地球連邦に比べ、我がジオンの国力は30分の1以下である。\nにもかかわらず今日まで戦い抜いてこられたのは何故か?\n諸君!我がジオン公国の戦争目的が正義だからだ。これは諸君らが一番知っている。\n我々は地球を追われ、宇宙移民者にさせられた。\nそして、一握りのエリートらが宇宙にまで膨れ上がった地球連邦を支配して50余年、', metadata={})

Markdown Text Splitter#

MarkdownTextSplitter はMarkown記法の見出しやブロックなどで分割します。

markdown_text = """
# 🦜️🔗 LangChain

⚡ Building applications with LLMs through composability ⚡

## Quick Install

```bash
# Hopefully this code block isn't split
pip install langchain
```

As an open source project in a rapidly developing field, we are extremely open to contributions.
"""
from langchain.text_splitter import MarkdownTextSplitter


markdown_splitter = MarkdownTextSplitter(chunk_size=100, chunk_overlap=0)
docs = markdown_splitter.create_documents([markdown_text])
docs
[Document(page_content='# 🦜️🔗 LangChain\n\n⚡ Building applications with LLMs through composability ⚡', metadata={}),
 Document(page_content="Quick Install\n\n```bash\n# Hopefully this code block isn't split\npip install langchain", metadata={}),
 Document(page_content='As an open source project in a rapidly developing field, we are extremely open to contributions.', metadata={})]