paint-brush
Kelime Gömmeleri: Daha İyi Yanıtlar İçin ChatBot Bağlamınızı Sağlamanın Gizli Sosuile@tomfernblog
2,991 okumalar
2,991 okumalar

Kelime Gömmeleri: Daha İyi Yanıtlar İçin ChatBot Bağlamınızı Sağlamanın Gizli Sosu

ile Tomas Fernandez18m2023/07/26
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Kelime yerleştirmeleri ve ChatGPT'yi kullanarak uzman bir botun nasıl oluşturulacağını öğrenin. Sohbet robotunuzun yanıtlarını geliştirmek için kelime vektörlerinin gücünden yararlanın.
featured image - Kelime Gömmeleri: Daha İyi Yanıtlar İçin ChatBot Bağlamınızı Sağlamanın Gizli Sosu
Tomas Fernandez HackerNoon profile picture
0-item
1-item

OpenAI'nin ChatGPT'sinin son derece akıllı olduğuna şüphe yok; avukatlık sınavını geçmiş, doktor benzeri bilgiye sahip ve bazı testler IQ'sunun 155 olduğunu gösteriyor . Ancak cehaleti kabul etmek yerine bilgiyi uydurma eğilimindedir. Bu eğilim, bilgi birikiminin 2021'de sona ereceği gerçeğiyle birleştiğinde, GPT API'yi kullanarak özel ürünler oluşturma konusunda zorluklar ortaya çıkarıyor.


Bu engelleri nasıl aşabiliriz? GPT-3 gibi bir modele yeni bilgileri nasıl aktarabiliriz? Amacım Python, OpenAI API ve sözcük yerleştirmeleri kullanan bir soru yanıtlayan bot oluşturarak bu soruları yanıtlamak.

Ne İnşa Edeceğim

Bildiğiniz gibi Semaphore CI/CD'de YAML ile biçimlendirilmiş bir istemden sürekli entegrasyon ardışık düzenleri oluşturan bir bot oluşturmayı düşünüyorum.


İşte botun çalışırken bir örneği:

Çalışan programın ekran görüntüsü. Ekranda şu komut yürütülür: python query.py "Docker görüntüsünü oluşturup Docker Hub'a yükleyen bir CI işlem hattı oluşturun" ve program, istenen eylemi gerçekleştiren bir CI işlem hattına karşılık gelen YAML'yi yazdırır. Çalışan programın ekran görüntüsü. Ekranda python query.py "Create a CI pipeline that builds and uploads a Docker image to Docker Hub" yürütülür ve program, istenen eylemi gerçekleştiren bir CI işlem hattına karşılık gelen YAML'yi yazdırır.


DocsGPT , My AskAI ve Libraria gibi projelerin ruhuna uygun olarak, GPT-3 modelini Semaphore ve ardışık düzen yapılandırma dosyalarının nasıl oluşturulacağı hakkında "öğretmeyi" planlıyorum. Bunu mevcut belgelerden yararlanarak başaracağım.


Bot oluşturma konusunda önceden bilgi sahibi olduğumu varsaymayacağım ve gereksinimlerinize uyarlayabilmeniz için temiz kodu koruyacağım.

Önkoşullar

Bu öğreticiyi takip etmek için bir bot kodlama deneyimine veya sinir ağları bilgisine ihtiyacınız yoktur. Ancak ihtiyacınız olacak:


Ama ChatGPT Öğrenemez, Değil mi?

ChatGPT veya daha doğrusu GPT-3 ve GPT-4, onları destekleyen Büyük Dil Modelleri (LLM), Eylül 2021 civarında sonlanma tarihi olan devasa bir veri kümesi üzerinde eğitildi.


Aslında GPT-3 bu tarihin ötesindeki olaylar hakkında çok az şey biliyor. Bunu basit bir istemle doğrulayabiliriz:

ChatGPT'in ekran görüntüsü ChatGPT, 2022'de Dünya Kupasını kimin kazandığını bilmiyor.


Bazı OpenAI modelleri ince ayardan geçebilirken, ilgilenilenler gibi daha gelişmiş modeller bunu yapamaz; onların eğitim verilerini artıramayız.


GPT-3'ten eğitim verilerinin ötesinde nasıl yanıt alabiliriz? Yöntemlerden biri metni anlama yeteneklerinden yararlanmayı içerir; Bilgi istemini ilgili bağlamla zenginleştirerek muhtemelen doğru cevabı elde edebiliriz.


Aşağıdaki örnekte, FIFA'nın resmi sitesinden bağlamı aktarıyorum ve yanıtlar önemli ölçüde farklılık gösteriyor:

Soruya ikinci yanıt verme girişimi Sağlanan bağlamla ChatGPT doğru yanıt verebilir.


Yeterince ilgili bağlam verildiğinde modelin herhangi bir soruya yanıt verebileceği sonucunu çıkarabiliriz. Soru hala ortada: Keyfi bir istemle neyin alakalı olduğunu nasıl bilebiliriz? Bu sorunu çözmek için kelime yerleştirmelerin ne olduğunu araştırmamız gerekiyor.

Kelime Gömmeleri Nelerdir?

Dil modelleri bağlamında gömme, kelimeleri, cümleleri veya tüm belgeleri vektörler veya sayı listeleri olarak temsil etmenin bir yoludur.


Gömmeleri hesaplamak için word2vec veya text-embedding-ada-002 gibi bir sinir ağına ihtiyacımız olacak. Bu ağlar çok büyük miktarda metin üzerinde eğitilmiştir ve eğitim verilerinde belirli kalıpların görünme sıklığını analiz ederek kelimeler arasındaki ilişkileri bulabilirler.


Diyelim ki elimizde şu kelimeler var:

  • Kedi
  • Köpek
  • Top
  • Ev


Her kelimenin vektörlerini hesaplamak için bu yerleştirme ağlarından birini kullandığımızı hayal edin. Örneğin:

Kelime

Vektör

Bağlam

Kedi

[0,1, 0,2, 0,3, 0,4, 0,5]

Hayvanlar, nesneler, küçük şeyler

Köpek

[0,6, 0,7, 0,8, 0,9, 1,0]

Hayvanlar, nesneler, büyük şeyler

Top

[0,2, 0,4, 0,6, 0,8, 1,0]

Nesneler, oyuncaklar, küçük şeyler

Ev

[0,3, 0,6, 0,9, 1,2, 1,5]

Binalar, evler, büyük şeyler

Her kelimenin vektörlerini aldıktan sonra bunları metnin anlamını temsil etmek için kullanabiliriz. Örneğin, "Kedi topu kovaladı" cümlesi şu şekilde gösterilebilir: [0,1, 0,2, 0,3, 0,4, 0,5] + [0,2, 0,4, 0,6, 0,8, 1,0] = [0,3, 0,6, 0,9, 1,2 , 1.5]. Bu vektör bir nesneyi kovalayan bir hayvanla ilgili bir cümleyi temsil ediyor.


Kelime gömmeleri, benzer anlamlara sahip kelime veya cümlelerin birbirine yakın olduğu çok boyutlu alanlar olarak görselleştirilebilir. Herhangi bir girdi metnine benzer anlamlar bulmak için vektörler arasındaki "mesafeyi" hesaplayabiliriz.

Vektörlerin üç boyutlu gösterimleri. Bunlardan ilki 'Erkek-Kadın' olarak etiketlenmiş ve erkek-kadın ve kral-kraliçe veri noktalarına sahipken, ikincisi 'Fiil-Zamanı' etiketli olup yürüme-yürüyüş yüzme-yüzme gibi fiiller içermektedir. Sonuncusu 'Ülke Başkenti' olarak etiketlenmiştir ve ülkelerine bağlı birçok başkente sahiptir. Gömmelerin vektör uzayları olarak 3 boyutlu gösterimi. Gerçekte bu uzayların yüzlerce ya da binlerce boyutu olabilir. Kaynak: Yapay Zekanın Çok Amaçlı Aracıyla Tanışın: Vektör Yerleştirmeleri


Tüm bunların ardındaki gerçek matematik bu makalenin kapsamı dışındadır. Bununla birlikte, önemli çıkarım , vektör işlemlerinin matematiği kullanarak anlamı değiştirmemize veya belirlememize olanak sağlamasıdır . “Kraliçe” kelimesini temsil eden vektörü alın, “kadın” vektörünü bundan çıkarın ve “erkek” vektörünü ekleyin. Sonuç “kral”ın yakınında bir vektör olmalıdır. “Oğul”u eklersek “prens”e yakın bir yere gelmeliyiz.

Sinir Ağlarını Belirteçlerle Yerleştirme

Şu ana kadar kelimeleri girdi, sayıları da çıktı olarak alan sinir ağlarının yerleştirilmesini tartıştık. Ancak birçok modern ağ, kelimeleri işlemekten jetonları işlemeye geçti.


Belirteç , model tarafından işlenebilen en küçük metin birimidir. Belirteçler sözcükler, karakterler, noktalama işaretleri, semboller veya sözcük parçaları olabilir.


Metni belirteçlere dönüştürmek ve her birini bir sayıyla temsil etmek için Bayt Çifti Kodlama (BPE) kullanan OpenAI çevrimiçi belirteç oluşturucuyu deneyerek kelimelerin nasıl belirteçlere dönüştürüldüğünü görebiliriz:

OpenAI tokenizer'ın ekran görüntüsü. Bir miktar metin girildi ve her simge farklı renklerle temsil ediliyor, bu da kelimelerin simgelerle nasıl eşleştirildiğini görmemize olanak tanıyor. Metinde şu yazıyor: Herhangi bir yerleştirme modelinin arkasında, giriş metnini vektörlere dönüştüren bir sinir ağı vardır. Her tür yerleştirme modelinin farklı yetenekleri ve hızları vardır. Örneğin Word2vec, kelimeleri alıp 100 ila 300 boyut aralığında vektörler üretiyor. Belirteçler ve kelimeler arasında genellikle 1'e 1 ilişki vardır. Çoğu jeton, kelimeyi ve baştaki boşluğu içerir. Bununla birlikte, "embed" ve "ding" olmak üzere iki jetondan oluşan "gömme" veya dört jetondan oluşan "yetenekler" gibi özel durumlar da vardır. "Jeton Kimlikleri"ne tıklarsanız modelin her bir jetonun sayısal temsilini görebilirsiniz.

Gömmeleri Kullanarak Daha Akıllı Bir Bot Tasarlamak

Artık yerleştirmelerin ne olduğunu anladığımıza göre bir sonraki soru şu: Daha akıllı bir bot oluşturmamıza nasıl yardımcı olabilirler?


Öncelikle GPT-3 API'sini doğrudan kullandığımızda ne olacağına bakalım. Kullanıcı bir istem gönderir ve model, yeteneğinin en iyisine yanıt verir.

Kullanıcı ile GPT-3 arasındaki etkileşimi gösteren diyagram. Kullanıcı bir bilgi istemi gönderir ve model yanıt verir.


Ancak denkleme bağlam eklediğimizde işler değişiyor. Örneğin, bağlamı sağladıktan sonra ChatGPT'ye Dünya Kupası'nın galibi hakkında soru sorduğumda büyük fark yarattı.


Yani daha akıllı bir bot oluşturma planı şu şekildedir:

  1. Kullanıcının istemini durdurun.
  2. Bu istemin yerleştirmelerini hesaplayarak bir vektör elde edin.
  3. Başlangıçtaki bilgi istemiyle anlamsal olarak alakalı olmaları gerektiğinden, vektörün yakınındaki belgeler için bir veritabanında arama yapın.
  4. Orijinal istemi ilgili bağlamla birlikte GPT-3'e gönderin.
  5. GPT-3'ün yanıtını kullanıcıya iletin.

Bir botun daha karmaşık bir uygulaması. Kullanıcı, istemi bir bağlam veritabanında arama yapan ve bunu istemi zenginleştirmek için kullanan bir sohbet robotu uygulamasına gönderir. İstem GPT-3'e gönderilir ve yanıtı kullanıcıya iletilir.


Çoğu projede olduğu gibi veritabanını tasarlayarak başlayalım.

Gömmelerle Bilgi Veritabanı Oluşturma

Bağlam veritabanımız orijinal belgeleri ve bunların ilgili vektörlerini içermelidir. Prensip olarak bu görev için her tür veritabanını kullanabiliriz ancak vektör veritabanı bu iş için en uygun araçtır.


Vektör veritabanları, yüksek boyutlu vektör verilerini depolamak ve almak için tasarlanmış özel veritabanlarıdır. Arama için SQL gibi bir sorgu dili kullanmak yerine bir vektör sağlıyoruz ve en yakın N komşuyu talep ediyoruz.


Vektörleri oluşturmak için OpenAI'nin text-embedding-ada-002'sini kullanacağız çünkü bu, sundukları en hızlı ve en uygun maliyetli modeldir. Model, giriş metnini belirteçlere dönüştürür ve aralarındaki ilişkileri öğrenmek için Transformer olarak bilinen bir dikkat mekanizmasını kullanır. Bu sinir ağının çıktısı metnin anlamını temsil eden vektörlerdir.

Tokenizasyon sürecini gösteren diyagram. Bir belge tokenleştirilir ve daha sonra yerleşik bir sinir ağına gönderilir. Ağın çıktısı bir vektördür.


Bir bağlam veritabanı oluşturmak için şunları yapacağım:

  1. Tüm kaynak belgelerini toplayın.
  2. İlgisiz belgeleri filtreleyin.
  3. Her belge için yerleştirmeleri hesaplayın.
  4. Vektörleri, orijinal metni ve diğer ilgili meta verileri veritabanında saklayın.

Bağlam veritabanında veri saklama sürecini gösteren diyagram. Kaynak belge gömülü sinir ağına gönderilir. Veritabanı, vektörü orijinal metinle birlikte saklar.

Belgeleri Vektörlere Dönüştürme

Öncelikle OpenAI API anahtarıyla bir ortam dosyasını başlatmalıyım. API anahtarı özel olduğundan ve hesabınıza bağlı olduğundan bu dosya hiçbir zaman sürüm kontrolüne alınmamalıdır.

 export OPENAI_API_KEY=YOUR_API_KEY

Daha sonra Python uygulamam için bir virtualenv oluşturacağım:

 $ virtualenv venv $ source venv/bin/activate $ source .env

Ve OpenAI paketini yükleyin:

 ```bash $ pip install openai numpy

"Docker Container" dizisinin yerleştirmesini hesaplamayı deneyelim. Bunu Python REPL'de veya Python betiği olarak çalıştırabilirsiniz:

 $ python >>> import openai >>> embeddings = openai.Embedding.create(input="Docker Containers", engine="text-embedding-ada-002") >>> embeddings JSON: { "data": [ { "embedding": [ -0.00530336843803525, 0.0013223182177171111, ... 1533 more items ..., -0.015645816922187805 ], "index": 0, "object": "embedding" } ], "model": "text-embedding-ada-002-v2", "object": "list", "usage": { "prompt_tokens": 2, "total_tokens": 2 } }

Gördüğünüz gibi, OpenAI'nin modeli 1536 öğe içeren bir embedding listesiyle yanıt veriyor - metin yerleştirme-ada-002'nin vektör boyutu.

Gömmelerin Çam Kozalağı'nda saklanması

Açık kaynaklı Chroma gibi seçilebilecek birden fazla vektör veritabanı motoru olmasına rağmen, Pinecone'u seçtim çünkü bu, ücretsiz katmana sahip yönetilen bir veritabanı, bu da işleri kolaylaştırıyor. Başlangıç planları ihtiyaç duyacağım tüm verileri fazlasıyla karşılayabilecek kapasitede.


Pinecone hesabımı oluşturup API anahtarımı ve ortamımı aldıktan sonra her iki değeri de .env dosyama ekliyorum.

Çam Kozalağı API Anahtarı oluşturma ekran görüntüsü

Artık .env benim Pinecone ve OpenAI sırlarımı içermeli.

 export OPENAI_API_KEY=YOUR_API_KEY # Pinecone secrets export PINECONE_API_KEY=YOUR_API_KEY export PINECONE_ENVIRONMENT=YOUR_PINECONE_DATACENTER

Daha sonra Python için Pinecone istemcisini kuruyorum:

 $ pip install pinecone-client

Bir veritabanını başlatmam gerekiyor; db_create.py betiğinin içeriği şunlardır:

 # db_create.py import pinecone import openai import os index_name = "semaphore" embed_model = "text-embedding-ada-002" api_key = os.getenv("PINECONE_API_KEY") env = os.getenv("PINECONE_ENVIRONMENT") pinecone.init(api_key=api_key, environment=env) embedding = openai.Embedding.create( input=[ "Sample document text goes here", "there will be several phrases in each batch" ], engine=embed_model ) if index_name not in pinecone.list_indexes(): print("Creating pinecone index: " + index_name) pinecone.create_index( index_name, dimension=len(embedding['data'][0]['embedding']), metric='cosine', metadata_config={'indexed': ['source', 'id']} )

Komut dosyasının veritabanını oluşturması birkaç dakika sürebilir.

 $ python db_create.py

Daha sonra tiktoken paketini kuracağım. Kaynak belgelerin kaç jetona sahip olduğunu hesaplamak için kullanacağım. Bu önemlidir çünkü yerleştirme modeli yalnızca 8191 jetona kadar işleyebilir.

 $ pip install tiktoken

Paketleri kurarken güzel görünümlü bir ilerleme çubuğu oluşturmak için tqdm de kuralım.

 $ pip install tqdm

Şimdi belgeleri veritabanına yüklemem gerekiyor. Bunun betiğine index_docs.py adı verilecek. Gerekli modülleri içe aktararak ve bazı sabitleri tanımlayarak başlayalım:

 # index_docs.py # Pinecone db name and upload batch size index_name = 'semaphore' upsert_batch_size = 20 # OpenAI embedding and tokenizer models embed_model = "text-embedding-ada-002" encoding_model = "cl100k_base" max_tokens_model = 8191

Daha sonra jetonları saymak için bir fonksiyona ihtiyacımız olacak. OpenAI sayfasında bir jeton sayacı örneği var:

 import tiktoken def num_tokens_from_string(string: str) -> int: """Returns the number of tokens in a text string.""" encoding = tiktoken.get_encoding(encoding_model) num_tokens = len(encoding.encode(string)) return num_tokens

Son olarak orijinal belgeyi kullanılabilir örneklere dönüştürmek için bazı filtreleme işlevlerine ihtiyacım olacak. Belgelerdeki örneklerin çoğu kod sınırları arasındadır, bu nedenle tüm YAML kodunu her dosyadan çıkaracağım:

 import re def extract_yaml(text: str) -> str: """Returns list with all the YAML code blocks found in text.""" matches = [m.group(1) for m in re.finditer("```yaml([\w\W]*?)```", text)] return matches

Fonksiyonlarla işim bitti. Daha sonra bu, dosyaları belleğe yükleyecek ve örnekleri çıkaracaktır:

 from tqdm import tqdm import sys import os import pathlib repo_path = sys.argv[1] repo_path = os.path.abspath(repo_path) repo = pathlib.Path(repo_path) markdown_files = list(repo.glob("**/*.md")) + list( repo.glob("**/*.mdx") ) print(f"Extracting YAML from Markdown files in {repo_path}") new_data = [] for i in tqdm(range(0, len(markdown_files))): markdown_file = markdown_files[i] with open(markdown_file, "r") as f: relative_path = markdown_file.relative_to(repo_path) text = str(f.read()) if text == '': continue yamls = extract_yaml(text) j = 0 for y in yamls: j = j+1 new_data.append({ "source": str(relative_path), "text": y, "id": f"github.com/semaphore/docs/{relative_path}[{j}]" })

Bu noktada tüm YAML'lerin new_data listesinde saklanması gerekir. Son adım, yerleştirmeleri Çam Kozalağı'na yüklemektir.

 import pinecone import openai api_key = os.getenv("PINECONE_API_KEY") env = os.getenv("PINECONE_ENVIRONMENT") pinecone.init(api_key=api_key, enviroment=env) index = pinecone.Index(index_name) print(f"Creating embeddings and uploading vectors to database") for i in tqdm(range(0, len(new_data), upsert_batch_size)): i_end = min(len(new_data), i+upsert_batch_size) meta_batch = new_data[i:i_end] ids_batch = [x['id'] for x in meta_batch] texts = [x['text'] for x in meta_batch] embedding = openai.Embedding.create(input=texts, engine=embed_model) embeds = [record['embedding'] for record in embedding['data']] # clean metadata before upserting meta_batch = [{ 'id': x['id'], 'text': x['text'], 'source': x['source'] } for x in meta_batch] to_upsert = list(zip(ids_batch, embeds, meta_batch)) index.upsert(vectors=to_upsert)

Referans olarak index_docs.py dosyasının tamamını demo deposunda bulabilirsiniz.

Veritabanı kurulumunu tamamlamak için indeks betiğini çalıştıralım:

 $ git clone https://github.com/semaphoreci/docs.git /tmp/docs $ source .env $ python index_docs.py /tmp/docs

Veritabanını test etme

Çam kozalağı kontrol paneli veritabanındaki vektörleri göstermelidir.

Toplam 79 vektör içeren veritabanını gösteren Çam Kozalağı kontrol panelinin ekran görüntüsü

Veritabanını, komut dosyası olarak veya doğrudan Python REPL'de çalıştırabileceğiniz aşağıdaki kodla sorgulayabiliriz:

 $ python >>> import os >>> import pinecone >>> import openai # Compute embeddings for string "Docker Container" >>> embeddings = openai.Embedding.create(input="Docker Containers", engine="text-embedding-ada-002") # Connect to database >>> index_name = "semaphore" >>> api_key = os.getenv("PINECONE_API_KEY") >>> env = os.getenv("PINECONE_ENVIRONMENT") >>> pinecone.init(api_key=api_key, environment=env) >>> index = pinecone.Index(index_name) # Query database >>> matches = index.query(embeddings['data'][0]['embedding'], top_k=1, include_metadata=True) >>> matches['matches'][0] {'id': 'github.com/semaphore/docs/docs/ci-cd-environment/docker-authentication.md[3]', 'metadata': {'id': 'github.com/semaphore/docs/docs/ci-cd-environment/docker-authentication.md[3]', 'source': 'docs/ci-cd-environment/docker-authentication.md', 'text': '\n' '# .semaphore/semaphore.yml\n' 'version: v1.0\n' 'name: Using a Docker image\n' 'agent:\n' ' machine:\n' ' type: e1-standard-2\n' ' os_image: ubuntu1804\n' '\n' 'blocks:\n' ' - name: Run container from Docker Hub\n' ' task:\n' ' jobs:\n' ' - name: Authenticate docker pull\n' ' commands:\n' ' - checkout\n' ' - echo $DOCKERHUB_PASSWORD | docker login ' '--username "$DOCKERHUB_USERNAME" --password-stdin\n' ' - docker pull /\n' ' - docker images\n' ' - docker run /\n' ' secrets:\n' ' - name: docker-hub\n'}, 'score': 0.796259582, 'values': []}

Gördüğünüz gibi ilk eşleşme, Docker görüntüsünü çeken ve çalıştıran Semafor hattının YAML'sidir. "Docker Konteynerleri" arama dizemizle alakalı olduğundan bu iyi bir başlangıç.

Botu oluşturma

Veriler elimizde ve onu nasıl sorgulayacağımızı biliyoruz. Bunu botta çalıştıralım.

İstemi işlemeye yönelik adımlar şunlardır:

  1. Kullanıcının istemini alın.
  2. Vektörünü hesaplayın.
  3. Veritabanından ilgili bağlamı alın.
  4. Kullanıcının istemini bağlamla birlikte GPT-3'e gönderin.
  5. Modelin yanıtını kullanıcıya iletin.

Bot için veri akışının şeması. Sol tarafta, gömülü sinir ağı tarafından işlenen ve ardından bağlam veritabanına gönderilen kullanıcı istemi girer. Arama, GPT-3 modeline gönderilen ilgili metni verir. Modelin çıktısı kullanıcıya nihai cevap olarak gönderilir. Her zamanki gibi, botun ana betiği complete.py dosyasında bazı sabitleri tanımlayarak başlayacağım:

 # complete.py # Pinecone database name, number of matched to retrieve # cutoff similarity score, and how much tokens as context index_name = 'semaphore' context_cap_per_query = 30 match_min_score = 0.75 context_tokens_per_query = 3000 # OpenAI LLM model parameters chat_engine_model = "gpt-3.5-turbo" max_tokens_model = 4096 temperature = 0.2 embed_model = "text-embedding-ada-002" encoding_model_messages = "gpt-3.5-turbo-0301" encoding_model_strings = "cl100k_base" import pinecone import os # Connect with Pinecone db and index api_key = os.getenv("PINECONE_API_KEY") env = os.getenv("PINECONE_ENVIRONMENT") pinecone.init(api_key=api_key, environment=env) index = pinecone.Index(index_name)

Daha sonra, OpenAI örneklerinde gösterildiği gibi jetonları saymak için işlevler ekleyeceğim. İlk işlev bir dizedeki belirteçleri sayarken, ikincisi mesajlardaki belirteçleri sayar. Mesajları birazdan detaylı olarak göreceğiz. Şimdilik konuşmanın durumunu hafızada tutan bir yapı olduğunu söyleyelim.

 import tiktoken def num_tokens_from_string(string: str) -> int: """Returns the number of tokens in a text string.""" encoding = tiktoken.get_encoding(encoding_model_strings) num_tokens = len(encoding.encode(string)) return num_tokens def num_tokens_from_messages(messages): """Returns the number of tokens used by a list of messages. Compatible with model """ try: encoding = tiktoken.encoding_for_model(encoding_model_messages) except KeyError: encoding = tiktoken.get_encoding(encoding_model_strings) num_tokens = 0 for message in messages: num_tokens += 4 # every message follows {role/name}\n{content}\n for key, value in message.items(): num_tokens += len(encoding.encode(value)) if key == "name": # if there's a name, the role is omitted num_tokens += -1 # role is always required and always 1 token num_tokens += 2 # every reply is primed with assistant return num_tokens

Aşağıdaki işlev, GPT-3 için zenginleştirilmiş bir bilgi istemi döndürmek üzere orijinal bilgi istemini ve bağlam dizelerini alır:

 def get_prompt(query: str, context: str) -> str: """Return the prompt with query and context.""" return ( f"Create the continuous integration pipeline YAML code to fullfil the requested task.\n" + f"Below you will find some context that may help. Ignore it if it seems irrelevant.\n\n" + f"Context:\n{context}" + f"\n\nTask: {query}\n\nYAML Code:" )

get_message işlevi istemi API ile uyumlu bir biçimde biçimlendirir:

 def get_message(role: str, content: str) -> dict: """Generate a message for OpenAI API completion.""" return {"role": role, "content": content}

Modelin nasıl tepki vereceğini etkileyen üç tür rol vardır:

  • Kullanıcı : Kullanıcının orijinal istemi için.
  • Sistem : asistanın davranışını ayarlamaya yardımcı olur. Etkinliği konusunda bazı tartışmalar olsa da mesaj listesinin sonunda gönderildiğinde daha etkili olduğu görülüyor.
  • Asistan : modelin geçmiş yanıtlarını temsil eder. OpenAI API'nin bir "belleği" yoktur; bunun yerine, konuşmayı sürdürmek için her etkileşim sırasında modelin önceki yanıtlarını geri göndermeliyiz.


Şimdi ilgi çekici kısım için. get_context işlevi istemi alır, veritabanını sorgular ve şu koşullardan biri karşılanana kadar bir bağlam dizesi oluşturur:

  • Metnin tamamı, bağlam için ayırdığım alan olan context_tokens_per_query alanını aşıyor.
  • Arama fonksiyonu istenen tüm eşleşmeleri alır.
  • Benzerlik puanı match_min_score altında olan eşleşmeler dikkate alınmaz.
 import openai def get_context(query: str, max_tokens: int) -> list: """Generate message for OpenAI model. Add context until hitting `context_token_limit` limit. Returns prompt string.""" embeddings = openai.Embedding.create( input=[query], engine=embed_model ) # search the database vectors = embeddings['data'][0]['embedding'] embeddings = index.query(vectors, top_k=context_cap_per_query, include_metadata=True) matches = embeddings['matches'] # filter and aggregate context usable_context = "" context_count = 0 for i in range(0, len(matches)): source = matches[i]['metadata']['source'] if matches[i]['score'] < match_min_score: # skip context with low similarity score continue context = matches[i]['metadata']['text'] token_count = num_tokens_from_string(usable_context + '\n---\n' + context) if token_count < context_tokens_per_query: usable_context = usable_context + '\n---\n' + context context_count = context_count + 1 print(f"Found {context_count} contexts for your query") return usable_context

Bir sonraki ve son işlev olan complete , API isteğini OpenAI'ye gönderir ve modelin yanıtını döndürür.

 def complete(messages): """Query the OpenAI model. Returns the first answer. """ res = openai.ChatCompletion.create( model=chat_engine_model, messages=messages, temperature=temperature ) return res.choices[0].message.content.strip()

Bu kadar; şimdi sadece komut satırı argümanlarıyla ilgilenmem ve fonksiyonları doğru sırayla çağırmam gerekiyor:

 import sys query = sys.argv[1] context = get_context(query, context_tokens_per_query) prompt = get_prompt(query, context) # initialize messages list to send to OpenAI API messages = [] messages.append(get_message('user', prompt)) messages.append(get_message('system', 'You are a helpful assistant that writes YAML code for Semaphore continuous integration pipelines and explains them. Return YAML code inside code fences.')) if num_tokens_from_messages(messages) >= max_tokens_model: raise Exception('Model token size limit reached') print("Working on your query... ") answer = complete(messages) print("Answer:\n") print(answer) messages.append(get_message('assistant', answer))

Komut dosyasını çalıştırmanın ve nasıl çalıştığını görmenin zamanı geldi:

 $ python complete.py "Create a CI pipeline that builds and uploads a Docker image to Docker Hub"

Sonuç:

 version: v1.0 name: Docker Build and Push agent: machine: type: e1-standard-2 os_image: ubuntu1804 blocks: - name: "Build and Push Docker Image" task: jobs: - name: "Docker Build and Push" commands: - checkout - docker build -t /: . - echo "$DOCKERHUB_PASSWORD" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push /: promotions: - name: Deploy to production pipeline_file: deploy-production.yml auto_promote: when: "result = 'passed' and branch = 'master'"

Bu ilk iyi sonuçtur. Model, sözdizimini sunduğumuz bağlam örneklerinden çıkarmıştır.

Botun Yeteneklerini Genişletmeye İlişkin Düşünceler

Mütevazı bir hedefle başladığımı unutmayın: YAML işlem hatlarını yazacak bir asistan yaratmak. Vektör veritabanımdaki daha zengin içerik sayesinde botu, Semaphore (veya herhangi bir ürün) hakkındaki her soruyu yanıtlayacak şekilde genelleştirebilirim; dokümanları /tmp içine kopyalamayı unutmayın.


İyi yanıtlar almanın anahtarı - şaşırtıcı olmayan bir şekilde - kaliteli bağlamdır. Her belgenin yalnızca vektör veri tabanına yüklenmesinin iyi sonuçlar vermesi pek mümkün değildir. Bağlam veritabanı düzenlenmeli, açıklayıcı meta verilerle etiketlenmeli ve kısa ve öz olmalıdır. Aksi takdirde, istemdeki belirteç kotasını alakasız bağlamla doldurma riskiyle karşı karşıya kalırız.


Yani, bir bakıma, ihtiyaçlarımızı karşılayacak şekilde botun ince ayarını yapmak bir sanat ve çok sayıda deneme yanılma içeriyor. Benzerlik puanını ayarlayarak bağlam sınırıyla denemeler yapabilir, düşük kaliteli içeriği kaldırabilir, özetleyebilir ve alakasız bağlamı filtreleyebiliriz.

Uygun Bir Chatbot Uygulamak

Botumun ChatGPT gibi gerçek sohbetler yapmamıza izin vermediğini fark etmiş olabilirsiniz. Bir soru soruyoruz ve bir cevap alıyoruz.


Botu tam teşekküllü bir chatbot'a dönüştürmek prensipte çok zor değil. Her API isteğinde modele verilen önceki yanıtları yeniden göndererek konuşmayı sürdürebiliriz. Önceki GPT-3 yanıtları "asistan" rolü altında geri gönderilir. Örneğin:

 messages = [] while True: query = input('Type your prompt:\n') context = get_context(query, context_tokens_per_query) prompt = get_prompt(query, context) messages.append(get_message('user', prompt)) messages.append(get_message('system', 'You are a helpful assistant that writes YAML code for Semaphore continuous integration pipelines and explains them. Return YAML code inside code fences.')) if num_tokens_from_messages(messages) >= max_tokens_model: raise Exception('Model token size limit reached') print("Working on your query... ") answer = complete(messages) print("Answer:\n") print(answer) # remove system message and append model's answer messages.pop() messages.append(get_message('assistant', answer))

Ne yazık ki, bu uygulama oldukça ilkeldir. Her etkileşimde belirteç sayısı arttığından, genişletilmiş konuşmaları desteklemeyecektir. Çok yakında GPT-3 için 4096 jeton sınırına ulaşacağız ve bu da daha fazla diyaloğu önleyecek.


Bu nedenle, isteği belirteç sınırları dahilinde tutmanın bir yolunu bulmalıyız. Birkaç strateji takip ediyor:

  • Eski mesajları silin. Bu en basit çözüm olsa da, konuşmanın "hafızasını" yalnızca en son mesajlarla sınırlandırır.
  • Önceki mesajları özetleyin. Daha önceki mesajları yoğunlaştırmak ve bunları orijinal soru ve yanıtların yerine koymak için "Modele sor" seçeneğini kullanabiliriz. Bu yaklaşım maliyeti ve sorgular arasındaki gecikmeyi artırsa da geçmiş mesajların silinmesine kıyasla daha üstün sonuçlar üretebilir.
  • Etkileşim sayısına katı bir sınır koyun.
  • Hem daha akıllı hem de çift token kapasitesine sahip olan GPT-4 API'nin genel kullanılabilirliğini bekleyin.
  • 16 bin token'a kadar işlem yapabilen "gpt-3.5-turbo-16k" gibi daha yeni bir model kullanın.

Çözüm

Botun yanıtlarını geliştirmek, kelime yerleştirmeler ve iyi bir bağlam veri tabanı ile mümkündür. Bunu başarmak için kaliteli belgelere ihtiyacımız var. Görünüşte konuyu kavrayabilen bir bot geliştirmede önemli miktarda deneme yanılma söz konusudur.


Kelime yerleştirmelerin ve büyük dil modellerinin bu derinlemesine incelenmesinin, gereksinimlerinize göre özelleştirilmiş daha güçlü bir bot oluşturmanıza yardımcı olacağını umuyorum.


Mutlu bina!


Burada da yayınlandı.