[NB: การติดตามการซื้อคืนนี้โดยใช้ GPT-4 สามารถพบได้ที่นี่]
โมเดลภาษาขนาดใหญ่ (LLMS) เช่น ChatGPT และ Claude ได้แสดงให้เห็นถึงความสามารถในการเขียนโปรแกรมที่น่าประทับใจและมีความสามารถในการแก้ปัญหาในภาษาที่หลากหลายและอนุกรมวิธานของพวกเขา แม้จะประสบความสำเร็จเหล่านี้ แต่ความสงสัยบางอย่างยังคงมีอยู่ในระดับที่แบบจำลองเหล่านี้แสดงให้เห็นถึงความซาบซึ้งในกฎทางวากยสัมพันธ์และกฎการปฏิบัติงานที่อยู่ภายใต้ภาษาเหล่านี้ ( กับ การท่องจำรูปแบบจากข้อมูลการฝึกอบรม)
ในพื้นที่เก็บข้อมูลที่มีวิศวกรรมพร้อมใช้งานนี้ความสามารถในการเขียนโปรแกรมของ ChatGPT ได้รับการสำรวจโดยใช้ภาษาเฉพาะโดเมน (DSL) โดยพลการ DSLs เป็นตัวแทนของสารตั้งต้นที่น่าสนใจสำหรับการศึกษาความสามารถในการอนุมานของ LLM เพราะพวกเขาเป็นนวนิยายและมีโอกาสน้อยที่จะได้พบและจดจำอย่างกว้างขวางในระหว่างการฝึกอบรม 1 ด้วยเหตุนี้พวกเขาจึงเปิดใช้งานการทดสอบโดยตรงมากขึ้นในขอบเขตที่ LLM สามารถอนุมานกฎของภาษาการเขียนโปรแกรมใหม่ใน ลักษณะไม่กี่นัด
ที่นี่ภาษาเฉพาะของโดเมน SIL (ภาษาการรวมสมมาตร) ได้รับการคัดเลือกด้วยเหตุผลสองประการ ประการแรกมันไม่น่าเป็นไปได้อย่างยิ่งที่ CHATGPT ได้สัมผัสกับรหัส SIL ใด ๆ ในระหว่างการฝึกอบรมเนื่องจากเป็น DSL ใน บริษัท ที่พัฒนาโดยกองทุนป้องกันความเสี่ยงที่มีเทคโนโลยีหนักที่เรียกว่า Symmetry Investments ประการที่สองเป็นภาษาการเขียนโปรแกรมมีคุณสมบัติที่น่าสนใจสำหรับแบบจำลองในการทำซ้ำ (เช่นเป็นภาษาที่ใช้งานได้ซึ่งเน้นการแสดงออก แต่ขาดการ let เช่นเดียวกับใน Haskell หรือ OCAML)

หลังจากมีการแจ้งรหัสตัวอย่างแล้ว Chatgpt พยายามเขียนโค้ดในนวนิยาย DSL ที่ใช้งานได้เรียกว่า 'SIL'
ด้านล่างนี้เป็นชุดของพรอมต์ซึ่งประกอบด้วยตัวอย่างสั้น ๆ ของรหัส SIL ซึ่งเน้นการทำงานของมัน หลังจากแจ้งให้ Chatgpt พร้อมงานและให้ตัวอย่างรหัส SIL (ดูรูปด้านล่าง; ตัวอย่างที่รวดเร็วและตัวอย่างรหัส SIL นั้นอยู่ใน repo นี้ด้วย) ฉันขอให้มันใช้งานการเขียนโปรแกรมหลักจำนวนหนึ่งใน SIL
ในส่วนด้านล่างฉันแสดงตัวอย่างสคริปต์รหัส SIL ที่มีการแจ้งเตือนแบบจำลอง (ชุดตัวอย่างเต็มรูปแบบสามารถพบได้ที่นี่) และความพยายามที่จะใช้ปัญหาต่าง ๆ ใน SIL
พรอมต์แรกคือสคริปต์เพื่อจัดการฟังก์ชั่นเซิร์ฟเวอร์เมลบางส่วน ดังนั้นมันจึงแตกต่างอย่างมากจากประเภทของปัญหาฉันจะแจ้งให้ Chatgpt แก้ปัญหา แต่มันแสดงให้เห็นถึงบางส่วนของไวยากรณ์โครงสร้างข้อมูลและแง่มุมการทำงานของ SIL (เช่น |> )
// example of using IMAP IDLE to run rules on new mail
import imap
moveMessages(session,ids,target) => if (ids.length > 0 ) then imap.moveUIDs(session,ids,target) else false
login = imap.ImapLogin(environment( " IMAP_USER " ),environment( " IMAP_PASS " ))
server = imap.ImapServer( " imap.fastmail.com " , " 993 " )
session = imap.Session(server,login, true ,imap.Options(debugMode: true )) | > imap.openConnection | > imap.login
rules=[ [
[ " INBOX/0receipts " ,
[
" FROM [email protected] " ,
" FROM interactivebrokers.com " ,
]],
[ " Junk " ,
[
" FROM Tapatalk " ,
]],
[ " INBOX/newsletters " ,
[
" FROM [email protected] " , " HEADER X-mailer mailgun " , " HEADER X-mailer WPMailSMTP/Mailer/mailgun 2.4.0 " , " HEADER X-mailer nlserver " ,
" FROM hbr.org " , " FROM elliottwave.com " , " OR FROM cio.com FROM cio.co.uk " , " FROM substack.com " , " FROM eaglealpha.com " ,
" FROM haaretz.com " , " FROM gavekal.com " , " FROM go.weka.io " , " FROM marketing.weka.io " , ` HEADER list-unsubscribe "" ` ,
` HEADER list-Id "" ` , ` HEADER list-Post "" ` , ` HEADER list-owner"" ` , ` HEADER Precedence bulk ` , ` HEADER Precedence list ` ,
` HEADER list-bounces "" ` , ` HEADER list-help "" ` , ` HEADER List-Unsubscribe "" ` , " FROM no-reply " ,
]],
[ " INBOX/notifications " ,
[
` KEYWORD "$IsNotification" ` , " FROM [email protected] " , " FROM [email protected] " , " FROM skillcast.com " ,
" FROM reedmac.co.uk " , " FROM [email protected] " , " FROM [email protected] " , " FROM [email protected] " ,
]],
]
runRules(Session,Rules) => Rules
| > map(target => [target[ 0 ],(target[ 1 ] | > map(term => imap.search(Session,term).ids))])
| > mapa(set => moveMessages(Session,set[ 1 ] | > join,set[ 0 ]))
runRulesBox(Session,Rules,Mailbox) => {
imap.select(Session,Mailbox)
in runRules (Session,Rules)
}
inboxes=[ " INBOX " ]
result = inboxes | > mapa(inbox => runRulesBox(session,rules,imap.Mailbox(session,inbox)))
print(result)
import parallel;
threadFunction(x) => {
imap.idle(session)
in inboxes | > mapa(inbox => runRulesBox(session,rules,imap.Mailbox(session,inbox)))
}
parallel.runEvents((x) => false ,[threadFunction]) ตัวอย่างรหัสที่สองพร้อมที่จะเน้นคุณสมบัติบางอย่างของ DSL นี้สำหรับรุ่นและแนะนำฟังก์ชั่นไลบรารีมาตรฐานใหม่เช่น iota และ fold
import imap
import imap_config
import string
// Get the configuration from the environment and command line.
config = imap_config.getConfig(commandLineArguments)
// -------------------------------------------------------------------------------------------------
// Some helper functions.
//
// Firstly, a function to join an array of strings.
joinFields(flds, sep) => {
len(flds) > 0 | > enforce( " Cannot join an empty array. " )
in fold (flds[ 1 :$], (str, fld) => str ~ sep ~ fld, flds[ 0 ])
}
// Secondly, a field formatter which strips the field prefix and pads to a fixed width.
// E.g., ("From: [email protected]" |> fmtField(20)) == "[email protected] "
fmtField(field, width) => {
pad(str) => iota(width - len(str)) | > fold((a, i) => a ~ " " , str)
in field
| > string .split( " : " )[ 1 :$]
| > joinFields( " : " )
| > pad
}
// And thirdly, a function which concatenates the headers into a formatted string.
fmtHeaders(outStr, headers) => {
outStr ~ " " ~ joinFields(headers, " | " ) ~ " n "
}
// -------------------------------------------------------------------------------------------------
// Connect to the inbox.
creds = imap.ImapLogin(config.user, config.pass)
server = imap.ImapServer(config.host, config.port)
session =
imap.Session(server, creds)
| > imap.openConnection()
| > imap.login()
inbox = imap.Mailbox(session, " INBOX " )
// Get the number of messages in the inbox.
msgCount = imap.status(session, inbox).messages
// Select the default inbox.
inbox | > imap.examine(session, _)
// Get the headers (date, from and subject) for each message, from oldest to newest, format and
// print them.
headers =
iota(msgCount)
| > map(id => " # " ~ toString(id + 1 ))
| > map(id =>
imap.fetchFields(session, id, " date from subject " ).lines
| > map(hdr => fmtField(hdr, 40 )))
| > fold(fmtHeaders, " INBOX: n " )
print(headers)ตัวอย่างโค้ดที่สามแสดงให้เห็นถึงคุณสมบัติที่ผิดปกติของ DSL นี้โดยมีจุดประสงค์ที่ ChatGPT จะใช้สิ่งเหล่านี้ในการใช้งานของตัวเองต่อไป
// This script will search for emails and match new issue numbers with resolutions to report the
// number of outstanding alerts.
import imap
import * from imap.query
import imap_config
import dates
import string
// Get the configuration from the environment and command line.
config = imap_config.getConfig(commandLineArguments)
// Connect to the inbox.
creds = imap.ImapLogin(config.user, config.pass)
server = imap.ImapServer(config.host, config.port)
session =
imap.Session(server, creds)
| > imap.openConnection()
| > imap.login()
inbox = imap.Mailbox(session, " support " )
// Select the default inbox.
inbox | > imap.examine(session, _)
// These criteria are common for both our searches.
commonCrit = imap.Query()
| > and(from( ` [email protected] ` ))
| > and(sentSince(dates. Date ( 2020 , 5 , 13 )))
// Get each of the alerts and resolutions from the past week (13-19 May 2020).
alertMsgIds =
imap.search(session, imap.Query(subject( " Alert: new issue " )) | > and(commonCrit)).ids
resolutionMsgIds =
imap.search(session, imap.Query(subject( " Resolution: issue " )) | > and(commonCrit)).ids
// A function to get the alert ID from a message subject.
getAlertId(msgId) => {
imap.fetchFields(session, toString (msgId), " subject " ).lines[ 0 ]
| > string .split()[$ - 1 ]
}
// A function to remove an entry from a table whether it's there or not.
removeIfExists(tbl, key) => {
if find( keys (tbl), key) == [] then
tbl
else
removeEntry(tbl, key)
}
// Now find those alerts which have no resolution. Firstly the subject for each alert, get the
// issue number end and store it in a table.
allAlertTable = alertMsgIds | > fold((tbl, msgId) => addEntry(tbl, getAlertId(msgId), msgId), {})
// Go through the resolutions and remove their corresponding alerts from the table.
unresolvedAlertTable =
resolutionMsgIds | > fold((tbl, msgId) => removeIfExists(tbl, getAlertId(msgId)), allAlertTable)
// Create a report with the date of the unresolved alerts.
report =
keys (unresolvedAlertTable)
| > map(alertId => {
msgId = unresolvedAlertTable[alertId] | > toString
in [ alertId
, imap.fetchFields(session, msgId, " date " ).lines[ 0 ]
, imap.fetchText(session, msgId).lines[ 0 ]
]
})
| > fold((outStr, tuple) => {
outStr ~ " Issue: " ~ tuple[ 0 ] ~ " n " ~ tuple[ 1 ] ~ " n Summary: " ~ tuple[ 2 ] ~ " n "
}, " n UNRESOLVED ISSUES FROM THE PAST 10 DAYS: nn " )
// Close the session.
imap.closeConnection(session)
// Print the report last.
print(report) ในการออกกำลังกายครั้งแรกฉันขอให้โมเดลใช้ฐานข้อมูลเชิงสัมพันธ์ที่ง่ายมากใน SIL ด้วยฟังก์ชันพื้นฐานเช่นการเปรียบเทียบและการพิมพ์ความแตกต่างระหว่างสองโครงสร้างข้อมูล (โปรดทราบว่า // หมายถึงการแสดงความคิดเห็นใน SIL)
// Here, ChatGPT was prompted to write a a very simple, schematic relational database in SIL
// This prompt proved too general, perhaps, and after requesting further information, I prompted the model to generate a simple, schematic database with functionalities such as "compare" and "diff" for two or more tables
users = [ { " id " : 1 , " name " : " John Doe " , " email " : " [email protected] " }, { " id " : 2 , " name " : " Jane Smith " , " email " : " [email protected] " }, { " id " : 3 , " name " : " Bob Johnson " , " email " : " [email protected] " },]
orders = [ { " id " : 1 , " user_id " : 1 , " product " : " Widget " , " quantity " : 2 , " price " : 19.99 }, { " id " : 2 , " user_id " : 2 , " product " : " Gadget " , " quantity " : 1 , " price " : 29.99 }, { " id " : 3 , " user_id " : 3 , " product " : " Thingamajig " , " quantity " : 3 , " price " : 39.99 },]
// Compare two tables
compareTables(table1, table2) => {
table1 == table2
}
// Diff two tables
diffTables(table1, table2) => {
table1.filter(i => ! table2.includes(i))
}
print(compareTables(users, users)) // true
print(diffTables(users, orders)) // [{"id": 1, "name": "John Doe", "email": "[email protected]"}]การใช้อัลกอริทึมการเรียงลำดับเป็นคำถามสัมภาษณ์วิศวกรรมซอฟต์แวร์แบบดั้งเดิม ที่นี่ฉันขอให้ Chatgpt ใช้ Bubblesort (แนวคิดอัลกอริทึมการเรียงลำดับขั้นพื้นฐานที่สุด) ใน SIL ด้านล่างคือการตอบสนอง:
bubbleSort(arr) => {
for i in 1 ... len(arr) {
for j in 1 ... len(arr) - i {
if (arr[j] > arr[j + 1 ]) {
temp = arr[j]
arr[j] = arr[j + 1 ]
arr[j + 1 ] = temp
}
}
}
arr
}
arr = [ 4 , 6 , 1 , 3 , 5 , 2 ]
print(bubbleSort(arr)) แม้ว่าสคริปต์นี้จะเป็นจริงการใช้งานของ Bubblesort แต่โมเดลนั้นก็เพิกเฉยต่อแง่มุม การทำงาน ของ SIL อย่างกว้างขวาง ตัวอย่างเช่นการใช้ bubblesort นี้โดยใช้ for ลูปแทนการเรียกซ้ำ
ต่อไปฉันแจ้งให้แบบจำลองเขียนสคริปต์สำหรับการคำนวณค่ามัธยฐานของรายการ (การตอบกลับที่สร้างขึ้นด้านล่าง) นี่อาจเป็นหนึ่งในคำตอบที่น่าพอใจน้อยที่สุด ประการแรกแม้จะมีคำสั่ง if/else ที่มีอยู่ในตัวอย่าง SIL Code ที่ฉันแจ้งให้โมเดลทราบว่าไวยากรณ์ในรหัสที่สร้างขึ้นนี้ไม่ถูกต้อง ประการที่สอง CHATGPT ภาพหลอน (หรือสันนิษฐาน) การปรากฏตัวของโมดูลที่เรียกว่า math และ sort ฟังก์ชั่น buil-in (สิ่งเหล่านี้เป็นสมมติฐานที่สมเหตุสมผล แต่มันลดความซับซ้อนของปัญหาที่ได้รับแจ้งอย่างมาก)
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
import math
// Function to compute the median of a list of integers
median(numbers) => {
// Sort the list of numbers
sortedNumbers = sort(numbers)
// Get the middle index of the sorted list
middleIndex = math.floor(len(sortedNumbers) / 2 )
// If the list has an odd number of elements, return the middle element
if len(sortedNumbers) % 2 == 1 :
return sortedNumbers[middleIndex]
// Otherwise, return the average of the two middle elements
else :
return (sortedNumbers[middleIndex - 1 ] + sortedNumbers[middleIndex]) / 2
}
Chatgpt ได้รับแจ้งต่อไปให้ใช้อัลกอริทึมเพื่อนบ้าน K -earest ใน Sil นี่เป็นผลลัพธ์ของการแจ้งเตือนสองครั้ง (ตามที่อธิบายไว้ในบล็อกรหัสที่สร้างขึ้นด้านล่าง) เนื่องจากโมเดลยาหลั่งไหล/สมมติว่าโมดูลที่เรียกว่า distances ในการพยายามครั้งแรก ในความพยายามครั้งที่สองฉันขอให้มันใช้อัลกอริทึมโดยไม่สมมติว่ามีอยู่ของโมดูลนี้
การแสดงของ CHATGPT ที่นี่ผสมกัน ประการแรกในบางกรณีมันจะไม่สนใจด้านการทำงานของ SIL (เช่นการใช้งาน for การวน let ในความพยายามครั้งแรกในส่วนอื่น ๆ ของการใช้งานอย่างไรก็ตามมันก็ชื่นชมว่า SIL นั้น |> งานได้และใช้ตัวดำเนินการของ map อย่างถูกต้อง
// Note that this is the fusion of two separate scripts generated by ChatGPT to solve the k-nearest neighbours algorithm, as described in the comments below
// Overall, these attempts seem reasonable, but it does appear to hallucinate "let" bindings which do not feature in the example code with which it was prompted. This is likely due to conflating the functionality of SIL code with OCaml or F#
// Attempt 1:
// This is the first ChatGPT attempt when prompted to generate a script for the k-nearest neighbours algorithm
// In this case, it assumes (or hallucinates) a library called "distances"
import distances
// Define a point as a tuple of x and y coordinates
type Point = (num, num)
// Find the distance between two points
distance(p1: Point, p2: Point) => {
let xDistance = p1[ 0 ] - p2[ 0 ]
let yDistance = p1[ 1 ] - p2[ 1 ]
in sqrt (xDistance * xDistance + yDistance * yDistance)
}
// Find the k nearest points to a given point
kNearest(point: Point, points: [Point], k: num) => {
// Compute the distances between the given point and all other points
let distances = points | > map(p => (p, distance(point, p)))
// Sort the points by distance
distances = distances | > sort((d1, d2) => d1[ 1 ] < d2[ 1 ])
// Return the k closest points
in distances[:k] | > map(d => d[ 0 ])
}
// Attempt 2:
// Next, ChatGPT is prompted to generate a script without importing the questionable "distances" library
// Again, it assumes some in-built functions, such as "sort" or "sqrt"
// Function to calculate the distance between two points
distance(p1, p2) => {
sum = 0
for i in 0 .. len(p1) - 1 {
sum = sum + (p1[i] - p2[i]) ^ 2
}
sqrt(sum)
}
// Function to find the k nearest neighbors
k_nearest_neighbors(data, point, k) => {
distances = data | > map(p => (p, distance(p, point)))
distances | > sort((a, b) => a[ 1 ] < b[ 1 ]) | > take(k) | > map(p => p[ 0 ])
}
หนึ่งในคุณสมบัติที่น่าสนใจของภาษาที่ใช้งานได้คือพวกเขาสามารถแสดงออกได้สูง ที่นี่ฉันแจ้งให้ ChatGPT ใช้ map ตัวดำเนินการฟังก์ชั่นพื้นฐาน filter และ reduce (หรือ fold ในบริบทของภาษาที่ใช้งานได้) สำหรับสองสามกรณีแรกโมเดลดูเหมือนจะสูญเสียการติดตามด้านการทำงานของ SIL แต่สามารถนำรหัสใหม่มาใช้ในลักษณะการทำงานได้มากขึ้นเมื่อได้รับแจ้ง
// map
map(fn, list) => {
result = []
for i in list {
result.append(fn(i))
}
return result
}
// filter
filter(fn, list) => {
result = []
for i in list {
if (fn(i)) {
result.append(i)
}
}
return result
}
// reduce
reduce(fn, list, initial) => {
result = initial
for i in list {
result = fn(result, i)
}
return result
}
// reduce (prompted to use functional operators such as pipe |>, in addition to the 'map' and 'filter' functions defined previously)
reduce(fn, list, initial) =>
list | >
filter(fn, _, initial) =>
map(fn, _, initial) =>
initialProject Euler เป็นชุดของปัญหาทางคณิตศาสตร์และการเขียนโปรแกรม (ซึ่งฉันคิดว่าทำพรอมต์ที่น่าสนใจสำหรับ LLMs) ที่นี่ฉันแจ้งให้ Chatgpt แก้ปัญหาออยเลอร์สองโครงการแรกโดยใช้ SIL เมื่อมาถึงจุดนี้ตัวแทนของ Chatgpt ค่อนข้างจะลดลงบ้าง โซลูชั่นเหล่านี้ไม่มีความคล้ายคลึงกับฟังก์ชั่นระดับสูงของ SIL หรือไวยากรณ์ exaxCT มันอาจจะน่าสนใจที่จะให้ตัวอย่างรหัส SIL เพิ่มเติม ณ จุดนี้จากนั้นนำเสนอโมเดลใหม่เพื่อแก้ปัญหาเหล่านี้
// Project Euler problem #1:
// Here, my prompt was to solve the (easy) first problem of the Project Euler series (https://projecteuler.net/problem=1)
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
result = 0
for i in 1 ... 1000 {
if (i % 3 == 0 || i % 5 == 0 ) {
result += i
}
}
print(result) // Project Euler problem #2:
// This prompt is to solve the second Project Euler problem (https://projecteuler.net/problem=2)
// The solution proposed by ChatGPT is sensible, but potentially inefficient, and ignores the recursion of functional languages
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
result = 0
fib(n) => {
if (n <= 1 ) {
return n
}
return fib (n - 1 ) + fib(n - 2 )
}
for i in 1 ... 100 {
val = fib(i)
if (val > 4000000 ) {
break
}
if (val % 2 == 0 ) {
result += val
}
}
print(result)
การสำรวจความสามารถของ LLMs ในการอนุมานและเข้าใจคุณสมบัติของภาษาการเขียนโปรแกรมใหม่ในลักษณะ ไม่กี่นัด ยังคงเป็นคำถามที่เปิดกว้างและน่าสนใจ ที่นี่ความสามารถเหล่านี้ได้รับการสำรวจในบริบทของการกระตุ้นให้ Chatgpt เพื่อแก้ปัญหาที่ได้รับแจ้งในภาษาเฉพาะโดเมน (DSL) ที่เรียกว่า SIL DSLs เป็นกรณีทดสอบที่มีประโยชน์สำหรับการสำรวจ การอนุมาน เทียบกับ การจดจำ ใน LLM เนื่องจากพวกเขามักจะมีคุณสมบัติที่โดดเด่นและมีโอกาสน้อยที่จะพบอย่างกว้างขวางในระหว่างการฝึกอบรม (ถ้าเลย)
โดยรวมแล้วประสิทธิภาพมีการผสม: ChatGPT เข้าใจอย่างถูกต้องว่า DSL นี้เป็นภาษาการเขียนโปรแกรมที่ใช้งานได้ (แม้ว่าบางครั้งจะต้องมีการแนะนำสิ่งนี้อีกครั้ง) และนำโซลูชันมาใช้ตามนั้น อย่างไรก็ตามมันล้มเหลวอย่างกว้างขวางในการจับกฎวากยสัมพันธ์ของ DSL นี้จากสคริปต์ตัวอย่างห้ารายการที่มีให้ การตรวจสอบเพิ่มเติม (เช่นการใช้ DSL อื่น ๆ การพัฒนาตัวชี้วัดที่เป็นทางการมากขึ้นสำหรับการประเมินรหัส LLM ที่สร้างขึ้นหรือการหาปริมาณการเรียนรู้ของแบบจำลอง) จะทำให้การขยายที่น่าสนใจของ repo นี้ ในที่สุดในเซสชัน chatgpt แยกต่างหากฉันได้จัดทำ meta-prompt นี้เพื่อพิจารณาว่าโมเดลตีความรหัส SIL ของตัวเองอย่างไร:

Chatgpt ตรวจสอบความพยายามของตนเองในการเขียนโค้ดในภาษาเฉพาะของโดเมน SIL และอธิบายคุณสมบัติบางอย่าง
มีหลักฐานว่าการจดจำ LLM ได้รับการส่งเสริมโดยความถี่ของการนำเสนอตัวอย่างการฝึกอบรมและจำนวนโทเค็นที่เกี่ยวข้องที่ใช้ในการกระตุ้นแบบจำลอง