การสร้างเวกเตอร์ฝังตัวด้วย OpenAI
ใช้โมเดล text-embedding-3-small และ text-embedding-3-large เพื่อสร้างเวกเตอร์ฝังตัวจากประโยค ย่อหน้า และเอกสาร พร้อมเปรียบเทียบข้อแลกเปลี่ยนด้านคุณภาพและค่าใช้จ่าย
การสร้างเวกเตอร์ฝังตัวด้วย OpenAI เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
ภาพรวมโมเดลเวกเตอร์ฝังความหมายของ OpenAI
OpenAI มีโมเดลเวกเตอร์ฝังความหมายสำหรับใช้งานจริงสองรุ่น ได้แก่ text-embedding-3-small และ text-embedding-3-large โมเดลขนาดเล็กสร้างเวกเตอร์ 1536 มิติและมีค่าใช้จ่ายต่อโทเคนถูกกว่า 5 เท่า ส่วนโมเดลขนาดใหญ่สร้างเวกเตอร์ 3072 มิติและมีความแม่นยำสูงกว่าในการทดสอบมาตรฐาน สำหรับแอปพลิเคชัน RAG ส่วนใหญ่ โมเดลขนาดเล็กเป็นจุดเริ่มต้นที่เหมาะสม
การเรียกสร้างเวกเตอร์ฝังความหมายครั้งแรกของคุณ
เมธอด client.embeddings.create() รับชื่อ model และสตริงหรือรายการ input โดยส่งคืนออบเจ็กต์การตอบกลับที่มีรายการ data ซึ่งแต่ละรายการมีแอตทริบิวต์ embedding ที่เก็บเวกเตอร์ในรูปแบบรายการค่าทศนิยมของ Python
เก็บคีย์ API ไว้ในตัวแปรสภาพแวดล้อมเสมอ อย่าเขียนคีย์ดังกล่าวลงในไฟล์ต้นฉบับโดยตรง
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])
response = client.embeddings.create(
model='text-embedding-3-small',
input='What is retrieval-augmented generation?'
)
vector = response.data[0].embedding
print(f'Vector length: {len(vector)}') # 1536
print(f'Type: {type(vector[0])}') # float
print(f'Sample values: {vector[:3]}') # [-0.02, 0.01, ...]การสร้างเวกเตอร์ฝังความหมายเป็นชุดอย่างมีประสิทธิภาพ
การส่งรายการสตริงไปยัง input จะสร้างเวกเตอร์ฝังความหมายให้ทั้งหมดด้วยการเดินทางไปกลับผ่าน API เพียงครั้งเดียว วิธีนี้เป็นแนวทางที่แนะนำเมื่อสร้างดัชนีคลังเอกสาร รายการ data ในการตอบกลับจะคงลำดับเดิมไว้ ทำให้สร้างพจนานุกรมสำหรับค้นหาได้ง่าย
แต่ละคำขอรองรับได้ไม่เกิน 2048 รายการ ต่อชุด และจำนวนโทเคนรวมของข้อมูลนำเข้าทั้งหมดต้องอยู่ภายในขีดจำกัดโทเคนของโมเดล
from openai import OpenAI
client = OpenAI()
documents = [
'RAG stands for Retrieval-Augmented Generation.',
'Embeddings convert text to numerical vectors.',
'Pinecone is a managed vector database service.'
]
response = client.embeddings.create(
model='text-embedding-3-small',
input=documents
)
embeddings = [item.embedding for item in response.data]
print(f'Got {len(embeddings)} embeddings')
print(f'Each has {len(embeddings[0])} dimensions')การลดจำนวนมิติของเวกเตอร์ฝังความหมาย
โมเดล text-embedding-3 ทั้งสองรุ่นรองรับพารามิเตอร์ dimensions ซึ่งตัดทอนเวกเตอร์ผลลัพธ์ ตัวอย่างเช่น การกำหนด dimensions=256 จะส่งคืนเวกเตอร์ที่มี 256 องค์ประกอบแทนที่จะเป็น 1536 องค์ประกอบ เวกเตอร์ที่สั้นกว่าใช้พื้นที่จัดเก็บและการคำนวณน้อยลง โดยแลกกับความแม่นยำที่ลดลงเล็กน้อย
วิธีนี้มีประโยชน์เมื่อคุณต้องการทดลองอย่างรวดเร็ว หรือเมื่อค่าใช้จ่ายในการจัดเก็บสำคัญกว่าคุณภาพการค้นคืนในระดับสูงสุด
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
model='text-embedding-3-small',
input='Shorter vectors save storage and query time.',
dimensions=256 # truncate from 1536 to 256
)
print(len(response.data[0].embedding)) # 256รูปแบบการเข้ารหัส: Base64 เทียบกับรายการค่าทศนิยม
โดยค่าเริ่มต้น API จะส่งคืนเวกเตอร์ฝังความหมายเป็นอาร์เรย์ JSON ของค่าทศนิยม (encoding_format='float') คุณสามารถขอ encoding_format='base64' เพื่อรับกลุ่มข้อมูลไบนารีที่เข้ารหัสแบบ base64 ซึ่งส่งผ่านเครือข่ายได้เร็วกว่าเมื่อประมวลผลเป็นชุดขนาดใหญ่
เมื่อใช้ base64 คุณต้องถอดรหัสด้วย NumPy: np.frombuffer(base64.b64decode(b64_str), dtype='float32')
import base64
import numpy as np
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
model='text-embedding-3-small',
input='Base64 encoding transfers faster.',
encoding_format='base64'
)
b64 = response.data[0].embedding
vector = np.frombuffer(base64.b64decode(b64), dtype='float32')
print(f'Decoded {len(vector)} floats')การติดตามการใช้โทเคนและค่าใช้จ่าย
การตอบกลับเวกเตอร์ฝังความหมายทุกครั้งจะมีออบเจ็กต์ usage พร้อม prompt_tokens คุณชำระเงินตามจำนวนโทเคน: text-embedding-3-small มีค่าใช้จ่าย $0.02 ต่อหนึ่งล้านโทเคน และ text-embedding-3-large มีค่าใช้จ่าย $0.13 ต่อหนึ่งล้านโทเคน (ณ กลางปี 2024)
การติดตามการใช้งานช่วยให้คุณประเมินค่าใช้จ่ายในการสร้างดัชนีคลังข้อมูลทั้งหมดได้ก่อนเริ่มการทำงานจริง
from openai import OpenAI
client = OpenAI()
texts = ['Document one content here.', 'Document two content here.']
response = client.embeddings.create(
model='text-embedding-3-small',
input=texts
)
tokens_used = response.usage.prompt_tokens
cost_usd = tokens_used * 0.00000002 # $0.02 per 1M tokens
print(f'Tokens: {tokens_used}, Cost: ${cost_usd:.6f}')การเปรียบเทียบ text-embedding-3-small กับรุ่นใหญ่
การเลือกระหว่างรุ่นเล็กกับรุ่นใหญ่ขึ้นอยู่กับข้อกำหนดด้านความแม่นยำและงบประมาณของคุณ:
- text-embedding-3-small: 1536 มิติ เร็วกว่า ถูกกว่า 5 เท่า เหมาะอย่างยิ่งกับงาน RAG ส่วนใหญ่
- text-embedding-3-large: 3072 มิติ ได้คะแนนการทดสอบมาตรฐาน MTEB สูงกว่า เหมาะกว่าสำหรับเนื้อหาหลายภาษาและงานด้านความหมายที่ซับซ้อน
แนวทางที่ใช้กันทั่วไปคือสร้างต้นแบบและตรวจสอบคุณภาพการค้นคืนด้วยโมเดลขนาดเล็กก่อน จากนั้นจึงเปลี่ยนไปใช้โมเดลขนาดใหญ่ก็ต่อเมื่อเมตริกการประเมินต่ำกว่าเป้าหมาย
การทำเวกเตอร์ฝังความหมายให้เป็นมาตรฐานสำหรับการค้นหาด้วยผลคูณจุด
OpenAI ส่งคืนเวกเตอร์ฝังความหมายที่ผ่านการทำให้เป็นมาตรฐานแบบ L2 แล้ว ซึ่งหมายความว่าเวกเตอร์แต่ละตัวมีขนาดเท่ากับ 1 อยู่แล้ว ดังนั้นคุณจึงใช้ ผลคูณจุด เป็นค่าประมาณความคล้ายคลึงโคไซน์ที่คำนวณได้รวดเร็ว โดยไม่ต้องทำขั้นตอนการทำให้เป็นมาตรฐานเพิ่มเติม เรื่องนี้สำคัญเมื่อค้นหาเวกเตอร์นับล้านรายการ เพราะการปรับปรุงเล็กน้อยจะสะสมจนเห็นผล
import numpy as np
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
model='text-embedding-3-small',
input='Are OpenAI embeddings normalized?'
)
vec = np.array(response.data[0].embedding)
magnitude = np.linalg.norm(vec)
print(f'Vector magnitude: {magnitude:.6f}') # very close to 1.0การจัดการเอกสารขนาดใหญ่
โมเดล text-embedding-3-small รองรับอินพุตได้สูงสุด 8191 โทเค็น หากเอกสารของคุณยาวเกินขีดจำกัดนี้ API จะส่งข้อผิดพลาดกลับมา วิธีมาตรฐานคือแบ่งเอกสารเป็นส่วนย่อยก่อน (โดยทั่วไปส่วนละ 200–500 โทเค็น) แล้วสร้างเวกเตอร์ฝังตัวให้แต่ละส่วนแยกกัน
การแบ่งเป็นส่วนย่อยนี้ไม่ได้เป็นเพียงข้อกำหนดทางเทคนิคเท่านั้น แต่ยังช่วยให้การค้นคืนมีประสิทธิภาพดีขึ้นด้วย เพราะการสร้างเวกเตอร์ฝังตัวจากส่วนที่มีเนื้อหาเฉพาะเจาะจงและมีขนาดเล็กจะให้ผลลัพธ์ที่แม่นยำกว่าการสร้างจากทั้งหน้าเอกสาร
import tiktoken
enc = tiktoken.encoding_for_model('text-embedding-3-small')
def count_tokens(text):
return len(enc.encode(text))
max_tokens = 8191
text = 'Very long document content...' # pretend this is huge
if count_tokens(text) > max_tokens:
print('Document too long — chunk before embedding')
else:
print(f'Safe to embed: {count_tokens(text)} tokens')การสร้างเวกเตอร์ฝังตัวแบบอะซิงโครนัสเพื่อประมวลผลปริมาณมาก
เมื่อจัดทำดัชนีเอกสารหลายพันรายการ ให้ใช้ ไคลเอนต์ OpenAI แบบอะซิงโครนัสร่วมกับ asyncio.gather เพื่อส่งคำขอสร้างเวกเตอร์ฝังตัวหลายรายการพร้อมกัน วิธีนี้เร็วกว่าการเรียกใช้งานตามลำดับมาก เพราะคอขวดอยู่ที่เวลาแฝงของเครือข่าย ไม่ใช่ CPU
เมื่อส่งคำขอพร้อมกัน ควรเพิ่มการจัดการขีดจำกัดอัตราการเรียกใช้ด้วยการหน่วงเวลาแบบทวีคูณเสมอ เพื่อหลีกเลี่ยงการใช้โทเค็นเกินขีดจำกัดต่อนาที
import asyncio
from openai import AsyncOpenAI
async def embed_batch(texts):
client = AsyncOpenAI()
response = await client.embeddings.create(
model='text-embedding-3-small',
input=texts
)
return [item.embedding for item in response.data]
async def main():
batches = [['doc1', 'doc2'], ['doc3', 'doc4']]
results = await asyncio.gather(*[embed_batch(b) for b in batches])
all_embeddings = [emb for batch in results for emb in batch]
print(f'Embedded {len(all_embeddings)} documents')
asyncio.run(main())การแคชเวกเตอร์ฝังตัวเพื่อประหยัดค่าใช้จ่าย
การสร้างเวกเตอร์ฝังตัวจากข้อความเดิมซ้ำหลายครั้งทำให้เสียทั้งเงินและเวลา ให้แคชเวกเตอร์ฝังตัวไว้ในพจนานุกรม โดยใช้สตริงข้อความ (หรือค่าแฮชของข้อความ) เป็นคีย์ และบันทึกแคชนี้ลงดิสก์ระหว่างแต่ละเซสชัน
สำหรับระบบใช้งานจริง ให้จัดเก็บเวกเตอร์ฝังตัวในฐานข้อมูลเวกเตอร์ที่กำจัดข้อมูลซ้ำโดยใช้รหัสเอกสาร สร้างเวกเตอร์ฝังตัวของเอกสารใหม่เฉพาะเมื่อเนื้อหาของเอกสารเปลี่ยนแปลงจริง ไม่ใช่ทุกครั้งที่เรียกใช้การจัดทำดัชนี
import json, hashlib, os
from openai import OpenAI
CACHE_FILE = '/tmp/embedding_cache.json'
client = OpenAI()
try:
cache = json.load(open(CACHE_FILE))
except FileNotFoundError:
cache = {}
def get_embedding(text):
key = hashlib.md5(text.encode()).hexdigest()
if key not in cache:
r = client.embeddings.create(model='text-embedding-3-small', input=text)
cache[key] = r.data[0].embedding
json.dump(cache, open(CACHE_FILE, 'w'))
return cache[key]
vec = get_embedding('Caching saves API costs.')
print(f'Retrieved {len(vec)}-dim embedding')ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิดด้านวิศวกรรม AI จากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า text-embedding-3-small เป็นตัวเลือกที่คุ้มค่าสำหรับงาน RAG ส่วนใหญ่ การสร้างเวกเตอร์ฝังตัวจากข้อความหลายรายการในการเรียก API ครั้งเดียวมีประสิทธิภาพมากกว่าการเรียกตามลำดับ และ พารามิเตอร์ dimensions สามารถลดขนาดเวกเตอร์เพื่อแลกความแม่นยำกับการประหยัดพื้นที่จัดเก็บ บทถัดไป เราจะสร้างระบบค้นหาเชิงความหมายโดยใช้เวกเตอร์ฝังตัวเหล่านี้และ NumPy
คำถามที่พบบ่อย
บทเรียน “การสร้างเวกเตอร์ฝังตัวด้วย OpenAI” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การสร้างเวกเตอร์ฝังตัวด้วย OpenAI” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การสร้างเวกเตอร์ฝังตัวด้วย OpenAI”
ใช้โมเดล text-embedding-3-small และ text-embedding-3-large เพื่อสร้างเวกเตอร์ฝังตัวจากประโยค ย่อหน้า และเอกสาร พร้อมเปรียบเทียบข้อแลกเปลี่ยนด้านคุณภาพและค่าใช้จ่าย คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การสร้างเวกเตอร์ฝังตัวด้วย OpenAI” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เวกเตอร์ฝังตัวคืออะไร
- การสร้างเวกเตอร์ฝังตัวด้วย OpenAI
- การค้นหาเชิงความหมายด้วย NumPy
- การจัดกลุ่มและแสดงภาพเวกเตอร์ฝังตัว