
先說結(jié)論Prompt 是 Agent 的操作系統(tǒng)。不是夸張 — Agent 的每一次決策、執(zhí)行、校驗都靠 Prompt 告訴 LLM 你是誰、做什么、怎么做、不能做什么。Prompt 寫得好Agent 就聰明Prompt 寫得亂Agent 就胡說八道。工程化的第一步模板化配置 變量注入。把 Prompt 從代碼里抽出來變成可配置、可版本管理的模板文件。一、System Prompt vs User Prompt角色分工LLM 的每次調(diào)用都有兩個 Prompt 槽位分工明確System Prompt告訴 LLM 你是誰定義角色身份、專業(yè)領(lǐng)域、行為邊界。LLM 會以此為世界觀來約束自己的輸出。你是一位美妝賽道的干貨科普專家風(fēng)格親和口語化。這一句話做了三件事角色干貨科普專家不是銷售、不是評測博主領(lǐng)域美妝賽道不會聊投資、不會聊健身風(fēng)格親和口語化不會寫論文腔User Prompt告訴 LLM 做什么具體的任務(wù)指令 上下文數(shù)據(jù)。每次調(diào)用都不同。標題夏季防曬的5個誤區(qū) 選題方向夏季防曬推薦 風(fēng)格約束語氣親和emoji中頻 請創(chuàng)作正文內(nèi)容。為什么分兩層System PromptUser Prompt角色定義身份下達任務(wù)變化頻率同一人設(shè)不變每次調(diào)用都變存儲位置模板文件代碼動態(tài)拼接類比操作系統(tǒng)應(yīng)用程序關(guān)鍵原則System Prompt 越穩(wěn)定LLM 的行為越一致。User Prompt 越具體LLM 的輸出越精準。二、Prompt 的模板化從硬編碼到配置文件反面教材Prompt 寫死在代碼里# ? 硬編碼改一個詞要改代碼、發(fā)版 result await llm.generate( system_prompt你是一位美妝賽道的干貨科普專家風(fēng)格親和口語化。, user_promptf請寫一篇關(guān)于{topic}的文章, )問題想改親和口語化為犀利直白 → 改代碼 → 提交 → 發(fā)版想加一條禁忌不要用眾所周知 → 改代碼 → 提交 → 發(fā)版想給不同賽道用不同 Prompt → if/else 堆積 → 代碼膨脹正面教材模板文件 變量注入項目中的prompts/body_generation.md你是一位{{ niche }}賽道的{{ persona_type }}風(fēng)格{{ writing_style }}。 ? # 任務(wù) 基于選題和標題創(chuàng)作一篇{{ content_format }}正文。 ? # 結(jié)構(gòu)要求 1. 開篇抓住眼球3秒內(nèi)留住讀者 2. 核心干貨分3-5段每段一個小標題干貨內(nèi)容 3. 總結(jié)收尾簡潔總結(jié)輕引導(dǎo)互動 ? # 風(fēng)格約束 - 語氣{{ writing_style }} - emoji頻率{{ emoji_frequency }} - 嚴格遵循禁忌規(guī)則 - 不要使用AI生硬書面語保持自媒體口語化表達{{ niche }}、{{ writing_style }}是 Jinja2 占位符運行時由代碼注入真實值。模板化的好處改 Prompt 不改代碼直接編輯.md文件不同人設(shè)自動適配美妝人設(shè)注入niche美妝職場人設(shè)注入niche職場Prompt 可以版本管理、Code Review、A/B 測試模板引擎PromptManager項目用 Jinja2 做 Prompt 模板渲染核心代碼llm/prompt.pyclass PromptManager: def __init__(self, prompts_dir: str prompts): self.env Environment( loaderFileSystemLoader(str(self.prompts_dir)), keep_trailing_newlineTrue, ) ? def get_template(self, name: str) - str: 獲取原始模板不渲染 template self.env.get_template(f{name}.md) return template.render() ? def render(self, name: str, **kwargs: str) - str: 渲染模板占位符 → 真實值 template self.env.get_template(f{name}.md) return template.render(**kwargs)調(diào)用方式# 獲取 System Prompt模板已渲染占位符 system_prompt prompt_mgr.get_template(body_generation) ? # 或者動態(tài)渲染 rendered prompt_mgr.render(body_generation, niche美妝, writing_style親和口語化)三、Prompt 的多段式像搭積木一樣組裝一個好的 Prompt 不是一段文字而是多段組裝每段有明確職責(zé)角色設(shè)定 任務(wù)描述 約束條件 輸出格式項目中的實戰(zhàn)正文生成的完整 Prompt 拼裝content/body.py中的generate_text()方法展示了 User Prompt 如何多段組裝user_prompt ( # ━━ 第1段上下文信息 ━━ f賽道{persona.niche}\n f人設(shè)類型{persona.persona_type}\n f文案風(fēng)格{persona.writing_style}\n f內(nèi)容形式{persona.content_format}\n\n ? # ━━ 第2段任務(wù)數(shù)據(jù) ━━ f標題{title}\n f選題方向{topic.title}\n f選題分類{topic.category}\n\n ? # ━━ 第3段結(jié)構(gòu)約束 ━━ f結(jié)構(gòu)要求\n f1. 開篇{opening_rendered}\n f2. 核心干貨分3-5段每段一個小標題干貨內(nèi)容\n f3. 總結(jié)收尾{closing_rendered}\n f4. 段落字數(shù)≤{persona.paragraph_max_chars}字\n\n ? # ━━ 第4段風(fēng)格約束 ━━ f風(fēng)格約束\n f- 語氣{persona.writing_style}\n f- emoji頻率{persona.emoji_frequency}\n f- 禁忌{banned_rules}\n\n ) ? # ━━ 第5段風(fēng)格畫像動態(tài)注入 ━━ style_hint StyleLearner.build_style_hint(persona) if style_hint: user_prompt style_hint \n\n ? # ━━ 第6段執(zhí)行指令 ━━ user_prompt 請創(chuàng)作正文內(nèi)容。6段式 Prompt每段職責(zé)清晰段職責(zé)變化頻率來源上下文信息告訴LLM當前環(huán)境每個人設(shè)不同PersonaConfig任務(wù)數(shù)據(jù)具體要處理的內(nèi)容每篇文章不同Topic Title結(jié)構(gòu)約束輸出的格式要求相對人設(shè)穩(wěn)定PersonaConfig風(fēng)格約束輸出的風(fēng)格限制相對人設(shè)穩(wěn)定PersonaConfig風(fēng)格畫像從修改中學(xué)習(xí)的偏好隨使用積累StyleLearner執(zhí)行指令最終的動作指令固定硬編碼為什么不能寫成一段試想如果把上面6段揉成一段你是美妝專家寫一篇關(guān)于夏季防曬的文章風(fēng)格親和emoji中頻 不要用眾所周知你之前3次要求語氣活潑段落別太長 開篇要抓眼球結(jié)尾要引導(dǎo)互動請創(chuàng)作正文內(nèi)容。LLM 看到這一坨大概率會遺漏一半約束。分段 標題 編號 LLM 能逐條遵循。四、約束的藝術(shù)禁忌規(guī)則怎么寫Prompt 中最容易被忽略、但最影響質(zhì)量的部分 —禁忌規(guī)則。項目中的禁忌規(guī)則構(gòu)建def _build_banned_rules(self, persona: PersonaConfig) - str: rules [] if persona.banned_words: rules.append(f禁止使用{, .join(persona.banned_words)}) if persona.banned_topics: rules.append(f禁止涉及{, .join(persona.banned_topics)}) # 通用禁忌 rules.append(禁止使用眾所周知、不言而喻等AI書面語) rules.append(禁止編造數(shù)據(jù)或引用不存在的來源) return .join(rules)禁忌規(guī)則的三層設(shè)計人設(shè)級禁忌banned_wordsbanned_topics每個人設(shè)不同通用禁忌所有賽道都適用的規(guī)則不編造數(shù)據(jù)、不用AI書面語風(fēng)格畫像禁忌從修改記錄中學(xué)到的偏好我之前3次要求減少emoji踩坑禁忌太松 vs 太嚴太松LLM 編造數(shù)據(jù)、用眾所周知、寫論文腔 → 讀者一眼看出是AI太嚴禁了太多詞LLM 無話可說 → 輸出空洞解法禁AI書面語不禁專業(yè)術(shù)語禁編造數(shù)據(jù)不禁引用常識五、輸出格式約束讓LLM輸出結(jié)構(gòu)化數(shù)據(jù)Prompt 最后一段通常是輸出格式要求這直接決定下游代碼能不能解析。選題生成要求JSON輸出prompts/topic_generation.md的末尾# 輸出格式 JSON對象 { topics: [ { title: 選題方向, category: knowledge/pitfall/comparison/tutorial/experience, content_format: 適配內(nèi)容形式, estimated_potential: high/medium/low } ] }標題生成要求JSON數(shù)組 額外字段prompts/title_generation.md的末尾# 輸出格式 JSON數(shù)組[{title: ..., formula_type: ..., estimated_ctr: 0.0-1.0}]為什么必須指定輸出格式不指定指定LLM 可能返回一整段散文返回結(jié)構(gòu)化JSON下游代碼無法解析json.loads()直接用每次格式不同格式穩(wěn)定可預(yù)期但即使指定了JSONLLM也可能返回 json 代碼塊所以下游一定要加容錯解析# 容錯解析去掉 markdown 代碼塊 result result.strip() if result.startswith(): lines result.split(\n) lines [l for l in lines if not l.startswith()] result \n.join(lines).strip() data json.loads(result)六、風(fēng)格畫像注入Prompt 的動態(tài)進化這是項目中最有Agent味的 Prompt 設(shè)計 —風(fēng)格畫像不是寫死在模板里的是從修改記錄中動態(tài)學(xué)習(xí)、動態(tài)注入的。# content/body.py — 風(fēng)格畫像注入 from ..persona.style_learner import StyleLearner style_hint StyleLearner.build_style_hint(persona) if style_hint: user_prompt style_hint \n\n當人設(shè)積累了風(fēng)格畫像后Prompt 會自動多出一段【風(fēng)格畫像】 傾向于活潑口語化表達emoji使用克制喜歡用數(shù)據(jù)支撐觀點段落簡短有力 【風(fēng)格偏好提醒】 - 語氣活潑我之前 3 次要求此調(diào)整 - emoji低頻我之前 2 次要求此調(diào)整這不是開發(fā)者寫的 Prompt是 Agent 自己從用戶行為中學(xué)到的 Prompt。這就是 Agent 和普通軟件的本質(zhì)區(qū)別 — Agent 的 Prompt 會進化。踩坑總結(jié)坑根因修復(fù)Prompt 寫死在代碼里沒有模板化抽成.md模板文件 Jinja2 渲染改一個詞要改代碼發(fā)版Prompt 和邏輯耦合Prompt 獨立文件代碼只負責(zé)注入變量LLM 輸出格式不穩(wěn)定沒有指定輸出格式Prompt 末尾加 JSON schema 約束LLM 返回 json 代碼塊LLM 的 markdown 習(xí)慣加容錯解析去掉代碼塊標記禁忌太松AI書面語滿天飛通用禁忌缺失加禁止AI書面語通用規(guī)則風(fēng)格每次隨機Prompt 沒有記憶風(fēng)格畫像動態(tài)注入 Prompt經(jīng)驗總結(jié)Prompt 是 Agent 的操作系統(tǒng)System Prompt 定義身份User Prompt 下達任務(wù)兩者分工明確模板化 變量注入是工程化的第一步改 Prompt 不改代碼不同人設(shè)自動適配多段式 Prompt 角色設(shè)定 任務(wù)描述 約束條件 輸出格式分段越清晰LLM 遵循越好下篇預(yù)告下一篇講Pydantic 數(shù)據(jù)建模— 給 Agent 裝上結(jié)構(gòu)化思維讓 LLM 的輸出不再胡說八道。