Open8

llama-index

happpyboyhapppyboy

llama-indexとは

LlamaIndex (GPT Index) is a project that provides a central interface to connect your LLM’s with external data.

LlamaIndex (GPT Index)は、あなたのLLMと外部データを接続するための中央インターフェースを提供するプロジェクトです。
https://gpt-index.readthedocs.io/en/stable/index.html

LLMと外部データソースがつながると何故嬉しいのか

LLMを個人データで補強することができる。

LLMを個人データで補強するための手段

fine-tuning

事前トレーニング済みモデルの重みが新しいデータでトレーニングされる転移学習へのアプローチ
https://en.wikipedia.org/wiki/Fine-tuning_(machine_learning)

プロンプトに文脈を埋め込む


https://speakerdeck.com/ryoheiigushi/chatgpt-apinoembedding-kasutamaisuru-men?slide=15 より引用
※ llama-indexはこの方法を簡単に実現できるようにしてくれる

具体的にできること

参考: https://gpt-index.readthedocs.io/en/stable/index.html#proposed-solution

happpyboyhapppyboy

検証環境

python -V
Python 3.9.16

パッケージのインストール

pip install llama-index

pip show llama-index
Name: llama-index
Version: 0.6.0
Summary: Interface between LLMs and your data
happpyboyhapppyboy

いろんな外部データソースと接続してみる

ローカルにあるデータからドキュメントを作成する

データをテキストファイルとして保存しておく。
今回はリコリス・リコイル - アニヲタWiki(仮) - atwiki(アットウィキ)をコピペ

from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader

# dataディレクトリ配下にテキストファイルを置いておく
documents = SimpleDirectoryReader('data').load_data()
index = GPTVectorStoreIndex.from_documents(documents)

query_engine = index.as_query_engine()
response = query_engine.query("リコリコとは?")
print(response)

参考:https://gpt-index.readthedocs.io/en/stable/getting_started/starter_example.html#build-and-query-index

リコリコとは、社会福祉公社が開発したリコリス(Robot Corps)を操作するためのプログラムである。リコリスは戦闘技術だけでなく、他言語の取得や車の運転技術取得も必須であり、取れなければリコリスになれないとの事。リコリスは制服の色でランクが区別され、エース扱いのファーストが赤、そのファーストを補助するセカンドが紺、そのさらに下の使い捨てモブサードリコリスがベージュとなっている。

URLを指定してドキュメントを作成する

参考:https://llamahub.ai/l/web-simple_web

データソース
リコリス・リコイル - Wikipedia
リコリス・リコイル - アニヲタWiki(仮) - atwiki(アットウィキ)
リコリス・リコイル(漫画)- マンガペディア

from llama_index import download_loader, GPTVectorStoreIndex

SimpleWebPageReader = download_loader("SimpleWebPageReader")

loader = SimpleWebPageReader()
urls = [
    'https://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%B3%E3%83%AA%E3%82%B9%E3%83%BB%E3%83%AA%E3%82%B3%E3%82%A4%E3%83%AB',
    'https://w.atwiki.jp/aniwotawiki/pages/51534.html',
    'https://mangapedia.com/%E3%83%AA%E3%82%B3%E3%83%AA%E3%82%B9%E3%83%BB%E3%83%AA%E3%82%B3%E3%82%A4%E3%83%AB-wa9beuxlr',
]

documents = loader.load_data(urls=urls)

index = GPTVectorStoreIndex.from_documents(documents)

# indexをローカルに保存
index.storage_context.persist(persist_dir="./storage")
# indexをロードする場合は
# from llama_index import StorageContext, load_index_from_storage
# storage_context = StorageContext.from_defaults(persist_dir="<persist_dir>")
# index = load_index_from_storage(storage_context)


query_engine = index.as_query_engine()
response = query_engine.query("リコリコとは?")
print(response)
リコリコは、都内某所の小さな喫茶店であり、美味しいコーヒーや甘いスイーツが評判なだけでなく、ご町内の困りごとを解決するボランティアも行っているという場所です。
response = query_engine.query("リコリコの主人公について教えて下さい")
錦木千束がリコリコの主人公です。17歳で、いつも明朗快活で、人との間に壁を作らず、他人にも作らせない程人懐っこい。どんな依頼にも一生懸命であり、その裏表のない人柄は多くの人を惹きつける。一方、年齢の割にどこか達観した部分もある。

その他

Llama Hubに利用できるデータソースのリストがある
自分でデータソースを追加することも可能

happpyboyhapppyboy

LLMのカスタマイズ

参考:https://gpt-index.readthedocs.io/en/stable/guides/primer/usage_pattern.html#customizing-llm-s
詳細:https://gpt-index.readthedocs.io/en/stable/how_to/customization/custom_llms.html

from llama_index import LLMPredictor, GPTVectorStoreIndex, PromptHelper, ServiceContext, SimpleDirectoryReader
from langchain import OpenAI

llm_predictor = LLMPredictor(llm=OpenAI(temperature=0, model_name="gpt-3.5-turbo"))

# define prompt helper
# set maximum input size
max_input_size = 4096
# set number of output tokens
num_output = 256
# set maximum chunk overlap
max_chunk_overlap = 20
prompt_helper = PromptHelper(max_input_size, num_output, max_chunk_overlap)
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper)

documents = SimpleDirectoryReader('data').load_data()
index = GPTVectorStoreIndex.from_documents(documents, service_context=service_context)

query_engine = index.as_query_engine()
response = query_engine.query("リコリコとは?")
print(response)
"""
リコリコは、戦闘技術や他言語の取得、車の運転技術などが必須とされる、特殊な兵士のことを指す。
彼女たちは、洗脳されていないが、教育の質や待遇が良いため、上官の命令に忠実であり、暴走・反逆の危険性も殺人への忌避感もない理想的な兵隊に仕上がっている。
制服の色でランクが区別されており、エース扱いのファーストが赤、そのファーストを補助するセカンドが紺、そのさらに下の使い捨てモブサードリコリスはベージュとなっている。
"""
happpyboyhapppyboy

プロンプトのカスタマイズ

from llama_index import QuestionAnswerPrompt, GPTVectorStoreIndex, SimpleDirectoryReader

# load documents
documents = SimpleDirectoryReader('data').load_data()

# define custom QuestionAnswerPrompt
QA_PROMPT_TMPL = (
    "We have provided context information below. \n"
    "---------------------\n"
    "{context_str}"
    "\n---------------------\n"
    "Given this information, please answer the question: {query_str}\n"
    "you should answer the question in the following format:\n"
    "question: {query_str}\n"
    "answer: [here is your answer]"
)
QA_PROMPT = QuestionAnswerPrompt(QA_PROMPT_TMPL)
index = GPTVectorStoreIndex.from_documents(documents)

query_engine = index.as_query_engine(text_qa_template=QA_PROMPT)
response = query_engine.query("リコリコとは?")
print(response)
Answer: リコリコとは、社会福祉公社が開発したリコリス(Robot Corps)を操作するためのプログラムである。リコリスは、戦闘技術だけでなく、他言語の取得や車の運転技術取得も必須であり、取れなければリコリスになれないとの事。リコリスは、薬物・催眠等を用いた洗脳を施されていないが、上官の命令に忠実であり、暴走・反逆の危険性も殺人への忌避感もない理想的な兵隊
response = query_engine.query("主人公は誰ですか?")
print(response)
question: 主人公は誰ですか?
answer: 錦木千束と井ノ上たきなです。

参考

https://gpt-index.readthedocs.io/en/stable/how_to/customization/custom_prompts.html
https://gpt-index.readthedocs.io/en/stable/reference/prompts.html

happpyboyhapppyboy

query engineのカスタマイズ

0.6.0からhigh-level-apiLow-level APIが提供された

細かい解説はこちら
https://medium.com/better-programming/llamaindex-0-6-0-a-new-query-interface-over-your-data-331996d47e89

細かい設定
https://gpt-index.readthedocs.io/en/stable/reference/query.html

High-level API

from llama_index import StorageContext, load_index_from_storage

storage_context = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(storage_context)

query_engine = index.as_query_engine()
response = query_engine.query("リコリコの主な登場人物は?")
print(response)
"""The main characters of Rikoriko are 錦木千束 and 井ノ上たきな."""

Low-level API

from llama_index import (
    GPTVectorStoreIndex,
    ResponseSynthesizer,
)
from llama_index.retrievers import VectorIndexRetriever
from llama_index.query_engine import RetrieverQueryEngine
from llama_index.indices.postprocessor import SimilarityPostprocessor

# build index
storage_context = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(storage_context)

# configure retriever
retriever = VectorIndexRetriever(
    index=index,
    similarity_top_k=1,
)

# configure response synthesizer
response_synthesizer = ResponseSynthesizer.from_args(
    node_postprocessors=[
        SimilarityPostprocessor(similarity_cutoff=0.7)
    ]
)

# assemble query engine
query_engine = RetrieverQueryEngine(
    retriever=retriever,
    response_synthesizer=response_synthesizer,
)

# query
response = query_engine.query("リコリコの主な登場人物は?")
print(response)
"""
1. 井ノ上たきな
2. エリカ
3. 真島
4. マシンガンを殲滅した武器商人達
5. アランチルドレン
"""

happpyboyhapppyboy

langchainを利用したchat bot

https://gpt-index.readthedocs.io/en/stable/guides/tutorials/building_a_chatbot.html

from langchain.chains.conversation.memory import ConversationBufferMemory
from llama_index.langchain_helpers.agents import LlamaToolkit, create_llama_chat_agent, IndexToolConfig
from llama_index.indices.query.query_transform.base import DecomposeQueryTransform
from llama_index import StorageContext, load_index_from_storage, LLMPredictor
from langchain import OpenAI

llm_predictor = LLMPredictor(llm=OpenAI(temperature=0, max_tokens=512))
decompose_transform = DecomposeQueryTransform(llm_predictor, verbose=True)
storage_context = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(storage_context)

query_engine = index.as_query_engine()

# tool config
graph_config = IndexToolConfig(
    query_engine=query_engine,
    name=f"ricorico Index",
    description="useful for when you want to answer queries that ricorico or リコリコ can answer",
    tool_kwargs={"return_direct": True}
)

toolkit = LlamaToolkit(index_configs=[graph_config])
memory = ConversationBufferMemory(memory_key="chat_history")
llm=OpenAI(temperature=0)
agent_chain = create_llama_chat_agent(
    toolkit,
    llm,
    memory=memory,
    verbose=True
)

while True:
    text_input = input("User: ")
    response = agent_chain.run(input=text_input)
    print(f'Agent: {response}')