Không còn nghi ngờ gì nữa, ChatGPT của OpenAI đặc biệt thông minh — nó đã vượt qua bài kiểm tra của luật sư , nó sở hữu kiến thức tương đương với bác sĩ và một số bài kiểm tra đã cho chỉ số IQ của nó là 155 . Tuy nhiên, nó có xu hướng bịa đặt thông tin thay vì thừa nhận sự thiếu hiểu biết. Xu hướng này, cùng với thực tế là kiến thức của nó sẽ ngừng hoạt động vào năm 2021, đặt ra những thách thức trong việc xây dựng các sản phẩm chuyên biệt sử dụng API GPT.
Làm thế nào chúng ta có thể vượt qua những trở ngại này? Làm cách nào chúng tôi có thể truyền đạt kiến thức mới cho một mô hình như GPT-3? Mục tiêu của tôi là giải quyết những câu hỏi này bằng cách xây dựng bot trả lời câu hỏi sử dụng Python, API OpenAI và nhúng từ.
Tôi dự định tạo một bot tạo ra các quy trình tích hợp liên tục từ một lời nhắc, như bạn có thể biết, được định dạng bằng YAML trong Semaphore CI/CD.
Dưới đây là một ví dụ về bot đang hoạt động:
Ảnh chụp màn hình của chương trình đang chạy. Trên màn hình, lệnh python query.py "Create a CI pipeline that builds and uploads a Docker image to Docker Hub"
được thực thi và chương trình in ra YAML tương ứng với đường dẫn CI thực hiện hành động được yêu cầu.
Theo tinh thần của các dự án như DocsGPT , My AskAI và Libraria , tôi dự định "dạy" mô hình GPT-3 về Semaphore và cách tạo tệp cấu hình đường ống. Tôi sẽ đạt được điều này bằng cách tận dụng các tài liệu hiện có .
Tôi sẽ không cho rằng mình đã có kiến thức trước về xây dựng bot và sẽ duy trì mã sạch để bạn có thể điều chỉnh mã theo yêu cầu của mình.
Bạn không cần có kinh nghiệm viết mã bot hoặc kiến thức về mạng thần kinh để làm theo hướng dẫn này. Tuy nhiên, bạn sẽ cần:
ChatGPT, hay chính xác hơn là GPT-3 và GPT-4, các Mô hình ngôn ngữ lớn (LLM) cung cấp năng lượng cho chúng, đã được đào tạo trên một tập dữ liệu lớn với ngày giới hạn vào khoảng tháng 9 năm 2021.
Về bản chất, GPT-3 biết rất ít về các sự kiện sau ngày đó. Chúng tôi có thể xác minh điều này bằng một lời nhắc đơn giản:
ChatGPT không biết đội nào vô địch World Cup 2022.
Mặc dù một số mô hình OpenAI có thể trải qua quá trình tinh chỉnh , nhưng các mô hình cao cấp hơn, chẳng hạn như những mô hình được quan tâm, thì không thể; chúng tôi không thể tăng cường dữ liệu đào tạo của họ.
Làm cách nào chúng tôi có thể nhận được câu trả lời từ GPT-3 ngoài dữ liệu đào tạo của nó? Một phương pháp liên quan đến việc khai thác khả năng hiểu văn bản của nó; bằng cách tăng cường lời nhắc với ngữ cảnh phù hợp, chúng ta có thể có được câu trả lời chính xác.
Trong ví dụ bên dưới, tôi cung cấp ngữ cảnh từ trang web chính thức của FIFA và phản hồi có sự khác biệt đáng kể:
Với ngữ cảnh được cung cấp, ChatGPT có thể trả lời chính xác.
Chúng ta có thể suy luận rằng mô hình có thể phản hồi bất kỳ lời nhắc nào nếu được cung cấp đủ ngữ cảnh phù hợp. Câu hỏi vẫn là: làm thế nào chúng ta có thể biết điều gì có liên quan khi được nhắc tùy ý? Để giải quyết vấn đề này, chúng ta cần khám phá nhúng từ là gì.
Trong ngữ cảnh của các mô hình ngôn ngữ, nhúng là một cách biểu diễn các từ, câu hoặc toàn bộ tài liệu dưới dạng vectơ hoặc danh sách số.
Để tính toán các lần nhúng, chúng ta sẽ cần một mạng thần kinh chẳng hạn như word2vec hoặc text-embedding-ada-002 . Các mạng này đã được đào tạo trên một lượng lớn văn bản và có thể tìm thấy mối quan hệ giữa các từ bằng cách phân tích tần suất xuất hiện của các mẫu cụ thể trong dữ liệu đào tạo.
Giả sử chúng ta có các từ sau:
Hãy tưởng tượng chúng ta sử dụng một trong những mạng nhúng này để tính toán các vectơ cho mỗi từ. Ví dụ:
Từ | véc tơ | Bối cảnh |
---|---|---|
Con mèo | [0,1, 0,2, 0,3, 0,4, 0,5] | Động vật, đồ vật, đồ vật nhỏ |
Chó | [0,6, 0,7, 0,8, 0,9, 1,0] | Động vật, đồ vật, vật lớn |
Quả bóng | [0,2, 0,4, 0,6, 0,8, 1,0] | Đồ vật, đồ chơi, đồ vật nhỏ |
Căn nhà | [0,3, 0,6, 0,9, 1,2, 1,5] | Tòa nhà, nhà ở, những thứ lớn |
Khi chúng ta có các vectơ cho mỗi từ, chúng ta có thể sử dụng chúng để biểu thị ý nghĩa của văn bản. Ví dụ: câu “Con mèo đuổi theo quả bóng” có thể được biểu diễn dưới dạng vectơ [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]. Vectơ này đại diện cho một câu nói về một con vật đang đuổi theo một vật thể.
Các nhúng từ có thể được hình dung dưới dạng không gian đa chiều trong đó các từ hoặc câu có nghĩa tương tự gần nhau. Chúng ta có thể tính toán "khoảng cách" giữa các vectơ để tìm ý nghĩa tương tự cho bất kỳ văn bản đầu vào nào.
Biểu diễn 3D của các phần nhúng dưới dạng không gian vectơ. Trong thực tế, những không gian này có thể có hàng trăm hoặc hàng nghìn chiều. Nguồn: Gặp gỡ Multitool của AI: Vector Embeddings
Toán học thực tế đằng sau tất cả những điều này nằm ngoài phạm vi của bài viết này. Tuy nhiên, điều quan trọng cần rút ra là các phép toán vectơ cho phép chúng ta thao tác hoặc xác định ý nghĩa bằng toán học . Lấy vectơ đại diện cho từ “nữ hoàng”, trừ vectơ “phụ nữ” khỏi từ đó và thêm vectơ “đàn ông”. Kết quả phải là một vectơ trong vùng lân cận của “vua”. Nếu chúng ta thêm "con trai", chúng ta sẽ đến một nơi nào đó gần với "hoàng tử".
Cho đến nay, chúng ta đã thảo luận về việc nhúng các mạng thần kinh lấy từ làm đầu vào và số làm đầu ra. Tuy nhiên, nhiều mạng hiện đại đã chuyển từ xử lý từ sang xử lý mã thông báo.
Mã thông báo là đơn vị văn bản nhỏ nhất mà mô hình có thể xử lý. Mã thông báo có thể là từ, ký tự, dấu chấm câu, ký hiệu hoặc một phần của từ.
Chúng ta có thể xem cách các từ được chuyển đổi thành mã thông báo bằng cách thử nghiệm với trình mã thông báo trực tuyến OpenAI , sử dụng Mã hóa cặp byte (BPE) để chuyển đổi văn bản thành mã thông báo và đại diện cho mỗi mã bằng một số:
Thường có mối quan hệ 1-1 giữa mã thông báo và từ. Hầu hết các mã thông báo bao gồm từ và khoảng trắng ở đầu. Tuy nhiên, có những trường hợp đặc biệt như "nhúng", bao gồm hai mã thông báo, "nhúng" và "ding" hoặc "khả năng", bao gồm bốn mã thông báo. Nếu bạn nhấp vào "ID mã thông báo", bạn có thể thấy biểu thị số của mô hình cho từng mã thông báo.
Bây giờ chúng ta đã hiểu nhúng là gì, câu hỏi tiếp theo là: làm thế nào chúng có thể giúp chúng ta xây dựng một bot thông minh hơn?
Trước tiên, hãy xem xét điều gì xảy ra khi chúng ta sử dụng trực tiếp API GPT-3. Người dùng đưa ra lời nhắc và mô hình phản hồi với khả năng tốt nhất của nó.
Tuy nhiên, khi chúng ta thêm bối cảnh vào phương trình, mọi thứ sẽ thay đổi. Ví dụ: khi tôi hỏi ChatGPT về đội vô địch World Cup sau khi cung cấp ngữ cảnh, nó đã tạo nên sự khác biệt.
Vì vậy, kế hoạch xây dựng một bot thông minh hơn như sau:
Hãy bắt đầu giống như hầu hết các dự án, bằng cách thiết kế cơ sở dữ liệu.
Cơ sở dữ liệu ngữ cảnh của chúng tôi phải bao gồm tài liệu gốc và các vectơ tương ứng của chúng. Về nguyên tắc, chúng ta có thể sử dụng bất kỳ loại cơ sở dữ liệu nào cho nhiệm vụ này, nhưng cơ sở dữ liệu vectơ là công cụ tối ưu cho công việc này.
Cơ sở dữ liệu vectơ là cơ sở dữ liệu chuyên biệt được thiết kế để lưu trữ và truy xuất dữ liệu vectơ chiều cao. Thay vì sử dụng một ngôn ngữ truy vấn như SQL để tìm kiếm, chúng tôi cung cấp một vectơ và yêu cầu N hàng xóm gần nhất.
Để tạo các vectơ, chúng tôi sẽ sử dụng text-embedding-ada-002 từ OpenAI, vì đây là mô hình nhanh nhất và tiết kiệm chi phí nhất mà họ cung cấp. Mô hình chuyển đổi văn bản đầu vào thành mã thông báo và sử dụng cơ chế chú ý được gọi là Transformer để tìm hiểu mối quan hệ của chúng. Đầu ra của mạng thần kinh này là các vectơ biểu thị ý nghĩa của văn bản.
Để tạo một cơ sở dữ liệu ngữ cảnh, tôi sẽ:
Trước tiên, tôi phải khởi tạo tệp môi trường bằng khóa API OpenAI. Tệp này không bao giờ được cam kết kiểm soát phiên bản vì khóa API là riêng tư và được liên kết với tài khoản của bạn.
export OPENAI_API_KEY=YOUR_API_KEY
Tiếp theo, tôi sẽ tạo một virtualenv cho ứng dụng Python của mình:
$ virtualenv venv $ source venv/bin/activate $ source .env
Và cài đặt gói OpenAI:
```bash $ pip install openai numpy
Hãy thử tính toán nhúng cho chuỗi "Docker Container". Bạn có thể chạy cái này trên Python REPL hoặc dưới dạng tập lệnh Python:
$ 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 } }
Như bạn có thể thấy, mô hình của OpenAI phản hồi bằng một danh sách embedding
chứa 1536 mục — kích thước vectơ cho text-embedding-ada-002.
Mặc dù có nhiều công cụ cơ sở dữ liệu vectơ để lựa chọn, chẳng hạn như Chroma là mã nguồn mở, nhưng tôi đã chọn Pinecone vì đây là cơ sở dữ liệu được quản lý với một bậc miễn phí, giúp mọi thứ trở nên đơn giản hơn. Gói Starter của họ thừa khả năng xử lý tất cả dữ liệu tôi cần.
Sau khi tạo tài khoản Pinecone và truy xuất khóa API cũng như môi trường của mình, tôi thêm cả hai giá trị vào tệp .env
của mình.
Bây giờ .env
sẽ chứa các bí mật Pinecone và OpenAI của tôi.
export OPENAI_API_KEY=YOUR_API_KEY # Pinecone secrets export PINECONE_API_KEY=YOUR_API_KEY export PINECONE_ENVIRONMENT=YOUR_PINECONE_DATACENTER
Sau đó, tôi cài đặt ứng dụng khách Pinecone cho Python:
$ pip install pinecone-client
Tôi cần khởi tạo cơ sở dữ liệu; đây là nội dung của tập lệnh db_create.py
:
# 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']} )
Tập lệnh có thể mất vài phút để tạo cơ sở dữ liệu.
$ python db_create.py
Tiếp theo, tôi sẽ cài đặt gói tiktoken . Tôi sẽ sử dụng nó để tính xem tài liệu nguồn có bao nhiêu mã thông báo. Điều này rất quan trọng vì mô hình nhúng chỉ có thể xử lý tối đa 8191 mã thông báo.
$ pip install tiktoken
Trong khi cài đặt các gói, chúng ta cũng hãy cài đặt tqdm
để tạo ra một thanh tiến trình đẹp mắt.
$ pip install tqdm
Bây giờ tôi cần tải tài liệu lên cơ sở dữ liệu. Tập lệnh cho điều này sẽ được gọi là index_docs.py
. Hãy bắt đầu bằng cách nhập các mô-đun cần thiết và xác định một số hằng số:
# 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
Tiếp theo, chúng ta sẽ cần một chức năng để đếm mã thông báo. Có một ví dụ về bộ đếm mã thông báo trên trang OpenAI:
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
Cuối cùng, tôi sẽ cần một số chức năng lọc để chuyển đổi tài liệu gốc thành các ví dụ có thể sử dụng được. Hầu hết các ví dụ trong tài liệu nằm giữa các hàng rào mã, vì vậy tôi sẽ chỉ trích xuất tất cả mã YAML từ mọi tệp:
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
Tôi đã hoàn thành với các chức năng. Tiếp theo, thao tác này sẽ tải các tệp trong bộ nhớ và trích xuất các ví dụ:
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}]" })
Tại thời điểm này, tất cả các YAML sẽ được lưu trữ trong danh sách new_data
. Bước cuối cùng là tải các phần nhúng vào Pinecone.
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)
Để tham khảo, bạn có thể tìm thấy tệp index_docs.py đầy đủ trong kho lưu trữ demo
Hãy chạy tập lệnh chỉ mục để kết thúc quá trình thiết lập cơ sở dữ liệu:
$ git clone https://github.com/semaphoreci/docs.git /tmp/docs $ source .env $ python index_docs.py /tmp/docs
Bảng điều khiển Pinecone sẽ hiển thị các vectơ trong cơ sở dữ liệu.
Chúng ta có thể truy vấn cơ sở dữ liệu bằng mã sau, bạn có thể chạy mã này dưới dạng tập lệnh hoặc trực tiếp trong REPL của Python:
$ 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': []}
Như bạn có thể thấy, đối sánh đầu tiên là YAML cho một đường dẫn Semaphore lấy một hình ảnh Docker và chạy nó. Đó là một khởi đầu tốt vì nó có liên quan đến chuỗi tìm kiếm "Docker Container" của chúng tôi.
Chúng tôi có dữ liệu và chúng tôi biết cách truy vấn nó. Hãy để nó hoạt động trong bot.
Các bước để xử lý lời nhắc là:
Như thường lệ, tôi sẽ bắt đầu bằng cách xác định một số hằng số trong complete.py
, tập lệnh chính của bot:
# 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)
Tiếp theo, tôi sẽ thêm các chức năng để đếm mã thông báo như trong các ví dụ về OpenAI . Hàm đầu tiên đếm mã thông báo trong một chuỗi, trong khi hàm thứ hai đếm mã thông báo trong tin nhắn. Chúng ta sẽ xem chi tiết các tin nhắn trong giây lát. Hiện tại, hãy coi đó là một cấu trúc lưu giữ trạng thái của cuộc hội thoại trong bộ nhớ.
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
Hàm sau đây nhận lời nhắc ban đầu và chuỗi ngữ cảnh để trả về lời nhắc phong phú cho GPT-3:
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:" )
Hàm get_message
định dạng lời nhắc ở định dạng tương thích với API:
def get_message(role: str, content: str) -> dict: """Generate a message for OpenAI API completion.""" return {"role": role, "content": content}
Có ba loại vai trò ảnh hưởng đến cách mô hình phản ứng:
Bây giờ cho phần hấp dẫn. Hàm get_context
nhận lời nhắc, truy vấn cơ sở dữ liệu và tạo chuỗi ngữ cảnh cho đến khi đáp ứng một trong các điều kiện sau:
context_tokens_per_query
, không gian tôi dành riêng cho ngữ cảnh.match_min_score
sẽ bị bỏ qua. 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
Chức năng tiếp theo và chức năng cuối cùng, complete
, đưa ra yêu cầu API tới OpenAI và trả về phản hồi của mô hình.
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()
Đó là tất cả; bây giờ tôi chỉ phải xử lý các đối số dòng lệnh và gọi các hàm theo đúng thứ tự:
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))
Đã đến lúc chạy tập lệnh và xem nó hoạt động như thế nào:
$ python complete.py "Create a CI pipeline that builds and uploads a Docker image to Docker Hub"
Kết quả là:
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'"
Đây là kết quả tốt đầu tiên. Mô hình đã suy ra cú pháp từ các ví dụ ngữ cảnh mà chúng tôi đã cung cấp.
Hãy nhớ rằng tôi đã bắt đầu với một mục tiêu khiêm tốn: tạo một trợ lý để viết các đường dẫn YAML. Với nội dung phong phú hơn trong cơ sở dữ liệu vectơ của tôi, tôi có thể khái quát hóa bot để trả lời bất kỳ câu hỏi nào về Semaphore (hoặc bất kỳ sản phẩm nào — hãy nhớ sao chép tài liệu vào /tmp
?).
Chìa khóa để có được câu trả lời hay là — không ngạc nhiên — ngữ cảnh chất lượng. Chỉ tải mọi tài liệu lên cơ sở dữ liệu vectơ không chắc sẽ mang lại kết quả tốt. Cơ sở dữ liệu ngữ cảnh phải được sắp xếp, gắn thẻ với siêu dữ liệu mô tả và ngắn gọn. Nếu không, chúng tôi có nguy cơ lấp đầy hạn ngạch mã thông báo trong lời nhắc với ngữ cảnh không liên quan.
Vì vậy, theo một nghĩa nào đó, có một nghệ thuật — và rất nhiều lần thử và sai — liên quan đến việc tinh chỉnh bot để đáp ứng nhu cầu của chúng ta. Chúng tôi có thể thử nghiệm giới hạn ngữ cảnh, xóa nội dung chất lượng thấp, tóm tắt và lọc ra ngữ cảnh không liên quan bằng cách điều chỉnh điểm tương đồng.
Bạn có thể nhận thấy rằng bot của tôi không cho phép chúng tôi trò chuyện thực tế như ChatGPT. Chúng tôi hỏi một câu hỏi và nhận được một câu trả lời.
Về nguyên tắc, việc chuyển đổi bot thành một chatbot chính thức không quá khó. Chúng tôi có thể duy trì cuộc trò chuyện bằng cách gửi lại các phản hồi trước đó cho mô hình với mỗi yêu cầu API. Các câu trả lời trước về GPT-3 sẽ được gửi lại dưới vai trò "trợ lý". Ví dụ:
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))
Thật không may, việc triển khai này khá thô sơ. Nó sẽ không hỗ trợ các cuộc hội thoại mở rộng khi số lượng mã thông báo tăng lên sau mỗi lần tương tác. Chẳng bao lâu nữa, chúng tôi sẽ đạt đến giới hạn 4096 mã thông báo cho GPT-3, điều này sẽ ngăn chặn các cuộc đối thoại tiếp theo.
Vì vậy, chúng tôi phải tìm một số cách để giữ yêu cầu trong giới hạn mã thông báo. Một vài chiến lược sau:
Có thể nâng cao phản hồi của bot bằng cách nhúng từ và cơ sở dữ liệu ngữ cảnh tốt. Để đạt được điều này, chúng tôi cần tài liệu chất lượng tốt. Có một lượng lớn thử nghiệm và sai sót liên quan đến việc phát triển một bot dường như nắm bắt được chủ đề.
Tôi hy vọng việc khám phá chuyên sâu về nhúng từ và các mô hình ngôn ngữ lớn này sẽ hỗ trợ bạn xây dựng một bot mạnh mẽ hơn, được tùy chỉnh theo yêu cầu của bạn.
Chúc bạn xây dựng vui vẻ!
Cũng được xuất bản ở đây .