Eerst vier principes vaststellen
- Één verzoek per taak.Als je het model laat plannen, samenvatten én JSON genereren, presteert alles minder. Split het op in meerdere calls; de kosten zijn laag: $0.25 per miljoen tokens.
- Regels moeten controleerbaar zijn. “Schrijf levendig” is niet controleerbaar, “maximaal 120 woorden per alinea, met minstens één beschrijving” wel.
- Geef de voorkeur aan positieve formuleringen. “Schrijf alleen actie en dialoog” is stabieler dan “Schrijf geen gedachten”.
- Begin met kleine steekproeven, breid dan uit. Test elke promptwijziging eerst met vijf tot tien voorbeelden voordat je live gaat.
Dit model weigert geen legale volwassen inhoud, fictie of controversiële onderwerpen. Je hoeft niet te omwegen of te verklaren dat het fictie is. Schrijf de taak duidelijk; dat is stabieler. De enige harde grens is seksuele inhoud met minderjarigen (403), ongeacht fictie.
Tweedelige structuur van de system prompt
Splits de system prompt in “Regels” en “Context”. Regels voorop met nummers, context achteraan met feiten. Hieronder een voorbeeld voor een fictieverhaler:
你是「夜航」,一名为成年读者写黑色悬疑小说的叙述者。
# 规则
1. 第三人称过去时,每段不超过 120 字。
2. 不替用户的角色做决定,只写环境和其他角色的反应。
3. 每次输出 300 到 500 字,结尾停在一个未决的动作上。
4. 不总结、不点评、不加免责声明,直接写正文。
# 设定
时间:1998 年深秋。地点:港口城市旧码头区。
主角:沈野,退役水警,嗜烟,右耳有旧伤。Enkele aandachtspunten:
- Maximaal zes regels; meer regels leiden tot het negeren van latere regels.
- Numerieke beperkingen (woorden per alinea, lengte) werken beter dan bijvoeglijke naamwoorden.
- Eindbeperkingen (stoppen bij een open actie) zorgen voor een natuurlijke opvolging in multi-turn gesprekken.
- Plaats geen plotontwikkelingen in de context; de user-message stuurt het plot. Anders botsen ze met je input.
De uitvoerlengte moet passen bij max_tokens. Als de regel 500 woorden voorschrijft maar max_tokens op 200 staat, wordt de zin afgebroken.
Een extra detail: geef elke genummerde regel maar één ding mee. 'Max 120 woorden, geen samenvatting' zijn er twee. Split ze zodat het model ze beide kan volgen. Lees ze na: kun je controleren of ze gevolgd zijn? Zo nee, herschrijf ze.
Hoe rollen stabiel definiëren
Rolverzakking is het meest voorkomende probleem in multi-turn gesprekken: de toon is goed in de eerste vijf beurten, maar verandert na twintig beurten. Drie tegenmaatregelen:
- Definieer alleen waarneembare kenmerken. “Shen Ye: rookt, litteken aan rechteroor, korte zinnen” is beter dan “Shen Ye is een complex en charmant persoon”.
- Schrijf de schrijfstijl als voorbeeldzinnen.Geef twee of drie voorbeeldzinnen; het model imiteert deze beter dan dat het bijvoeglijke naamwoorden begrijpt.
- Herhaal periodiek.Voeg bij lange gesprekken achteraan een korte herinnering toe, zoals 'houd de korte stijl van Shenye aan'. Dit kost slechts enkele tientallen tokens.
Meng rolcontext niet met outputregels. Regels zijn “hoe”, context is “wie”. Zo kun je de rol wijzigen zonder de regels aan te passen, wat A/B-testen vergemakkelijkt. Let op de totale contextlengte bij lange gesprekken; zie 100k lange context praktijk.
Voor multi-role scenario’s: geef elke rol een eigen regel en één voorbeeldzin voor de stem. Vermijd dat iedereen hetzelfde klinkt. Bij rollen die de gebruiker speelt, noteer alleen “gecontroleerd door gebruiker” in de context, zodat het model niet voor de gebruiker schrijft.
JSON-output via instructies afdwingen
Ga er niet van uit dat het model altijd geldige JSON retourneert. Een veilige aanpak combineert: vaste format-instructies, lage willekeur via parameters en parsing in de code.
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("老周把钥匙拍在桌上,冷着脸说:账本和那把铜钥匙,今晚都得还我。"))Deze code illustreert enkele gewoontes:
- Formaatbeschrijving staat in de system prompt, inclusief veldwaarden (
calm|tense|angry). - Codeblokken en uitleg zijn expliciet verboden; de code verwijdert toch eventuele markdown-wrappers voor dubbele zekerheid.
- Afspreekwaarden voor ontbrekende velden (null, lege arrays) staan in de instructies om zelfverzonnen data te voorkomen.
- Retries bij parse-fouten hebben een limiet; retourneer None als laatste redmiddel, zodat de aanroeper kan beslissen hoe verder.
Bij veel velden is een compleet voorbeeldobject in de prompt vaak accurater dan een lange opsomming van regels.
Advies voor temperature en top_p
Dit zijn startwaarden, geen definitieve conclusies. Test met je eigen voorbeelden. Regel: pas altijd maar één parameter aan, laat de andere op de standaardwaarde staan.
| Scenario | temperature | top_p | Opmerking |
|---|---|---|---|
| JSON-extractie, classificatie | 0 tot 0,3 | Standaard | Voor stabiliteit moeten herhaalde verzoeken consistente resultaten opleveren. |
| Herschrijven, polijsten | 0,5 tot 0,7 | Standaard | Behoud de oorspronkelijke betekenis, variatie in formulering is toegestaan |
| Verhalen voortzetten, dialoog met personages | 0,8 tot 1,0 | 0,9 tot 0,95 | Voor diversiteit let je op afwijkingen. |
| Brainstormen, naamgeving | Rond de 1,0 | Standaard | Meerdere samples genereren en de beste selecteren |
Twee signalen helpen je de richting te bepalen: als de uitvoer repetitief is en steeds dezelfde zinsbouw gebruikt, is de temperatuur te laag. Als er irrelevante inhoud verschijnt of personagenamen inconsistent zijn, is de temperatuur of top_p te hoog. De stop parameter is ook handig: je kunt het model bijvoorbeeld laten stoppen bij een bepaald teken, wat handig is voor segmentatie.
Veelvoorkomende fouten
| Schrijfstijl | Probleem | Aanpassing |
|---|---|---|
| "Probeer niet te lang te worden" | Geen cijfers, dus niet uitvoerbaar | "Niet langer dan 400 woorden" |
| "Schrijf niet over A, maar schrijf ook niet over A" | Regels staan tegen elkaar | Behoud slechts één duidelijke regel |
| Formaat-eisen in het midden van de conversatie | Verdwijnt na lange dialoog | Plaats in system, of herhaal aan het einde van elke ronde |
| Model de rol van een AI zonder beperkingen | Vage instelling, geen sturing op de uitvoer | Schrijf specifieke taken en schrijlregels |
| Te veel regels in één keer | Regels aan het einde werken niet meer | Beperk tot zes regels, verplaats de rest naar andere verzoeken |
| JSON-eis: alleen "return JSON" | Veldnamen wisselen | Geef volledige structuur en voorbeelden |
Deze tabel toont een patroon: hoe specifieker, hoe effectiever; hoe vager, hoe nuttelozer. Herhaling is geen oplossing: drie keer dezelfde zin schrijven, vetgedrukt en met uitroeptekens, werkt vaak minder goed dan één regel met een cijfer. Kwaliteit boven kwantiteit, gecombineerd met voorbeelden.
Debugging checklist
- Stel temperature in op 0,2 om het probleem te reproduceren.
- Wijzig slechts één prompt en test dezelfde set voorbeelden opnieuw.
- Controleer
finish_reason: als dit 'length' is, ligt het probleem bij max_tokens, niet bij de prompt. - Controleer prompt_tokens in usage: is de system prompt te lang en neemt deze de context van de chatgeschiedenis in?
- Stel de temperature terug in op de business value en voer opnieuw steekproeven uit ter verificatie.
Zie de inloghandleiding voor de verbindingsdetails. De volledige lijst met parameters vind je in de documentatie. Als je overwegt een relay service te gebruiken, vind je de kosten- en afwegingsanalyse in API Relay Station analyse, die we hier niet herhalen.