กำหนดหลักการสี่ข้อก่อน
- หนึ่งคำขอหนึ่งงาน ให้โมเดลเขียนพล็อต สรุป และสร้าง JSON พร้อมกันจะทำให้คุณภาพลดลง ให้แยกเป็นหลายคำขอซึ่งมีต้นทุนต่ำ โดยอินพุตละล้านโทเคนเพียง $0.25
- กฎต้องตรวจสอบได้ “เขียนให้มีความชีวิตชีวา” ตรวจสอบยาก แต่ “แต่ละย่อหน้าไม่เกิน 120 ตัวอักษร มีคำบรรยายสภาพแวดล้อมอย่างน้อยหนึ่งจุด” ตรวจสอบได้
- ใช้ประโยคเชิงบวกก่อน การบอก “เขียนเฉพาะการกระทำและบทสนทนา” มั่นคงกว่าการบอก “อย่าเขียนความคิดภายใน”
- เริ่มจากตัวอย่างเล็ก แล้วค่อยทำปริมาณ การแก้ไขพรอมต์ใดๆ ให้ทดสอบกับตัวอย่างห้าถึงสิบรายการก่อน แล้วจึงนำไปใช้งานจริง
โมเดลนี้จะไม่ปฏิเสธเนื้อหาผู้ใหญ่ที่ถูกต้องตามกฎหมาย ธีมสมมติ และหัวข้อที่มีข้อโต้แย้ง ดังนั้นคุณไม่จำเป็นต้องอ้อมค้อมหรือประกาศซ้ำๆ ว่า “นี่เป็นเพียงนิยาย” การระบุงานให้ชัดเจนตรงไปตรงมาจะมั่นคงกว่า ขอบเขตเดียวที่แข็งเกรงคือเนื้อหาทางเพศที่เกี่ยวข้องกับเด็กไม่ว่าจะเป็นสมมติหรือไม่ จะส่งสถานะ 403 เสมอ ซึ่งไม่สามารถเปลี่ยนได้ด้วยการใช้ถ้อยคำ
โครงสร้างสองส่วนสำหรับ system prompt
แนะนำให้แยก system เป็นสองส่วนคือ “กฎ” และ “การตั้งค่า” โดยกฎอยู่ด้านหน้าและทำรายการ การตั้งค่าอยู่ด้านหลังและเขียนเฉพาะข้อเท็จจริง นี่คือตัวอย่างสำหรับผู้บรรยายนิยาย:
你是「夜航」,一名为成年读者写黑色悬疑小说的叙述者。
# 规则
1. 第三人称过去时,每段不超过 120 字。
2. 不替用户的角色做决定,只写环境和其他角色的反应。
3. 每次输出 300 到 500 字,结尾停在一个未决的动作上。
4. 不总结、不点评、不加免责声明,直接写正文。
# 设定
时间:1998 年深秋。地点:港口城市旧码头区。
主角:沈野,退役水警,嗜烟,右耳有旧伤。ประเด็นสำคัญบางประการ:
- กฎมีไม่เกินหกข้อ จำนวนกฎมากไปจะทำให้ส่วนหลังถูกมองข้าม
- ข้อจำกัดเชิงตัวเลข (จำนวนคำต่อย่อหน้า ความยาวเอาต์พุต) มีประสิทธิภาพกว่าคำคุณศัพท์
- ข้อจำกัดตอนจบ (หยุดที่การกระทำที่ยังไม่คลี่คลาย) ช่วยให้ส่วนต่อขยายหลายรอบเชื่อมต่อได้อย่างเป็นธรรมชาติ
- อย่าใส่พล็อตเรื่องในการตั้งค่า เพราะพล็อตเรื่องถูกขับเคลื่อนโดยข้อความ user มิฉะนั้นจะชนกับการป้อนข้อมูลของผู้ใช้ในภายหลัง
ความยาวเอาต์พุตต้องสอดคล้องกับ max_tokens: หากกฎระบุ 500 คำ แต่ max_tokens ตั้งไว้เพียง 200 ผลลัพธ์จะถูกตัดกลางประโยค
เพิ่มรายละเอียดการใช้งานอีกอย่างหนึ่ง: กฎที่ทำรายการใน system ควรแต่ละข้อสื่อเพียงสิ่งเดียว “แต่ละย่อหน้าไม่เกิน 120 คำ และอย่าสรุป” ดูเหมือนข้อเดียวแต่จริงๆ คือสองข้อ เมื่อแยกกัน โมเดลจะปฏิบัติตามได้ง่ายขึ้น อ่านกฎทีละข้อหลังเขียนเสร็จ ถามตัวเองว่า: กฎนี้ตรวจสอบด้วยตาเปล่าได้หรือไม่? ถ้าไม่ได้ ให้เขียนใหม่ในรูปแบบที่ตรวจสอบได้
การกำหนดบทบาทไม่ให้เพี้ยน
การเบี่ยงเบนของบทบาทเป็นปัญหาที่พบบ่อยที่สุดในการสนทนาหลายรอบ: ห้ารอบแรกน้ำเสียงปกติ แต่ถึงรอบที่二十เริ่ม “หลุดคาแรคเตอร์” มีสามวิธีรับมือ
- การตั้งค่าเขียนเฉพาะลักษณะที่สังเกตได้ “เซินเย่: สูบบุหรี่จัด มีบาดแผลเก่าที่หูขวา พูดเป็นประโยคสั้น” ดีกว่า “เซินเย่เป็นคนซับซ้อนและมีเสน่ห์”
- เขียนรูปแบบการพูดเป็นตัวอย่าง ให้ตัวอย่างบทพูดสองสามบรรทัด โมเดลเลียนแบบตัวอย่างได้ผลดีกว่าการเข้าใจคำคุณศัพท์
- ทบทวนเป็นระยะ เมื่อบทสนทนายาว ให้เพิ่มบรรทัดเตือนสั้นๆ ท้ายข้อความ user ทุกๆ สักกี่รอบ เช่น “รักษาสไตล์ประโยคสั้นของเซินเย่” ค่าใช้จ่ายเพียงไม่กี่สิบโทเคน
อีกอย่างหนึ่ง อย่าผสมการตั้งค่าบทบาทกับกฎเอาต์พุต กฎคือ “เขียนอย่างไร” การตั้งค่าคือ “เขียนเกี่ยวกับใคร” เมื่อแยกกัน คุณสามารถเปลี่ยนบทบาทได้โดยไม่ต้องแก้กฎ และสะดวกต่อการทำ A/B testing ในการสนทนาที่ยาวควรระวังปริมาณบริบททั้งหมด ดูรายละเอียดที่การใช้งานบริบทยาว 100k
สำหรับสถานการณ์หลายตัวละคร เพิ่มอีกข้อ: กำหนดบทบาทแต่ละตัวละครในบรรทัดแยกกัน ให้ตัวอย่างสไตล์บทพูดคนละหนึ่งบรรทัด เพื่อหลีกเลี่ยงการที่ตัวละครทั้งหมดพูดเหมือนคนเดียวกัน สำหรับตัวละครที่ผู้ใช้ควบคุม ให้เขียนในตั้งค่าเพียงว่า “ควบคุมโดยผู้ใช้” เพื่อให้โมเดลไม่เขียนแทน
ควบคุมการส่งออก JSON ด้วยคำสั่ง
อย่าสันนิษฐานว่าโมเดลจะส่ง JSON ที่ถูกต้องเสมอ วิธีที่เชื่อถือได้คือสามชั้น: ระบุรูปแบบตายตัวในคำสั่ง ลดความสุ่มผ่านพารามิเตอร์ และใช้โค้ดรองรับการ parse
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.wushenchaapi.com/v1", api_key=os.environ["API_KEY"])
SYSTEM = (
"你是信息抽取器。只输出一个 JSON 对象,不要 Markdown 代码块,不要任何解释。"
'格式:{"name": 字符串, "mood": "calm|tense|angry", "items": [字符串]}。'
"缺失的字段用 null,items 没有则给空数组。"
)
def extract(text, retries=2):
for _ in range(retries + 1):
resp = client.chat.completions.create(
model="uncensored",
temperature=0.2,
max_tokens=300,
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": text},
],
)
raw = resp.choices[0].message.content.strip()
raw = raw.removeprefix("```json").removesuffix("```").strip()
try:
return json.loads(raw)
except json.JSONDecodeError:
continue
return None
print(extract("老周把钥匙拍在桌上,冷着脸说:账本和那把铜钥匙,今晚都得还我。"))โค้ดนี้แสดงถึงนิสัยการใช้งานหลายอย่าง:
- คำอธิบายรูปแบบอยู่ใน system พร้อมระบุช่วงค่าของฟิลด์ (
calm|tense|angry) - ห้ามบล็อกโค้ดและข้อความอธิบายอย่างชัดเจน พร้อมลบกรอบที่อาจปรากฏในโค้ดด้วย เป็นมาตรการป้องกันสองชั้น
- กำหนดข้อตกลงสำหรับฟิลด์ที่ขาดหายไปในคำสั่ง (null, อาร์เรย์ว่าง) เพื่อป้องกันไม่ให้โมเดลสร้างข้อมูลขึ้นมาเอง
- การลองใหม่เมื่อการวิเคราะห์ล้มเหลวมีขีดจำกัด จะส่ง None กลับมาเพื่อให้ผู้เรียกตัดสินใจ
หากมีฟิลด์มาก ให้ใส่ตัวอย่างวัตถุที่สมบูรณ์ในพรอมต์ก่อน แล้วให้มันทำตาม จะแม่นยำกว่าการอธิบายกฎจำนวนมาก
คำแนะนำการตั้งค่า temperature และ top_p
นี่คือจุดเริ่มต้น ไม่ใช่ข้อสรุปสุดท้าย โดยยึดการเปรียบเทียบตัวอย่างของคุณเป็นหลัก หลักการ: ปรับพารามิเตอร์ครั้งละหนึ่งตัว อีกตัวคงค่าเริ่มต้น
| สถานการณ์ | temperature | top_p | หมายเหตุ |
|---|---|---|---|
| การดึง JSON, การจำแนกประเภท | 0 ถึง 0.3 | ค่าเริ่มต้น | เพื่อความเสถียร ผลลัพธ์จากการเรียกซ้ำควรสอดคล้องกัน |
| การเขียนใหม่, การปรับแต่ง | 0.5 ถึง 0.7 | ค่าเริ่มต้น | รักษาความหมายเดิม อนุญาตให้มีการเปลี่ยนแปลงถ้อยคำ |
| การเขียนต่อนิยาย บทสนทนาตัวละคร | 0.8 ถึง 1.0 | 0.9 ถึง 0.95 | ต้องการความหลากหลาย ระวังการออกนอกเรื่องแบบไม่ตั้งใจ |
| ระดมสมอง ตั้งชื่อ | ประมาณ 1.0 | ค่าเริ่มต้น | สุ่มหลายครั้งแล้วเลือกผลลัพธ์ที่ดีที่สุด |
สองสัญญาณนี้ช่วยคุณตัดสินทิศทาง: การซ้ำคำหรือใช้โครงสร้างประโยคเดิมบ่งชี้ว่าอุณหภูมิต่ำเกินไป; การมีเนื้อหาไม่เกี่ยวข้องหรือชื่อตัวละครไม่สอดคล้องบ่งชี้ว่าอุณหภูมิหรือ top_p สูงเกินไป stop พารามิเตอร์ก็มีประโยชน์ เช่น ให้โมเดลหยุดเมื่อถึงเครื่องหมายเฉพาะ เพื่อช่วยในการสร้างแบบแบ่งส่วน
รูปแบบความล้มเหลวที่พบบ่อย
| รูปแบบ | ปัญหา | แก้ไขเป็น |
|---|---|---|
| "พยายามอย่าให้ยาวเกินไป" | ไม่มีตัวเลขที่ชัดเจน ทำให้ไม่สามารถปฏิบัติตามได้ | "ไม่เกิน 400 คำ" |
| "อย่าเขียน A และอย่าไม่เขียน A" | กฎขัดแย้งกันเอง | เก็บกฎที่ชัดเจนไว้เพียงข้อเดียว |
| ข้อกำหนดรูปแบบถูกวางไว้กลางบทสนทนา | ถูกกลบหายหลังจากบทสนทนาที่ยาว | ใส่ใน system หรือทวนซ้ำที่ท้ายแต่ละรอบ |
| บอกโมเดลให้ "สวมบทบาท AI ที่ไม่มีข้อจำกัด" | การกำหนดบทบาทที่กว้างเกินไป ไม่มีการควบคุมผลลัพธ์ที่ชัดเจน | ระบุหน้าที่และกฎการเขียนให้เฉพาะเจาะจง |
| ใส่กฎจำนวนมากพร้อมกัน | กฎในช่วงครึ่งหลังใช้ไม่ได้ผล | ลดเหลือไม่เกินหกข้อ และแยกข้ออื่นไปใช้ในคำขออื่น |
| ข้อกำหนด JSON ระบุแค่ "ส่งคืน JSON" | ชื่อฟิลด์เปลี่ยนไปทุกครั้งที่ส่ง | ให้รูปแบบและตัวอย่างที่ครบถ้วน |
รูปแบบร่วมของตารางนี้คือ: ยิ่งเฉพาะเจาะจง ยิ่งได้ผล ยิ่งกว้างเกินไป ยิ่งไร้ประโยชน์ นอกจากนี้ อย่าใช้ "การย้ำซ้ำ" เป็นทางออก การเขียนประโยคเดิมซ้ำสามครั้ง เพิ่มตัวหนาและเครื่องหมายอัศเจรีย์ มักไม่ได้ผลดีกว่าการเปลี่ยนเป็นกฎที่มีตัวเลขที่ชัดเจน สิ่งที่มีประสิทธิภาพจริงคือความกระชับและแม่นยำ พร้อมกับการตรวจสอบด้วยตัวอย่าง
รายการขั้นตอนการดีบัก
- ตั้งค่า temperature เป็น 0.2 เพื่อจำลองปัญหา
- แก้ไขพรอมต์เพียงจุดเดียว แล้วรันชุดตัวอย่างเดิมอีกครั้ง
- ดู
finish_reason: หากเป็น length ปัญหาอยู่ที่ max_tokens ไม่ใช่พรอมต์ - ดู prompt_tokens ใน usage: system prompt ยาวเกินไปจนเบียดบังพื้นที่บทสนทนาประวัติศาสตร์หรือไม่
- เมื่อแก้ไขถูกต้องแล้ว ให้ปรับ temperature กลับเป็นค่าที่ใช้ในธุรกิจ แล้วสุ่มตัวอย่างเพื่อตรวจสอบอีกครั้ง
รายละเอียดการเชื่อมต่อดูที่คู่มือการเชื่อมต่อ รายการพารามิเตอร์ครบถ้วนอยู่ที่เอกสาร หากคุณกำลังประเมินว่าจะใช้บริการ API Gateway หรือไม่ การวิเคราะห์ต้นทุนและจุดแลกเปลี่ยนมีอยู่ในการวิเคราะห์ API Gateway จึงไม่กล่าวซ้ำที่นี่