הקדמה
מעבירה את הקורס מי שאחראית על openai cookbook .
סוגי LLM
סוג 1: LLM בסיסי (Base LLM)
נבא את המילה הבא, בהתבסס על טקסט האימון. הערה שלי: נקרא לפעמים Completion.
סוג 2: LLM מכוון הנחיות (Instruction tune LLM)
מנסה לענות ע”פ הנחיות. בוצע Fine-tunning על הנחיות ודוגמאות טובות של מענה להנחיות. נעשה שימוש בלמידה מחיזוקים עם פידבק אנושי (RLHF) לישר את המענה כך שיהיה אדיב, כנה, לא מזיק. בקורס הזה נתרכז בו.
הנחיות (Guidelines)
עקרונות
- לכתוב בהיר והנחיות ספציפיות.
- לתת זמן למודל לחשוב.
כתיבה בהירה והנחיות ספציפיות
שימוש בתוחמים (delimiters)
כדי לעשות סדר - דוגמת: “ , ’ , — , <> ,
הזרקת פרומפטים (prompt injection)
כאשר משתמש כותב פרומפט שמצורף אליו טקסט ארוך ייתכן ובתוך הטקסט יהיו חלקים שישמעו כסותרים את ההנחייה, וזה יכול להטעות את המודל. כאשר הטקסט הוא קלט של מישהו הוא יכול להזריק הנחיה.
בקשת פלט מובנה (structured output)
לבקש את הפלט בפורמטים כמו JSON או HTML.
לבדוק האם תנאים מתקיימים
לבדוק את ההנחות הדרושות למשימה ולהגיב בהתאם.
Few-shot prompting
לספק דוגמאות מוצלחות של השלמת המשימה, לפני בקשה לביצוע המשימה.
לתת זמן למודל לחשוב
ציון הצעדים הדרושים לביצוע המשימה
פירוט המשימה כסדרת צעדים של משימות פשוטות ולבקש מהמודל לכתוב את התוצאות של כל אחת מהן בפורמט של סדרת צעדים.
הנחיית המודל לתת פתרון לפני הגעה למסקנות
בקשה מהמודל לפתור את הבעיה בעצמו לפני שהוא חווה דעה על פתרון. נניח בפתרון בעיה מתמטית לבקש ממנו לבצע את הפתרון ואז להשוות עם הפתרון שסופק מסטודנט.
גבולות במודלים (Model Limitations)
הזיות (Hallucinations)
עונה תשובות שנשמעות הגיוניות אך לא נכונות.
הפחתת הזיות
נבקש מהמודל למצוא את המידע הרלוונטי, לאחר מכן לתת מענה על בסיס המידע הרלוונטי.
קוד בסיסי
טעינת מפתח (key)
כדי לגשת למודל נצטרך מפתח, נשמור אותו בסביבה ונטען אותו בצורה הבאה:
import openai
import os
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
openai.api_key = os.getenv('OPENAI_API_KEY')פונקציית מענה
מימוש של פונקציית צאט פשוטה שממשת פרומפט-תגובה, וכל הAPI שקוף:
def get_completion(prompt, model="gpt-3.5-turbo"):
messages = [{"role": "user", "content": prompt}]
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=0, # this is the degree of randomness of the model's output
)
return response.choices[0].message["content"]מימוש זה הוא לopenai=0.27.0.
עבור גרסא openai=1.0.0 נשתמש ב:
def get_completion(prompt, model="gpt-3.5-turbo"):
messages = [{"role": "user", "content": prompt}]
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0
)
return response.choices[0].message.contentפיתוח Prompt איטרטיבי (Iterative Prompt Development)
כאשר באים לפתח מודל באמצעות Prompt Engineering פיתוח המודל דומה מאוד לתהליך שקורה במחקר DS רגיל, מתואר בתרגשים הבא:

הנחיות לפרומפט (Prompt guidelines)
- צריך להיות ברור וספציפי.
- ניתוח למה לא ניתנה את התוצאה המבוקשת.
- לזקק את הרעיון ובהתאם את הPrompt.
- חזרה.
דוגמא: בקשה לתיאור טכני מהמוצר
ניתן למודל תיאור ארוך של המוצר ונבקש ממנו את הפרטים הטכניים שלו.
- תשובה ארוכה מידי: קיבלנו תשובה ארוכה מידי, נבקש מהמודל להגביל את עצמו למספר שורות או אורך מילים מקסימלי (שהיא בעיה קשה למודל כי הוא מדבר בטוקנים).
- מתרכז בפרטים לא נכונים: הוא מתרכז בחלקים מהטקסט שלא רלוונטים למה שהמשתמש ירצה לדעת, נבקש ממנו להתייחס לפרטים שאדם שקורא את הפרטים הטכניים ירצה לראות באופן טבעיץ
- תוצאה לא בפורמט: קיבלנו תוצאה טובה אבל לא מסודרת וקשה לקריאה (טקסט ארוך), נבקש מהמודל תוצאה בתצורה של
HTMLונציג אותה באמצעות ספרייה מתאימה:
from IPython.display import display, HTML
display(HTML(response))וככה בתהליך חזרתי הגענו לתוצאה הרצויה שניתן ממש להציג באתר.
סיכום (Summarizing)
אחת המשימות המרכזיות שניתן להשיג ע”י מודל LLM הוא משימת סיכום, נחוץ במיוחד בגלל כמויות המידע הקיימות כיום. דברים שמקובל מהמודל לבקש:
- סכם את הטקסט.
- סכם את הטקס עם הגבלת משפטים/מילים/תווים.
- סכם את הטקסט והתמקד בנושאים ספציפיים.
- חלץ (extract) את המידע הרלוונטי במקום לסכם.
הסקה (Inferring)
מודלי שפה גדולים טובים במיוחד בלחלץ דברים ספציפיים שמבקשים מהם, ולכן ניתן בקלות לחלץ נתונים מעניינים על טקסט נתון. דוגמאות:
- ניתוח סנטימנט (שלילי/חיובי)
- זיהוי סוגי רגשות
- זיהוי כעס
- זיהוי מוצר וחברה מביקרות של לקוח
הסקה מרובה (Multiple Inferring)
לעיתים נרצה לבקש מהמודל להסיק ריבוי של משימות על הטקסט ולבקש תשובה בפורמט מוגדר מראש (לרוב זה יהיה JSON ונציין מפתחות) דבר שגם אותו הוא עושה לרוב בצורה טובה, ועם הערך המפורמט יהיה לנו נוח מאוד לעבוד.
חילוץ נושאים
עוד משימה נפוצה היא לבקש מהמודל לחלץ את הנושאים עליו הטקסט מדבר. או x נושאים עליהם הטקסט מדבר.
דוגמא: התראת חדשות לנושא ספציפי
בהינתן פרסום כתבה חדשה נבקש מהמודל להחזיר JSON עבור רשימת נושאים עם אינדיקציה בוליאנית האם הפרסום הוא בנושא. ניתן התראה עבור הנושאים הרלוונטיים.
העברה (Transforming)
מודלי שפה גדולים טובים במיוחד במשימות העברה דוגמת תרגום או תיקון איות או דקדוק. או העברת HTML ל JSON.
תרגום
ניתן לבקש בצורה פשוטה מהמודל לתרגם טקסט נתון לשפה אחרת, או לכמה שפות אחרות. מעניין הוא שגם שפה לא בדיוק קיימת (ניתנה דוגמה עם English Pirate) הוא מתרגם, כלומר גם בהיבטים סגנוניים ולא רק שפתיים המודל טוב. ניתן בקלות לייצר מתרגם לכלל השפות בהינתן 2 חוליות של בקשות שהראשונה מבקשת לזהות את השפה והשנייה לתרגם מהשפה המזוהה לשפה הרצויה.
שינוי טון
שינוי סגנון דיבור נעשה בצורה טובה מאוד, נבקש מהמודל לתרגם מסגנון מסוים לאחר. לדוגמה: שנה את משפט הבא מסלנג למכתב עסקי.
העברת פורמט
נבקש מהמודל להעביר קטעי קוד בין פורמטים שונים.
לדוגמא: העברת JSON לטבלה בHTML.
בדיקת איות ודקדוק
נבקש מהמודל להגות או להגות ולתקן את הטקסט הנתון.
ספרייה מעניינת לא מוכרת שמתמשים בה להשוות את הטקסט המתוקן היא Redlines:
from redlines import Redlines
diff = Redlines(text,response)
display(Markdown(diff.output_markdown))הרחבה (Expanding)
משימה שימושית נוספת של מודלי שפה גדולים, היא הרחבת מענה נקודתי למענה נרחב בעל צורך מסוים. במקרים רבים נרצה לייצר התנהגות דמוית בן אדם כאשר לענות בצורה נקודתית יהיה מענה לא מספיק טוב, ולכן נבקש מהמודל להרחיב את המודל בצורה דמוית בן אדם. לדוגמא: נבקש מהמודל לזהות אם הביקורת של הלקוח חיובית או שלילת, אם חיובית להודות לו בנעימות, אחרת להציע לו שירות לקוחות. כדאי לבקש מהמודל להתייחס לפרטים שהלקוח צייןץ
שימוש בטמפרטורה (temprature)
במקרים מסוג זה נרצה לרוב להשתמש במדד הטמפרטורה (temprature) במידה גבוהה מהרגיל, כי נהיה מוכנים לוותר על הדיוק בשביל תשובות יותר יצירתיות.
צ’אטבוט (ChatBot)
משימה מהנפוצות ביותר ביכולות של מודל שפה גדול, הוא לייצר סוכן שיענה באופן אוטמטי בצאט (צ’אטבוט).
הקדמה
הפונקצייה get_complition שכתבנו למעלה מניחה שאנחנו פונים בצורה יחידה למודל, ללא זיכרון.
הבנייה של ChatGPT היא בצורה שהוא יכול לקבל את כל הסטוריית השיחה, נצטרך בכל פנייה מחדש לשלוח את הסטוריית השיחה. נעדכן את הפונקצייה שתתאים למשימה הנוכחית שלנו:
def get_completion_from_messages(messages, model="gpt-3.5-turbo", temperature=0):
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=temperature, # this is the degree of randomness of the model's output
)נציין שהקלט לmessages הוא מהצורה:
messages = [
{'role':'system', 'content':'You are an assistant that speaks like Shakespeare.'},
{'role':'user', 'content':'tell me a joke'},
{'role':'assistant', 'content':'Why did the chicken cross the road'},
{'role':'user', 'content':'I don\'t know'} ]צמדים של תפקיד (role) והודעה (content), כאשר התפקיד יכול להיות אחד מבין:
- מערכת (
system) - הגדרת התפקיד של העוזר - עוזר (
assistant) - תגובה של העוזר - משתמש (
user) - תגובה של המשתמש
דוגמא לצ’אטבוט
נשתמש בספרייה panel שבונה UI מקומי בתוך המחברת.
import panel as pn # GUI
pn.extension()נייצר משתנים של היסטוריית שיחות למודל, והיסטוריית שיחות לתצוגה:
panels = [] # collect display
context = [ {'role':'system', 'content':"""
...
"""} ] # accumulate messagesנייצר שדה קלט ולחצן למשתמש.
inp = pn.widgets.TextInput(value="", placeholder='Enter text here…')
button_conversation = pn.widgets.Button(name="Chat!")נייצר פונקציה שלוקחת את הקלט שהמשתמש הכניס, מוסיפה אותו להסטוריית השיחות, שולחת למודל ומעדכנת את היסטוריית השיחות למשתמש:
def collect_messages(_):
prompt = inp.value_input
inp.value = ''
context.append({'role':'user', 'content':f"{prompt}"})
response = get_completion_from_messages(context)
context.append({'role':'assistant', 'content':f"{response}"})
panels.append(
pn.Row('User:', pn.pane.Markdown(prompt, width=600)))
panels.append(
pn.Row('Assistant:', pn.pane.Markdown(response, width=600, style={'background-color': '#F6F6F6'})))
return pn.Column(*panels)נבנה את הקשר האינטרקטיבי של קריאה לפונקצייה בעת לחיצה, ונבנה את הפאנל שלנו:
interactive_conversation = pn.bind(collect_messages, button_conversation)
dashboard = pn.Column(
inp,
pn.Row(button_conversation),
pn.panel(interactive_conversation, loading_indicator=True, height=300),
)
dashboard