上星期,我發現咗一件有啲尷尬嘅事。
我個AI podcast pipeline有個精心編寫嘅系統提示——「對話指南」——我花咗幾日時間先寫好。佢話畀兩位主持(兩個AI足球評論員)知,應該點樣同對方講嘢。唔好重複相同嘅開場。唔同段落要有唔同結構。口頭禪要克制使用。絕對唔好老作統計數據。
LLM逐字閱讀咗。然後幾乎全部無視晒。
越南主持一集講咗13次「Trời ơi」(天呀)。日本主持每個段落嘅開頭都係「いやー、健一さん!」(哎吔,健一先生!)。英文主持信心十足咁引用xG 0.35同65%控球率——呢啲數字喺我個database度根本唔存在。
個prompt被禮貌地接收咗。然後被無視咗。
呢個係我喺prompt engineering學到最有用嘅一件事:LLM有兩種閱讀模式,而且佢哋對待呢兩種模式嘅方式完全唔同。
兩種閱讀模式嘅問題
呢個係我最初嘅對話指南嘅樣。因為結構完全一樣,我將越南文版本翻譯成英文嚟展示:
STYLE GUIDELINES:
HOST INTERACTION PATTERN: Emotional Host + Analytical Host.
STRICT RULES FOR EVERY SEGMENT:
0. NEVER REPEAT THE SAME OPENING. Vary which host initiates,
which match moment they react to first.
1. EMOTIONAL START (mandatory): Every segment begins with
the emotional host's pure reaction.
2. DATA-GROUNDING RULE (mandatory): Every claim must cite
specific numbers. Not "they dominated" but "61% possession,
3.17 xG to 0.65."
3. CATCHPHRASES:
Emotional host: "You see that?!" "Wait wait wait..."
Analytical host: "There's a deeper reason..." "Let me tell you."
睇落好周全啦?我真係以為自己做足晒功課。
但當我睇到實際生成出嚟嘅script,情況係咁:
| 規則 | 指南寫嘅內容 | LLM實際做咗嘅 |
|---|---|---|
| 規則0(禁止重複) | 變化開場方式 | 每個段落都以情緒化主持嘅口頭禪開場 |
| 規則2(數據) | 引用具體數字 | 引用咗完全老作嘅數字,語氣仲極之篤定 |
| 規則3(口頭禪) | 標誌性短語列表 | 每條短語每集用咗5到13次 |
規則明明喺度。LLM讀過晒。但呢啲規則嘅效力只係相當於建議,而唔係要求。
就喺呢個時候我醒覺:LLM將我嘅規則當作「風格背景資訊」——而唔係「可執行嘅約束條件」。
模式:Context vs. Command
諗下你閱讀唔同類型文本嘅方式。如果我畀張餐廳menu你,你會當佢係行動資訊咁睇。如果我畀篇關於意粉歷史嘅Wikipedia文章你,你會當佢係背景知識咁睇。
LLM對prompt嘅處理都係類似。當規則出現喺標記為「STYLE GUIDELINES」、「HOST INTERACTION PATTERN」或者「RULES FOR SEGMENTS」嘅段落嗰陣,個model會當佢係環境資訊——為回答提供色彩嘅背景,但唔構成約束。
當規則出現喺標記為「CRITICAL IMPROVEMENTS REQUIRED」或者「SPECIFIC PHRASE LIMITS」嘅段落嗰陣,個model會當佢係可執行嘅命令——必須驗證同糾正嘅事項。
呢個洞察嘅關鍵唔係「CRITICAL」或者「REQUIRED」呢啲字。關鍵係規則喺pipeline嘅邊個位置。
解決方案:令review step強制執行generation step忽略嘅嘢
我個pipeline有兩個LLM call:
- Generation step —— 以對話指南做背景,逐段撰寫script
- Review step —— 通讀完整嘅script並加以改進
最初,所有規則都喺generation step度。Review step只有通用嘅反重複規則(「唔好講兩次'That's fascinating'」),完全以英文為中心,對我啲主持特有嘅口頭禪或者結構要求一無所知。
個fix係結構性嘅,唔係詞彙性嘅。我將enforcement轉移咗去review step——因為嗰度可以同時睇到完整script。
改變如下:
Before:規則喺generation prompt度(被無視)
STYLE GUIDELINES:
0. NEVER REPEAT THE SAME OPENING...
1. EMOTIONAL START...
2. DATA-GROUNDING...
3. CATCHPHRASES: "You see that?!" ...
After:規則被提取並注入review prompt(強制執行)
CRITICAL IMPROVEMENTS REQUIRED ACROSS THE ENTIRE SCRIPT:
2a. ENFORCE STYLE GUIDELINES' STRUCTURAL RULES:
The STYLE GUIDELINES above contain specific requirements
about segment structure. These are REQUIREMENTS, not suggestions.
- If the guidelines say "X of Y segments must vary," CHANGE
segments that violate this.
- Check how EACH segment opens. If 4+ out of 5 open identically,
VARY at least 2.
3b. LOCALE-SPECIFIC PHRASE LIMITS (extracted from host profiles —
MAXIMUM 2 TIMES each across entire script):
- "Trời ơi" / "Trời má" — max 4x combined
- "Có một lý do sâu hơn" — max 2x
- "Mày thấy chưa?!" — max 2x
...
呢度發生咗兩件事:
-
結構規則從context升級為command——被重新表述為「強制執行」同「修改違反此規則嘅段落」,而唔係「呢個係推薦模式」
-
口頭禪從主持profile中提取出嚟,以明確嘅限制而非建議列表嘅形式呈現。"Catchphrases: here are some"變成咗"These phrases: MAXIMUM 2 TIMES each。"
兩處修改都喺review prompt度,而唔係generation prompt度。呢個係關鍵嘅architecture決策。Generation step將style guide作為context接收——佢需要個性色彩。Review step將規則作為enforcement command接收——佢需要compliance權限。
提取細節(點解呢個喺7種語言都work)
我唔想手動maintain每種語言嘅phrase list。每次調整主持profile,我都要同時update review prompt。呢種drift足以毁咗一個solo developer嘅產品。
於是我寫咗一個細extraction function,喺review時parse主持profile。每種語言嘅profile都有一個帶標準label嘅口頭禪section:
- 越南文:
Câu cửa miệng: - 日文:
口癖: - 西班牙文:
Latiguillos: - 法文:
Phrases fétiches: - 韓文:
입버릇: - 中文:
口头禅:
個function搵到對應嘅label,提取其後所有嘅引用string,並format為可執行嘅限制:
@staticmethod
def _extract_catchphrase_limits(host_profiles: str) -> str:
patterns = [
(r'Câu cửa miệng:?', r'"([^"]+)"'), # Vietnamese
(r'口癖:?', r'「([^」]+)」'), # Japanese
(r'Latiguillos:?', r'"([^"]+)"'), # Spanish
# ... etc for all 7 languages
]
limits = []
for marker_pattern, quote_pattern in patterns:
match = re.search(marker_pattern, host_profiles)
if match:
phrases = re.findall(quote_pattern, host_profiles[match.end():])
for phrase in phrases:
limits.append(f' - "{phrase}" — max 2x')
return "\n".join(limits)
而家,當我edit主持profile、修改佢哋嘅口頭禪時,review prompt會自動update。冇drift。冇漏咗嘅語言。
實際fix咗邊啲問題(用數據說話)
以下係fix前同fix後生成嘅episode之間嘅變化:
| 指標 | Fix前 | Fix後 |
|---|---|---|
| "Trời ơi"次數(quota:最多4次) | 13次 | 越南文未測試,但日文中所有4個口頭禪均在quota內 |
| "Có một lý do sâu hơn"(quota:最多2次) | 5次 | 喺對應嘅日文測試中喺quota內 |
| 老作統計數據(xG、控球率、陣型闊度) | 4個老作嘅數字 | 零個老作嘅數字 |
| 相同模式嘅段落開頭 | 6/6完全一樣 | 日文中仍然係5/5——見下文 |
| 越南/日本關聯保留 | 1/4存活(review刪除咗3個) | 11/11存活 |
| 主持口吻cross-contamination | 雙方互相使用對方嘅phrase | 清晰分離 |
口頭禪quota、反老作規則同localization保留都已經奏效。主持profile而家能夠足夠清晰咁表達每位主持嘅個性,LLM唔再混淆邊個該講咩。
仲有邊啲問題
有一條規則仍然fail:結構多樣性。對話指南話「5個段落中至少有2個必須使用唔同嘅結構入口。」Fix後,日文episode仍然以完全一樣嘅方式打開每一個段落:「いやー、健一さん!」——一集裏面出現咗五次。
呢個唔係prompt enforcement嘅問題。呢個係architecture嘅問題。
Generation step獨立生成每個segment。Segment 3唔知道segment 1同2係以情緒化主持嘅口頭禪開頭嘅。每個segment都用同一個對話指南獨立生成,所以每個segment都做出同樣嘅「用情緒化主持開場」嘅決定。
Review step理應能夠發現呢一點——佢可以同時睇到完整script。而且我都加咗明確嘅enforcement language,要求佢變化開場方式。但係run review嘅Gemini 3.5 Flash顯然覺得重組segment開場比削減口頭禪或者soften老作聲明更困難。開場嘅多樣性需要regenerate部分內容,而唔係單單trim或者remove。呢個對model嚟講係更heavy嘅task。
我仲喺度處理緊呢個問題——可能需要更強嘅review model,或者重新設計pipeline structure,令segment之間share開場狀態。更廣泛嘅啟示係:**prompt enforcement冇辦法fix architecture問題。**如果pipeline structure本身令規則無法被遵守,喺prompt度寫再多「CRITICAL」或者「MANDATORY」都救唔到你。
Framework:每條規則問自己三個問題
經過今次經驗,我而家對每一個system prompt都用三個問題做audit:
1. 呢條規則放喺邊度——generation定係review? 關於個性同tone嘅規則放喺generation。關於compliance、consistency同structure嘅規則放喺review。如果一條規則同時涉及兩者(例如口頭禪——佢係個性嘅體現但需要限制),就兩邊都放。
2. 呢條規則嘅措辭係context定係command? 「呢啲係口頭禪」係context。「每條最多2次」係command。同一條規則需要兩種形式——generation step需要知道口頭禪係咩,review step需要強制執行佢哋出現嘅frequency。
3. 個pipeline真係能夠執行呢條規則嗎? 逐segment生成冇辦法強制執行跨segment嘅多樣性。任何prompt都無法解決呢個問題。你需要將規則移到review step(能夠睇到完整script),或者重新設計pipeline,令segment之間share狀態。
呢個framework唔單止適用於podcast generation。佢適用於任何multi-step LLM pipeline——content generation、code review、document summarization,任何有單獨嘅generation同quality control pass嘅場景。
我仲喺度持續iterate緊,但如果你正在build你嘅第一個multi-step LLM pipeline:至少分成兩個step。第一個step帶着個性同自由度生成——畀佢context、example、tone guidance。第二個step帶着精確性同enforcement review——畀佢明確嘅limit、compliance check同修改嘅authority。
Generation step應該好似同creative collaborator做briefing咁。Review step應該好似將checklist交畀editor咁。
而當你兩樣都做咗之後,規則仍然被無視,先問architecture嘅問題。係prompt嘅問題,定係pipeline嘅問題?
常見問題
呢個對單一prompt setup(冇pipeline)適用嗎?
適用,但作用有限。喺單一prompt度,你要求同一個model同時具有創造性同compliance——兩者衝突時,創造性永遠贏compliance。即使喺單一prompt度,將instruction分成「context」section同明確嘅「constraint」section都有幫助。但係天花板係存在嘅。兩個帶住唔同instruction嘅獨立call幾乎總是優於一次。
你點解唔直接將generation prompt嘅規則寫得更強硬?
我試過。我加咗「MANDATORY」、「CRITICAL」、「NEVER」,全大寫寫滿晒。Generation step有太多互相競爭嘅demand——佢要同時做到engaging、聽落natural、diverse、locally authentic,仲要compliant。當個model必須喺「聽落似一個興奮嘅越南football fan」同「只講兩次'Trời ơi'」之間做選擇嗰陣,個性永遠贏。Review step冇呢種衝突——佢唯一嘅job就係enforce。
Review step用緊咩model?
Gemini 3.5 Flash(出於cost考慮——review喺7種語言所有episode上行)。佢能夠好好處理簡單嘅enforcement(削減口頭禪、soften老作stat)。但佢喺需要content regeneration嘅task上吃力,例如重組segment開場。更強嘅model會有幫助,但我仲未能夠justify個cost。
我利用夜晚同weekend solo開發DIALØGUE(對話)——一個AI podcast平台。口頭禪extraction同review prompt修改嘅code係open source嘅——你可以喺我嘅Podcast Engine repo度睇到完整嘅system prompt同enforcement logic。我喺度記錄一路上學到嘅嘢。
如果你遇過類似嘅問題——規則被讀取但冇被執行——我好有興趣想知:嗰條規則係咩,佢喺你個pipeline嘅邊個位置?
就係咁多啦。
祝好,Chandler