เรียนรู้ AI วันแรก กับ OpenAI API ด้วย JavaScript

สวัสดีครับ บทความนี้จะเป็นการบันทึกการเรียนรู้ AI ของผมเอง เอาจริงๆ เนื้อหาก็จะผสมๆกันไป เน้นเรียนรู้ ลงมือทำ และทดลองไปเรื่อยๆ
ก่อนหน้านี้ผมก็ได้ลองเล่น AI มาบ้างแล้ว แต่ส่วนใหญ่ก็จะเป็นการใช้ผ่านหน้าเว็บ เช่น ChatGPT, Claude หรือ Gemini เท่านั้น แบบใช้แค่ Prompt จริงๆ ยังไม่เคยได้ลองเอามาต่อ API เลย
ก็เลยนึกไอเดียขึ้นมาได้ว่า น่าจะลองทำเป็นบล็อกบันทึกการเรียนรู้ AI ของตัวเองดู จดบันทึกการเรียนรู้ของตัวเองเป็น TIL (Today I Learned) และอาจจะมีประโยชน์กับคนอื่นๆ ที่สนใจ AI ด้วย
Getting Started
เริ่มต้น ก็ต้องลองใช้ OpenAI ผ่าน API กันก่อนเลย โดยผมใช้เป็น JavaScript/TypeScript นะครับ โดนใช้ Runtime Node.js/Bun ก็ได้ เนื่องจากว่า ถนัดและเข้ามือมากกว่า Python ครับ
import OpenAI from 'openai'const client = new OpenAI()
const response = await client.responses.create({ model: 'gpt-4.1-nano', input: 'Write a one-sentence bedtime story about a unicorn.'})
console.log(response.output_text)
Dependency ที่ต้องติดตั้ง
npm install openai
ทดลอง นำโค๊ดจากตัวอย่างเว็บ OpenAI มาลองรันดู (เปลี่ยนแค่ model เป็น gpt-4.1-nano) เผื่อเสียเงิน จะได้ประหยัดค่าใช้จ่ายครับ 🤣
ซึ่ง การต่อ API เราจำเป็นต้องมี API Key ก่อน โดยสามารถเข้าไปที่ OpenAI API เพื่อสร้าง API Key ได้เลยครับ (ไม่แน่ใจว่ามี Trial ให้ใช้ฟรี หรือต้องเติม Credit เข้าไปก่อนนะครับ)
export OPENAI_API_KEY=sk-...
หรือถ้าใช้ Bun ก็สามารถใช้ Environment Variable ได้เลย เวลารัน คำสั่ง ก็ใส่ -e
เข้าไปด้วย
bun run -e OPENAI_API_KEY=sk-...
หรือถ้าใช้ Node.js ก็สามารถใช้ dotenv ได้เช่นกัน
npm install dotenv
ในโค๊ดก็ให้เพิ่มบรรทัดนี้เข้าไปก่อน
import dotenv from 'dotenv'dotenv.config()
ผลลัพธ์ที่ได้จากการรันโค๊ดด้านบน จะได้เป็น
Once upon a time, a gentle unicorn who loved to paint stars in the night sky drifted peacefully into a dream-filled sleep beneath the glowing moon.
Prompt Engineering
Prompt Engineering คือกระบวนการสร้างและปรับแต่งคำสั่ง (prompt) ที่จะป้อนให้กับโมเดล AI เพื่อให้ได้ผลลัพธ์ที่ต้องการมากที่สุด ถ้าเคยเล่น Midjourney จะเห็นว่า ยิ่งเราอธิบาย Prompt ให้ชัดเจนมากเท่าไหร่ โมเดลก็จะสามารถสร้างภาพที่ตรงตามความต้องการได้มากขึ้น
ตัวอย่าง สมมติ เรา ใช้ Prompt ทั่วๆไปว่า
เขียนโค๊ดปุ่ม button ด้วย React
ทีนี้ ถ้าเป็น Prompt Engineering เราอาจจะต้องปรับแต่งให้มันมีความเฉพาะเจาะจงมากขึ้น เช่น
ช่วยเขียนโค๊ดปุ่ม button ด้วย React โดยใช้ Tailwind CSS มีพื้นหลังสี green-500 และเมื่อ hover จะเปลี่ยนเป็นสี green-700
สังเกตได้ว่า ยิ่งเราระบุรายละเอียดมากเท่าไหร่ โมเดลก็จะเข้าใจได้มากขึ้นเท่านั้น Prompt Engineering จึงเป็นทักษะที่สำคัญมากในการทำงานกับ AI
References อ่านเพิ่มเติม เกี่ยวกับ Prompt Engineering

Instruction
Instruction คือการให้คำสั่งหรือคำแนะนำเพิ่มเติมกับโมเดล AI เพื่อให้มันทำงานตามที่เราต้องการ ช่วยให้ model เข้าใจว่าควรทำอะไร อย่างไร ทำให้คำสั่งมีความชัดเจน เฉพาะเจาะจงมากขึ้น
ตัวอย่างการใช้ instruction โดยใช้ parameter instructions
โดยผมส่ง instruction บอก AI ว่าให้ตอบเป็นภาษาไทย (จริงๆ ตัว instruction นี้ ก็คล้ายๆ กับเรา input ภาษาไทยไปใน prompt เลย และ model ก็จะเข้าใจว่าเราต้องการให้มันตอบเป็นภาษาไทย)
const response = await client.responses.create({ model: 'gpt-4.1-nano', input: 'Are semicolons optional in JavaScript?', instructions: 'ตอบเป็นภาษาไทย'})console.log(response.output_text)
ผลลัพธ์
ใน JavaScript, เซมิโคลอน (semicolon) เป็นเครื่องหมายที่ใช้ในการบอกจุดสิ้นสุดของคำสั่ง (statement) โดยปกติแล้ว JavaScript จะมีการทำงานแบบ "automatic semicolon insertion" (ASI) ซึ่งหมายความว่า ถ้าคุณไม่เขียนเซมิโคลอนในตอนจบคำสั่ง JavaScript ก็จะพยายามแทรกเซมิโคลอนให้โดยอัตโนมัติในบางกรณี
อย่างไรก็ตาม การละเว้นเซมิโคลอนอาจทำให้เกิดความเข้าใจผิดหรือบั๊กที่คาดไม่ถึงได้ โดยเฉพาะในกรณีที่คำสั่งต่อไปนี้เริ่มต้นด้วยบรรทัดใหม่ที่อาจถูกตีความผิดว่าเป็นการต่อคำสั่งเดียวกัน
ตัวอย่างเช่น:
```javascriptfunction foo() { return { a: 1 };}```
ในตัวอย่างนี้ เนื่องจากไม่มีเซมิโคลอนหลัง `return` และบรรทัดใหม่ที่ตามมามีการขึ้นบรรทัดใหม่ ก็จะกลายเป็นว่า `return` กลับว่างเปล่า (คืนค่า `undefined`) โดยไม่คืนอ็อบเจกต์ตามที่คาดหวัง
**สรุป:**- ในทางเทคนิค JavaScript อนุญาตให้ละเว้นเซมิโคลอนในบางกรณีด้วยกลไก ASI- แต่ในทางปฏิบัติ ควรเขียนเซมิโคลอนให้ครบเพื่อความชัดเจน ลดความผิดพลาด และเพิ่มความเข้าใจง่าย
**คำแนะนำ:**- ใช้เซมิโคลอนเสมอเมื่อเขียนคำสั่งใหม่- หรือใช้เครื่องมือ linting เช่น ESLint ที่สามารถบังคับให้เขียนเซมิโคลอนตามแนวทางที่ดีที่สุด
กำหนดแบบ Prompt instruction file
สร้างไฟล์ prompt.txt
ขึ้นมา โดยใส่คำสั่งที่เราต้องการให้ AI ทำงาน เช่น
# Identity
คุณเป็นผู้ช่วยสอนเขียนโปรแกรม JavaScript และ TypeScript
# Instructions
- อธิบายสั้นๆ กระชับ เน้นเข้าใจง่าย- ไม่ต้องใส่ comment ในโค๊ด- prefer ไม่ต้องใช้ semicolon และ string เป็น single quote- ตัวอย่างเป็น TypeScript
แล้วในโค๊ดให้เราอ่านไฟล์นี้เข้าไป
import fs from 'fs/promises'import path from 'path'import { fileURLToPath } from 'url'const __filename = fileURLToPath(import.meta.url)const __dirname = path.dirname(__filename)const promptFilePath = path.join(__dirname, 'prompt.txt')
const instructions = await fs.readFile(promptFilePath, 'utf-8')
const response = await client.responses.create({ model: 'gpt-4.1-nano', instructions, input: 'อธิบายเกี่ยวกับ async/await ใน JavaScript และแสดงตัวอย่างประกอบ'})console.log(response.output_text)
ผลลัพธ์ที่ได้จากการให้ AI สอนเกี่ยวกับ async/await
`async/await` เป็นแนวทางในการเขียนโค้ด asynchronous ให้อ่านง่ายขึ้น โดยใช้คำสั่ง `async` เพื่อประกาศฟังก์ชันเป็นแบบ asynchronous และใช้ `await` เพื่อรอผลลัพธ์จาก Promise จนกว่าจะเสร็จ
ตัวอย่าง:
```typescriptfunction fetchData(): Promise<string> { return new Promise(resolve => { setTimeout(() => resolve('Data fetched'), 2000) })}
async function getData() { console.log('Start fetching') const data = await fetchData() console.log(data) console.log('Done')}
getData()```
ในตัวอย่างนี้ ฟังก์ชัน `getData` เป็นแบบ async และใช้ `await` เพื่อรอผลจาก `fetchData` ซึ่งเป็น Promise หลังจากนั้น โค้ดจะดำเนินต่อเมื่อ Promise เสร็จแล้ว ทำให้เขียนโค้ด asynchronous ได้เหมือนเขียน synchronous ง่ายขึ้น
ตัวอย่าง prompt เดียวกัน แต่เปลี่ยน model เป็น gpt-4.1
ได้แบบนี้
**async/await** ใช้สำหรับจัดการ asynchronous code ให้อ่านง่ายเหมือน synchronous code- async ใส่หน้าฟังก์ชันให้ return เป็น Promise- await ใช้รอผลลัพธ์จาก Promise ก่อนจะดำเนินการต่อ
ตัวอย่าง TypeScript
```typescriptconst fetchData = async (): Promise<string> => { return 'data loaded'}
const main = async () => { const result = await fetchData() console.log(result)}
main()```
ผลลัพธ์:data loaded
ลองเปรีบบเทียบกันดูระหว่าง 2 model gpt-4.1-nano
กับ gpt-4.1
ว่าชอบคำตอบแบบไหนมากกว่ากัน?
ตัวอย่าง Prompt อื่นๆ
Generate Image
ต่อมา ลองสร้าง image จาก prompt กันบ้าง โดยใช้ model gpt-image-1
ซึ่งเป็น model ที่ใช้สำหรับสร้างภาพจาก prompt
gpt-image-1
ทดลองสร้าง image จาก prompt โดยใช้โค๊ดตัวอย่างจาก OpenAI แบบนี้
import OpenAI from 'openai'import fs from 'fs'const openai = new OpenAI()
const prompt = `A children's book drawing of a veterinarian using a stethoscope tolisten to the heartbeat of a baby otter.`
const result = await openai.images.generate({ model: 'gpt-image-1', prompt})
// Save the image to a fileconst image_base64 = result.data[0].b64_jsonconst image_bytes = Buffer.from(image_base64, 'base64')fs.writeFileSync('otter.png', image_bytes)
แน่นอน ผลลัพธ์ ได้รูปแบบเดียวกันกับตัวอย่าง ในเว็บ OpenAI
สุดท้าย ก็ลองปรับ prompt นิดหน่อย ให้มัน gen image ทำ cover image ให้กับบทความนี้ด้วยเลย จำ prompt เปะๆ ไม่ได้นะครับ แต่ประมาณนี้แหละ
"A children's book drawing of a baby programmer using a notebook to learn AI, with a fluffy baby snow fox sitting nearby"
สรุป
แม้ว่าวันนี้ได้แค่ลองเล่น API ที่อ่านจากตัวอย่างในเว็บ OpenAI แต่ก็ถือว่าเป็นการเริ่มต้นที่ดี ได้ทดลอง call API ปรับ prompt เอง (จริงๆ ตอนนี้ผมใช้หลักๆ คือ Gemini และก็มี Gem Manager) ว่าจะก็อปมาใส่ prompt กลัวว่า input มันจะเยอะไป คิดว่า ใครที่เป็น User ที่ใช้ AI ปกติอยู่แล้ว ก็น่าจะเข้าใจการใช้งานผ่าน API ได้ไม่ยากครับ
สุดท้าย Source Code ที่ใช้ในบทความนี้ สามารถดูได้ทีนี่ (จะพยายามอัพเดทและรวมเป็น repo เดียวกัน)
Happy Coding ❤️
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust