LLAMA-INDEXによるQ＆A開発

**概要:** この記事では、LLAMA-INDEXという強力なツールの仕組みと、それを使ってどのように情報を取得し処理するかについて詳細に解説します。

### **LLAMA-INDEXとは何か**

- LLAMA-INDEXは、大規模な言語モデル（LLM）ベースのアプリケーション開発をサポートするために特別に設計された革新的なデータフレームワークです。これは、PDFやPowerPointなどの様々なファイル形式や、NotionやSlackのようなアプリケーション、PostgresやMongoDBのようなデータベースなど、多様なデータソースをLLMと統合するための高度なフレームワークを提供します。
- LLAMA-INDEXの主な特徴としては、様々なデータソースやフォーマットからのデータ取り込みを可能にする「LlamaHub」、文書操作の実施、異なる文書やデータソースからのデータ統合、異なるクエリエンジン間で選択可能な「Router」機能、出力品質を向上させるための仮想文書エンベディング、多様なベクトルストア、ChatGPTプラグイン、追跡ツール、LangChainなどとの統合、最新のOpenAI機能呼び出しAPIのサポートなどが挙げられます。
- LLAMA-INDEXのメリットは、特定の主題に関するクエリに答えるチャットボットの構築、長い文書や記事の要約の生成、外部知識ベースに接続して回答を提供する質問応答システムの構築、未構造化データからのトピック抽出など、多様な用途に適用できることです。しかし、特定のトークン制限のため、大規模な企業文書の取り扱いにおいては、商業的なChatGPTだけでは最適ではない可能性があります。LLAMA-INDEXは、文書、PDF、データベースなど多様なデータセットをインデックス化し、必要な情報を迅速かつ容易に検索することを可能にします。
- ストレージ管理においては、従来のSQLやNoSQLデータベースのようなストレージオプションと、インデックスやベクトルストレージのような新しいストレージタイプがありますが、これらにはそれぞれ固有の課題があります。従来のストレージシステムは、類似する意味を持つ広範なテキストチャンクの検索に効率的ではない場合がありますが、LLMアプリケーション用に設計された新しいストレージタイプは、管理や統合の面で独自の課題を提起します。このような状況において、LLAMA-INDEXのような革新的なソリューションは、LLMアプリケーションの効率的かつ効果的な管理に不可欠です。

### **LLAMA-INDEXの動作の流れ**

1. **文書のインデックス化:** まず、文書データをロードし、**`VectorStoreIndex.from_documents`**を使用してインデックスを作成します。これにより、クエリに対する効率的な検索が可能になります。
2. **クエリの処理:** ユーザーからのクエリ（例えば、特定のTOEICスコアに適した映画についての質問）が入力されると、LLAMA-INDEXはこのクエリを処理します。
3. **ChatGPTとの連携:** ChatGPTのAPIを使用して、クエリに対する回答を生成します。このプロセスは、提供された文書コンテキストに基づいて行われます。
4. **結果の取得:** ChatGPTからの回答が返され、出力として表示されます。

### 実演

以下のPythonコードを例に、LLAMA-INDEXがどのように動作するかを詳しく見ていきましょう。

構造はこちら：

.
├── database
│   └── abceed君_textv2.txt
└── llama-index-playground.ipynb **←code**

```python
import os
from llama_index.llms import OpenAI
os.environ['OPENAI_API_KEY'] = 'my secret key'
from llama_index import VectorStoreIndex, SimpleDirectoryReader, ServiceContext
# モデルの指定は、service_contextを作ることが必要
llm = OpenAI(temperature=0.1, model="gpt-3.5-turbo")
service_context = ServiceContext.from_defaults(llm=llm)

documents = SimpleDirectoryReader("database").load_data()
index = VectorStoreIndex.from_documents(documents, service_context=service_context)

query_engine = index.as_query_engine()
response = query_engine.query("TOEIC700点だけど、具体的には、どういう映画を見ればいい？")
print(response)
```

実行結果

```bash
DEBUG:openai._base_client:Request options: {'method': 'post', 'url': '/embeddings', 'files': None, 'post_parser': <function Embeddings.create.<locals>.parser at 0x7f86dbdc9fc0>, 'json_data': {'input': ['TOEIC700点だけど、具体的には、どういう映画を見ればいい？'], 'model': <OpenAIEmbeddingModeModel.TEXT_EMBED_ADA_002: 'text-embedding-ada-002'>, 'encoding_format': 'base64'}}
Request options: {'method': 'post', 'url': '/embeddings', 'files': None, 'post_parser': <function Embeddings.create.<locals>.parser at 0x7f86dbdc9fc0>, 'json_data': {'input': ['TOEIC700点だけど、具体的には、どういう映画を見ればいい？'], 'model': <OpenAIEmbeddingModeModel.TEXT_EMBED_ADA_002: 'text-embedding-ada-002'>, 'encoding_format': 'base64'}}
DEBUG:httpcore.connection:close.started
close.started
DEBUG:httpcore.connection:close.complete
close.complete
DEBUG:httpcore.connection:connect_tcp.started host='api.openai.com' port=443 local_address=None timeout=60.0 socket_options=None
connect_tcp.started host='api.openai.com' port=443 local_address=None timeout=60.0 socket_options=None
DEBUG:httpcore.connection:connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f86dbdf00a0>
connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f86dbdf00a0>
DEBUG:httpcore.connection:start_tls.started ssl_context=<ssl.SSLContext object at 0x7f872fcc2ac0> server_hostname='api.openai.com' timeout=60.0
start_tls.started ssl_context=<ssl.SSLContext object at 0x7f872fcc2ac0> server_hostname='api.openai.com' timeout=60.0
DEBUG:httpcore.connection:start_tls.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f86dbdf0130>
start_tls.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f86dbdf0130>
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'POST']>
send_request_headers.started request=<Request [b'POST']>
DEBUG:httpcore.http11:send_request_headers.complete
send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'POST']>
send_request_body.started request=<Request [b'POST']>
DEBUG:httpcore.http11:send_request_body.complete
send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'POST']>
receive_response_headers.started request=<Request [b'POST']>
DEBUG:httpcore.http11:receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'OK', [(b'Date', b'Sun, 26 Nov 2023 16:15:40 GMT'), (b'Content-Type', b'application/json'), (b'Transfer-Encoding', b'chunked'), (b'Connection', b'keep-alive'), (b'access-control-allow-origin', b'*'), (b'openai-organization', b'user-eun44vmtz9ill7xpo99m12nf'), (b'openai-processing-ms', b'24'), (b'openai-version', b'2020-10-01'), (b'strict-transport-security', b'max-age=15724800; includeSubDomains'), (b'x-ratelimit-limit-requests', b'10000'), (b'x-ratelimit-limit-tokens', b'10000000'), (b'x-ratelimit-remaining-requests', b'9999'), (b'x-ratelimit-remaining-tokens', b'9999979'), (b'x-ratelimit-reset-requests', b'6ms'), (b'x-ratelimit-reset-tokens', b'0s'), (b'x-request-id', b'1b15091fc0d79bf1d5f18057672281e1'), (b'CF-Cache-Status', b'DYNAMIC'), (b'Server', b'cloudflare'), (b'CF-RAY', b'82c36e718afa6885-NRT'), (b'Content-Encoding', b'br'), (b'alt-svc', b'h3=":443"; ma=86400')])
receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'OK', [(b'Date', b'Sun, 26 Nov 2023 16:15:40 GMT'), (b'Content-Type', b'application/json'), (b'Transfer-Encoding', b'chunked'), (b'Connection', b'keep-alive'), (b'access-control-allow-origin', b'*'), (b'openai-organization', b'user-eun44vmtz9ill7xpo99m12nf'), (b'openai-processing-ms', b'24'), (b'openai-version', b'2020-10-01'), (b'strict-transport-security', b'max-age=15724800; includeSubDomains'), (b'x-ratelimit-limit-requests', b'10000'), (b'x-ratelimit-limit-tokens', b'10000000'), (b'x-ratelimit-remaining-requests', b'9999'), (b'x-ratelimit-remaining-tokens', b'9999979'), (b'x-ratelimit-reset-requests', b'6ms'), (b'x-ratelimit-reset-tokens', b'0s'), (b'x-request-id', b'1b15091fc0d79bf1d5f18057672281e1'), (b'CF-Cache-Status', b'DYNAMIC'), (b'Server', b'cloudflare'), (b'CF-RAY', b'82c36e718afa6885-NRT'), (b'Content-Encoding', b'br'), (b'alt-svc', b'h3=":443"; ma=86400')])
INFO:httpx:HTTP Request: POST https://api.openai.com/v1/embeddings "HTTP/1.1 200 OK"
HTTP Request: POST https://api.openai.com/v1/embeddings "HTTP/1.1 200 OK"
DEBUG:httpcore.http11:receive_response_body.started request=<Request [b'POST']>
receive_response_body.started request=<Request [b'POST']>
DEBUG:httpcore.http11:receive_response_body.complete
receive_response_body.complete
DEBUG:httpcore.http11:response_closed.started
response_closed.started
DEBUG:httpcore.http11:response_closed.complete
response_closed.complete
DEBUG:openai._base_client:HTTP Request: POST https://api.openai.com/v1/embeddings "200 OK"
HTTP Request: POST https://api.openai.com/v1/embeddings "200 OK"
DEBUG:llama_index.indices.utils:> Top 2 nodes:
> [Node f192443c-1ccf-4cdb-88b5-7963323fd6f5] [Similarity score:             0.862702] ﻿## TOEICユーザーにおすすめの学習法
まずはレベル診断テストを受験しましょう。
最低10問の問題を解くだけで、今の自分の今の予測スコアを知ることができます。
以下、予測スコア別のオススメ...
> [Node 38dfe3b5-8939-4ed4-9253-1556fbb543b3] [Similarity score:             0.812858] ［語彙力・リーディング力を強化する学習手順］
これらのスキルを強化したい方は、映画を「英字幕で鑑賞できる状態」を目指しましょう。

映画は、英語話者が実際に使っている表現の宝庫です。幅広い語彙や...
> Top 2 nodes:
> [Node f192443c-1ccf-4cdb-88b5-7963323fd6f5] [Similarity score:             0.862702] ﻿## TOEICユーザーにおすすめの学習法
まずはレベル診断テストを受験しましょう。
最低10問の問題を解くだけで、今の自分の今の予測スコアを知ることができます。
以下、予測スコア別のオススメ...
> [Node 38dfe3b5-8939-4ed4-9253-1556fbb543b3] [Similarity score:             0.812858] ［語彙力・リーディング力を強化する学習手順］
これらのスキルを強化したい方は、映画を「英字幕で鑑賞できる状態」を目指しましょう。

映画は、英語話者が実際に使っている表現の宝庫です。幅広い語彙や...
DEBUG:openai._base_client:Request options: {'method': 'post', 'url': '/chat/completions', 'files': None, 'json_data': {'messages': [{'role': <MessageRole.SYSTEM: 'system'>, 'content': "You are an expert Q&A system that is trusted around the world.\nAlways answer the query using the provided context information, and not prior knowledge.\nSome rules to follow:\n1. Never directly reference the given context in your answer.\n2. Avoid statements like 'Based on the context, ...' or 'The context information ...' or anything along those lines."}, {'role': <MessageRole.USER: 'user'>, 'content': 'Context information is below.\n---------------------\nfile_path: database/abceed君_textv2.txt\n\n\ufeff## TOEICユーザーにおすすめの学習法\nまずはレベル診断テストを受験しましょう。\n最低10問の問題を解くだけで、今の自分の今の予測スコアを知ることができます。\n以下、予測スコア別のオススメ学習法です。\n\n### ~500点\nまずは「英文法解説講義」を閲覧し、英語の基礎を身に着けましょう。\n単語力に不安のある方は「TOEIC L&R TEST 出る単特急 銀のフレーズ」という教材で、基礎的な単語を身に着けましょう。\nある程度基礎が身に着いたら、Part125を中心におすすめの問題を解いてみましょう。\n\n### 500点~700点\n苦手なPartを中心におすすめの問題を解いてみましょう。\n単語力に不安のある方は「TOEIC L&R TEST 出る単特急 金のフレーズ」という教材で、基礎的な単語を身に着けましょう。\nPart5を鍛えたい場合、「TOEIC L&R テスト 文法問題 でる1000問」もおすすめです。\nリスニング力に不安がある場合、映画を使ったトレーニングを時々やるのもおすすめです。\n\n### 700点~\nおすすめの問題と映画を使ったトレーニングを中心に学習しましょう。\nこのレベルだと、普通の参考書では簡単に解ける問題が多くなってきます。\nおすすめの問題は、今のあなたがぎりぎり解けそうな問題を出題しますので、効率的に学習することができます。\n映画の会話スピードは、TOEICのリスニング音声よりも、格段に速いです。そのため、映画を使って学習することは、アスリートが高地トレーニングで心肺機能を強化するのと同じく、リスニング力を底上げします。映画のスピードに慣れたら、テストのリスニング音声はゆっくりしたものに聞こえるはずです。\nさらに、TOEIC 800点以上を目指すには、ネイティブが普段使っているこなれた表現を身に付ける必要があります。それには、ネイティブのリアルな会話で構成されている映画コンテンツを使った学習が特に効果的です。\n\nfile_path: database/abceed君_textv2.txt\n\n［語彙力・リーディング力を強化する学習手順］\nこれらのスキルを強化したい方は、映画を「英字幕で鑑賞できる状態」を目指しましょう。\n\n映画は、英語話者が実際に使っている表現の宝庫です。幅広い語彙や文法事項を学習できます。さらに、語句やフレーズと映像をリンクさせられるので、記憶への定着も促進されます。以下の学習手順は、まず語彙と文法を字幕を読んで理解し、その上で、英文理解の速度を高められるよう設計しています。\n\nStep 1：ストーリー把握（日本語字幕に設定・１回実施）\nまずは日本語字幕の設定で全体を鑑賞し、ストーリーを理解します。\n\nStep 2：フレーズ理解（英字幕／英･日同時字幕に設定・〈シーン〉ごとに実施）\n字幕を英語のみ、もしくは英･日同時字幕に設定。再生を停止しながら、フレーズごとに字幕の英文を読んで理解します。知らない単語の意味や文構造を確認して、日本語字幕の意味になる理由を理解しましょう。目安としては１つの〈シーン〉が理解できたら次のStepへ進みます。\n\nStep 3：音読トレーニング（英字幕／英･日同時字幕に設定・〈シーン〉ごとに実施）\n英字幕のみ、もしくは英･日同時字幕で、通常速度で再生。その速度で流れていく字幕を読んで理解できるか確認します。ついていけないフレーズは、〈リピート再生〉にして5〜10回程度、意味を考えながら音読しましょう。\n\nStep 4：学習成果チェック（英字幕に設定・１回実施）\n英字幕のみで、理解に詰まることなく、映画１本を通しで視聴できる状態を目指します。うまくいかない場合は、Step 2〜3をやり込みましょう。\n\n\n［発音・リスニング力を強化する学習手順］\nこれらのスキルを強化したい方は、映画を「字幕なしで鑑賞できる状態」を目指しましょう。\n\n映画には、さまざまなアクセントが登場するので、発音・リスニングを学習するのに最適です。特に以下の手順で学習すると、自分の弱点となる音声を洗い出すことができ、効率的にスキルを伸ばせます。\n※Step 1〜2は［語彙力・リーディング力を強化する学習手順］と共通です。\n---------------------\nGiven the context information and not prior knowledge, answer the query.\nQuery: TOEIC700点だけど、具体的には、どういう映画を見ればいい？\nAnswer: '}], 'model': 'gpt-3.5-turbo', 'stream': False, 'temperature': 0.1}}
Request options: {'method': 'post', 'url': '/chat/completions', 'files': None, 'json_data': {'messages': [{'role': <MessageRole.SYSTEM: 'system'>, 'content': "You are an expert Q&A system that is trusted around the world.\nAlways answer the query using the provided context information, and not prior knowledge.\nSome rules to follow:\n1. Never directly reference the given context in your answer.\n2. Avoid statements like 'Based on the context, ...' or 'The context information ...' or anything along those lines."}, {'role': <MessageRole.USER: 'user'>, 'content': 'Context information is below.\n---------------------\nfile_path: database/abceed君_textv2.txt\n\n\ufeff## TOEICユーザーにおすすめの学習法\nまずはレベル診断テストを受験しましょう。\n最低10問の問題を解くだけで、今の自分の今の予測スコアを知ることができます。\n以下、予測スコア別のオススメ学習法です。\n\n### ~500点\nまずは「英文法解説講義」を閲覧し、英語の基礎を身に着けましょう。\n単語力に不安のある方は「TOEIC L&R TEST 出る単特急 銀のフレーズ」という教材で、基礎的な単語を身に着けましょう。\nある程度基礎が身に着いたら、Part125を中心におすすめの問題を解いてみましょう。\n\n### 500点~700点\n苦手なPartを中心におすすめの問題を解いてみましょう。\n単語力に不安のある方は「TOEIC L&R TEST 出る単特急 金のフレーズ」という教材で、基礎的な単語を身に着けましょう。\nPart5を鍛えたい場合、「TOEIC L&R テスト 文法問題 でる1000問」もおすすめです。\nリスニング力に不安がある場合、映画を使ったトレーニングを時々やるのもおすすめです。\n\n### 700点~\nおすすめの問題と映画を使ったトレーニングを中心に学習しましょう。\nこのレベルだと、普通の参考書では簡単に解ける問題が多くなってきます。\nおすすめの問題は、今のあなたがぎりぎり解けそうな問題を出題しますので、効率的に学習することができます。\n映画の会話スピードは、TOEICのリスニング音声よりも、格段に速いです。そのため、映画を使って学習することは、アスリートが高地トレーニングで心肺機能を強化するのと同じく、リスニング力を底上げします。映画のスピードに慣れたら、テストのリスニング音声はゆっくりしたものに聞こえるはずです。\nさらに、TOEIC 800点以上を目指すには、ネイティブが普段使っているこなれた表現を身に付ける必要があります。それには、ネイティブのリアルな会話で構成されている映画コンテンツを使った学習が特に効果的です。\n\nfile_path: database/abceed君_textv2.txt\n\n［語彙力・リーディング力を強化する学習手順］\nこれらのスキルを強化したい方は、映画を「英字幕で鑑賞できる状態」を目指しましょう。\n\n映画は、英語話者が実際に使っている表現の宝庫です。幅広い語彙や文法事項を学習できます。さらに、語句やフレーズと映像をリンクさせられるので、記憶への定着も促進されます。以下の学習手順は、まず語彙と文法を字幕を読んで理解し、その上で、英文理解の速度を高められるよう設計しています。\n\nStep 1：ストーリー把握（日本語字幕に設定・１回実施）\nまずは日本語字幕の設定で全体を鑑賞し、ストーリーを理解します。\n\nStep 2：フレーズ理解（英字幕／英･日同時字幕に設定・〈シーン〉ごとに実施）\n字幕を英語のみ、もしくは英･日同時字幕に設定。再生を停止しながら、フレーズごとに字幕の英文を読んで理解します。知らない単語の意味や文構造を確認して、日本語字幕の意味になる理由を理解しましょう。目安としては１つの〈シーン〉が理解できたら次のStepへ進みます。\n\nStep 3：音読トレーニング（英字幕／英･日同時字幕に設定・〈シーン〉ごとに実施）\n英字幕のみ、もしくは英･日同時字幕で、通常速度で再生。その速度で流れていく字幕を読んで理解できるか確認します。ついていけないフレーズは、〈リピート再生〉にして5〜10回程度、意味を考えながら音読しましょう。\n\nStep 4：学習成果チェック（英字幕に設定・１回実施）\n英字幕のみで、理解に詰まることなく、映画１本を通しで視聴できる状態を目指します。うまくいかない場合は、Step 2〜3をやり込みましょう。\n\n\n［発音・リスニング力を強化する学習手順］\nこれらのスキルを強化したい方は、映画を「字幕なしで鑑賞できる状態」を目指しましょう。\n\n映画には、さまざまなアクセントが登場するので、発音・リスニングを学習するのに最適です。特に以下の手順で学習すると、自分の弱点となる音声を洗い出すことができ、効率的にスキルを伸ばせます。\n※Step 1〜2は［語彙力・リーディング力を強化する学習手順］と共通です。\n---------------------\nGiven the context information and not prior knowledge, answer the query.\nQuery: TOEIC700点だけど、具体的には、どういう映画を見ればいい？\nAnswer: '}], 'model': 'gpt-3.5-turbo', 'stream': False, 'temperature': 0.1}}
DEBUG:httpcore.connection:connect_tcp.started host='api.openai.com' port=443 local_address=None timeout=60.0 socket_options=None
connect_tcp.started host='api.openai.com' port=443 local_address=None timeout=60.0 socket_options=None
DEBUG:httpcore.connection:connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f872f9de050>
connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f872f9de050>
DEBUG:httpcore.connection:start_tls.started ssl_context=<ssl.SSLContext object at 0x7f872fcc24c0> server_hostname='api.openai.com' timeout=60.0
start_tls.started ssl_context=<ssl.SSLContext object at 0x7f872fcc24c0> server_hostname='api.openai.com' timeout=60.0
DEBUG:httpcore.connection:start_tls.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f872f9ddff0>
start_tls.complete return_value=<httpcore._backends.sync.SyncStream object at 0x7f872f9ddff0>
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'POST']>
send_request_headers.started request=<Request [b'POST']>
DEBUG:httpcore.http11:send_request_headers.complete
send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'POST']>
send_request_body.started request=<Request [b'POST']>
DEBUG:httpcore.http11:send_request_body.complete
send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'POST']>
receive_response_headers.started request=<Request [b'POST']>
DEBUG:httpcore.http11:receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'OK', [(b'Date', b'Sun, 26 Nov 2023 16:15:43 GMT'), (b'Content-Type', b'application/json'), (b'Transfer-Encoding', b'chunked'), (b'Connection', b'keep-alive'), (b'access-control-allow-origin', b'*'), (b'Cache-Control', b'no-cache, must-revalidate'), (b'openai-model', b'gpt-3.5-turbo-0613'), (b'openai-organization', b'user-eun44vmtz9ill7xpo99m12nf'), (b'openai-processing-ms', b'2241'), (b'openai-version', b'2020-10-01'), (b'strict-transport-security', b'max-age=15724800; includeSubDomains'), (b'x-ratelimit-limit-requests', b'10000'), (b'x-ratelimit-limit-tokens', b'1000000'), (b'x-ratelimit-limit-tokens_usage_based', b'1000000'), (b'x-ratelimit-remaining-requests', b'9999'), (b'x-ratelimit-remaining-tokens', b'998623'), (b'x-ratelimit-remaining-tokens_usage_based', b'998623'), (b'x-ratelimit-reset-requests', b'6ms'), (b'x-ratelimit-reset-tokens', b'82ms'), (b'x-ratelimit-reset-tokens_usage_based', b'82ms'), (b'x-request-id', b'e4a36612eec795fa5af299bdfd098b97'), (b'CF-Cache-Status', b'DYNAMIC'), (b'Set-Cookie', b'__cf_bm=27m6C3x7X54DWftRMSznhVPgp9qyqIr5qFBWFDPi.TY-1701015343-0-AZtNpm3T+1XbjdumxvrZ9TTYvFYjFVJBI2zo2/8SXe2zdDm38iShwZgIzIujnSyUqI3S7Xx7YdMurSWUWsIMvr0=; path=/; expires=Sun, 26-Nov-23 16:45:43 GMT; domain=.api.openai.com; HttpOnly; Secure; SameSite=None'), (b'Set-Cookie', b'_cfuvid=lstRes7eoujm1WJc_gabFXh4wvA0tnulJdms4Fo8hhg-1701015343099-0-604800000; path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None'), (b'Server', b'cloudflare'), (b'CF-RAY', b'82c36e737e046837-NRT'), (b'Content-Encoding', b'br'), (b'alt-svc', b'h3=":443"; ma=86400')])
receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'OK', [(b'Date', b'Sun, 26 Nov 2023 16:15:43 GMT'), (b'Content-Type', b'application/json'), (b'Transfer-Encoding', b'chunked'), (b'Connection', b'keep-alive'), (b'access-control-allow-origin', b'*'), (b'Cache-Control', b'no-cache, must-revalidate'), (b'openai-model', b'gpt-3.5-turbo-0613'), (b'openai-organization', b'user-eun44vmtz9ill7xpo99m12nf'), (b'openai-processing-ms', b'2241'), (b'openai-version', b'2020-10-01'), (b'strict-transport-security', b'max-age=15724800; includeSubDomains'), (b'x-ratelimit-limit-requests', b'10000'), (b'x-ratelimit-limit-tokens', b'1000000'), (b'x-ratelimit-limit-tokens_usage_based', b'1000000'), (b'x-ratelimit-remaining-requests', b'9999'), (b'x-ratelimit-remaining-tokens', b'998623'), (b'x-ratelimit-remaining-tokens_usage_based', b'998623'), (b'x-ratelimit-reset-requests', b'6ms'), (b'x-ratelimit-reset-tokens', b'82ms'), (b'x-ratelimit-reset-tokens_usage_based', b'82ms'), (b'x-request-id', b'e4a36612eec795fa5af299bdfd098b97'), (b'CF-Cache-Status', b'DYNAMIC'), (b'Set-Cookie', b'__cf_bm=27m6C3x7X54DWftRMSznhVPgp9qyqIr5qFBWFDPi.TY-1701015343-0-AZtNpm3T+1XbjdumxvrZ9TTYvFYjFVJBI2zo2/8SXe2zdDm38iShwZgIzIujnSyUqI3S7Xx7YdMurSWUWsIMvr0=; path=/; expires=Sun, 26-Nov-23 16:45:43 GMT; domain=.api.openai.com; HttpOnly; Secure; SameSite=None'), (b'Set-Cookie', b'_cfuvid=lstRes7eoujm1WJc_gabFXh4wvA0tnulJdms4Fo8hhg-1701015343099-0-604800000; path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None'), (b'Server', b'cloudflare'), (b'CF-RAY', b'82c36e737e046837-NRT'), (b'Content-Encoding', b'br'), (b'alt-svc', b'h3=":443"; ma=86400')])
INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
DEBUG:httpcore.http11:receive_response_body.started request=<Request [b'POST']>
receive_response_body.started request=<Request [b'POST']>
DEBUG:httpcore.http11:receive_response_body.complete
receive_response_body.complete
DEBUG:httpcore.http11:response_closed.started
response_closed.started
DEBUG:httpcore.http11:response_closed.complete
response_closed.complete
DEBUG:openai._base_client:HTTP Request: POST https://api.openai.com/v1/chat/completions "200 OK"
HTTP Request: POST https://api.openai.com/v1/chat/completions "200 OK"
DEBUG:llama_index.llm_predictor.base:You should watch movies that are composed of real native conversations. This will help you learn natural expressions that native speakers use in their daily lives. Additionally, watching movies will enhance your listening skills as the conversation speed in movies is faster than that in TOEIC listening audio. Once you get used to the speed of movies, the listening audio in the test should sound slower to you.
You should watch movies that are composed of real native conversations. This will help you learn natural expressions that native speakers use in their daily lives. Additionally, watching movies will enhance your listening skills as the conversation speed in movies is faster than that in TOEIC listening audio. Once you get used to the speed of movies, the listening audio in the test should sound slower to you.
You should watch movies that are composed of real native conversations. This will help you learn natural expressions that native speakers use in their daily lives. Additionally, watching movies will enhance your listening skills as the conversation speed in movies is faster than that in TOEIC listening audio. Once you get used to the speed of movies, the listening audio in the test should sound slower to you.
```

### ログ解析

ログの解析を進めるには、それぞれの行が何を意味しているのかを詳細に見ていくことが重要です。以下に、主要な部分について説明します。

1. **クエリのエンベディングの取得:**
    - **`DEBUG:openai._base_client:Request options: {'method': 'post', 'url': '/embeddings', ...}`**
    - このステップでは、ユーザーの質問「TOEIC700点だけど、具体的には、どういう映画を見ればいい？」をエンベディングに変換しています。
2. **APIへの接続とリクエストの送信:**
    - **`DEBUG:httpcore.connection:connect_tcp.started host='api.openai.com' port=443 ...`**
    - ここでは、OpenAIのAPIに対して安全な接続が確立され、その後リクエストが送信されています。
3. **関連文書の選択:**
    - **`DEBUG:llama_index.indices.utils:> Top 2 nodes: > [Node f192443c-1ccf-4cdb-88b5-7963323fd6f5] ...`**
    - 選択された「Top 2 nodes」は、ユーザーの質問に最も関連する文書を示しています。
4. **ChatGPTによる回答の生成:**
    - **`DEBUG:openai._base_client:Request options: {'method': 'post', 'url': '/chat/completions', ...}`**
    - 最終的に、ChatGPTが選ばれた文書コンテキストを基に回答を生成します。

このログにより、質問に対する回答を効率的に生成するためのLLAMA-INDEXとChatGPTの連携が明らかになります。