先说结论Prompt 是 Agent 的操作系统。不是夸张 — Agent 的每一次决策、执行、校验都靠 Prompt 告诉 LLM 你是谁、做什么、怎么做、不能做什么。Prompt 写得好Agent 就聪明Prompt 写得乱Agent 就胡说八道。工程化的第一步模板化配置 变量注入。把 Prompt 从代码里抽出来变成可配置、可版本管理的模板文件。一、System Prompt vs User Prompt角色分工LLM 的每次调用都有两个 Prompt 槽位分工明确System Prompt告诉 LLM 你是谁定义角色身份、专业领域、行为边界。LLM 会以此为世界观来约束自己的输出。你是一位美妆赛道的干货科普专家风格亲和口语化。这一句话做了三件事角色干货科普专家不是销售、不是评测博主领域美妆赛道不会聊投资、不会聊健身风格亲和口语化不会写论文腔User Prompt告诉 LLM 做什么具体的任务指令 上下文数据。每次调用都不同。标题夏季防晒的5个误区 选题方向夏季防晒推荐 风格约束语气亲和emoji中频 请创作正文内容。为什么分两层System PromptUser Prompt角色定义身份下达任务变化频率同一人设不变每次调用都变存储位置模板文件代码动态拼接类比操作系统应用程序关键原则System Prompt 越稳定LLM 的行为越一致。User Prompt 越具体LLM 的输出越精准。二、Prompt 的模板化从硬编码到配置文件反面教材Prompt 写死在代码里# ❌ 硬编码改一个词要改代码、发版 result await llm.generate( system_prompt你是一位美妆赛道的干货科普专家风格亲和口语化。, user_promptf请写一篇关于{topic}的文章, )问题想改亲和口语化为犀利直白 → 改代码 → 提交 → 发版想加一条禁忌不要用众所周知 → 改代码 → 提交 → 发版想给不同赛道用不同 Prompt → if/else 堆积 → 代码膨胀正面教材模板文件 变量注入项目中的prompts/body_generation.md你是一位{{ niche }}赛道的{{ persona_type }}风格{{ writing_style }}。 # 任务 基于选题和标题创作一篇{{ content_format }}正文。 # 结构要求 1. 开篇抓住眼球3秒内留住读者 2. 核心干货分3-5段每段一个小标题干货内容 3. 总结收尾简洁总结轻引导互动 # 风格约束 - 语气{{ writing_style }} - emoji频率{{ emoji_frequency }} - 严格遵循禁忌规则 - 不要使用AI生硬书面语保持自媒体口语化表达{{ niche }}、{{ writing_style }}是 Jinja2 占位符运行时由代码注入真实值。模板化的好处改 Prompt 不改代码直接编辑.md文件不同人设自动适配美妆人设注入niche美妆职场人设注入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)调用方式# 获取 System Prompt模板已渲染占位符 system_prompt prompt_mgr.get_template(body_generation) # 或者动态渲染 rendered prompt_mgr.render(body_generation, niche美妆, writing_style亲和口语化)三、Prompt 的多段式像搭积木一样组装一个好的 Prompt 不是一段文字而是多段组装每段有明确职责角色设定 任务描述 约束条件 输出格式项目中的实战正文生成的完整 Prompt 拼装content/body.py中的generate_text()方法展示了 User Prompt 如何多段组装user_prompt ( # ━━ 第1段上下文信息 ━━ f赛道{persona.niche}\n f人设类型{persona.persona_type}\n f文案风格{persona.writing_style}\n f内容形式{persona.content_format}\n\n # ━━ 第2段任务数据 ━━ f标题{title}\n f选题方向{topic.title}\n f选题分类{topic.category}\n\n # ━━ 第3段结构约束 ━━ f结构要求\n f1. 开篇{opening_rendered}\n f2. 核心干货分3-5段每段一个小标题干货内容\n f3. 总结收尾{closing_rendered}\n f4. 段落字数≤{persona.paragraph_max_chars}字\n\n # ━━ 第4段风格约束 ━━ f风格约束\n f- 语气{persona.writing_style}\n f- emoji频率{persona.emoji_frequency}\n f- 禁忌{banned_rules}\n\n ) # ━━ 第5段风格画像动态注入 ━━ style_hint StyleLearner.build_style_hint(persona) if style_hint: user_prompt style_hint \n\n # ━━ 第6段执行指令 ━━ user_prompt 请创作正文内容。6段式 Prompt每段职责清晰段职责变化频率来源上下文信息告诉LLM当前环境每个人设不同PersonaConfig任务数据具体要处理的内容每篇文章不同Topic Title结构约束输出的格式要求相对人设稳定PersonaConfig风格约束输出的风格限制相对人设稳定PersonaConfig风格画像从修改中学习的偏好随使用积累StyleLearner执行指令最终的动作指令固定硬编码为什么不能写成一段试想如果把上面6段揉成一段你是美妆专家写一篇关于夏季防晒的文章风格亲和emoji中频 不要用众所周知你之前3次要求语气活泼段落别太长 开篇要抓眼球结尾要引导互动请创作正文内容。LLM 看到这一坨大概率会遗漏一半约束。分段 标题 编号 LLM 能逐条遵循。四、约束的艺术禁忌规则怎么写Prompt 中最容易被忽略、但最影响质量的部分 —禁忌规则。项目中的禁忌规则构建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(禁止编造数据或引用不存在的来源) return .join(rules)禁忌规则的三层设计人设级禁忌banned_wordsbanned_topics每个人设不同通用禁忌所有赛道都适用的规则不编造数据、不用AI书面语风格画像禁忌从修改记录中学到的偏好我之前3次要求减少emoji踩坑禁忌太松 vs 太严太松LLM 编造数据、用众所周知、写论文腔 → 读者一眼看出是AI太严禁了太多词LLM 无话可说 → 输出空洞解法禁AI书面语不禁专业术语禁编造数据不禁引用常识五、输出格式约束让LLM输出结构化数据Prompt 最后一段通常是输出格式要求这直接决定下游代码能不能解析。选题生成要求JSON输出prompts/topic_generation.md的末尾# 输出格式 JSON对象 { topics: [ { title: 选题方向, category: knowledge/pitfall/comparison/tutorial/experience, content_format: 适配内容形式, estimated_potential: high/medium/low } ] }标题生成要求JSON数组 额外字段prompts/title_generation.md的末尾# 输出格式 JSON数组[{title: ..., formula_type: ..., estimated_ctr: 0.0-1.0}]为什么必须指定输出格式不指定指定LLM 可能返回一整段散文返回结构化JSON下游代码无法解析json.loads()直接用每次格式不同格式稳定可预期但即使指定了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)六、风格画像注入Prompt 的动态进化这是项目中最有Agent味的 Prompt 设计 —风格画像不是写死在模板里的是从修改记录中动态学习、动态注入的。# content/body.py — 风格画像注入 from ..persona.style_learner import StyleLearner style_hint StyleLearner.build_style_hint(persona) if style_hint: user_prompt style_hint \n\n当人设积累了风格画像后Prompt 会自动多出一段【风格画像】 倾向于活泼口语化表达emoji使用克制喜欢用数据支撑观点段落简短有力 【风格偏好提醒】 - 语气活泼我之前 3 次要求此调整 - emoji低频我之前 2 次要求此调整这不是开发者写的 Prompt是 Agent 自己从用户行为中学到的 Prompt。这就是 Agent 和普通软件的本质区别 — Agent 的 Prompt 会进化。踩坑总结坑根因修复Prompt 写死在代码里没有模板化抽成.md模板文件 Jinja2 渲染改一个词要改代码发版Prompt 和逻辑耦合Prompt 独立文件代码只负责注入变量LLM 输出格式不稳定没有指定输出格式Prompt 末尾加 JSON schema 约束LLM 返回 json 代码块LLM 的 markdown 习惯加容错解析去掉代码块标记禁忌太松AI书面语满天飞通用禁忌缺失加禁止AI书面语通用规则风格每次随机Prompt 没有记忆风格画像动态注入 Prompt经验总结Prompt 是 Agent 的操作系统System Prompt 定义身份User Prompt 下达任务两者分工明确模板化 变量注入是工程化的第一步改 Prompt 不改代码不同人设自动适配多段式 Prompt 角色设定 任务描述 约束条件 输出格式分段越清晰LLM 遵循越好下篇预告下一篇讲Pydantic 数据建模— 给 Agent 装上结构化思维让 LLM 的输出不再胡说八道。