LlamaIndex v0.10のLLMのカスタマイズをやってみる

2024/03/06

こちらの公式ドキュメント(v0.10.16)を参考に評価についてまとめていきます.

LlamaIndex アブストラクションにおけるLLMのカスタマイズ

LLMの抽象化をLlamaIndexの他のモジュール(インデックス、検索器、クエリエンジン、エージェント)にプラグインすると、データに対して高度なワークフローを構築することができます。

デフォルトでは、OpenAIの`gpt-3.5-turbo`モデルを使用します。ただし、使用されているベースLLMをカスタマイズすることもできます。

以下に、LLMカスタマイズの例をいくつか示します。

  • underlyingなLLMを変更する

  • 出力トークンの数の変更(OpenAI, Cohere, AI21の場合)

  • コンテキストウィンドウからチャンクオーバーラップまで、LLMの全てのパラメータをよりきめ細かく制御

例: underlying LLMの変更

使用されているLLMをカスタマイズするスニペットの例を以下に示します。この例では、`gpt-3.5-turbo`の代わりに`gpt-4`を使用します。

使用可能なモデルには、gpt-3.5-turbo, gpt-3.5-turbo-instruct, gpt-3.5-turbo-16k, gpt-4, gpt-4-32k, text-davinci-003, text-davinci-002 が含まれます。

LangchainのLLMページに表示されているLLMをプラグインすることもできます。

from llama_index.core import KeywordTableIndex, SimpleDirectoryReader
from llama_index.llms.openai import OpenAI

# alternatively
$ from langchain.llms import ...

documents = SimpleDirectoryReader("data").load_data()

# define LLM
llm = OpenAI(temperature=0,1, model="gpt-4")

# インデックス構築
index = KeywordTableIndex.form_documents(documents, llm=llm)

# クエリから応答を取得
query_engine = index.as_query_engine()
response = query_engine.query(
    "What did the author do after his time at Y Combinator?"
)

例: 出力トークン数の変更(OpenAI, Cohere, AI21の場合)

出力トークンの数は通常、デフォルトで低い数値に設定されます(たとえば、OpenAIデフォルトは256)。

OpenAI、Cohere、AI21の場合はパラメーター(AI21の場合はmaxTokens)を設定するだけです。テキストのチャンク化や計算は内部で処理できます。

from llama_index.core import KeywordTableIndex, SimpleDirectoryReader
from llama_index.llms.openai import OpenAI
from llama_index.core import Settings

documents = SimpleDirectoryReader("data").load_data()

# グローバルLLMを定義
Settings.llm = OpenAI(temperature=0, model="gpt-3.5-turbo", max_tokens=512)

例: context_windowとnum_outputの明示的な環境設定

languchainからの他のLLMクラスを使用している場合、デフォルトでは情報が利用できないため、context_windowおよびnum_outputを明示的に設定する必要があるかもしれません。

from llama_index.core import KeywordTableIndex, SimpleDirectoryReader
from llama_index.llms.openai import OpenAI
from llama_index.core import Settings

documents = SimpleDirectoryReader("data").load_data()

# コンテキストウィンドウのセット
Settings.context_window = 4096
# 出力トークンの数をセット
Settings.num_output = 256

# LLMの定義
Settings.llm = OpenAI(
    temperature=0,
    model="gpt-3.5-turbo",
    max_tokens=num_output,
)

例: HuggingFace LLM の使用

LlamaIndexはHuggingFaceからのLLMを直接使用することができます。完全にプライベートな実行をしたい場合は、ローカル埋め込みモデルもセットアップすることに注意してください。

HuggingFaceの多くのオープンソースモデルでは、各プロンプトの前になんらかのプリアンブル(事前説明)が必要です。これは`system_prompt`と呼ばれます。さらに、クエリ自体には、`query_str`自体を囲む追加のラッパーが必要になることもあります。通常、これらの情報はすべて使用しているモデルのHuggingFaceモデルカードから入手できます。

以下の例では、system_prompt とquery_wrapper_prompt の両方を使用して、

from llama_index.core import PromptTemplate

# stringを入力zephyr-specificに変形
def completion_to_prompt(completion):
    return f"<|system|>\n</s>\n</s>\n<|user|>\n{completion}</s>\n<|assistant|>\n"

# チャットメッセージリストをzephyr-specific 入力に変換
def messages_to_prompt(messages):
    prompt = ""
    for message in messages:
        if message.role == "system":
            prompt += f"<|system|>\n{message.content}</s>\n"
        elif message.role == "user":
            prompt += f"<|user|>\n{message.content}</s>\n"
        elif message.role == "assistant":
            prompt += f"<|assistant|>\n{message.content}</s>\n"

    # ensure we start with a system prompt, insert blank if needed
    if not prompt.startswith("<|system|>\n"):
        prompt = "<|system|>\n</s>\n" + prompt

    # add final assistant prompt
    prompt = prompt + "<|assistant|>\n"

    return prompt

import torch
from llama_index.llms.huggingface import HuggingFaceLLM
from llama_idnex.core import Settings

Settings.llm = HuggingFaceLLM(
    model_name="HuggingFaceH4/zephyr-7b-beta",
    tokenizer_name="HuggingFaceH4/zephyr-7b-beta",
    context_window=3900,
    max_new_tokens=256,
    generate_kwargs={"temperature": 0.7, "top_k": 50, "top_p": 0.95},
    messages_to_prompt=messages_to_prompt,
    completion_to_prompt=completion_to_prompt,
    device_map="auto",
)

一部のモデルでは、トークナイザーからの全てのキーがモデルに渡されるとエラーが発生します。問題を引き起こす一般的なトークナイザー出力は`token_type_ids`です。以下は、入力をモデルに渡す前にこれを削除するようにpredictorを構成する例です。

HuggingFaceLLM(
    # ...
    tokenizer_outputs_to_remove=["token_type_ids"]
)

完全なAPIリファレンスはこちらです。
いくつかのノートブックの例もあります。

例: カスタムLLMモデルの使用 - 発展

カスタムLLMモデルを使用するには、LLM(またはより単純なインタフェースのCustomLLM)を実装するだけで良いです。テキストをモデルに私、新しく生成されたトークンを返す必要があります。

この実装は、ローカルモデルである場合もあれば、独自のAPIのラッパーである場合もあります。

完全にプライベートな実行を得るには、ローカル埋め込みモデルのセットアップする必要があります。

以下に短いテンプレート例を示します。

from typing import Optional, List, Mapping, Any

from llama_index.core import SImpleDirectoryReader, SummaryIndex
from llama_index.core.callbacks import CallbackManager
from llama_index.core.llms import(
CustomLLM,
    CompletionResponse,
    CompletionResponseGen,
    LLMMetadata,
)
from llama_index.core.llms.callbacks import llm_completion_callback
from llama_index.core import Settings

class OurLLM(CustomLLM):
    context_window: int = 3900
    num_output: int = 256
    model_name: str = "custom"
    dummy_response: str = "My response"

    @property
    def metadata(self) -> LLMMetadata:
        """Get LLM metadata."""
        return LLMMetadata(
            context_window=self.context_window,
            num_output=self.num_output,
            model_name=self.model_name,
        )

    @llm_completion_callback()
    def complete(self, prompt: str, **kwargs: Any) -> CompletionResponse:
        return CompletionResponse(text=self.dummy_response)

    @llm_completion_callback()
    def stream_complete(
        self, prompt: str, **kwargs: Any
    ) -> CompletionResponseGen:
        response = ""
        for token in self.dummy_response:
            response += token
            yield CompletionResponse(text=response, delta=token)


# define our LLM
Settings.llm = OurLLM()

# define embed model
Settings.embed_model = "local:BAAI/bge-base-en-v1.5"


# Load the your data
documents = SimpleDirectoryReader("./data").load_data()
index = SummaryIndex.from_documents(documents)

# Query and print response
query_engine = index.as_query_engine()
response = query_engine.query("<query_text>")
print(response)

この方法を使用すると、任意のLLMを使用できます。ローカルで実行するものも、独自のサーバーで実行するものもあります。クラスが実装され、生成されたトークンが返される限り、うまくいくはずです。

各モデルのコンテキストの長さはわずかに異なるため、プロンプトサイズをカスタマイズするにはプロンプトヘルパーを使用する必要があることに注意してください。

デコレーターはオプションですが、LLM呼び出しのコールバックを介して可観測性を提供します。

良好なパフォーマンスを得るには、内部プロンプトの調整が必要であることも注意してください。その場合でも、LlamaIndexが内部で使用する複雑なクエリを確実に処理できるように、十分な大きさのLLMを使用する必要があるため、得られるものは異なる場合があります。

すべてのデフォルトの内部プロンプトのリストはここにあり、チャット固有のプロンプトはここにリストされています。独自のカスタム プロンプトを実装することもできます。

まとめ

  • indexの引数に`llm=`を指定することで使用するLLMを変更できる

  • LangchainやHuggingFaceからモデルを引っ張ってくることができる

  • カスタムモデルを使用する際は、


次に読む記事

https://docs.llamaindex.ai/en/stable/understanding/evaluating/cost_analysis/root.html


支援のお願い

ここまで読んでいただきありがとうございます。「スキ」で反応をいただけると励みになります。

また、継続的な記事の公開のために、支援をしていただけると幸いです。

https://note.com/rhe/n/n01096a6aed38


この記事が気に入ったらサポートをしてみませんか?