Definisci prima quattro principi
- Una richiesta per compito.Chiedere al modello di scrivere una trama, fare un riassunto ed emettere JSON in una sola volta fa calare la qualità di tutti e tre. Suddividi in più chiamate: il costo è minimo, $0.25 per milione di token di input.
- Le regole devono essere verificabili."Scrivi in modo vivace" non è verificabile; "massimo 120 caratteri per paragrafo, almeno una descrizione ambientale" sì.
- Preferisci la formulazione positiva. "Scrivi solo azioni e dialoghi" è più stabile di "Non scrivere pensieri interiori".
- Inizia con pochi esempi, poi scala. Testa ogni modifica con 5-10 campioni prima di andare in produzione.
Il modello non rifiuta contenuti per adulti leciti, narrativa o temi controversi, quindi non serve girarci intorno nel prompt. Specifica il compito chiaramente. L'unico limite rigido è il contenuto sessuale che coinvolge minori: restituisce 403 sempre, anche nella finzione, e non si può cambiare con le parole.
Struttura a due parti del system prompt
Dividi il system in "Regole" e "Impostazioni": regole in alto con numeri, impostazioni in basso con solo fatti. Ecco un esempio per un narratore:
你是「夜航」,一名为成年读者写黑色悬疑小说的叙述者。
# 规则
1. 第三人称过去时,每段不超过 120 字。
2. 不替用户的角色做决定,只写环境和其他角色的反应。
3. 每次输出 300 到 500 字,结尾停在一个未决的动作上。
4. 不总结、不点评、不加免责声明,直接写正文。
# 设定
时间:1998 年深秋。地点:港口城市旧码头区。
主角:沈野,退役水警,嗜烟,右耳有旧伤。Punti chiave:
- Non superare sei regole: più sono, più le ultime vengono ignorate.
- I vincoli numerici (lunghezza paragrafo) funzionano meglio degli aggettivi.
- Vincoli di fine testo (es. interrompere su un'azione) facilitano le continuazioni multi-turno.
- Non inserire la trama nelle impostazioni: la trama avanza con i messaggi user, altrimenti crei conflitti.
Allinea la lunghezza all'output con max_tokens: se la regola dice 500 parole ma max_tokens è 200, il testo verrà troncato a metà frase.
Un altro dettaglio pratico: le regole di numerazione nel system prompt dovrebbero esprimere un solo concetto per riga. "Ogni paragrafo non deve superare i 120 caratteri e non deve fare riassunti" sembra una regola, ma sono due. Dopo averle separate, il modello riesce più facilmente a soddisfarle entrambe. Dopo averle scritte, leggile una per una e chiediti: questa regola è verificabile a occhio nudo? Se no, riscrivila in modo verificabile.
Come definire il ruolo senza deviazioni
Il drift del personaggio è il problema più comune: i primi turni sono ok, poi il modello "esce di scena". Ecco tre contromisure.
- Impostazioni solo su caratteristiche osservabili. "Shen Ye: fuma, ferita all'orecchio destro, frasi brevi" è meglio di "Shen Ye è complesso e affascinante".
- Scrivi lo stile di parlato come esempio. Fornisci 2-3 battute campione: il modello imita meglio gli esempi che non capisce gli aggettivi.
- Riassumi periodicamente. Nelle conversazioni lunghe, aggiungi un breve promemoria alla fine dei messaggi user (es. "Mantieni stile frasi brevi"). Costo: pochi token.
Inoltre, non mescolare le istruzioni di sistema con le regole di output. Le istruzioni definiscono «come scrivere», le regole definiscono «chi scrivere». Separandole puoi cambiare personaggio senza modificare le regole e facilitare i test A/B. Per le conversazioni lunghe, fai attenzione alla quantità totale del contesto; per i dettagli, consulta Esempi pratici con contesto lungo 100k.
Per scenari multi-personaggio: una riga di impostazione per personaggio, una battuta campione per ciascuno. Per il personaggio user, scrivi solo "controllato dall'utente" per evitare che il modello ne scriva le azioni.
Controllo dell'output JSON tramite istruzioni
Non assumere che il modello restituisca sempre JSON valido. Usa tre livelli: formato fisso nel prompt, bassa randomicità nei parametri e analisi di fallback nel codice.
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("老周把钥匙拍在桌上,冷着脸说:账本和那把铜钥匙,今晚都得还我。"))Questo codice mostra alcune buone pratiche:
- La descrizione del formato è nel system, con range di valori (
calm|tense|angry). - Vieta esplicitamente blocchi di codice e testo esplicativo; il codice rimuove comunque i delimitatori per sicurezza.
- Definisce i valori per campi mancanti (null, array vuoto) per evitare allucinazioni.
- Il retry ha un limite massimo; se fallisce tutto, restituisce None e lascia la decisione al chiamante.
Se i campi sono molti, incolla un esempio completo di oggetto nel prompt: è più preciso di lunghe descrizioni.
Consigli su temperature e top_p
Questi sono solo punti di partenza; confrontali con i tuoi esempi. Principio: modifica un parametro alla volta, lasciando gli altri predefiniti.
| Scenario | temperature | top_p | Note |
|---|---|---|---|
| Estrazione e classificazione JSON | 0-0.3 | Default | Stabile: le chiamate ripetute devono essere consistenti |
| Riscrittura e rifinitura | 0.5 a 0.7 | Predefinito | Mantieni il significato originale, consentendo variazioni di wording |
| Continuazione di romanzi, dialoghi tra personaggi | 0.8 a 1.0 | 0.9 a 0.95 | Per la diversità, attenzione alle divagazioni occasionali |
| Brainstorming, creazione di nomi | Circa 1.0 | Predefinito | Esegui più campionamenti e scegli il risultato migliore |
Due segnali possono aiutarti a orientarti: output ripetitivi e ridondanti, sempre con la stessa struttura, indicano una temperatura troppo bassa; contenuti irrilevanti o incoerenze sui nomi dei personaggi indicano una temperatura o un top_p troppo alti. Il parametro stop è molto utile, ad esempio per far fermare il modello a un determinato marcatore, facilitando la generazione a blocchi.
Errori comuni
| Metodo | Problema | Modifica in |
|---|---|---|
| "Cerca di non essere troppo lungo" | Nessun numero, impossibile da eseguire | "Non superare le 400 parole" |
| "Non scrivere A, ma non omettere A" | Regole contraddittorie | Mantieni una sola regola chiara |
| La richiesta di formato è persa nel mezzo del dialogo | Viene sommersa dopo una conversazione lunga | Inseriscila nel system o ripropila alla fine di ogni turno |
| Chiedi al modello di "interpretare un'IA senza limiti" | Impostazione generica, nessuna vincolante sull'output | Definisci responsabilità e regole di scrittura specifiche |
| Inserisci decine di regole in una volta | Le regole nella seconda metà non funzionano più | Riduci a meno di sei regole, sposta le altre in richieste separate |
| La richiesta JSON si limita a "restituisci JSON" | I nomi dei campi cambiano ogni volta | Fornisci il formato completo con un esempio |
La tabella rivela una regola comune: più sei specifico, più è efficace; più sei vago, più è inutile. Non considerare la ripetizione ossessiva la soluzione: scrivere tre volte la stessa frase, in grassetto e con i punti esclamativi, di solito funziona meno di una singola regola numerica. La chiave è la precisione, unita alla verifica con gli esempi.
Checklist per il debug
- Fissa temperature a 0.2 per riprodurre il problema.
- Modifica solo un punto del prompt e ripeti lo stesso set di esempi.
- Controlla
finish_reason: se è length, il problema è max_tokens, non il prompt. - Controlla prompt_tokens nei dati di usage: il system è troppo lungo e occupa spazio nella conversazione.
- Dopo la correzione, riporta temperature al valore di produzione e verifica con nuovi campionamenti.
Per i dettagli di integrazione, consulta Guida all'integrazione. L'elenco completo dei parametri è disponibile nella documentazione. Se stai valutando se utilizzare servizi di relay, l'analisi dei costi e dei compromessi è riportata nell'articolo Analisi dei servizi di relay, qui non la ripetiamo.