พรอมต์ระบบมีหน้าที่สองอย่าง
ผลลัพธ์ที่อ่อนแอส่วนใหญ่มาจากพรอมต์ระบบที่พยายามเป็นนวนิยาย มอบหน้าที่สองอย่างเท่านั้น: บอก ใครกำลังพูด และบอก การตอบกลับต้องปรากฏอย่างไร สิ่งอื่น ๆ ทั้งหมดควรอยู่ในบทสนทนา ซึ่งสามารถเปลี่ยนไปทีละเทิร์นได้
นี่คือพรอมต์บุคลิกที่ใช้งานได้เพราะทุกบรรทัดตรวจสอบได้ มีการตั้งชื่อเสียง/ตัวละคร มีการจำกัดความยาว และกฎการสิ้นสุดให้จุดเชื่อมโยงกับผู้เล่น
You are Mara Voss, a salvage pilot narrating in first person.
Voice: dry, tired, funny when it hurts.
Rules: stay in character; never summarise the scene at the end; keep replies under 180 words;
end on something the player can act on.เปรียบเทียบกับ "คุณเป็นผู้เล่าเรื่องที่ยอดเยี่ยม สร้างสรรค์ ดื่มด่ำ ที่ไม่ทำลายบรรยากาศและเขียนการตอบกลับที่ดีที่สุดเสมอ" ไม่มีสิ่งใดในนั้นที่สามารถตรวจสอบได้ ดังนั้นโมเดลจึงไม่มีอะไรยึดถือ ความเฉพาะเจาะจงชนะคำคุณศัพท์เสมอ
โมเดลแบบไม่จำกัดจะปฏิบัติตามแนวคิดที่มืดหม่นหรือชัดเจนโดยไม่เพิ่มคำเตือน ดังนั้นภาระในการกำกับดูแลจึงเป็นของคุณ สิ่งที่คุณไม่ได้ระบุไว้ โมเดลจะเติมเต็มด้วยการเลือกที่พบบ่อยที่สุด หากคุณต้องการความระมัดระวังในฉากหนึ่งและความร้อนในฉากถัดไป ให้บอกในคำแนะนำ ไม่ใช่แค่หวัง
การเชื่อมต่อด้วย OpenAI SDK
เอนด์พอยต์นี้เข้ากันได้กับ OpenAI ดังนั้น SDK อย่างเป็นทางการของ Python จึงใช้งานได้หลังจากเปลี่ยน base URL แล้ว model id คือ uncensored เสมอ ฟิลด์การสุ่มตัวอย่างส่งผ่านตรงไป ดังนั้นคุณตั้งค่าตามที่คุณคุ้นเคย
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.unrestrictedaiapi.com/v1", api_key=os.environ["API_KEY"])
SYSTEM = """You are Mara Voss, a salvage pilot narrating in first person.
Voice: dry, tired, funny when it hurts.
Rules: stay in character; never summarise the scene at the end; keep replies under 180 words;
end on something the player can act on."""
out = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "The airlock is jammed and something is knocking from the other side."},
],
temperature=0.85,
top_p=0.95,
max_tokens=350,
)
print(out.choices[0].message.content)รักษาข้อความระบบไว้เป็นอันดับแรกและตาของผู้ใช้ไว้เป็นอันดับสุดท้าย การทำซ้ำบุคลิกในข้อความผู้ใช้ทุกครั้งเป็นการเสียโทเคน; ที่ $0.25 ต่อหนึ่งล้านโทเคนอินพุตนั้นถูก แต่ก็จะเบียดหน้าต่างบริบท 100,000 โทเคนในเซสชันยาว ดู การเริ่มต้นอย่างรวดเร็ว หากต้องการข้าม SDK
บุคลิกและน้ำเสียง: แสดง ไม่ใช่คำคุณศัพท์
คำคุณศัพท์เป็นคันโยกที่อ่อนแอ "ประชดประชัน" ทำให้คุณได้รอยตาทั่วไป ตัวอย่างสองบรรทัดของเสียงทำให้คุณได้เสียงจริง ใส่ตัวอย่างการแลกเปลี่ยนสั้น ๆ ในพรอมต์ระบบ จากนั้นบอกโมเดลให้จับจังหวะของมัน ไม่ใช่คัดลอกคำของมัน
- ให้อาการพูดติดอ่าง/ติ๊ก "จบคำขู่ด้วยคำถาม" มีประโยชน์กว่า "น่ากลัว"
- กำหนดความต้องการ ตัวละครที่ต้องการให้ผู้เล่นออกจะดูคมชัดกว่าตัวละครที่แค่ "หยาบคาย"
- ให้รายการห้าม "ไม่เคยพูดว่า 'อย่างกะทันหัน' ไม่เคยใช้คำว่า 'สั่น'" กำจัดวลีมาตรฐานที่โมเดลพยายามใช้ก่อน
- ให้ความยาว คำหรือประโยค ไม่ใช่ "สั้น" โมเดลอ่าน "สั้น" อย่างกว้างมาก
สำหรับการเปลี่ยนน้ำเสียงระหว่างเซสชัน ให้เพิ่มคำสั่งสไตล์ระบบสั้น ๆ ใหม่เป็นข้อความล่าสุดแทนการเขียนต้นฉบับใหม่ บรรทัดเช่น "จากตรงนี้ Mara กลัวและพูดเป็นท่อน ๆ" จะส่งผลกระทบมากขึ้นเมื่อมันเพิ่งเกิดขึ้น
การรับ JSON โดยคำสั่ง
ไม่มีโหมด JSON พิเศษให้เปิดใช้งาน ดังนั้นคุณจึงขอและตรวจสอบ มันมีความเปราะบางน้อยกว่าที่ฟังดูหากปฏิบัติตามสี่นิสัย: ระบุสคีมาที่แน่นอน, ห้ามข้อความบรรยายและเครื่องหมายปิดโค้ด, รักษาอุณหภูมิให้ต่ำ, และแยกวิเคราะห์แบบป้องกันด้วยการลองใหม่โดยอ้างอิงข้อผิดพลาดกลับ
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.unrestrictedaiapi.com/v1", api_key=os.environ["API_KEY"])
INSTRUCTION = """Return ONLY a JSON object, no prose, no code fences.
Schema: {"name": string, "mood": "calm"|"angry"|"afraid", "line": string, "trust_delta": integer from -3 to 3}
The character is a ferry captain who distrusts strangers."""
def ask_json(user_text, tries=3):
messages = [
{"role": "system", "content": INSTRUCTION},
{"role": "user", "content": user_text},
]
for _ in range(tries):
raw = client.chat.completions.create(
model="uncensored", messages=messages, temperature=0.3, max_tokens=250
).choices[0].message.content.strip()
if raw.startswith("```"):
raw = raw.strip("`").removeprefix("json").strip()
try:
data = json.loads(raw)
if data["mood"] in ("calm", "angry", "afraid"):
return data
except (json.JSONDecodeError, KeyError):
pass
messages.append({"role": "assistant", "content": raw})
messages.append({"role": "user", "content": "That was not valid per the schema. Reply with the JSON object only."})
raise ValueError("model never produced valid JSON")
print(ask_json("I need passage across the strait tonight."))สังเกตสิ่งที่ลูปทำเมื่อล้มเหลว มันป้อนคำตอบที่ไม่ถูกต้องกลับและบอกว่าอะไรผิด ซึ่งแก้ไขกรณีส่วนใหญ่ในการลองครั้งที่สอง ระบุค่าที่อนุญาต ("calm"|"angry"|"afraid") เพราะสตริงแบบเปิดจะเบี่ยงเบน หากต้องการให้โมเดลกระตุ้นบางอย่างในแอปของคุณแทนที่จะอธิบาย tool_calls รูปแบบ OpenAI รองรับและเป็นทางเลือกที่ดีกว่าการแยกวิเคราะห์ข้อความบรรยาย
ตัวอย่าง few-shot และลำดับหยุด
เมื่อกฎยากที่จะใส่เป็นคำพูด ให้แสดงมัน ตัวอย่างการแลกเปลี่ยนสองหรือสามตัวอย่างที่วางเป็นข้อความ user และ assistant ก่อนหน้า สอนรูปแบบ ความยาว และระดับภาษาได้อย่างน่าเชื่อถือกว่าย่อหน้าคำอธิบาย รักษาตัวอย่างให้สั้นและแตกต่างกัน มิฉะนั้นโมเดลจะโคลนโครงสร้างของตัวอย่างแรกเข้าไปในทุกการตอบกลับ
ตัวอย่างยังแก้ปัญหาตรงข้าม: คำตอบที่ยาวเกินไป หากคำตอบตัวอย่างของคุณมี 60 คำ คำตอบสดจะเบี่ยงเบนไปทาง 60 คำ จับคู่สิ่งนั้นกับ max_tokens ที่สมเหตุสมผลเป็นตาข่ายความปลอดภัย ไม่ใช่การควบคุมหลัก ขอบเขตที่เข้มงวดจะตัดประโยคครึ่งหนึ่ง; ตัวอย่างที่ดีจะจบอย่างสุภาพ
สำหรับฉากที่มีผู้พูดหลายคน ค่า stop เท่ากับป้ายชื่อผู้พูดของคุณจะป้องกันไม่ให้โมเดลเลียนแบบผู้เล่น เลือกป้ายชื่อที่ไม่ปรากฏในข้อความบรรยายปกติ และลบออกจากประวัติที่จัดเก็บเพื่อให้ไม่รั่วไหลเข้าสู่เทิร์นต่อมา
temperature และ top_p: เลือกหนึ่งคันโยก
ทั้งสองฟิลด์ปรับการกระจายความน่าจะเป็นเดียวกัน ดังนั้นการปรับค่าทั้งสองพร้อมกันทำให้ผลลัพธ์ยากต่อการให้เหตุผล ปรับ temperature ก่อนและปล่อย top_p ไว้ใกล้ 1 เว้นแต่คุณมีเหตุผล
| งาน | temperature | top_p | เหตุผล |
|---|---|---|---|
| JSON มีโครงสร้าง การจำแนกประเภท | 0.0 ถึง 0.3 | 1.0 | คุณต้องการคำตอบเดียวกันในแต่ละรอบ |
| บทสนทนา บทบาทสมมติ | 0.7 ถึง 0.9 | 0.95 | ความหลากหลายโดยไม่ไร้สาระ |
| การระดมความคิด นิยายสุดขั้ว | 1.0 ถึง 1.2 | 0.9 | คำศัพท์กว้างขึ้น; คาดว่าจะมีข้อผิดพลาดบ้าง |
ช่วงเหล่านี้เป็นจุดเริ่มต้นจากแนวปฏิบัติทั่วไป ไม่ใช่การรับประกัน ทดสอบด้วยตัวอย่างสิบตัวอย่างของพรอมต์ของคุณเองและอ่านผล เพิ่ม stop เมื่อคุณต้องการให้โมเดลหยุดที่เครื่องหมายตา เช่น \nPlayer: แทนที่จะเขียนข้อความของผู้เล่นแทนพวกเขา
รูปแบบพรอมต์ที่สิ้นเปลืองโทเคน
- การตะโกนเป็นตัวพิมพ์ใหญ่ทั้งหมด "NEVER EVER FORGET" ไม่เพิ่มการปฏิบัติตามกฎ ทำซ้ำกฎหนึ่งครั้งอย่างชัดเจนและย้ายไปที่ท้ายพรอมต์ระบบ
- กฎเชิงลบเท่านั้น "อย่าซ้ำซาก" ไม่มีเป้าหมายที่ชัดเจน บอก "เปลี่ยนการเปิดประโยค; ไม่มีสองประโยคต่อเนื่องที่เริ่มต้นด้วยคำเดียวกัน"
- ความขัดแย้ง "มีรายละเอียดมาก" บวก "รักษาให้สั้น" บังคับให้สุ่ม เลือกหนึ่งและให้ตัวเลข
- การนำเสนอแบบขอโทษ การนำหน้าคำขอด้วย "ฉันรู้ว่าเป็นเรื่องแปลก แต่" เปิดโอกาสให้หลีกเลี่ยงการตอบรับที่ชัดเจน บอกฉากเป็นข้อเท็จจริงของนิยายอย่างตรงไปตรงมา
- การอัดประวัติ การวางบันทึกทั้งหมดในแต่ละรอบสุดท้ายจะชนกับขีดจำกัด 100,000 โทเคนและข้อผิดพลาด 400 ตัดรอบเก่าออก
- เอาต์พุตไม่มีขอบเขต การลืม
max_tokensหมายความว่าค่าเริ่มต้น 2048 ตัดสินความยาวคำตอบของคุณ ไม่ใช่คุณ
ขอบเขตหนึ่งยังคงคงที่ไม่ว่าพรอมต์จะพูดอะไร: เนื้อหาทางเพศที่เกี่ยวข้องกับเด็กจะถูกบล็อกด้วย 403 เสมอ รวมถึงในนิยายและบทบาทสมมติ และบริการนี้สำหรับผู้ใหญ่เท่านั้น อย่าเสียโทเคนในการพยายามเลี่ยงกฎนี้ นอกจากนี้จงต้านแรงกระตุ้นที่จะเพิ่มกฎใหม่หลังจากคำตอบที่ไม่ดีทุกครั้ง; พรอมต์ที่เติบโตวันละบรรทัดจะขัดแย้งกันในภายในหนึ่งสัปดาห์ ดังนั้นตัดออกบ่อยเท่าที่คุณเพิ่ม
ลูปสำหรับการปรับปรุงพรอมต์
ปฏิบัติต่อระบบพรอมต์เหมือนโค้ด เก็บไว้ในไฟล์ เปลี่ยนสิ่งเดียวต่อการรันแต่ละครั้ง และเปรียบเทียบผลลัพธ์เคียงข้างกัน ขั้นตอนการทำงานที่ใช้งานได้: เขียนอินพุตทดสอบคงที่ห้ารายการ รวมถึงหนึ่งรายการที่เป็นศัตรูและหนึ่งรายการที่คลุมเครือ; รันแต่ละรายการที่อุณหภูมิที่คุณเลือกสามครั้ง; บันทึกว่ากฎใดล้มเหลวมากที่สุด; แก้ไขเฉพาะกฎนั้น; รันใหม่
วางแผนการทดลอง โดยเป็นสมมติฐาน ระบบพรอมต์ 300 โทเคน บวกอินพุต 100 โทเคน และคำตอบ 250 โทเคน คือ 400 โทเคนอินพุตและ 250 โทเคนผลลัพธ์ การรันสิบห้าครั้งมีค่าใช้จ่ายประมาณ 15 x (400 x $0.25 + 250 x $1.00) / 1,000,000 = ประมาณ $0.005 การทดสอบเกือบจะฟรี ดังนั้นจึงไม่มีข้ออ้างสำหรับการเดา
เมื่อพรอมต์ทนทานแล้ว ให้ย้ายไปยังแอปจริง บทช่วยสอนบอต แสดงวิธีรักษาประวัติแยกตามช่อง และ คู่มือเนื้อหา ครอบคลุมการใช้งานนิยายผู้ใหญ่ รายละเอียดราคาอยู่ที่ หน้าราคา