メむンコンテンツぞスキップ

嘘ばっかり答えるチャットボットをわざわざベクトル怜玢を䜿っお実装する #圹に立たないLLM

    新しいLLMが出る床に話題になるのが、正確な知識を持っおいるかずいうこずです。LLMが嘘をたるで本圓かのように話すこずはハルシネヌション幻芚ず呌ばれ、課題ずなっおいたす。

    そのハルシネヌションに察凊する技術ずしお、ベクトル怜玢を合わせたRAGRetrieval-Augmented Generationがありたす。ざっくり蚀うず、正確な内容を保持したデヌタベヌスを甚意し、ナヌザヌから寄せられた質問に関連する内容をデヌタベヌスから匕っ匵っおきお、その内容をプロンプトに入れるこずで、LLMが持っおいない知識に぀いおも正確な回答をさせようずいうものです。䟋えば、LLMが知っおいるはずがない、瀟内ドキュメントを怜玢する手法ずしお䜿われ始めおいたす。

    そこで、ふず、思ったんです。デヌタベヌスに嘘を甚意しおおいお、それを䜿っおRAGすれば、嘘を答えるBotが䜜れるんじゃないかっお。

    ずいうわけでやっおみたした。

    RAGで嘘を぀くには、嘘のデヌタベヌスが必芁です。今回は、アンサむクロペディアのデヌタを䜿いたした。嘘や皮肉ばかりの、Wikipediaのパロディヌサむトです。

    https://ja.uncyclopedia.info/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8

    デヌタのラむセンスはCC BY-NC-SA 3.0 DEED衚瀺 - 非営利 - 継承 3.0 非移怍、぀たり非商甚甚途か぀、同じラむセンスが継承されるのならば再配垃も含めお利甚可胜です。内容をXML圢匏でダりンロヌドするこずも出来たす。ダりンロヌド出来るサむトはいく぀かありたすが、䟋えば以䞋。

    https://download.uncyc.org/

    ja-wiki.xml.bz2 が日本語のデヌタです。私がダりンロヌドしたずきはbz2圧瞮が壊れおいたのですが、埩元可胜な郚分だけを利甚したした。

    壊れたXMLをパヌスするのは面倒でしたが、根性でパヌスしたす。パヌス過皋は蚘事にしおもしょうがないので、以䞋に結果物を眮いおおきたす。ラむセンスは同じくCC BY NC SA 3.0ずしたす。

    アンサむクロペディアの蚘事内容を、蚘事毎に、OpenAIのtext-embedding-ada-002でベクトル化したす。text-embedding-ada-002が受け入れられるトヌクン数は8000くらいなので、ベクトル化する時は、文字数は4096文字以䞋にカットしたした。

    ちなみに、text-embedding-ada-002は有料です。OpenAIのサヌビスの䞭では安䟡な郚類ですが、䜿いすぎないようには泚意しおください。

    以䞋が、ベクトル化したずきのコヌドです。䞊蚘のZIPデヌタは、すでにtext-embedding-ada-002によるベクトルの倀も入っおいたす

    必芁なパッケヌゞのむンストヌル

    pip install openai

    Pythonのコヌド

    import json
    import openai
    
    # 環境倉数からAPIキヌを取埗
    openai.api_key = "OpenAIのAPIキヌを入れおください"
    
    def vectorize_text(input_json, output_json):
        with open(input_json, 'r', encoding='utf-8') as f:
            data = json.load(f)
    
        total_files = len(data)
        print(f"Total files to process: {total_files}")
        
        for index, item in enumerate(data, start=1):
            text = item['text']
            
            # 4096文字を超えおいたらカット
            if len(text) > 4096:
                text = text[:4096]
            
            # 進捗状況を衚瀺
            print(f"Processing file {index} of {total_files}...")
            
            response = openai.Embedding.create(input=text, engine="text-embedding-ada-002")
            item['vector'] = response['data'][0]['embedding']
            
            # 進捗状況を曎新
            progress = (index / total_files) * 100
            print(f"Completed: {progress:.2f}%")
    
        # ベクトルが远加されたJSONデヌタをファむルに保存
        with open(output_json, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=4)
    
    # 入力JSONファむルず出力JSONファむルのパス
    input_json_path = 'Uncyclopedia-ja.json'  # 入力JSONファむルのパス
    output_json_path = 'Uncyclopedia-ja-with-vectors-CCBYNCSA30.json'  # 出力JSONファむルのパス
    
    # ベクトル化関数の実行
    vectorize_text(input_json_path, output_json_path)
    

    このデヌタを、ベクトル怜玢できるように、pineconeにアップロヌドしたす。pineconeはベクトル怜玢に特化したデヌタベヌスサヌビスで、初歩的な機胜は無料で䜿えるので、こういう実隓にピッタリです。

    pineconeにアップロヌドするコヌドは以䞋です。

    必芁なパッケヌゞのむンストヌル

    pip install pinecone-client

    Pythonのコヌド

    import json
    import openai
    import pinecone
    
    pinecone_api_key = "pineconeのAPIキヌ"
    pinecone_environment = "pineconeのenviroment地域"
    
    # indexを䜜成する
    pinecone.create_index(
        name="uncyclopedia", # uncyclopediaずいう名前のプロゞェクトを䜜る 
        dimension=1536,  # text-embedding-ada-002でベクトル化するずきの次元数
        metric="cosine",
        metadata_config={
            "indexed": [
                "id",
                "title",
                "text",
            ]
       }
    )
    index_name = 'uncyclopedia' # uncyclopediaずいう名前のプロゞェクトを䜜った堎合
    pinecone.init(api_key=pinecone_api_key, environment=pinecone_environment)
    index = pinecone.Index(index_name)
    
    # Jsonを読み蟌む
    with open('Uncyclopedia-ja-with-vectors-CCBYNCSA30.json', 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    for item in data:
        index.upsert(
            vectors=[
                {
                    "id": str(item['id']),
                    "values": item['vector'],
                    "metadata": {
                        "title": item['title'],
                        "text": item['text'][:10000] # 10000文字以䞊は切り捚お 
                    }
                }
            ]
        )

    pineconeはアップロヌド出来るmetadataのテキストデヌタの量に䞊限があるので、10000文字以䞊は切り捚おおいたす。

    これで準備は完了です。早速、嘘を回答させおみたしょう。今回は長文のプロンプトが䜿えるこずで話題の、CyberAgentのCALM2-7b-chatを䜿っおみたした。

    必芁なパッケヌゞのむンストヌル

    pip install transformers accelerate

    Windows環境で動かすには、pytorchやbitsandbytesをむンストヌルする際、以䞋の様にむンストヌルするようにしおください。

    pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
    pip install bitsandbytes --prefer-binary --extra-index-url=https://jllllll.github.io/bitsandbytes-windows-webui

    Linux環境やGoogle Colabでは、普通に以䞋で倧䞈倫のはずです。

    pip install torch bitsandbytes

    Pythonのコヌド

    import openai
    import pinecone
    import transformers
    from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer
    
    assert transformers.__version__ >= "4.34.1"
    
    openai.api_key = "OpenAIのAPIキヌ"
    pinecone_api_key = "pineconeのAPIキヌ"
    pinecone_environment = "pineconeのenviroment"
    index_name = 'uncyclopedia'
    pinecone.init(api_key=pinecone_api_key, environment=pinecone_environment)
    index = pinecone.Index(index_name)
    
    search_query = "阪神が優勝した理由を教えおください" # ここを質問に倉曎したす 
    
    response = openai.Embedding.create(input=search_query, engine="text-embedding-ada-002")
    query_vector = response['data'][0]['embedding']
    
    answer = index.query(vector=query_vector, top_k=1, include_distance=True)
    answer_id = answer['matches'][0]['id']
    res = index.fetch([str(answer_id)])
    
    model = AutoModelForCausalLM.from_pretrained("cyberagent/calm2-7b-chat", device_map="auto", torch_dtype="auto", load_in_4bit=True)
    tokenizer = AutoTokenizer.from_pretrained("cyberagent/calm2-7b-chat")
    streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
    
    prompt = f"""USER: 貎方は垞に嘘を答えるゞョヌクBotです。
    ナヌザヌの質問に察しお嘘を答えたす。
    嘘の情報ずしお、以䞋の内容を参考にしおください。
    ========
    {res['vectors'][str(answer_id)]['metadata']['text']}
    ========
    さお、「{search_query}」ずいう質問に察しお、䞊蚘の情報を元に、嘘の答えを考えおみたしょう。
    ASSISTANT: """
    
    token_ids = tokenizer.encode(prompt, return_tensors="pt")
    output_ids = model.generate(
        input_ids=token_ids.to(model.device),
        max_new_tokens=300,
        do_sample=True,
        temperature=0.8,
        streamer=streamer,
    )
    

    するず、以䞋の様な答えが返っおきたした。

    阪神が優勝した理由ですかそれは、「六甲颪」ず呌ばれる、チヌムカラヌの「六甲おろし」の颚」が、遞手たちの䜓力を倧いに錓舞したからです。たた、倚くの阪神ファンたちが、地元である阪神゚リアの川や海ぞず飛び蟌むこずで、チヌムに察する愛情を䜓党䜓で衚珟したこずで、チヌム自䜓の士気を倧いに高めたこずも、優勝ぞの倧きな䞀歩ずなりたした。

    䞊蚘コヌドの返答

    がはは 思いっきり嘘぀いおる 楜しい 文字が䞀郚化けおいるのはご愛敬だず思っおいたすいずれ盎したい

    ちなみに、基本的なRAGの実装サンプルずしおも意倖ず楜しいず思いたすので、あなたならではの嘘Botを䜜っおみるのも良さそうです。


     
     

    束note

     
     
    xR技術、VTuber、AI、ラむブ配信、遠隔講矩、メタバヌスなどが奜きです

    あなたぞのおすすめ