prompt engineering 2026 practices

Prompt 工程 2026 最新实践:从技巧到工程化体系

从手工艺到工程化:Prompt 工程的范式转变 2026 年,Prompt 工程已经走过了"调参数式"的手工艺阶段。随着大模型能力边界的不断扩展,Prompt 的设计、测试、部署和维护已经形成了一套完整的工程化体系。根据 Gartner 2026 年 Q1 报告,超过 78% 的企业级 AI 应用已经建立了专门的 Prompt 工程团队,而 2024 年这一比例仅为 23%。 一、Prompt 工程化的核心要素 1.1 结构化 Prompt 架构 现代 Prompt 已从简单的文本指令发展为结构化的工程产物: # prompt-config.yaml prompt: metadata: name: "customer-support-v2" version: "2.3.1" author: "prompt-team" last_updated: "2026-06-15" system_prompt: role: "你是一个专业的客服助手" constraints: - "回答必须基于知识库内容" - "不确定时明确告知用户" - "单次回复不超过500字" knowledge_sources: - "product_docs" - "faq_database" user_template: | 用户问题:{{user_query}} 上下文信息:{{context}} 历史对话:{{history}} expected_output: format: "json" schema: answer: "string" confidence: "float" sources: "array" 1.2 Prompt 生命周期管理 设计 → 测试 → 评审 → 部署 → 监控 → 迭代 ↑ ↓ ←─────────── 反馈循环 ←─────────────← 二、2026 年 Prompt 设计核心原则 2.1 明确性原则(Clarity First) 维度 错误示例 正确示例 角色 “帮我写文章” “你是科技领域资深编辑,擅长将复杂技术概念转化为通俗易懂的文章” 任务 “总结一下” “用3段话总结以下内容,每段不超过100字,重点突出数据和结论” 约束 “写得好一点” “语气专业但不失亲和力,避免使用行业黑话,目标读者是产品经理” 格式 “列出来” “用Markdown表格输出,包含名称、描述、优缺点三列” 2.2 上下文工程(Context Engineering) 2026 年最重要的进化是"上下文工程"概念的兴起——不再只关注单条 Prompt 的措辞,而是整体上下文的构建: ...

2026-06-28 · 4 min · 711 words · 硅基 AGI 探索者
prompt version management

Prompt版本管理实践

引言 Prompt是大语言模型应用的核心资产,但在很多团队中,Prompt的管理方式仍然停留在复制粘贴和聊天记录中。随着Prompt复杂度增长和团队协作需求增加,缺乏版本管理的Prompt会导致:无法追溯变更历史、无法回滚有问题的修改、无法复现线上效果、团队成员各自维护不同版本。本文分享将Prompt纳入专业版本管理的实践方案。 为什么Prompt需要版本管理 Prompt是代码 Prompt与代码有相似的特性:需要迭代调试、存在依赖关系(系统Prompt→Few-Shot示例→用户输入模板)、需要测试验证、可能引入回归问题。因此,Prompt应享受与代码同等的版本管理待遇。 Prompt变更的影响 一个看似微小的Prompt修改可能导致模型行为的显著变化:将"请分析"改为"请详细分析"可能使输出长度翻倍;调整示例顺序可能影响Few-Shot效果;修改约束条件的措辞可能改变模型的遵守程度。没有版本管理,这些变更的影响无法被追踪和评估。 Git工作流设计 仓库结构 prompts/ ├── system/ │ ├── assistant.md # 通用助手系统Prompt │ ├── code-reviewer.md # 代码审查专家 │ └── data-analyst.md # 数据分析师 ├── templates/ │ ├── classification/ # 分类任务模板 │ ├── extraction/ # 信息提取模板 │ └── generation/ # 内容生成模板 ├── few-shot/ │ ├── sentiment/ # 情感分析示例 │ └── ner/ # 命名实体识别示例 ├── tests/ │ ├── test_cases/ # 测试用例 │ ├── expected_outputs/ # 期望输出 │ └── runners/ # 测试运行器 ├── configs/ │ ├── models.yaml # 模型配置 │ └── environments.yaml # 环境配置 └── README.md Prompt文件格式 每个Prompt文件采用统一的格式: ...

2026-06-27 · 3 min · 559 words · 硅基 AGI 探索者
prompt template management system

Prompt模板管理系统设计

引言 当团队从单条Prompt调优走向规模化Prompt管理时,散落在代码和配置文件中的Prompt字符串很快会变成维护噩梦。Prompt模板管理系统是解决这一问题的工程化方案,它将Prompt视为一等公民进行管理,支持版本控制、参数化、A/B测试和效果监控。本文设计一套完整的Prompt模板管理系统架构。 核心需求分析 功能性需求 模板存储与检索:集中存储所有Prompt模板,支持按名称、标签、分类检索 参数化:支持变量插值和条件逻辑,实现模板复用 版本控制:每次修改生成新版本,支持回滚和版本对比 A/B测试:支持多个变体并行运行,自动统计效果指标 权限管理:不同角色(开发者、审阅者、管理员)的权限控制 效果监控:追踪每个模板的使用量、成功率、延迟等指标 非功能性需求 低延迟:模板加载延迟控制在50ms以内 高可用:模板服务可用性99.9%以上 缓存友好:支持本地缓存减少网络请求 SDK友好:提供多语言SDK,简化接入 系统架构 数据模型 Template { id: string // 唯一标识 name: string // 模板名称 category: string // 分类 tags: []string // 标签 description: string // 描述 variables: []Variable // 变量定义 content: string // 模板内容(含变量占位符) version: string // 当前版本号 status: string // draft/review/published/archived created_at: timestamp updated_at: timestamp author: string } Variable { name: string // 变量名 type: string // string/number/boolean/list required: boolean // 是否必填 default: any // 默认值 description: string // 变量说明 } Version { template_id: string version: string content: string changelog: string created_at: timestamp author: string } 模板语言设计 设计轻量级的模板语法,支持变量插值、条件判断和循环: 你是一位{{role}},请完成以下任务: {{#if context}} # 背景 {{context}} {{/if}} # 任务 {{task}} {{#each examples}} 示例{{@index}}: 输入:{{this.input}} 输出:{{this.output}} {{/each}} # 约束 {{#each constraints}} - {{this}} {{/each}} API设计 核心API端点: ...

2026-06-27 · 2 min · 346 words · 硅基 AGI 探索者
agent prompt iteration

Prompt 迭代优化:从经验到工程化

从手工艺到工程:Prompt 优化的范式转变 大多数开发者在接触 LLM 初期,Prompt 优化的方式是这样的:想一个提示词,在几条测试用例上跑一下,看看效果,感觉不错就用,感觉不行就改几个字再试。这种方式本质上是手工艺——依赖个人经验和直觉,难以复制,难以扩展,难以追踪。 当你的应用从 Demo 走向生产,从几个用例变成几千个用例,从单一模型变成多模型对比,这种手工艺方式就会彻底失效。你需要的是一套工程化的 Prompt 迭代流程——有版本管理、有评估指标、有自动化测试、有持续优化机制。 本文将介绍如何建立这样一套系统化的 Prompt 迭代优化流程。 Prompt 即代码:版本管理 为什么需要 Prompt 版本管理 Prompt 是 LLM 应用的"源代码"。和传统代码一样,它需要版本管理来: 追踪每次修改的内容和原因 在新版本出问题时快速回滚 对比不同版本的效果差异 管理不同环境(开发/测试/生产)的 Prompt 实践方案 方案一:Git 仓库管理 将 Prompt 作为结构化文件存储在 Git 仓库中: prompts/ ├── README.md ├── customer_service/ │ ├── v1.0/ │ │ ├── system.txt │ │ ├── user_template.txt │ │ └── config.yaml │ ├── v1.1/ │ │ ├── system.txt │ │ ├── user_template.txt │ │ └── config.yaml │ └── current -> v1.1 ├── code_review/ │ └── ... └── shared/ ├── safety.txt └── format_guidelines.txt 方案二:数据库管理 ...

2026-06-26 · 6 min · 1197 words · 硅基 AGI 探索者
prompt engineering production

Prompt 工程化生产实践:版本管理与 A/B 测试

为什么需要 Prompt 工程化 在原型阶段,Prompt 通常是一个写在代码里的字符串常量。但当应用走向生产,问题开始浮现: 改了一个词,线上效果突然变差,却不知道回退到哪个版本 A/B 测试靠手动切换环境变量,数据散落在日志文件里 新来的同事改了 Prompt,破坏了之前精心设计的 Few-shot 格式 同一个功能有 5 个 Prompt 变体,没人知道哪个在跑 Prompt 工程化的核心目标:让 Prompt 成为可追踪、可测试、可回滚的一等公民。 Prompt 版本管理 目录结构设计 prompts/ ├── config.yaml # 全局配置 ├── chatbot/ # 功能模块 │ ├── meta.yaml # 模块元数据 │ ├── v1.0.0/ # 语义化版本 │ │ ├── system.txt # 系统提示 │ │ ├── few_shot.jsonl # Few-shot 示例 │ │ └── config.yaml # 模型参数 │ ├── v1.1.0/ │ │ ├── system.txt │ │ ├── few_shot.jsonl │ │ └── config.yaml │ └── v2.0.0/ # 大版本变更 │ ├── system.txt │ ├── few_shot.jsonl │ └── config.yaml └── classifier/ └── ... Prompt 注册中心实现 import yaml import json from pathlib import Path from dataclasses import dataclass, field from typing import Any @dataclass class PromptVersion: """单个 Prompt 版本""" name: str version: str system: str few_shot: list[dict] = field(default_factory=list) model: str = "gpt-4o-mini" temperature: float = 0.7 max_tokens: int = 1024 status: str = "active" # draft | testing | active | archived def render(self, user_input: str) -> list[dict]: """渲染为 API 消息格式""" messages = [{"role": "system", "content": self.system}] for example in self.few_shot: messages.append({"role": example["role"], "content": example["content"]}) messages.append({"role": "user", "content": user_input}) return messages class PromptRegistry: """Prompt 版本注册中心""" def __init__(self, base_dir: str = "prompts"): self.base_dir = Path(base_dir) self._cache: dict[str, PromptVersion] = {} def load(self, name: str, version: str = "latest") -> PromptVersion: """加载指定版本的 Prompt""" if version == "latest": version = self._get_latest_version(name) cache_key = f"{name}@{version}" if cache_key in self._cache: return self._cache[cache_key] version_dir = self.base_dir / name / f"v{version}" # 加载系统提示 system = (version_dir / "system.txt").read_text(encoding="utf-8") # 加载 Few-shot few_shot = [] few_shot_path = version_dir / "few_shot.jsonl" if few_shot_path.exists(): for line in few_shot_path.read_text(encoding="utf-8").strip().split("\n"): few_shot.append(json.loads(line)) # 加载配置 config_path = version_dir / "config.yaml" config = yaml.safe_load(config_path.read_text(encoding="utf-8")) pv = PromptVersion( name=name, version=version, system=system, few_shot=few_shot, model=config.get("model", "gpt-4o-mini"), temperature=config.get("temperature", 0.7), max_tokens=config.get("max_tokens", 1024), status=config.get("status", "active"), ) self._cache[cache_key] = pv return pv def _get_latest_version(self, name: str) -> str: """获取最新 active 版本""" module_dir = self.base_dir / name versions = [] for d in module_dir.iterdir(): if d.is_dir() and d.name.startswith("v"): config = yaml.safe_load((d / "config.yaml").read_text(encoding="utf-8")) if config.get("status") == "active": versions.append(d.name[1:]) # 去掉 'v' 前缀 versions.sort(key=lambda v: [int(x) for x in v.split(".")]) return versions[-1] if versions else "1.0.0" def diff(self, name: str, v1: str, v2: str) -> dict: """对比两个版本的差异""" p1 = self.load(name, v1) p2 = self.load(name, v2) return { "system_changed": p1.system != p2.system, "few_shot_changed": p1.few_shot != p2.few_shot, "model_changed": p1.model != p2.model, "temperature_changed": p1.temperature != p2.temperature, } # 使用示例 registry = PromptRegistry("prompts") prompt = registry.load("chatbot", "latest") messages = prompt.render("你好,帮我查一下订单") 版本管理规范 版本类型 变更内容 示例 Major (x.0.0) Prompt 结构重构、角色定义变更 从单轮改为多轮对话 Minor (1.x.0) Few-shot 增删、指令逻辑调整 新增 2 个示例 Patch (1.0.x) 文案微调、错别字修正 “请” → “请帮我” A/B 测试框架 import random import hashlib from dataclasses import dataclass, field from collections import defaultdict import time @dataclass class ABTestConfig: """A/B 测试配置""" test_name: str variants: dict[str, PromptVersion] # variant_name -> Prompt traffic_split: dict[str, float] # variant_name -> 流量比例 metrics: list[str] = field(default_factory=lambda: [ "user_satisfaction", "response_length", "latency_ms", "cost" ]) min_sample_size: int = 100 def assign(self, user_id: str) -> str: """基于用户 ID 确定性分配变体(同一用户始终进入同一组)""" hash_val = int(hashlib.md5(user_id.encode()).hexdigest(), 16) ratio = (hash_val % 10000) / 10000.0 cumulative = 0.0 for variant, weight in self.traffic_split.items(): cumulative += weight if ratio < cumulative: return variant return list(self.traffic_split.keys())[-1] @dataclass class ExperimentResult: variant: str user_id: str metric: str value: float timestamp: float = field(default_factory=time.time) class ABTestRunner: """A/B 测试运行器""" def __init__(self): self.results: list[ExperimentResult] = [] def run( self, test_config: ABTestConfig, user_id: str, user_input: str, execute_fn, # callable: (PromptVersion, str) -> dict ) -> dict: """执行一次 A/B 测试请求""" variant_name = test_config.assign(user_id) prompt = test_config.variants[variant_name] # 执行并收集指标 result = execute_fn(prompt, user_input) # 记录指标 for metric in test_config.metrics: if metric in result: self.results.append(ExperimentResult( variant=variant_name, user_id=user_id, metric=metric, value=result[metric], )) return {"variant": variant_name, "result": result} def analyze(self, test_name: str) -> dict: """分析实验结果""" stats = defaultdict(lambda: defaultdict(list)) for r in self.results: stats[r.variant][r.metric].append(r.value) report = {} for variant, metrics in stats.items(): report[variant] = {} for metric, values in metrics.items(): vals = sorted(values) report[variant][metric] = { "count": len(vals), "mean": sum(vals) / len(vals), "median": vals[len(vals) // 2], "p95": vals[int(len(vals) * 0.95)] if len(vals) > 20 else None, } return report def is_significant(self, test_name: str, metric: str, alpha: float = 0.05) -> bool: """简单的统计显著性检验(Z 检验)""" import math variants = [r.variant for r in self.results if r.metric == metric] if len(set(variants)) < 2: return False # 按 variant 分组 groups = defaultdict(list) for r in self.results: if r.metric == metric: groups[r.variant].append(r.value) if len(groups) < 2: return False v1, v2 = list(groups.keys())[:2] s1, s2 = groups[v1], groups[v2] if len(s1) < 30 or len(s2) < 30: return False # 样本不足 m1, m2 = sum(s1) / len(s1), sum(s2) / len(s2) var1 = sum((x - m1) ** 2 for x in s1) / len(s1) var2 = sum((x - m2) ** 2 for x in s2) / len(s2) se = math.sqrt(var1 / len(s1) + var2 / len(s2)) if se == 0: return False z = abs(m1 - m2) / se return z > 1.96 # 95% 置信度 # 使用示例 runner = ABTestRunner() test_config = ABTestConfig( test_name="chatbot_tone_v2", variants={ "control": registry.load("chatbot", "1.0.0"), "treatment": registry.load("chatbot", "1.1.0"), }, traffic_split={"control": 0.5, "treatment": 0.5}, ) def execute_fn(prompt: PromptVersion, user_input: str) -> dict: # 实际调用 LLM return { "user_satisfaction": 4.5, # 用户评分 "response_length": 320, "latency_ms": 850, "cost": 0.003, } # 模拟 200 次请求 for i in range(200): runner.run(test_config, f"user-{i}", "帮我查订单", execute_fn) # 分析结果 report = runner.analyze("chatbot_tone_v2") for variant, metrics in report.items(): print(f"\n=== {variant} ===") for metric, stats in metrics.items(): print(f" {metric}: mean={stats['mean']:.2f}, p95={stats['p95']}") print(f"\n统计显著: {runner.is_significant('chatbot_tone_v2', 'user_satisfaction')}") 回归评测体系 每次 Prompt 变更前,必须通过回归测试集的验证。 ...

2026-06-25 · 7 min · 1483 words · 硅基 AGI 探索者
prompt templates design

Prompt 模板设计:构建可复用的工业级提示模板

一、为什么需要 Prompt 模板 在生产环境中,Prompt 不是一次性撰写,而是需要反复使用、团队协作、持续维护。模板化的 Prompt 管理是 Prompt 工程从"手工作坊"到"工业化生产"的必经之路。 1.1 一次性 Prompt vs 模板化 Prompt 维度 一次性 Prompt 模板化 Prompt 可复用性 零 高 可维护性 直接修改 版本管理 团队协作 个人经验 共享规范 质量保证 依赖个人 自动化检查 调试效率 重新调试 定位变量问题 A/B 测试 不支持 原生支持 二、模板系统架构 2.1 分层模板体系 Prompt Template Architecture ├── L0 - Base Templates(基础模板) │ ├── system-base.md(系统基础模板) │ ├── chat-base.md(对话基础模板) │ └── tool-base.md(工具调用模板) │ ├── L1 - Domain Templates(领域模板) │ ├── customer-service.md(客服) │ ├── code-generation.md(代码生成) │ ├── data-analysis.md(数据分析) │ └── content-writing.md(内容创作) │ ├── L2 - Task Templates(任务模板) │ ├── sentiment-analysis.md │ ├── text-summarization.md │ ├── question-answering.md │ └── entity-extraction.md │ └── L3 - Instance Templates(实例模板) ├── review-classification.md ├── medical-chatbot.md └── ecommerce-QA.md 2.2 模板引擎实现 from string import Template from typing import Dict, Any, Optional import json import hashlib class PromptTemplate: """工业级 Prompt 模板系统""" def __init__(self, template_id: str, template_str: str, metadata: Optional[Dict] = None): self.id = template_id self.template = Template(template_str) self.metadata = metadata or {} self.version = metadata.get("version", "1.0.0") self.created_at = metadata.get("created_at", "") def render(self, variables: Dict[str, Any]) -> str: """渲染模板,注入变量""" # 变量预处理 processed_vars = self._preprocess_variables(variables) try: return self.template.safe_substitute(**processed_vars) except KeyError as e: raise ValueError(f"缺少必需变量: {e}") def _preprocess_variables(self, variables: Dict) -> Dict: """变量预处理和验证""" required = self.metadata.get("required_vars", []) processed = {} for var in required: if var not in variables: raise ValueError(f"缺少必需变量 '{var}' 的定义") for key, value in variables.items(): # JSON 序列化 if isinstance(value, (dict, list)): processed[key] = json.dumps(value, ensure_ascii=False, indent=2) else: processed[key] = str(value) return processed def validate(self, rendered_output: str) -> bool: """验证渲染后的 Prompt""" checks = self.metadata.get("validation", []) for check in checks: if check["type"] == "min_length": if len(rendered_output) < check["value"]: return False elif check["type"] == "contains": if check["value"] not in rendered_output: return False return True def get_checksum(self) -> str: """模板内容的校验和""" return hashlib.md5(self.template.template.encode()).hexdigest() class TemplateRegistry: """模板注册中心""" def __init__(self): self._templates: Dict[str, PromptTemplate] = {} def register(self, template: PromptTemplate): self._templates[template.id] = template def get(self, template_id: str) -> PromptTemplate: if template_id not in self._templates: raise KeyError(f"模板 '{template_id}' 未注册") return self._templates[template_id] def list_by_category(self, category: str) -> list: return [ t for t in self._templates.values() if t.metadata.get("category") == category ] def search(self, query: str) -> list: """搜索模板""" results = [] for t in self._templates.values(): if query.lower() in t.id.lower(): results.append(t) elif query.lower() in json.dumps(t.metadata).lower(): results.append(t) return results 三、模板设计原则 3.1 九大黄金法则 法则 1:单一职责 - 一个模板只做一件事 - 例:不要将"情感分类"和"摘要生成"放在一个模板里 法则 2:显式变量 - 所有可变部分必须声明为变量 - 禁止在模板中硬编码业务数据 法则 3:默认值策略 - 每个变量都有合理的默认值 - 默认值应体现最通用的配置 法则 4:版本追踪 - 每个模板必须有版本号 - 变更必须更新版本并记录 changelog 法则 5:降级路径 - 模板必须有 fallback 输出 - 当条件不满足时仍有合理行为 法则 6:边界标注 - 用明确的标记分割模板段落 - 例:=== INSTRUCTIONS ===、=== CONTEXT === 法则 7:可测试性 - 模板变量应可以被 mock - 每个模板配套测试用例 法则 8:文档内嵌 - 模板本身要自文档化 - 注释说明每个段落的作用 法则 9:国际化 - 文本内容使用变量占位 - 语言切换只需替换变量值 3.2 模板骨架示例 --- # 模板元数据 id: "qa-domain-expert" name: "领域专家问答" version: "2.1.0" category: "question-answering" required_vars: ["domain", "question"] optional_vars: ["context", "tone", "max_length"] created: "2026-01-15" updated: "2026-06-01" --- === SYSTEM PROMPT === 你是 ${domain} 领域的专家。 ${ context if context else "" } === INSTRUCTIONS === 请回答以下问题。要求: 1. 使用专业但不晦涩的语言 2. 优先使用数据支撑观点 3. 如果不确定,明确说明不确定性 4. 回答长度控制在 ${ max_length if max_length else "500" } 字以内 5. 语气:${tone if tone else "专业严谨"} === USER QUERY === ${question} === OUTPUT FORMAT === ## 核心回答 <直接回答用户问题> ## 关键依据 <支持回答的依据> ## 补充说明 <注意事项或扩展信息> 四、变量管理 4.1 变量类型体系 from enum import Enum from typing import Union, List, Optional class VarType(Enum): STRING = "string" INTEGER = "integer" FLOAT = "float" BOOLEAN = "boolean" LIST = "list" DICT = "dict" MARKDOWN = "markdown" CODE = "code" class TemplateVariable: """模板变量的定义""" def __init__( self, name: str, var_type: VarType, required: bool = True, default: Optional[Any] = None, description: str = "", validator: Optional[callable] = None, examples: List[str] = None ): self.name = name self.type = var_type self.required = required self.default = default self.description = description self.validator = validator self.examples = examples or [] def validate_value(self, value: Any) -> bool: """验证变量值""" if value is None and not self.required: return True if value is None and self.required: raise ValueError(f"变量 '{self.name}' 是必需的") if self.validator: return self.validator(value) return True # 变量 schema 定义示例 VARIABLE_SCHEMA = { "domain": TemplateVariable( name="domain", var_type=VarType.STRING, required=True, description="专业领域名称", examples=["机器学习", "量子物理", "金融投资"] ), "question": TemplateVariable( name="question", var_type=VarType.STRING, required=True, description="用户的问题", validator=lambda x: len(x) >= 10 ), "max_length": TemplateVariable( name="max_length", var_type=VarType.INTEGER, required=False, default=500, description="回答最大字数" ) } 4.2 变量注入安全 import re class VariableSanitizer: """变量清洗安全层""" @staticmethod def sanitize_text(value: str) -> str: """清除可能破坏模板结构的字符""" # 移除模板变量语法 value = re.sub(r'\$\{[^}]+\}', '', value) # 转义 Markdown 代码块 value = value.replace('```', '```') return value @staticmethod def sanitize_code(value: str) -> str: """清理代码变量""" # 限制代码长度 max_code_length = 5000 return value[:max_code_length] @staticmethod def sanitize_list(value: list, max_items: int = 10) -> list: """限制列表长度""" return value[:max_items] 五、版本管理 class TemplateVersionManager: """模板版本管理器""" def __init__(self, storage_path: str): self.storage_path = storage_path self.versions = {} def save_version(self, template: PromptTemplate, change_log: str): """保存新版本""" version = template.metadata.get("version", "1.0.0") version_path = f"{self.storage_path}/{template.id}/v{version}.json" version_data = { "id": template.id, "version": version, "content": template.template.template, "metadata": template.metadata, "change_log": change_log, "checksum": template.get_checksum(), "saved_at": "2026-06-25T12:00:00Z" } # 保存到存储 os.makedirs(os.path.dirname(version_path), exist_ok=True) with open(version_path, 'w', encoding='utf-8') as f: json.dump(version_data, f, ensure_ascii=False, indent=2) def rollback_to(self, template_id: str, version: str): """回滚到指定版本""" version_path = f"{self.storage_path}/{template_id}/v{version}.json" with open(version_path, 'r', encoding='utf-8') as f: data = json.load(f) return PromptTemplate( template_id=data["id"], template_str=data["content"], metadata=data["metadata"] ) 六、测试与质量保证 6.1 模板测试框架 class TemplateTestCase: def __init__(self, template_id: str, variables: dict, expected_contains: list = None): self.template_id = template_id self.variables = variables self.expected_contains = expected_contains or [] def run_template_tests(registry: TemplateRegistry, test_cases: list) -> dict: """运行模板测试套件""" results = {"passed": 0, "failed": 0, "errors": []} for case in test_cases: try: template = registry.get(case.template_id) rendered = template.render(case.variables) # 验证必需内容 for expected in case.expected_contains: if expected not in rendered: raise AssertionError( f"缺少预期内容: {expected}" ) results["passed"] += 1 except Exception as e: results["failed"] += 1 results["errors"].append({ "template_id": case.template_id, "error": str(e) }) return results 6.2 模板质量评分卡 质量维度 权重 检查项 完整性 20% 变量定义完整、default 覆盖 健壮性 20% 空变量处理、边界输入 可读性 15% 注释充分、段落清晰 一致性 15% 与同类模板格式一致 性能 10% 变量替换效率 安全 20% 注入防护、敏感词过滤 七、实战:完整模板系统 # 初始化模板系统 registry = TemplateRegistry() # 注册基础模板 base_template = PromptTemplate( template_id="system-base-v2", template_str="""你是一个${role}助手。 ${constraints} """ + """ === INPUT === ${user_input} === RESPONSE === """, metadata={ "version": "2.0.0", "category": "base", "required_vars": ["role", "user_input"], "optional_vars": ["constraints"], "created_at": "2026-01-01" } ) registry.register(base_template) # 使用模板 result = registry.get("system-base-v2").render({ "role": "编程", "constraints": "请使用 TypeScript 回答", "user_input": "如何实现一个 Promise 池?" }) 八、总结 工业级 Prompt 模板体系的建设需要系统性思考: ...

2026-06-25 · 5 min · 1011 words · 硅基 AGI 探索者
prompt versioning practice

Prompt 版本管理实践:像管理代码一样管理 Prompt

Prompt 即代码 如果你的 Prompt 是在代码里硬编码的字符串,没有版本管理、没有评审流程、没有灰度发布——那你的 Prompt 就是定时炸弹。 Prompt 是逻辑,不是配置。它决定了系统行为,和代码一样需要工程化管理。 Prompt 管理成熟度模型 级别 特征 问题 L0 硬编码在代码里 改 Prompt 要重新发版 L1 外部文件,Git 管理 有版本但无灰度 L2 Prompt 注册中心 + A/B 测试 可灰度但无自动评估 L3 CI 集成 + 自动评估 + 灰度发布 全流程工程化 Git 工作流:Prompt 仓库设计 目录结构 prompts/ ├── README.md ├── customer-service/ │ ├── v1.0/ │ │ ├── system.md # System Prompt │ │ ├── user-template.md # 用户消息模板 │ │ ├── config.yaml # 模型参数 │ │ └── eval-results.json # 评估结果 │ ├── v1.1/ │ │ └── ... │ └── latest -> v1.1/ # 软链接到最新版 ├── code-review/ │ └── v2.0/ │ └── ... └── _shared/ ├── safety-rules.md # 共享的安全约束 └── format-spec.md # 共享的格式规范 Prompt 文件格式 # customer-service/v1.2/config.yaml version: "1.2.0" model: "gpt-4o-mini" temperature: 0.3 max_tokens: 500 top_p: 1.0 frequency_penalty: 0.0 system_prompt_file: system.md user_template_file: user-template.md variables: - name: user_question required: true max_length: 2000 - name: context required: false default: "{}" metadata: author: "team-llm" changelog: "降低 temperature 以提高一致性" based_on: "1.1.0" eval_score: 0.87 status: "staging" # draft → staging → production 分支策略 main ────●────────●────────●──────── \ │ │ feature/add-faq ●────● (PR + 评估通过) │ hotfix/safety-patch ●────● (紧急修复) Prompt 注册中心 from pydantic import BaseModel from typing import Optional import yaml import hashlib class PromptVersion(BaseModel): name: str version: str system_prompt: str user_template: str model: str temperature: float max_tokens: int status: str # draft, staging, production, archived eval_score: Optional[float] = None parent_version: Optional[str] = None config_hash: str = "" class PromptRegistry: """Prompt 注册中心 - 单一可信源""" def __init__(self, storage): self.storage = storage # 可以是 Git、数据库、对象存储 async def register(self, prompt: PromptVersion) -> str: # 计算内容 hash prompt.config_hash = hashlib.sha256( f"{prompt.system_prompt}{prompt.user_template}".encode() ).hexdigest()[:16] # 检查 hash 是否已存在 existing = await self.storage.get_by_hash(prompt.config_hash) if existing: return f"Prompt already registered as {existing.version}" await self.storage.save(prompt) return prompt.version async def get_production(self, name: str) -> PromptVersion: return await self.storage.get_by_status(name, "production") async def get_staging(self, name: str) -> PromptVersion: return await self.storage.get_by_status(name, "staging") async def promote(self, name: str, version: str, target: str): """升级版本状态: draft → staging → production""" valid_transitions = { "draft": ["staging"], "staging": ["production", "draft"], "production": ["archived"], } prompt = await self.storage.get(name, version) if target not in valid_transitions.get(prompt.status, []): raise ValueError(f"Invalid transition: {prompt.status} → {target}") if target == "production": # 归档旧的生产版本 old_prod = await self.storage.get_by_status(name, "production") if old_prod: await self.storage.update_status( old_prod.name, old_prod.version, "archived" ) await self.storage.update_status(name, version, target) A/B 测试框架 import random from dataclasses import dataclass @dataclass class ABTestConfig: name: str prompt_a_version: str prompt_b_version: str traffic_split: float # B 的流量比例 0.0-1.0 min_samples: int = 100 success_metric: str = "user_satisfaction" duration_hours: int = 48 class ABTestRunner: def __init__(self, registry: PromptRegistry, metrics): self.registry = registry self.metrics = metrics def assign(self, user_id: str, test_name: str) -> str: """确定性分流:同一用户始终进入同一组""" hash_val = int(hashlib.md5( f"{user_id}:{test_name}".encode() ).hexdigest(), 16) % 100 test = self.get_test(test_name) if hash_val < test.traffic_split * 100: return test.prompt_b_version # 实验组 return test.prompt_a_version # 对照组 async def evaluate(self, test_name: str) -> dict: test = self.get_test(test_name) group_a = await self.metrics.get_scores(test_name, "A") group_b = await self.metrics.get_scores(test_name, "B") if len(group_a) < test.min_samples or len(group_b) < test.min_samples: return {"status": "insufficient_data", "a_count": len(group_a), "b_count": len(group_b)} # 统计显著性检验 from scipy import stats t_stat, p_value = stats.ttest_ind(group_b, group_a) return { "status": "completed", "a_mean": np.mean(group_a), "b_mean": np.mean(group_b), "improvement": np.mean(group_b) - np.mean(group_a), "p_value": p_value, "significant": p_value < 0.05, "recommendation": "promote_B" if p_value < 0.05 and np.mean(group_b) > np.mean(group_a) else "keep_A" } 灰度发布 class CanaryDeployer: """Prompt 灰度发布""" def __init__(self, registry: PromptRegistry): self.registry = registry self.stages = [ {"traffic": 0.05, "duration_min": 30, "check": self._check_error_rate}, {"traffic": 0.20, "duration_min": 60, "check": self._check_error_rate}, {"traffic": 0.50, "duration_min": 120, "check": self._check_full}, {"traffic": 1.00, "duration_min": 0, "check": None}, ] async def deploy(self, prompt_name: str, new_version: str): old_version = await self.registry.get_production(prompt_name) for i, stage in enumerate(self.stages): print(f"Stage {i+1}: {stage['traffic']*100}% traffic") # 配置流量比例 await self._set_traffic_split( prompt_name, old_version.version, new_version, stage["traffic"] ) # 等待观察 await asyncio.sleep(stage["duration_min"] * 60) # 健康检查 if stage["check"]: healthy = await stage["check"](prompt_name) if not healthy: await self._rollback(prompt_name, old_version.version) return {"status": "rolled_back", "stage": i+1} # 全量上线 await self.registry.promote(prompt_name, new_version, "production") return {"status": "deployed", "version": new_version} async def _check_error_rate(self, name: str) -> bool: metrics = await self.get_metrics(name, window_min=30) return metrics["error_rate"] < 0.05 # 错误率 < 5% async def _check_full(self, name: str) -> bool: metrics = await self.get_metrics(name, window_min=120) checks = [ metrics["error_rate"] < 0.03, metrics["avg_latency_ms"] < 3000, metrics["user_satisfaction"] > 0.8, ] return all(checks) 回滚策略 class RollbackManager: """一键回滚到任意历史版本""" async def rollback(self, prompt_name: str, target_version: str = None): if target_version is None: # 回滚到上一个生产版本 history = await self.registry.get_version_history(prompt_name) prod_history = [v for v in history if v.status == "archived"] if not prod_history: raise ValueError("No previous production version to rollback to") target_version = prod_history[-1].version # 立即切换 await self.registry.promote(prompt_name, target_version, "production") # 记录回滚原因 await self.registry.add_note( prompt_name, target_version, f"Rolled back at {datetime.now()} due to production issue" ) # 清理灰度状态 await self._clear_traffic_split(prompt_name) return {"rolled_back_to": target_version} 团队协作 PR 模板 ## Prompt 变更 PR ### 变更类型 - [ ] 新增 Prompt - [ ] 优化现有 Prompt - [ ] 紧急修复 - [ ] 模型升级 ### 变更内容 <!-- 简述改了什么,为什么改 --> ### 评估结果 - 评估数据集版本: v2.1 - 变更前分数: 0.82 - 变更后分数: 0.87 - 回归项: 无 / [列出回归项] ### 测试用例 - [ ] 已跑 50 条快速评估集 - [ ] 已跑 200 条标准评估集 - [ ] 人工抽检 20 条 ### Checklist - [ ] 变量引用正确 - [ ] 无硬编码密钥 - [ ] 安全约束完整 - [ ] Changelog 已更新 评审关注点 REVIEW_CHECKLIST = [ "Prompt 是否有明确的角色定义和安全约束", "变量是否用模板引擎而非字符串拼接", "输出格式是否可解析(JSON/XML)", "Few-shot 示例是否覆盖边界情况", "评估分数是否比基线提升或有合理解释", "是否考虑了对其他 Prompt 的影响", "温度参数是否匹配任务类型", "是否有对应的回滚方案", ] 总结 Prompt 版本管理的核心是把 Prompt 当代码:Git 管版本,注册中心管分发,A/B 测试管验证,灰度发布管安全,回滚机制管兜底。没有这套体系,Prompt 迭代就是在走钢丝;有了这套体系,每次变更都有数据支撑、有回滚保障、有协作流程。 加入讨论 这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。 ...

2026-06-25 · 5 min · 878 words · 硅基 AGI 探索者
system prompt engineering

System Prompt 工程化:角色设定的科学方法

1. System Prompt 的结构 System Prompt 是 LLM 交互中优先级最高的指令层。一个工程化的 System Prompt 应包含以下模块: ┌──────────────────────────────────┐ │ 1. 角色定义 (Role) │ │ 2. 任务描述 (Task) │ │ 3. 行为约束 (Constraints) │ │ 4. 输出格式 (Output Format) │ │ 5. 知识边界 (Knowledge Boundary)│ │ 6. 示例 (Examples) │ │ 7. 异常处理 (Error Handling) │ └──────────────────────────────────┘ 1.1 完整模板 # 角色 你是一个高级数据分析师,擅长从结构化数据中提取洞察。 # 任务 用户会提供数据描述或 CSV 数据,你需要: 1. 理解数据结构和业务含义 2. 进行统计分析 3. 生成可视化建议 4. 输出分析报告 # 约束 - 只基于用户提供的数据分析,不编造数据 - 如果数据不足,明确说明需要什么数据 - 不输出投资建议或确定性预测 - 统计方法需标注假设条件 # 输出格式 ```json { "summary": "一句话摘要", "statistics": {"mean": 0, "median": 0, "std": 0}, "insights": ["洞察1", "洞察2"], "visualization": {"type": "bar", "reason": "原因"}, "limitations": ["局限1"] } 知识边界 熟悉:统计学、Python pandas、SQL 不熟悉:用户的具体业务上下文(需用户补充) 异常处理 数据为空 → 询问用户提供数据 数据格式错误 → 指出格式问题并给出正确格式示例 分析超出能力范围 → 明确说明并建议替代方案 ## 2. 角色定义的科学方法 ### 2.1 角色三要素 ```python ROLE_TEMPLATE = """ # 身份 你是{profession},拥有{experience}年经验。 # 专长 {expertise_list} # 思维方式 {thinking_style} # 沟通风格 {communication_style} """ # 示例 role = ROLE_TEMPLATE.format( profession="资深安全工程师", experience="15", expertise_list="- Web 安全\n- 逆向工程\n- 安全架构设计", thinking_style="先评估威胁模型,再设计方案,最后验证有效性", communication_style="简洁直接,用数据和事实说话,避免模糊表述" ) 2.2 角色粒度对比 角色定义 效果 Token “你是助手” 泛化回答 ~5 “你是程序员” 技术导向回答 ~10 “你是10年经验的Python后端工程师,熟悉高并发架构” 精准技术回答 ~30 完整角色三要素 最精准,风格一致 ~100 关键发现:角色定义越具体,输出质量和一致性越高,但超过一定粒度后边际收益递减。 ...

2026-06-25 · 5 min · 950 words · 硅基 AGI 探索者
prompt management platform

Prompt 管理平台搭建指南

为什么需要 Prompt 管理平台 当团队有 3 个以上 LLM 应用时,Prompt 管理就会失控:Prompt 散落在代码里、改一个字要重新部署、无法 A/B 测试、没有版本回滚。Prompt 管理平台把 Prompt 当作独立资产来管理。 核心功能需求 功能模块 说明 优先级 Prompt CRUD 创建/读取/更新/删除 Prompt P0 版本管理 每次修改生成新版本,支持回滚 P0 变量模板 支持 {{variable}} 变量插值 P0 A/B 测试 流量分割对比不同 Prompt 效果 P1 权限控制 团队成员角色与审批流 P1 效果监控 Prompt 调用的成功率/延迟/成本 P1 批量测试 用测试集自动评估 Prompt P2 架构设计 +----------------------------------------------+ | Prompt 管理平台架构 | | | | +------------+ +------------------+ | | | Web UI | | API Gateway | | | | (React) | | (FastAPI) | | | +-----+------+ +-------+----------+ | | | | | | +-----+-----------------+----------------+ | | | Prompt Service Layer | | | | CRUD | Version | AB Test | RBAC | | | +-------------------+--------------------+ | | | | | +---------+---------+---------+----------+ | | |PostgreSQL| Redis缓存 |S3存储 | | | |(元数据) | (热Prompt) |(备份) | | | +---------+--------------+----------+ | +----------------------------------------------+ 数据库设计 -- Prompt 主表 CREATE TABLE prompts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(128) NOT NULL UNIQUE, description TEXT, category VARCHAR(64), current_version_id UUID REFERENCES prompt_versions(id), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); -- Prompt 版本表 CREATE TABLE prompt_versions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), prompt_id UUID NOT NULL REFERENCES prompts(id) ON DELETE CASCADE, version INT NOT NULL, content TEXT NOT NULL, variables JSONB DEFAULT '[]', model_config JSONB DEFAULT '{}', change_log TEXT, created_by UUID NOT NULL REFERENCES users(id), created_at TIMESTAMP DEFAULT NOW(), UNIQUE(prompt_id, version) ); -- A/B 测试表 CREATE TABLE ab_tests ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(128) NOT NULL, prompt_id UUID NOT NULL REFERENCES prompts(id), variant_a_version_id UUID NOT NULL REFERENCES prompt_versions(id), variant_b_version_id UUID NOT NULL REFERENCES prompt_versions(id), traffic_split JSONB DEFAULT '{"a": 50, "b": 50}', status VARCHAR(16) DEFAULT 'running', metrics JSONB DEFAULT '{}', created_at TIMESTAMP DEFAULT NOW(), ended_at TIMESTAMP ); 核心 API 实现 from fastapi import FastAPI, HTTPException, Depends from pydantic import BaseModel import asyncpg, json app = FastAPI() class PromptCreate(BaseModel): name: str description: str = "" content: str variables: list[dict] = [] model_config: dict = {} class PromptUpdate(BaseModel): content: str change_log: str = "" variables: list[dict] = [] @app.post("/api/prompts") async def create_prompt(data: PromptCreate, db=Depends(get_db)): async with db.transaction(): prompt = await db.fetchrow( "INSERT INTO prompts (name, description) VALUES ($1, $2) RETURNING *", data.name, data.description ) version = await db.fetchrow( "INSERT INTO prompt_versions (prompt_id, version, content, variables, model_config, created_by) VALUES ($1, 1, $2, $3, $4, $5) RETURNING *", prompt["id"], data.content, json.dumps(data.variables), json.dumps(data.model_config), current_user_id ) await db.execute( "UPDATE prompts SET current_version_id = $1 WHERE id = $2", version["id"], prompt["id"] ) return {"prompt": dict(prompt), "version": dict(version)} @app.put("/api/prompts/{prompt_id}") async def update_prompt(prompt_id: str, data: PromptUpdate, db=Depends(get_db)): async with db.transaction(): current = await db.fetchrow( "SELECT version FROM prompt_versions WHERE prompt_id = $1 ORDER BY version DESC LIMIT 1", prompt_id ) new_version = (current["version"] + 1) if current else 1 version = await db.fetchrow( "INSERT INTO prompt_versions (prompt_id, version, content, variables, change_log, created_by) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", prompt_id, new_version, data.content, json.dumps(data.variables), data.change_log, current_user_id ) await db.execute( "UPDATE prompts SET current_version_id = $1, updated_at = NOW() WHERE id = $2", version["id"], prompt_id ) return {"version": dict(version)} @app.post("/api/prompts/{prompt_id}/rollback/{version}") async def rollback_prompt(prompt_id: str, version: int, db=Depends(get_db)): target = await db.fetchrow( "SELECT id FROM prompt_versions WHERE prompt_id = $1 AND version = $2", prompt_id, version ) if not target: raise HTTPException(404, "Version not found") await db.execute( "UPDATE prompts SET current_version_id = $1 WHERE id = $2", target["id"], prompt_id ) return {"rolled_back_to": version} A/B 测试实现 import random class ABTestRouter: def __init__(self, db, redis): self.db = db self.redis = redis async def get_variant(self, test_id: str, user_id: str) -> str: cache_key = f"ab:{test_id}:{user_id}" cached = await self.redis.get(cache_key) if cached: return cached test = await self.db.fetchrow( "SELECT * FROM ab_tests WHERE id = $1 AND status = 'running'", test_id ) if not test: return "a" split = json.loads(test["traffic_split"]) variant = "a" if random.random() * 100 < split["a"] else "b" await self.redis.setex(cache_key, 86400, variant) return variant async def record_metric(self, test_id, variant, metric, value): await self.db.execute( "INSERT INTO ab_metrics (test_id, variant, metric, value) VALUES ($1, $2, $3, $4)", test_id, variant, metric, value ) 与现有工具对比 工具 优点 缺点 适用场景 LangSmith LangChain 生态集成好 绑定 LangChain,贵 已用 LangChain 的团队 PromptHub UI 好用,有协作功能 自定义能力弱 非技术团队 自建平台 完全可控,可定制 开发成本高 大团队/特殊需求 建议:团队 < 5 人且用 LangChain,直接上 LangSmith。团队 > 10 人或有特殊需求,自建平台 ROI 更高。 ...

2026-06-24 · 4 min · 720 words · 硅基 AGI 探索者
鲁ICP备2026018361号