Prompt工程化实战:System四段式、五块积木与工具描述五件套
如果你还在用“请扮演一个专家帮我写一篇关于XX的文章”这样的简单指令与大模型对话然后对生成结果反复修改、来回拉扯那么你可能已经浪费了太多时间在低效的“人肉调试”上。这就像用记事本写代码每次运行都靠猜。真正的效率提升来自于将 Prompt 当作可管理、可复用、可迭代的“代码”来对待。今天我们不再讨论零散的 Prompt 技巧而是深入一套经过实战检验的工程化方法System 四段式、五块积木与工具描述五件套。这套方法的核心价值在于它将一次性的、模糊的对话指令转变为结构清晰、职责明确、易于版本管理的“工程资产”。无论是构建一个复杂的 AI Agent还是开发一个稳定的文本生成服务你都能像管理代码库一样管理你的 Prompt 体系。读完本文你将能理解并应用System Prompt 的四段式结构让模型角色定位清晰、行为稳定。掌握Prompt 的五块积木模型像搭乐高一样组合出功能强大的指令。学会为 AI 工具编写标准的“五件套”描述实现工具的精准调用。建立一套基于 Git 的Prompt 版本管理与协作流程告别混乱。1. 为什么你的 Prompt 总是“跑偏”从对话到工程的思维转变很多开发者在初次接触大模型时容易陷入一个误区把与模型的交互看作是一次性的、自由的“聊天”。这种模式下产生的 Prompt 往往是临时的、高度依赖上下文的、且难以复现的。典型问题场景结果不稳定同样的任务今天效果好明天效果差你无法确定是模型更新了还是你的描述有歧义。难以协作你写了一个很棒的 Prompt交给同事他稍微改几个词效果天差地别。没有标准就无法讨论和优化。无法迭代你想优化一个总结报告的 Prompt但改了十版后已经记不清哪一版在什么场景下最有效。工具调用混乱你让模型“查一下天气”它可能直接编造或者调用错误的工具因为你没有清晰地告诉它“工具是什么”以及“何时用”。这些问题的根源在于我们缺乏对 Prompt 的结构化设计和工程化管理。本文将介绍的“四段式”、“五块积木”和“五件套”正是为了解决这些问题而生。它们不是魔法而是一套严谨的、可落地的工程框架。2. 基石System Prompt 的四段式结构System Prompt 是对话的“宪法”它定义了 AI 的底层身份、行为准则和知识边界。一个混乱的 System Prompt 会导致整个对话的失控。我们将其拆解为四个逻辑段落每段承担明确职责。2.1 第一段角色与核心职责定义这部分回答“你是谁”和“你主要干什么”。要具体、唯一避免宽泛。反面示例“你是一个有帮助的助手。”过于模糊正面示例“你是‘代码安全审计专家’AI专门负责分析用户提供的代码片段识别潜在的安全漏洞如SQL注入、XSS、命令注入等并提供修复建议和代码示例。”# 在配置文件中或作为初始化参数 system_prompt_segment_1: | 角色金融数据分析师 核心职责 1. 解读用户提供的财务报表利润表、资产负债表、现金流量表。 2. 计算关键财务比率如流动比率、负债权益比、毛利率。 3. 基于历史数据指出趋势性风险和潜在机会。 4. 所有分析必须基于提供的数据不做无依据的推测。2.2 第二段工作流程与约束条件这部分定义“你怎么做”和“什么不能做”。设定清晰的步骤和边界是稳定输出的关键。流程可以要求模型遵循“理解问题-检索知识-分析-输出-自检”的步骤。约束包括输出格式JSON、Markdown、长度限制、禁用内容、事实核查要求等。system_prompt_segment_2: | 工作流程 1. 首先确认你完全理解用户的问题和数据。 2. 其次严格按照核心职责中的方法进行分析。 3. 然后将分析结果组织成“结论-依据-建议”的结构。 4. 最后检查输出是否满足以下所有约束条件。 约束条件 - 输出格式必须使用Markdown表格和列表。 - 语言仅使用中文。 - 事实性如果数据不足以得出结论必须明确声明“数据不足”。 - 安全性不得生成任何投资建议仅提供分析。2.3 第三段沟通风格与交互范式这部分塑造 AI 的“性格”和对话方式影响用户体验。风格可以是专业严谨、简洁直接、鼓励启发式等。交互范式例如是否主动提问澄清如何处理模糊请求system_prompt_segment_3: | 沟通风格 - 保持专业、冷静、客观的语气。 - 使用行业术语但同时对关键术语提供简短解释。 - 对复杂分析分步骤说明。 交互范式 - 如果用户请求不清晰或数据缺失关键字段主动提出最多一个澄清性问题。 - 在给出最终答案前可以简要概述你的分析思路。2.4 第四段知识截止与免责声明这部分管理期望明确 AI 的能力边界减少法律和事实性风险。知识截止明确声明训练数据的截止日期。免责声明说明内容的局限性建议用户进行二次核实。system_prompt_segment_4: | 知识截止我的知识更新至2024年7月。此后的市场动态、政策法规可能未被涵盖。 免责声明我的分析基于您提供的数据和公开的财务分析模型仅供参考不构成任何决策依据。对于重大财务决策请咨询持牌专业顾问。将这四段组合起来就是一个强大且稳定的 System Prompt。在代码中你可以将它们拼接成一个字符串。# 示例在Python中构建完整的System Prompt def build_system_prompt(): segments [ system_prompt_segment_1, system_prompt_segment_2, system_prompt_segment_3, system_prompt_segment_4 ] full_system_prompt “\n\n”.join(segments) # 用两个换行连接各段 return full_system_prompt # 用于初始化OpenAI等Chat模型 from openai import OpenAI client OpenAI() response client.chat.completions.create( model“gpt-4”, messages[ {“role”: “system”, “content”: build_system_prompt()}, {“role”: “user”, “content”: “请分析这份利润表...”} ] )3. 构建User Prompt 的五块积木模型如果说 System Prompt 是宪法那么 User Prompt用户指令就是具体的“法律条文”或“项目需求”。我们将其分解为五块可组合的“积木”确保每次请求都信息完备。3.1 积木一核心指令这是 Prompt 的“主谓宾”必须清晰、无歧义。使用祈使句或明确的任务描述。差“做个总结。”好“总结以下会议纪要的核心决议事项、负责人及截止日期。”3.2 积木二上下文信息提供任务相关的背景信息将模型置于正确的“情境”中。这是 Few-shot Learning 的关键。示例“我们正在开发一个电商推荐系统。以下是用户‘张三’过去一个月的浏览和购买记录[数据]。当前季节是夏季。”3.3 积木三输入数据需要模型处理的具体材料。务必与核心指令对应。示例“需要你处理的文本是[这里粘贴完整的会议纪要文本]”3.4 积木四输出规范明确限定输出的格式、结构、长度、语言等。这是获得可直接使用结果的关键。示例“请以 JSON 格式输出包含resolutions数组、owners字典、deadlines数组三个字段。使用中文。”3.5 积木五示例与示范提供一个或几个输入-输出对Few-shot让模型精准模仿。对于复杂或易错任务尤其有效。示例“例如对于输入‘会议讨论了项目A延期决定由小李负责下周复查’输出应为{\”resolutions\”: [\”项目A延期复查\”], \”owners\”: {\”项目A延期复查\”: \”小李\”}, \”deadlines\”: [\”下周五\”]}”五块积木组合实战 假设我们要构建一个“技术博客标题优化器”的 User Prompt。# 这是一个结构化的Prompt定义可以存入JSON/YAML文件 user_prompt_template: 核心指令: “为给定的技术博客主题生成3个吸引人的CSDN风格标题。” 上下文信息: “目标读者是中国的初中级开发者。平台是CSDN标题需要包含关键词吸引点击同时不失专业性。” 输入数据: “博客主题{blog_topic}” 输出规范: “1. 输出必须是一个Python列表list格式包含三个字符串。2. 每个标题长度在15-25字之间。3. 标题需包含主题中的核心关键词。” 示例与示范: | 输入主题“Python列表推导式详解” 输出示例[【深度解析】Python列表推导式从入门到精通提升代码效率必备, “别再for循环了一篇文章掌握Python列表推导式所有技巧” “Python列表推导式的10个实用场景让你的代码更Pythonic”]在代码中我们可以这样使用这个模板import json def generate_blog_titles(topic: str) - list: # 加载Prompt模板可从文件读取 with open(‘prompt_templates/blog_title_generator.json’, ‘r’) as f: template json.load(f)[‘user_prompt_template’] # 构建完整User Prompt user_prompt f“”” {template[‘核心指令’]} {template[‘上下文信息’]} 输入数据博客主题{topic} {template[‘输出规范’]} 参考示例 {template[‘示例与示范’]} “”” # 调用模型此处为模拟 # response client.chat.completions.create(...) # 假设返回的文本是 ‘[“标题1”, “标题2”, “标题3”]’ simulated_response ‘[“实战指南System Prompt四段式设计让你的AI角色稳定输出” “Prompt工程化五块积木法从此告别与模型的无效沟通” “像管理代码一样管理Prompt版本控制与团队协作全流程”]’ try: titles json.loads(simulated_response) return titles except json.JSONDecodeError: # 如果模型未返回标准JSON可进行后处理或重试 return [“格式解析失败请检查模型输出。”] # 使用 titles generate_blog_titles(“Prompt工程化与版本管理”) for i, title in enumerate(titles, 1): print(f“{i}. {title}”)4. 赋能工具描述的“五件套”当你的 AI 应用需要调用外部 API、查询数据库或执行特定函数时如 Function Calling 或 Tool Calling清晰、标准的工具描述至关重要。混乱的工具描述会导致模型不理解、调用错误或参数缺失。我们将其标准化为五个部分。4.1 名称简洁、具象的动词名词组合反映工具核心功能。好get_current_weather,search_technical_docs差tool_1,query4.2 描述用一两句话说明工具做什么、解决什么问题。这是模型决定是否调用该工具的主要依据。示例“根据城市名称查询该城市当前的天气情况。用于回答用户关于天气的询问。”4.3 参数规范明确定义每个参数的名称、类型、描述以及是否必需。使用 JSON Schema 风格。关键描述要说明“这个参数是什么”例如“城市名称必须是完整的中国城市名如‘北京市’、‘上海市’。”4.4 返回说明描述工具成功调用后的返回结果格式和含义。帮助模型理解如何向用户解释结果。示例“返回一个JSON对象包含city城市、temperature温度摄氏度、condition天气状况如‘晴’、‘多云’、humidity湿度百分比字段。”4.5 错误处理说明工具可能遇到的常见错误及模型应如何应对。这能提升交互的鲁棒性。示例“如果城市名称不存在或网络错误工具将返回{‘error’: ‘具体错误信息’}。此时你应该向用户道歉并说明无法获取该城市天气建议用户检查城市名或稍后再试。”五件套完整示例 以下是一个符合 OpenAI Function Calling 格式的“查询股票价格”工具描述。{ “tools”: [ { “type”: “function”, “function”: { “name”: “get_stock_price”, “description”: “根据股票代码Ticker Symbol查询该股票的实时最新价格。用于回答用户关于特定股票价格的询问。”, “parameters”: { “type”: “object”, “properties”: { “symbol”: { “type”: “string”, “description”: “股票代码必须是标准的交易所代码。例如苹果公司为‘AAPL’腾讯控股为‘0700.HK’。对于A股需加上交易所后缀如‘000001.SZ’平安银行。, “enum”: [“AAPL”, “GOOGL”, “0700.HK”, “000001.SZ”, “399001.SZ”] // 可选限定可选范围 }, “currency”: { “type”: “string”, “description”: “返回价格的货币单位。默认为该股票的主要交易货币。”, “default”: “原生货币” } }, “required”: [“symbol”] }, “returns”: { “description”: “返回一个JSON对象包含股票代码、公司名称、最新价格、货币单位、更新时间戳以及与前一日收盘价的涨跌幅。”, “schema”: { “type”: “object”, “properties”: { “symbol”: {“type”: “string”}, “name”: {“type”: “string”}, “price”: {“type”: “number”}, “currency”: {“type”: “string”}, “change_percent”: {“type”: “string”}, “timestamp”: {“type”: “string”, “format”: “date-time”} } } }, “error_handling”: “如果股票代码无效、市场已闭市或API请求失败将返回错误信息。模型应提示用户‘无法获取该股票信息请确认代码是否正确或稍后再试’。” } } ] }在实际调用中returns和error_handling字段可能不被API直接支持但它们是你内部维护工具文档和编写模拟器时不可或缺的部分。核心的name,description,parameters必须严格遵循所用框架如 OpenAI, Anthropic的格式。5. 实战从零构建一个技术文档问答 Agent现在我们将前三部分组合起来构建一个简单的“技术文档智能问答助手”。这个 Agent 能基于给定的技术文档如 API 文档回答用户问题。5.1 定义 System Prompt四段式# system_prompt.yaml role_definition: | 你是“技术文档专家”AI专门负责基于我提供的技术文档片段精准、简洁地回答用户提出的相关问题。你的知识仅限于我提供的文档内容。 workflow_constraints: | 工作流程 1. 仔细阅读并理解我提供的“文档内容”。 2. 严格基于“文档内容”来回答用户的“问题”。 3. 如果答案能在文档中找到确切依据直接引用相关部分。 4. 如果文档内容不足以完全回答问题请明确说明“根据现有文档无法完全确定...”并给出基于文档的最合理推断。 5. 如果问题完全超出文档范围直接回答“该问题超出本次提供的文档范围。” 输出约束 - 答案必须用中文。 - 优先使用列表和要点形式组织答案。 - 必须注明答案在文档中的依据位置例如“见文档第X部分”。 communication_style: | 沟通风格专业、直接、乐于助人。避免不必要的寒暄。 knowledge_disclaimer: | 免责声明我的回答完全基于您本次提供的文档。文档的准确性、时效性由您负责。对于关键的技术决策请务必查阅官方最新文档。5.2 定义 User Prompt 模板五块积木// user_prompt_template.json { “core_instruction”: “请基于以下‘文档内容’回答用户的‘问题’。”, “context”: “你是一名技术文档专家正在帮助同事理解一段API文档。”, “input_data”: “文档内容\n{{document_text}}\n\n用户问题\n{{user_question}}”, “output_spec”: “请按照System Prompt中的要求输出答案。”, “few_shot_example”: { “input”: { “document_text”: “接口GET /api/v1/users\n描述获取用户列表。\n参数page (整数可选默认为1) size (整数可选默认为20最大100)。\n返回包含用户对象数组和分页信息的JSON。”, “user_question”: “怎么获取用户列表最多能一次拿多少条” }, “output”: “根据文档\n1. **调用方式**使用 GET 方法请求 /api/v1/users 接口。见文档‘接口’行\n2. **分页参数**可以使用 page 和 size 参数控制分页size 默认20条。见文档‘参数’行\n3. **最大数量**size 参数最大值限制为100条因此一次最多能获取100条用户数据。见文档‘参数’行” } }5.3 实现 Agent 逻辑# tech_doc_agent.py import yaml import json from openai import OpenAI from typing import Dict, Any class TechDocQAAgent: def __init__(self, api_key: str, model: str “gpt-4-turbo-preview”): self.client OpenAI(api_keyapi_key) self.model model self.system_prompt self._load_system_prompt() self.user_prompt_template self._load_user_prompt_template() def _load_system_prompt(self) - str: with open(‘system_prompt.yaml’, ‘r’, encoding‘utf-8’) as f: data yaml.safe_load(f) # 拼接四段 return “\n\n”.join([ data[‘role_definition’], data[‘workflow_constraints’], data[‘communication_style’], data[‘knowledge_disclaimer’] ]) def _load_user_prompt_template(self) - Dict[str, Any]: with open(‘user_prompt_template.json’, ‘r’, encoding‘utf-8’) as f: return json.load(f) def _build_user_message(self, document_text: str, user_question: str) - str: 使用五块积木构建用户消息 template self.user_prompt_template # 使用模板引擎或简单替换 input_data template[‘input_data’].replace(‘{{document_text}}’, document_text).replace(‘{{user_question}}’, user_question) user_message f“”” {template[‘core_instruction’]} {template[‘context’]} {input_data} {template[‘output_spec’]} 参考示例 输入{json.dumps(template[‘few_shot_example’][‘input’], ensure_asciiFalse)} 输出{template[‘few_shot_example’][‘output’]} “”” return user_message def ask(self, document_text: str, user_question: str) - str: 向Agent提问 user_message self._build_user_message(document_text, user_question) try: response self.client.chat.completions.create( modelself.model, messages[ {“role”: “system”, “content”: self.system_prompt}, {“role”: “user”, “content”: user_message} ], temperature0.1, # 低温度保证输出稳定 max_tokens1000 ) return response.choices[0].message.content except Exception as e: return f“请求模型时出错{str(e)}” # 使用示例 if __name__ “__main__”: # 注意此处需要你的OpenAI API Key agent TechDocQAAgent(api_key“your-api-key-here”) sample_doc “”” 数据库连接配置 - 参数host (字符串数据库服务器地址) - 参数port (整数默认3306) - 参数username (字符串登录用户名) - 参数password (字符串登录密码) - 参数database (字符串要连接的数据库名) - 说明所有参数均为必填项。 “”” question “连接数据库时port是不是必须的默认值是多少” answer agent.ask(sample_doc, question) print(“用户问题”, question) print(“\nAgent回答\n”, answer)5.4 运行与验证运行上述tech_doc_agent.py脚本需配置正确的 API Key你应当会得到类似以下的输出用户问题 连接数据库时port是不是必须的默认值是多少 Agent回答 根据文档 1. **参数必要性**文档中明确指出“所有参数均为必填项”因此 port 参数是必须提供的。见文档“说明”行 2. **默认值**文档中说明 port 参数的默认值是 3306。见文档“参数port”行 3. **结论**在配置时port 必须填写但如果你不填写具体值系统可能会使用其默认值3306。然而根据“所有参数均为必填项”的说明最稳妥的方式是显式指定 port 值即使它是3306。这个回答严格遵循了 System Prompt 的约束基于文档、引用位置、中文、列表形式证明了我们架构的有效性。6. 工程化像管理代码一样管理 Prompt至此我们已经有了结构化的 Prompt 组件。下一步是将其工程化核心就是版本管理。6.1 目录结构建议为 Prompt 工程创建独立的项目目录。prompt-engineering-repo/ ├── README.md ├── system_prompts/ │ ├── technical_expert.yaml │ ├── creative_writer.yaml │ └── customer_service.yaml ├── user_prompt_templates/ │ ├── qa_template.json │ ├── summarization_template.json │ └── code_review_template.json ├── tool_descriptions/ │ ├── weather_tool.json │ ├── stock_tool.json │ └── search_tool.json ├── agents/ │ └── tech_doc_agent.py ├── tests/ │ └── test_tech_doc_agent.py └── .gitignore6.2 版本控制 (Git)初始化仓库git init提交 Prompt 组件将 YAML、JSON 等配置文件纳入版本控制。git add system_prompts/ user_prompt_templates/ tool_descriptions/ git commit -m “feat: add initial prompt components for TechDocQA agent”分支管理为不同的实验或优化创建分支。git checkout -b experiment/improve-summarization-prompt # 修改 user_prompt_templates/summarization_template.json git commit -am “refactor: adjust output format in summarization template”版本标签为稳定版本打 Tag。git tag -a v1.0.0 -m “Stable version of TechDocQA agent prompts”6.3 变更记录与评审在README.md或CHANGELOG.md中记录 Prompt 的变更。# 变更日志 ## [1.0.0] - 2024-05-27 ### 新增 - TechDocQA Agent 全套 System Prompt (四段式) 和 User Prompt 模板 (五块积木)。 - 技术文档问答示例代码。 ### 修改 - 优化了 System Prompt 中“输出约束”的表述使其更清晰。 ### 修复 - 无。团队协作时对system_prompts/和user_prompt_templates/下文件的修改应发起 Pull Request进行代码评审讨论修改是否会影响其他关联的 Agent。6.4 测试与评估为关键 Prompt 编写测试用例确保其行为符合预期。# tests/test_tech_doc_agent.py import pytest from your_agent_module import TechDocQAAgent class MockLLMClient: # 模拟一个总是返回固定答案的客户端 def chat(self, *args, **kwargs): class MockChoice: message type(‘obj’, (object,), {‘content’: ‘根据文档参数port是必填项默认值为3306。见文档“参数port”行’})() class MockResponse: choices [MockChoice()] return MockResponse() def test_agent_answers_from_doc(): agent TechDocQAAgent(api_key“fake”) agent.client MockLLMClient() # 注入模拟客户端 doc “port (整数默认3306)” question “port的默认值是什么” answer agent.ask(doc, question) assert “3306” in answer assert “见文档” in answer print(“测试通过Agent能正确提取文档中的默认值并引用来源。”)7. 常见问题与排查思路在实践上述框架时你可能会遇到以下典型问题。问题现象可能原因排查方式解决方案模型完全忽略 System Prompt1. System Prompt 过长或结构混乱被模型“遗忘”。2. 某些平台或库对 System Prompt 的支持有差异。1. 简化 System Prompt确保核心指令在前100字内。2. 在对话历史中检查 System Prompt 是否被正确传入。1. 使用“四段式”精简内容。2. 查阅所用模型/API的文档确认 System Prompt 的使用方式。模型不遵循输出格式1. 输出规范描述模糊。2. 缺少 Few-shot 示例。3. 模型温度 (temperature) 参数过高。1. 检查“输出规范”积木是否具体如“请输出一个 JSON 对象包含 A, B, C 字段”。2. 查看是否提供了格式正确的示例。1. 强化输出规范使用 JSON Schema 描述。2. 提供1-2个精准的 Few-shot 示例。3. 将temperature调低如0.1。工具调用错误或不被触发1. 工具描述 (description) 不清晰模型不理解何时调用。2. 参数描述 (parameters.description) 含糊。1. 让同事阅读工具描述看是否能准确猜出工具用途和参数。2. 测试时打印出模型收到工具列表后的中间思考过程如果API支持。1. 严格按照“五件套”重写工具描述确保description直白。2. 在parameters.description中举例说明。Prompt 版本混乱效果回退1. 直接修改生产环境 Prompt 文件。2. 没有记录修改原因和效果。1. 检查 Git 历史对比当前版本与之前稳定版本的差异。2. 回顾 CHANGELOG。1.强制所有修改必须通过 Git 分支和 PR 进行。2. 建立 A/B 测试流程用数据评估 Prompt 修改的效果。Few-shot 示例效果不佳1. 示例太少或没有代表性。2. 示例与当前任务差异过大。1. 分析失败案例看是哪种模式没被覆盖。2. 尝试增加示例数量3-5个。1. 精心构造示例覆盖主要任务类型和常见边缘情况。2. 确保示例的输入、输出格式与你的要求完全一致。8. 最佳实践与进阶建议单一职责一个 System Prompt 尽量只定义一个核心角色。不要试图让一个“专家”既写代码又做设计还处理客服。迭代优化将 Prompt 优化视为一个迭代过程。记录每次修改Git Commit并用一组固定的测试用例评估效果。环境隔离区分开发、测试、生产环境的 Prompt。可以使用环境变量或配置文件来加载不同版本的 Prompt。监控与评估在生产环境中对 AI 的输出进行采样和人工评估建立关键指标如准确率、用户满意度持续驱动 Prompt 优化。安全与合规在 System Prompt 的“约束条件”中明确加入内容安全、隐私保护和合规性要求。对于生成内容考虑增加后处理过滤层。性能考量过长的 Prompt尤其是包含大量 Few-shot 示例会增加 Token 消耗和延迟。权衡效果与成本对于常用示例可以考虑通过微调Fine-tuning模型来内化这些知识。通过将 Prompt 视为“代码”采用“四段式”、“五块积木”、“五件套”进行结构化设计并辅以 Git 版本管理你就能建立起一套可靠、可协作、可迭代的 Prompt 工程体系。这不仅能极大提升你与 AI 协作的效率和效果更是构建复杂、可靠 AI 应用不可或缺的工程基础。