→ بازگشت به هوش مصنوعی مولد

طراحی پرسش‌های پیشرفته

بیایید برخی از یادگیری‌ها را از فصل قبلی مرور کنیم:

مهندسی پرسش، فرایند هدایت مدل به سمت پاسخ‌های مرتبط‌تر با ارائه دستورالعمل‌ها یا زمینه‌های مفیدتر است.

همچنین دو مرحله در نوشتن پرسش وجود دارد: ساختن پرسش، با ارائه زمینه مربوطه و بخش دوم بهینه‌سازی، یعنی بهبود تدریجی پرسش.

در این مرحله، ما درک اولیه‌ای از نحوه نوشتن پرسش‌ها داریم، اما نیاز داریم عمیق‌تر برویم. در این فصل، شما از آزمایش‌های مختلف با پرسش‌ها به درک اینکه چرا یک پرسش بهتر از دیگری است، خواهید رسید. شما یاد خواهید گرفت که چگونه پرسش‌ها را با رعایت برخی تکنیک‌های اساسی که می‌توانند به هر مدلی اعمال شوند، ساختاردهی کنید.

مقدمه

در این فصل، ما به موضوعات زیر خواهیم پرداخت:

  • گسترش دانش خود در زمینه مهندسی پرسش با اعمال تکنیک‌های مختلف بر روی پرسش‌ها.
  • پیکربندی پرسش‌ها برای تنوع در خروجی.

اهداف یادگیری

پس از اتمام این درس، شما قادر خواهید بود:

  • تکنیک‌های مهندسی پرسش را که به بهبود نتیجه پرسش‌های شما کمک می‌کند، به کار ببرید.
  • طراحی پرسش را به صورت متنوع یا معین انجام دهید.

مهندسی پرسش

مهندسی پرسش فرایند ایجاد پرسش‌هایی است که نتیجه مطلوب را تولید کنند. مهندسی پرسش تنها نوشتن یک پرسش متنی نیست. مهندسی پرسش یک رشته مهندسی نیست، بلکه بیشتر مجموعه‌ای از تکنیک‌هاست که می‌توانید برای دستیابی به نتیجه مطلوب به کار ببرید.

یک مثال از پرسش

بیایید یک پرسش پایه‌ای مانند این را در نظر بگیریم:

Generate 10 questions on geography.

۱۰ پرسش درباره جغرافیا ایجاد کنید.

در این پرسش، شما در واقع از مجموعه‌ای از تکنیک‌های مختلف پرسش استفاده می‌کنید.

بیایید این را تحلیل کنیم.

  • زمینه، شما مشخص می‌کنید که باید درباره "جغرافیا" باشد.
  • محدود کردن خروجی، شما نمی‌خواهید بیشتر از ۱۰ پرسش باشد.

محدودیت‌های پرسش‌های ساده

شما ممکن است نتیجه مورد نظر را بگیرید یا نگیرید. شما سوالات خود را تولید خواهید کرد، اما جغرافیا موضوع بزرگی است و ممکن است به دلایل زیر نتوانید آنچه را که می‌خواهید، دریافت کنید:

  • موضوع بزرگ، شما نمی‌دانید که آیا قرار است درباره کشورهای مختلف، پایتخت‌ها، رودخانه‌ها و غیره باشد.
  • فرمت، اگر بخواهید سوالات به گونه‌ای خاص قالب‌بندی شوند چه؟

همان‌طور که می‌بینید، هنگام ایجاد پرسش‌ها عوامل زیادی باید در نظر گرفته شود.

تا به اینجا، ما یک مثال از پرسش ساده را مشاهده کرده‌ایم، اما هوش مصنوعی مولد قادر به انجام بیشتر از این‌ها است تا به افراد در زمینه‌های مختلف کمک کند. بیایید به برخی تکنیک‌های ابتدایی بپردازیم.

تکنیک‌هایی برای طراحی پرسش

ابتدا باید درک کنیم که طراحی پرسش یک خاصیت نوظهور از یک مدل زبانی بزرگ (LLM) است، به این معنی که این ویژگی بخشی از ساختار مدل نیست، بلکه چیزی است که ما در حین استفاده از مدل کشف می‌کنیم.

چند تکنیک اساسی وجود دارد که می‌توانیم برای طراحی پرسش به یک مدل زبانی بزرگ (LLM) استفاده کنیم. بیایید آنها را بررسی کنیم.

  • طراحی پرسش بدون نمونه، این ابتدایی‌ترین شکل طراحی پرسش است. این یک پرسش واحد است که درخواستی برای پاسخ از LLM بر اساس داده‌های آموزشی‌اش دارد.
  • طراحی پرسش با چند نمونه، این نوع طراحی پرسش مدل زبانی را با ارائه ۱ یا چند مثال برای استفاده از آنها در تولید پاسخ هدایت می‌کند.
  • زنجیره تفکر، این نوع طراحی پرسش به LLM می‌گوید که چگونه یک مسئله را به مراحل مختلف تقسیم کند.
  • دانش تولید شده، برای بهبود پاسخ یک پرسش، می‌توانید اطلاعات یا حقایق تولید شده را به پرسش خود اضافه کنید.
  • کم‌تر به بیش‌تر، مانند زنجیره تفکر، این تکنیک نیز به تقسیم یک مشکل به یک سری مراحل مربوط می‌شود و سپس از آنها درخواست می‌کند تا به ترتیب انجام شوند.
  • خودبازنگری، این تکنیک درباره نقد کردن خروجی LLM و سپس درخواست برای بهبود آن است.

پرسش بدون نمونه

این سبک پرسش‌گری بسیار ساده است و شامل یک پرسش واحد می‌باشد. این تکنیک احتمالاً همان چیزی است که شما در حال یادگیری درباره مدل‌های زبانی بزرگ (LLMs) استفاده می‌کنید. مثال زیر را ببینید:

  • Prompt: "What is Algebra?"

  • Answer: "Algebra is a branch of mathematics that studies mathematical symbols and the rules for manipulating these symbols."

  • پرسش: "Algebra چیست؟"

  • پاسخ: "Algebra یک شاخه از ریاضیات است که به مطالعه نمادهای ریاضی و قوانین مربوط به دستکاری این نمادها می‌پردازد."

پرسش با چند نمونه

این سبک پرسش‌گری با ارائه چند مثال همراه با درخواست به مدل کمک می‌کند. این سبک شامل یک پرسش واحد با داده‌های خاص وظیفه‌ای اضافی است. مثال زیر را ببینید:

  • Prompt: "Write a poem in the style of Shakespeare. Here are a few examples of Shakespearean sonnets.: Sonnet 18: 'Shall I compare thee to a summer's day? Thou art more lovely and more temperate...' Sonnet 116: 'Let me not to the marriage of true minds Admit impediments. Love is not love Which alters when it alteration finds...' Sonnet 132: 'Thine eyes I love, and they, as pitying me, Knowing thy heart torment me with disdain,...' Now, write a sonnet about the beauty of the moon."
  • Answer: "Upon the sky, the moon doth softly gleam, In silv'ry light that casts its gentle grace,..."

نمونه‌ها به LLM زمینه، قالب یا سبک خروجی مورد نظر را ارائه می‌دهند. آنها به مدل کمک می‌کنند تا وظیفه خاص را درک کرده و پاسخ‌های دقیق‌تر و مرتبط‌تری تولید کند.

زنجیره‌ی تفکر (Chain-of-thought)

زنجیره‌ی تفکر تکنیک بسیار جالبی است زیرا مربوط به هدایت مدل زبانی بزرگ (LLM) از طریق یک سری مراحل است. ایده این است که به LLM به گونه‌ای دستور بدهیم که درک کند چگونه چیزی را انجام دهد. به مثال زیر با زنجیره‌ی تفکر و بدون آن توجه کنید:

- Prompt: "Alice has 5 apples, throws 3 apples, gives 2 to Bob and Bob gives one back, how many apples does Alice have?"
- Answer: 5

مدل LLM با ۵ پاسخ می‌دهد که نادرست است. پاسخ صحیح ۱ سیب است، با توجه به محاسبه (۵ -۳ -۲ +۱ = ۱).

پس چگونه می‌توانیم به LLM بیاموزیم که این را به درستی انجام دهد؟

بیایید زنجیره‌ی تفکر را امتحان کنیم. اعمال زنجیره‌ی تفکر به این معناست که:

۱. یک مثال مشابه به LLM بدهید. ۲. محاسبه را نشان دهید و چگونگی محاسبه‌ی صحیح را توضیح دهید. ۳. پرسش اصلی را ارائه دهید.

به این شکل:

  • Prompt: "Lisa has 7 apples, throws 1 apple, gives 4 apples to Bart and Bart gives one back: 7 -1 = 6 6 -4 = 2 2 +1 = 3
    Alice has 5 apples, throws 3 apples, gives 2 to Bob and Bob gives one back, how many apples does Alice have?" Answer: 1

به طور واضح، ما پرسش‌های بسیار طولانی‌تری را با یک مثال دیگر، یک محاسبه و سپس پرسش اصلی نوشته‌ایم و به پاسخ صحیح ۱ می‌رسیم.

همان‌طور که می‌بینید، زنجیره‌ی تفکر یک تکنیک بسیار قدرتمند است.

Generated knowledge

Many times when you want to construct a prompt, you want to do so using your own company's data. You want part of the prompt to be from the company and the other part should be the actual prompt you're interested in.

As an example, this is what your prompt then can look like if you're in the insurance business:

{{company}}: {{company_name}}
{{products}}:
{{products_list}}
Please suggest an insurance given the following budget and requirements:
Budget: {{budget}}
Requirements: {{requirements}}

Above, you see how the prompt is constructed using a template. In the template there's a number of variables, denoted by {{variable}}, that will be replaced with actual values from a company API.

Here's an example of how the prompt could look like once the variables have been replaced by content from your company:

Insurance company: ACME Insurance
Insurance products (cost per month):
- Car, cheap, 500 USD
- Car, expensive, 1100 USD
- Home, cheap, 600 USD
- Home, expensive, 1200 USD
- Life, cheap, 100 USD

Please suggest an insurance given the following budget and requirements:
Budget: $1000
Requirements: Car, Home, and Life insurance

Running this prompt through an LLM will produce a response like this:

Given the budget and requirements, we suggest the following insurance package from ACME Insurance:
- Car, cheap, 500 USD
- Home, cheap, 600 USD
- Life, cheap, 100 USD
Total cost: $1,200 USD

As you can see, it also suggests the Life insurance, which it shouldn't. This result is an indication that we need to optimize the prompt by changing the prompt to be clearer on what it can allow. After some trial and error, we arrive at the following prompt:

Insurance company: ACME Insurance
Insurance products (cost per month):
- type: Car, cheap, cost: 500 USD
- type: Car, expensive, cost: 1100 USD
- type: Home, cheap, cost: 600 USD
- type: Home, expensive, cost: 1200 USD
- type: Life, cheap, cost: 100 USD

Please suggest an insurance given the following budget and requirements:
Budget: $1000 restrict choice to types: Car, Home

Note how adding type and cost and also using the keyword restrict helps the LLM to understand what we want.

Now we get the following response:

Given the budget and requirements, we suggest the Car, Cheap insurance product which costs 500 USD per month.

The point of this example was to show that even though we're using a basic technique like generated knowledge, we still need to optimize the prompt in most cases to get the desired outcome.

Least-to-most

The idea with Least-to-most prompting is to break down a bigger problem into subproblems. That way, you help guide the LLM on how to "conquer" the bigger problem. A good example could be for data science where you can ask the LLM to divide up a problem like so:

Prompt: How to perform data science in 5 steps?

With your AI assistant answering with:

  1. Collect data
  2. Clean data
  3. Analyze data
  4. Plot data
  5. Present data

Self-refine, critique the results

With generative AIs and LLMs, you can't trust the output. You need to verify it. After all, the LLM is just presenting you what's the next most likely thing to say, not what's correct. Therefore, a good idea is to ask the LLM to critique itself, which leads us to the self-refine technique.

How it works is that you follow the following steps:

  1. Initial prompt asking the LLM to solve a problem
  2. LLM answers
  3. You critique the answer and ask the AI to improve
  4. LLM answers again, this time considering the critique and suggest solutions it came up with

You can repeat this process as many times as you want.

Here's an example using this technique:

Prompt: "Create a Python Web API with routes products and customers"

AI Answer:

import flask
app = Flask(__name__)

@app.route('/products')
def products():
    return 'Products'

@app.route('/customers')
def customers():
    return 'Customers'

Prompt: suggest 3 improvements of the above code

AI Answer:

Sure, here are three suggestions to improve the code:

Import the correct module: The first line should import Flask instead of flask. The correct import statement should be from flask import Flask.

Add a main function: Add a if __name__ == '__main__': block to the end of the file to run the application when the file is executed.

Use f-strings: Use f-strings to format the return statements in the route functions. For example, return 'Products' can be changed to return f'This is the {request.path} page'.
from flask import Flask, request

app = Flask(__name__)

@app.route('/products')
def products():
    return f'This is the {request.path} page'

@app.route('/customers')
def customers():
    return f'This is the {request.path} page'

if __name__ == '__main__':
    app.run()

As you can see, the above AI response is improving the first suggested code thanks to critiquing the first answer.

Maieutic prompting

Maieutic prompting is a technique that is similar to self-refine but it's more about asking the LLM to explain itself. The goal is to reduce inconsistencies in the LLM's output so to ensure it arrives at the correct answer. The workflow to follow is:

  1. Ask the LLM to answer a question
  2. For each part of the answer, ask the LLM to explain it more in depth.
  3. If there are inconsistencies, discard the parts that are inconsistent.

Repeat 2 and 3 until you've gone through all the parts and you're satisfied with the answer.

Here's an example prompt:

prompt: How can I create a crisis plan to mitigate a pandemic in 5 steps? LLM answer:

1. Identify the risks
1. Identify the stakeholders
1. Identify the resources
1. Identify the actions
1. Identify the communication channels

It's identified 5 steps, but can we determine if this is correct? Let's ask the LLM to explain each step:

prompt: Explain the first step in more detail, what are the risks in detail with a pandemic?

The risks are the following:

- Loss of life
- Loss of business
- Loss of reputation
- Loss of customers
- Loss of employees

At this point, we want to make sure the LLM is correct so we ask it to explain the first risk in more detail and hope it's consistent with the answer above:

prompt: In a Pandemic, which is the biggest risk and why?

The biggest risk is loss of life because it's the most important thing to protect.

What are the two biggest risks in a pandemic?

The two biggest risks are loss of life and loss of business.

At this point, the LLM is consistent and mentions "life" and "business" as the top two risks. We can now continue to the next step and feel fairly confident. However, we shouldn't trust the LLM blindly, we should always verify the output.

Vary your output

LLMs are nondeterministic by nature, meaning that you will get different results each time you run the same prompt. Try the following prompt for example:

"Generate code for a Python Web API"

# Import necessary modules
import flask
from flask import request, jsonify

# Create a Flask app
app = flask.Flask(__name__)

# Create a route for the API
@app.route('/api', methods=['GET'])
def api():
    # Get the data from the request
    data = request.args

    # Process the data
    result = process_data(data)

    # Return the result as JSON
    return jsonify(result)

# Function to process the data
def process_data(data):
    # Do something with the data
    result = data + 1

    # Return the result
    return result

# Run the app
if __name__ == '__main__':
    app.run()

Running the same prompt again generates a slightly different response:

#import necessary packages
import flask
from flask import request, jsonify

#create the Flask application
app = flask.Flask(__name__)
app.config["DEBUG"] = True

#create a list of books
books = [
    {'id': 0,
     'title': 'A Fire Upon the Deep',
     'author': 'Vernor Vinge',
     'first_sentence': 'The coldsleep itself was dreamless.',
     'year_published': '1992'},
    {'id': 1,
     'title': 'The Ones Who Walk Away From Omelas',
     'author': 'Ursula K. Le Guin',
     'first_sentence': 'With a clamor of bells that set the swallows soaring, the Festival of Summer came to the city Omelas, bright-towered by the sea.',
     'published': '1973'},
    {'id': 2,
     'title': 'Dhalgren',
     'author': 'Samuel R. Delany',
     'first_sentence': 'to wound the autumnal city.',
     'published': '1975'}
]

#create an endpoint for the API
@app.route('/', methods=['GET'])
def home():
    return '''<h1>Books API</h1>
<p>A prototype API for retrieving books.</p>'''

#create an endpoint to return all books
@app.route('/api/v1/resources/books/all', methods=['GET'])
def api_all():
    return jsonify(books)

#create an endpoint to return a single book
@app.route('/api/v1/resources/books', methods=['GET'])
def api_id():
    #check if an ID was provided as part of the URL
    #if ID is provided, assign it to a variable
    #if no ID is provided, display an error
    if 'id' in request.args:
        id = int(request.args['id'])
    else:
        return "Error: No id field provided. Please specify an id."

    #create an empty list for our results
    results = []

    #loop through the data and match results that fit the requested ID
    #IDs are unique, but other fields might return many results
    for book in books:
        if book['id'] == id:
            results.append(book)

    #use the jsonify function from Flask to convert our list of
    #Python dictionaries to the JSON format
    return jsonify(results)

app.run()

So is the varied output a problem?

Depends on what you're trying to do. If you want a specific response then it's a problem. If you're ok with a varied output like "Generate any 3 questions on geography", then it's not a problem.

Using temperature to vary your output

Ok, so we've decided we want to limit the output to be more predictable, that is more deterministic. How do we do that?

Temperature is a value between 0 and 1, where 0 is the most deterministic and 1 is the most varied. The default value is 0.7. Let's see what happens with two runs of the same prompt with temperature set to 0.1:

"Generate code for a Python Web API"

#import necessary libraries
import flask
from flask import request, jsonify

#create an instance of the Flask class
app = flask.Flask(__name__)

#create an endpoint for the API
@app.route('/api/v1/endpoint', methods=['GET'])
def api_endpoint():
    #get the request data
    data = request.get_json()

    #process the data
    result = process_data(data)

    #return the result
    return jsonify(result)

#function to process the data
def process_data(data):
    #process the data
    result = {'result': 'success'}

    #return the result
    return result

#run the Flask app
if __name__ == '__main__':
    app.run()

Running the prompt again gives us this outcome:

#import necessary libraries
import flask
from flask import request, jsonify

#create a Flask app
app = flask.Flask(__name__)

#create a route for the API
@app.route('/api', methods=['GET'])
def api_call():
    #get the data from the request
    data = request.get_json()

    #process the data
    result = process_data(data)

    #return the result
    return jsonify(result)

#define the process_data function
def process_data(data):
    #do something with the data
    result = data + 1

    #return the result
    return result

#run the app
if __name__ == '__main__':
    app.run()

There's only a tiny difference between these two outputs. Let's do the opposite this time, let's set the temperature to 0.9:

# Import necessary libraries
import flask
from flask import request, jsonify

# Create a Flask app
app = flask.Flask(__name__)

# Create a route for the API
@app.route('/api', methods=['GET'])
def api_call():
    # Get the data from the request
    data = request.args

    # Process the data
    result = process_data(data)

    # Return the result
    return jsonify(result)

# Function to process the data
def process_data(data):
    # Do something with the data
    result = data + 1

    # Return the result
    return result

# Run the app
if __name__ == '__main__':
    app.run()

and the second attempt at 0.9 as temperature value:

import flask
from flask import request, jsonify

# create the Flask app
app = flask.Flask(__name__)
app.config['DEBUG'] = True

# create some test data
books = [
    {'id': 0, 'title': 'A Fire Upon The Deep', 'author': 'Vernor Vinge', 'first_sentence': 'The coldsleep itself was dreamless.', 'year_published': '1992'},
    {'id': 1, 'title': 'The Ones Who Walk Away From Omelas', 'author': 'Ursula K. Le Guin', 'first_sentence': 'With a clamor of bells that set the swallows soaring, the Festival of Summer came to the city Omelas, bright-towered by the sea.', 'published': '1973'},
    {'id': 2, 'title': 'Dhalgren', 'author': 'Samuel R. Delany', 'first_sentence': 'to wound the autumnal city.', 'published': '1975'}
]

# create an endpoint
@app.route('/', methods=['GET'])
def home():
    return '''<h1>Welcome to our book API!</h1>'''

@app.route('/api/v1/resources/books

As you can see, the results couldn't be more varied.

Note, that there are more parameters you can change to vary the output, like top-k, top-p, repetition penalty, length penalty and diversity penalty but these are outside the scope of this curriculum.

Good practices

There are many practices you can apply to try to get what you want. You will find your own style as you use prompting more and more.

Additionally to the techniques we've covered, there are some good practices to consider when prompting an LLM.

Here are some good practices to consider:

  • Specify context. Context matters, the more you can specify like domain, topic, etc. the better.
  • Limit the output. If you want a specific number of items or a specific length, specify it.
  • Specify both what and how. Remember to mention both what you want and how you want it, for example "Create a Python Web API with routes products and customers, divide it into 3 files".
  • Use templates. Often, you will want to enrich your prompts with data from your company. Use templates to do this. Templates can have variables that you replace with actual data.
  • Spell correctly. LLMs might provide you with a correct response, but if you spell correctly, you will get a better response.

Assignment

Here's code in Python showing how to build a simple API using Flask:

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def hello():
    name = request.args.get('name', 'World')
    return f'Hello, {name}!'

if __name__ == '__main__':
    app.run()

Use an AI assistant like GitHub Copilot or ChatGPT and apply the "self-refine" technique to improve the code.

Solution

Please attempt to solve the assignment by adding suitable prompts to the code.

[!TIP] Phrase a prompt to ask it to improve, it's a good idea to limit how many improvements. You can also ask to improve it in a certain way, for example architecture, performance, security, etc.

Solution

Knowledge check

Why would I use chain-of-thought prompting? Show me 1 correct response and 2 incorrect responses.

  1. To teach the LLM how to solve a problem.
  2. B, To teach the LLM to find errors in code.
  3. C, To instruct the LLM to come up with different solutions.

A: 1, because chain-of-thought is about showing the LLM how to solve a problem by providing it with a series of steps, and similar problems and how they were solved.

🚀 Challenge

You just used the self-refine technique in the assignment. Take any program you built and consider what improvements you would want to apply to it. Now use the self-refine technique to apply the proposed changes. What did you think the result, better or worse?

Great Work! Continue Your Learning

After completing this lesson, check out our Generative AI Learning collection to continue leveling up your Generative AI knowledge!

Head over to Lesson 6 where we will apply our knowledge of Prompt Engineering by building text generation apps