Bỏ qua tới nội dung
Bài 5/12 · Generative AI cho người mới bắt đầu (Microsoft)

Kỹ thuật prompt nâng cao

Các kỹ thuật zero-shot, few-shot, chain-of-thought, generated knowledge, least-to-most, self-refine, maieutic và cách dùng temperature để điều chỉnh độ đa dạng của đầu ra.

Cơ bản@shine190418 phút đọc

Bài này giúp bạn đi từ việc thử nhiều prompt khác nhau tới hiểu vì sao prompt này tốt hơn prompt kia, qua các kỹ thuật cơ bản áp dụng được cho mọi LLM.

Video bài học (tiếng Anh): xem trên YouTube.

Hãy ôn lại một chút từ bài trước:

Prompt engineering là quá trình dẫn model tới câu trả lời liên quan hơn bằng cách đưa chỉ dẫn hoặc ngữ cảnh hữu ích hơn.

Viết prompt cũng có hai bước: dựng prompt bằng cách đưa ngữ cảnh liên quan, và tối ưu, tức cải thiện prompt dần dần.

Tới đây, chúng ta đã có hiểu biết cơ bản về cách viết prompt, nhưng cần đi sâu hơn. Trong bài này, bạn sẽ học cách dựng prompt theo một số kỹ thuật cơ bản dùng được với mọi LLM.

Giới thiệu

Bài này gồm:

  • Mở rộng kiến thức prompt engineering bằng cách áp dụng nhiều kỹ thuật vào prompt.
  • Cấu hình prompt để thay đổi đầu ra.

Mục tiêu học tập

Sau bài này, bạn sẽ có thể:

  • Áp dụng các kỹ thuật prompt engineering để cải thiện kết quả.
  • Viết prompt cho kết quả đa dạng hoặc tất định (deterministic).

Prompt engineering

Prompt engineering là quá trình tạo prompt cho ra kết quả mong muốn. Prompt engineering không chỉ là viết một prompt văn bản. Nó không phải một ngành kỹ thuật, mà giống một tập kỹ thuật bạn áp dụng để có kết quả mong muốn.

Ví dụ về một prompt

Lấy một prompt cơ bản như sau:

Generate 10 questions on geography.

(Tạo 10 câu hỏi về địa lý.) Trong prompt này, bạn thực ra đang áp dụng nhiều kỹ thuật prompt khác nhau. Hãy phân tích:

  • Ngữ cảnh: bạn chỉ định chủ đề là "địa lý".
  • Giới hạn đầu ra: bạn muốn không quá 10 câu hỏi.

Giới hạn của prompt đơn giản

Bạn có thể nhận hoặc không nhận được kết quả mong muốn. Câu hỏi sẽ được tạo ra, nhưng địa lý là chủ đề rộng và bạn có thể không được thứ mình muốn vì:

  • Chủ đề rộng: bạn không biết câu hỏi sẽ về quốc gia, thủ đô, sông ngòi hay gì khác.
  • Định dạng: nếu bạn muốn câu hỏi được trình bày theo một kiểu nhất định thì sao?

Như bạn thấy, có rất nhiều điều cần cân nhắc khi tạo prompt.

Đến giờ chúng ta mới thấy một ví dụ đơn giản, nhưng AI tạo sinh (generative AI) có thể làm nhiều hơn để giúp người ở nhiều vai trò và ngành nghề. Hãy cùng xem các kỹ thuật cơ bản.

Các kỹ thuật viết prompt

Trước tiên, cần hiểu rằng prompting là một thuộc tính xuất hiện tự nhiên (emergent) của LLM: đây không phải tính năng được xây sẵn vào model, mà là thứ chúng ta khám phá ra khi dùng model.

Có một số kỹ thuật cơ bản để viết prompt cho LLM:

  • Zero-shot prompting: dạng cơ bản nhất. Một prompt duy nhất yêu cầu LLM trả lời chỉ dựa trên dữ liệu huấn luyện.
  • Few-shot prompting: dẫn dắt LLM bằng cách đưa 1 hoặc nhiều ví dụ để nó dựa vào khi trả lời.
  • Chain-of-thought: chỉ cho LLM cách chia một bài toán thành các bước.
  • Generated knowledge: để cải thiện câu trả lời, bạn đưa thêm dữ kiện hoặc kiến thức được sinh ra vào prompt.
  • Least-to-most: giống chain-of-thought, chia bài toán thành chuỗi bước rồi yêu cầu thực hiện các bước đó theo thứ tự.
  • Self-refine: phê bình đầu ra của LLM rồi yêu cầu nó cải thiện.
  • Maieutic prompting: bạn muốn đảm bảo câu trả lời của LLM đúng, nên yêu cầu nó giải thích từng phần của câu trả lời. Đây là một dạng self-refine.

Zero-shot prompting

Kiểu prompt này rất đơn giản, chỉ gồm một prompt. Đây có lẽ là kỹ thuật bạn đang dùng khi mới bắt đầu tìm hiểu LLM. Ví dụ:

  • Prompt: "What is Algebra?"
  • Câu trả lời: "Algebra is a branch of mathematics that studies mathematical symbols and the rules for manipulating these symbols."

Few-shot prompting

Kiểu prompt này giúp model bằng cách đưa vài ví dụ kèm yêu cầu. Nó gồm một prompt duy nhất với dữ liệu bổ sung riêng cho tác vụ. Ví dụ:

  • Prompt:

    text
    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.
    
  • Câu trả lời: "Upon the sky, the moon doth softly gleam, In silv'ry light that casts its gentle grace,..."

Ví dụ cung cấp cho LLM ngữ cảnh, định dạng hoặc phong cách của đầu ra mong muốn. Chúng giúp model hiểu tác vụ cụ thể và tạo câu trả lời chính xác, liên quan hơn.

Chain-of-thought

Chain-of-thought là kỹ thuật rất thú vị: dẫn LLM qua một chuỗi bước. Ý tưởng là chỉ dẫn LLM sao cho nó hiểu cách làm một việc. Xem ví dụ sau, khi chưa có chain-of-thought:

text
- 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 trả lời 5, sai. Đáp án đúng là 1 quả táo, theo phép tính (5 -3 -2 + 1 = 1).

Vậy làm sao dạy LLM làm đúng? Hãy thử chain-of-thought. Áp dụng chain-of-thought nghĩa là:

  1. Đưa cho LLM một ví dụ tương tự.
  2. Trình bày phép tính và cách tính đúng.
  3. Đưa prompt gốc.

Như sau:

text
- 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

Để ý rằng chúng ta viết prompt dài hơn đáng kể, với một ví dụ khác, một phép tính rồi mới tới prompt gốc, và nhận được đáp án đúng là 1. Như bạn thấy, chain-of-thought là kỹ thuật rất mạnh.

Generated knowledge

Nhiều khi bạn muốn dựng prompt bằng dữ liệu của chính công ty mình: một phần prompt lấy từ công ty, phần còn lại là prompt bạn thực sự quan tâm.

Ví dụ, nếu bạn làm trong ngành bảo hiểm, prompt có thể trông như sau:

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

Ở trên, prompt được dựng bằng một mẫu (template). Trong mẫu có các biến, ký hiệu {{variable}}, sẽ được thay bằng giá trị thực từ API của công ty.

Đây là prompt sau khi các biến được thay bằng nội dung của công ty:

text
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

Chạy prompt này qua LLM sẽ cho câu trả lời như sau:

output
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

Như bạn thấy, nó còn gợi ý cả bảo hiểm nhân thọ, điều không nên. Kết quả này cho thấy cần tối ưu prompt, viết rõ hơn những gì được phép. Sau vài lần thử và sai, chúng ta có prompt sau:

text
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

Để ý rằng thêm type và cost, cùng từ khoá restrict, giúp LLM hiểu điều chúng ta muốn. Giờ ta nhận được câu trả lời:

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

Mục đích của ví dụ này là cho thấy dù dùng kỹ thuật cơ bản như generated knowledge, trong đa số trường hợp ta vẫn cần tối ưu prompt để có kết quả mong muốn.

Least-to-most

Ý tưởng của least-to-most là chia một bài toán lớn thành các bài toán con. Nhờ vậy, bạn dẫn LLM cách "chinh phục" bài toán lớn. Một ví dụ tốt là trong khoa học dữ liệu, bạn có thể yêu cầu LLM chia bài toán như sau:

Prompt: How to perform data science in 5 steps?

Trợ lý AI trả lời:

  1. Thu thập dữ liệu
  2. Làm sạch dữ liệu
  3. Phân tích dữ liệu
  4. Vẽ biểu đồ dữ liệu
  5. Trình bày dữ liệu

Self-refine: phê bình kết quả

Với AI tạo sinh và LLM, bạn không thể tin ngay đầu ra. Bạn cần kiểm chứng. Rốt cuộc, LLM chỉ trình bày điều có khả năng cao nhất sẽ được nói tiếp, chứ không phải điều đúng. Vì vậy, một ý hay là yêu cầu LLM tự phê bình, dẫn tới kỹ thuật self-refine.

Cách làm theo các bước:

  1. Prompt ban đầu yêu cầu LLM giải một bài toán
  2. LLM trả lời
  3. Bạn phê bình câu trả lời và yêu cầu AI cải thiện
  4. LLM trả lời lại, lần này có xét tới lời phê bình và đề xuất các giải pháp nó nghĩ ra

Bạn có thể lặp lại quá trình này bao nhiêu lần tuỳ ý. Ví dụ:

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

Câu trả lời của AI:

python
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

Câu trả lời của AI:

text
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'.
python
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()

Như bạn thấy, câu trả lời trên của AI đã cải thiện đoạn code gợi ý đầu tiên nhờ phê bình câu trả lời ban đầu.

Maieutic prompting

Maieutic prompting giống self-refine nhưng thiên về yêu cầu LLM tự giải thích. Mục tiêu là giảm các điểm mâu thuẫn trong đầu ra của LLM để chắc nó đi tới đáp án đúng. Quy trình:

  1. Yêu cầu LLM trả lời một câu hỏi
  2. Với từng phần của câu trả lời, yêu cầu LLM giải thích sâu hơn
  3. Nếu có mâu thuẫn, loại bỏ các phần mâu thuẫn

Lặp lại bước 2 và 3 cho tới khi đi hết các phần và bạn hài lòng với câu trả lời.

Ví dụ:

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

Câu trả lời của LLM:

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

Nó đã đưa ra 5 bước, nhưng làm sao biết có đúng không? Hãy yêu cầu LLM giải thích từng bước:

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

text
The risks are the following:

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

Tới đây, chúng ta muốn chắc LLM đúng nên yêu cầu nó giải thích rủi ro đầu tiên chi tiết hơn, và mong nó nhất quán với câu trả lời trên:

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

text
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?

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

Lúc này LLM nhất quán, nêu "tính mạng" và "kinh doanh" là hai rủi ro lớn nhất. Ta có thể sang bước tiếp theo với sự tự tin tương đối. Tuy nhiên, không nên tin LLM mù quáng; luôn kiểm chứng đầu ra.

Thay đổi đầu ra

Bản chất LLM là không tất định, nghĩa là mỗi lần chạy cùng một prompt bạn sẽ nhận kết quả khác nhau. Thử prompt sau:

"Generate code for a Python Web API"

python
# 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()

Chạy lại cùng prompt cho câu trả lời hơi khác:

python
#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()

Vậy đầu ra thay đổi có phải là vấn đề?

Tuỳ bạn đang muốn làm gì. Nếu bạn cần một câu trả lời cụ thể thì đó là vấn đề. Nếu bạn chấp nhận đầu ra đa dạng, như "Generate any 3 questions on geography", thì không sao.

Dùng temperature để thay đổi đầu ra

Giả sử chúng ta muốn giới hạn đầu ra cho dễ đoán hơn, tức tất định hơn. Làm thế nào?

Temperature là giá trị từ 0 đến 1, trong đó 0 là tất định nhất và 1 là đa dạng nhất. Giá trị mặc định là 0.7. Hãy xem điều gì xảy ra với hai lần chạy cùng prompt khi đặt temperature là 0.1:

"Generate code for a Python Web API"

python
#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()

Chạy lại prompt cho kết quả:

python
#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()

Hai đầu ra chỉ khác nhau rất ít. Lần này hãy làm ngược lại, đặt temperature là 0.9:

python
# 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()

và lần thử thứ hai với temperature 0.9:

python
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

Như bạn thấy, hai kết quả khác nhau hoàn toàn.

Thói quen tốt

Có nhiều cách bạn có thể áp dụng để nhận được điều mình muốn. Bạn sẽ dần tìm ra phong cách riêng khi dùng prompt nhiều hơn. Ngoài các kỹ thuật đã học, đây là một số thói quen tốt khi viết prompt cho LLM:

  • Nêu rõ ngữ cảnh. Ngữ cảnh quan trọng: càng chỉ rõ lĩnh vực, chủ đề… càng tốt.
  • Giới hạn đầu ra. Nếu bạn muốn một số lượng mục hay độ dài cụ thể, hãy nói rõ.
  • Nêu cả "cái gì" lẫn "thế nào". Hãy nói cả điều bạn muốn và cách bạn muốn, ví dụ "Create a Python Web API with routes products and customers, divide it into 3 files".
  • Dùng mẫu. Bạn thường muốn làm giàu prompt bằng dữ liệu của công ty. Hãy dùng mẫu với các biến được thay bằng dữ liệu thật.
  • Viết đúng chính tả. LLM có thể vẫn trả lời đúng, nhưng viết đúng chính tả sẽ cho câu trả lời tốt hơn.

Bài tập

Đây là code Python dựng một API đơn giản bằng Flask:

python
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()

Dùng một trợ lý AI như GitHub Copilot hoặc ChatGPT và áp dụng kỹ thuật "self-refine" để cải thiện đoạn code.

Lời giải tham khảo: aoai-solution.py.

Thử thách

Bạn vừa dùng kỹ thuật self-refine trong bài tập. Hãy lấy một chương trình bất kỳ bạn đã viết và nghĩ xem muốn cải thiện gì. Giờ dùng self-refine để áp dụng các thay đổi đề xuất. Bạn thấy kết quả tốt hơn hay tệ hơn?

Bài tiếp theo: Xây ứng dụng sinh văn bản.

Nguồn