Prompt Engineering:从一句提示词到可维护系统

0阅读10分钟

提示词不是孤立文本

我在早期项目里写过大量提示词——一开始就是几行文字,复制粘贴到一个常量文件里,上线前手动读两遍,觉得没问题就提交了。这种做法在 demo 阶段撑得住,进入生产后问题一个接一个冒出来:同样的提示词换个模型版本效果骤降,不同开发者的措辞风格互相打架,出了问题不知道是 prompt 的锅还是数据变了。

根本原因是我把提示词当成了「一段文字」,而不是「一个系统」。

2026 年行业里已经在讨论从 Prompt Engineering 到 Context Engineering 的演进——提示词工程并没有过时,但它已经是更大系统的子集[1]。你需要关心的不再只是「这句话怎么写」,而是模型在每次推理时看到的全部信息是怎么组织、检索、拼装和验证的。

从模板到系统的理论框架

提示词的层次模型

一个可维护的提示词系统可以拆成五层,每一层有独立的关注点和验证方式:

┌─────────────────────────────────────────────────────┐
│  L5 验证层:评测集、回归指标、人工审查流程              │
├─────────────────────────────────────────────────────┤
│  L4 输出契约层:字段定义、格式、长度、错误状态          │
├─────────────────────────────────────────────────────┤
│  L3 约束层:禁止行为、兜底策略、安全边界               │
├─────────────────────────────────────────────────────┤
│  L2 上下文层:输入数据、用户意图、检索结果              │
├─────────────────────────────────────────────────────┤
│  L1 目标层:任务定义、角色设定、核心指令               │
└─────────────────────────────────────────────────────┘

这个分层不是理论摆设。arXiv 上有一篇关于 Promptware Engineering 的论文系统地论述了为什么提示词需要当作一等软件工件来管理——自然语言是无结构的、行为是概率性的、没有普适的正确性标准,这些特性让传统的软件工程方法必须做适配而不是直接套用[2]。

上下文工程的四个支柱

Sourcegraph 的工程博客把上下文工程拆成四个支柱,我觉得这个框架很实用[3]:

支柱关注点常见问题
系统指令角色、约束、输出格式指令矛盾、过度膨胀
检索外部数据如何进入上下文窗口检索质量差导致幻觉
记忆短期对话历史 + 长期用户偏好上下文窗口塞满后信息丢失
工具可调用的函数定义和返回格式工具集臃肿、选择歧义

这四个支柱之间不是独立关系——工具定义占 token,检索结果也占 token,记忆压缩又可能丢信息。上下文工程的核心矛盾是:模型的注意力预算有限,你要在有限窗口里最大化信号密度。

案例一:客服摘要生成的演进

v1:一句话提示词

请根据以下客服对话生成摘要:
{conversation}

这种写法在测试三条对话时看起来没问题。上线两周后,客服主管发现摘要里混进了用户情绪判断(「用户非常愤怒」),但业务要求只记录事实。

v2:加了约束的提示词

你是一个客服摘要助手。请根据对话生成客观摘要。
 
规则:
- 只记录事实,不做情绪判断
- 使用中文
- 不超过 200 字
 
对话内容:
{conversation}

好了一阵,又出问题了:有些对话涉及退款,摘要需要包含退款金额和原因,但提示词里没有定义输出结构,模型有时候写了有时候没写。

v3:结构化系统

# prompt/customer_summary.yaml
id: customer_summary
version: 3.1.0
model: claude-sonnet-4-20250514
temperature: 0.2
 
system: |
  你是客服对话摘要引擎。任务是将对话转为结构化记录。
 
  ## 输出契约
  严格按以下 JSON Schema 输出:
  {
    "summary": "string, 客观事实摘要, ≤200字",
    "refund": {
      "amount": "number | null, 退款金额(元)",
      "reason": "string | null, 退款原因"
    },
    "sentiment": "neutral | negative | positive, 仅标注对话整体走向",
    "action_items": ["string, 后续待办"]
  }
 
  ## 约束
  - 禁止使用「愤怒」「激动」等情绪形容词
  - 退款信息仅在对话中明确提及时填写
  - 若信息不足,对应字段填 null,不要推测
 
examples:
  - input: "用户:我买的手机屏幕碎了..."
    output:
      summary: "用户反映手机屏幕碎裂,要求维修..."
      refund: null
      sentiment: negative
      action_items: ["转接维修部门"]
 
eval_set: prompts/evals/customer_summary_v3.json

从 v1 到 v3,变化的不是文字功底,而是工程化程度。v3 的提示词有版本号、有 schema、有评测集、有温度参数——它更像一个工程制品而不是一段文字。

案例二:代码审查助手的上下文拼装

代码审查场景能说明上下文工程四个支柱怎么协同工作。

流程图画布 · 115%
Mermaid 流程图加载中...

这个流程里有几个关键决策:

决策点选项我最终的选择原因
检索策略全量加载 vs 按需检索按需检索大 PR 全量加载会超出窗口
记忆管理每次全量历史 vs 压缩摘要压缩摘要保留关键决策,丢弃冗余输出
工具数量12 个工具 vs 5 个工具5 个工具工具太多模型选择困难
输出格式自由文本 vs 结构化 JSON结构化 JSON下游要自动分类审查意见
温度设置0.0 vs 0.30.2太低会重复,太高会不稳定

Anthropic 的工程博客特别提到了「just in time」的检索策略——不要预加载大量数据,而是让 agent 持有轻量引用,在运行时按需获取具体内容[4]。这个思路在代码审查场景里效果很明显:先给模型看 diff 概览和文件列表,让它自己决定要深入查看哪些文件。

案例三:多语言内容生成的版本管理

第三个案例来自内容生成场景。我们的平台需要支持中、英、日三种语言的内容生成,每种语言的提示词都有微妙的差异——不是简单翻译,而是语气、文化适配和合规要求都不同。

# ❌ 之前的做法:硬编码在业务逻辑里
def generate_content(topic: str, locale: str) -> str:
    if locale == "zh-CN":
        prompt = f"请写一篇关于{topic}的文章,要求专业但易懂"
    elif locale == "en-US":
        prompt = f"Write a professional article about {topic}"
    elif locale == "ja-JP":
        prompt = f"{topic}についてプロフェッショナルな記事を書いてください"
    return llm.call(prompt)
# ✅ 之后的做法:提示词作为可管理资源
# prompts/content_gen/zh-CN.yaml
id: content_generation
locale: zh-CN
version: 2.3.0
variables:
  topic: { type: string, required: true }
  tone: { type: enum, values: [professional, casual, technical], default: professional }
  max_length: { type: integer, default: 2000 }
 
system: |
  你是一位中文技术内容创作者。
 
  ## 风格要求
  - 专业术语保留英文原文,首次出现时附中文注释
  - 段落不超过 4 行,保持阅读节奏
  - 禁止使用「赋能」「抓手」等空洞词汇
 
  ## 输出结构
  1. 标题(≤20 字)
  2. 导语(≤100 字,点明读者收益)
  3. 正文(按逻辑分节,每节 300-500 字)
  4. 关键要点(3-5 条)
 
template: |
  主题:{{ topic }}
  语气:{{ tone }}
  字数上限:{{ max_length }}
 
eval_set: prompts/evals/content_gen_zh.json
quality_gates:
  - check: length_within_bound
  - check: no_banned_words
    words: ["赋能", "抓手", "打通"]
  - check: has_required_sections
# prompts/content_gen/en-US.yaml — 独立版本,独立演进
id: content_generation
locale: en-US
version: 2.1.0
variables:
  topic: { type: string, required: true }
  tone: { type: enum, values: [professional, casual, technical], default: professional }
  max_length: { type: integer, default: 2000 }
 
system: |
  You are a technical content writer for an engineering blog.
 
  ## Style Requirements
  - Use active voice
  - One idea per paragraph, max 3 sentences
  - Include code examples where relevant
 
  ## Output Structure
  1. Title (≤60 chars)
  2. Lead paragraph (≤80 words, state reader benefit)
  3. Body (H2 sections, 200-400 words each)
  4. Key takeaways (3-5 bullets)
 
template: |
  Topic: {{ topic }}
  Tone: {{ tone }}
  Max words: {{ max_length }}
 
eval_set: prompts/evals/content_gen_en.json

两个语言版本的提示词现在可以独立迭代。中文版本更新到 v2.3.0 时,英文版本停在 v2.1.0,互不影响。每个版本有自己的评测集和质量门禁。

提示词系统的工程化流程

从上面三个案例可以提炼出一套工程化流程。我把它画成流程图:

流程图画布 · 115%
Mermaid 流程图加载中...

对应到具体实践:

需求分析阶段
  ├── 明确任务目标和成功指标
  ├── 梳理输入数据来源和可信度
  └── 确定输出契约和错误处理策略
 
草稿编写阶段
  ├── 按五层模型组织提示词结构
  ├── 编写 3-5 个正例 + 2-3 个反例
  └── 定义变量 schema 和默认值
 
本地评测阶段
  ├── 在评测集上跑回归测试
  ├── 检查输出格式是否符合契约
  └── 对比上一版本的成功率变化
 
Code Review 阶段
  ├── 审查提示词逻辑和约束完整性
  ├── 确认不影响其他提示词的共享部分
  └── 检查 token 用量和成本影响
 
金丝雀发布阶段
  ├── 10% 流量使用新版本
  ├── 监控关键指标(延迟、格式错误率、用户反馈)
  └── 48 小时无异常后扩到 50%
 
全量发布 + 持续监控
  ├── 记录版本变更日志
  ├── 定期刷新评测集
  └── 模型版本升级时重新跑回归

关键决策对比

把「临时模板」和「可维护系统」两种做法放在一起对比:

维度临时模板可维护系统
存储位置代码常量、配置文件散落在业务逻辑中独立目录,YAML/JSON 格式,有 schema 校验
版本管理跟代码一起 commit,没有独立版本号语义化版本号,独立 changelog
变量定义字符串拼接或 f-string显式变量 schema,有类型和默认值
评测方式手动试几条,感觉对了就上线结构化评测集 + 自动化回归 + 质量门禁
发布流程跟应用代码一起部署独立发布,支持金丝雀和快速回滚
多语言支持if-else 硬编码每个 locale 独立文件,独立演进
团队协作谁都能改,没有审查流程PR review,变更需要说明动机和影响
成本意识不关注 token 用量监控 token 消耗,有预算告警

再看提示词内部结构的对比——把约束塞在一段话里 vs 结构化分层:

# ❌ 所有要求混在一起
你是一个专业的客服助手,要礼貌、专业,不能泄露用户隐私,
回答要简洁不超过200字,如果不确定就说不知道,
不要编造信息,使用中文回答,遇到投诉要安抚用户情绪,
同时记录投诉内容并转接主管。
 
# ✅ 分层结构化
# 角色
你是客服对话助手,负责处理用户咨询和投诉。
 
# 输出契约
- 语言:中文
- 长度:≤200 字
- 格式:纯文本,段落间空行分隔
 
# 行为约束
- 禁止泄露用户个人信息(手机号、地址、订单号)
- 不确定的信息明确说「我不确定」,不推测
- 遇到投诉:先共情 → 记录要点 → 提供转接选项
 
# 兜底策略
- 超出能力范围的问题 → 引导转人工
- 系统异常 → 回复「请稍后重试」并记录错误
# ❌ 评测靠感觉
def test_prompt():
    result = llm.call(prompt, input="屏幕碎了怎么办")
    assert "维修" in result  # 只看关键词
    print("OK")
 
# ✅ 结构化评测
def test_customer_summary():
    eval_cases = load_eval_set("prompts/evals/customer_summary_v3.json")
    results = run_batch(prompt_version="3.1.0", cases=eval_cases)
 
    assert results.format_compliance >= 0.98  # JSON 格式合规率
    assert results.field_coverage >= 0.95    # 必填字段覆盖率
    assert results.factual_accuracy >= 0.90  # 事实准确率(LLM-as-judge)
    assert results.no_emotion_words == 1.0   # 不含情绪形容词
 
    # 与上一版本对比
    prev = load_baseline("3.0.0")
    assert results.compare(prev).no_regression()
# ❌ 版本管理缺失
# 不知道什么时候改的、为什么改、谁改的
# prompt = "生成摘要,要简短"
 
# ✅ 语义化版本 + 变更日志
# id: customer_summary
# version: 3.1.0
# changelog:
#   3.1.0 (2026-06-20): 增加 refund 字段,适配新退款流程
#   3.0.0 (2026-05-15): 重写输出契约,从自由文本改为 JSON
#   2.2.1 (2026-04-08): 修复情绪词泄露问题
#   2.2.0 (2026-03-20): 增加 action_items 字段

生产上线前的检查清单

每次提示词要上生产之前,我会过一遍这份清单。它不是一次性写好的,而是每次出事后加一条,慢慢攒到现在的规模:

结构与可维护性

  • 提示词有独立版本号(语义化版本)
  • 变量有显式 schema 定义(类型、必填、默认值)
  • 系统指令、约束、输出契约分层书写
  • 共享部分(如通用安全约束)抽成可复用片段,避免重复

评测与质量

  • 有正例评测集(≥10 条,覆盖主要场景)
  • 有反例评测集(≥5 条,覆盖边界和异常情况)
  • 评测集包含多语言/多区域场景(如适用)
  • 自动化回归测试通过,与上一版本无显著退化
  • 输出格式合规率 ≥ 98%

安全与合规

  • 不包含用户敏感信息(PII)
  • 有明确的禁止行为列表
  • 有兜底策略(模型不确定时怎么处理)
  • 经过 prompt injection 测试

发布与监控

  • 变更日志记录了本次修改的动机和预期影响
  • 金丝雀发布计划已准备(10% → 50% → 100%)
  • 线上监控指标已配置(延迟、错误率、格式合规率)
  • 回滚方案已验证

成本与性能

  • Token 用量在预算范围内
  • 检索结果有截断策略,不会把窗口塞满
  • 工具定义数量精简(≤8 个),选择无歧义

我踩过的坑

写这篇文章不是因为我有一套完美方法论,而是因为踩了足够多的坑。几个印象深刻的:

坑一:提示词里写了业务逻辑。早期我在提示词里写了一堆 if-else 规则(「如果用户提到退款且金额大于 500 元则……」)。后来发现这些规则用代码判断比让模型判断可靠得多。现在我的原则是:能确定性验证的逻辑放代码,需要判断力的指令放提示词。

坑二:评测集和提示词一起更新。有一次发现评测集的预期输出是照着提示词改的——提示词改了输出格式,评测集也跟着改了,回归测试永远通过。后来把评测集的维护权限和提示词分开了,评测集变更需要独立审批。

坑三:忽视模型版本升级的影响。某个模型小版本升级后,提示词的 JSON 输出偶尔会多出几个字段。没有 breaking change 通知,但下游解析代码崩了。现在每次模型版本升级都跑完整回归,即使只是 patch 版本。

坑四:工具定义太贪心。代码审查场景一开始定义了 12 个工具,模型经常在工具选择上犯迷糊,调用顺序也不对。砍到 5 个之后,准确率从 72% 涨到 91%。工具不是越多越好,正确的选择必须对模型来说毫无歧义。

结语

从「写一句提示词」到「维护一个提示词系统」,核心转变是:提示词不再是写完就不动的静态文本,而是一个需要版本管理、评测验证、灰度发布和持续监控的工程制品。

这个转变和微服务架构的演进有相似之处——单体应用拆成微服务后,每个服务都需要独立的 CI/CD、监控和告警。提示词从业务代码里拆出来后,同样需要自己的工程基础设施。

不需要一步到位。先给提示词加版本号,再建评测集,再做灰度发布——每一步都能解决真实问题。

参考资料

  1. BigData Boutique. Context Engineering > Prompt Engineering: What Changed. 2026.
  2. Xu et al. Software Engineering for Prompt-Enabled Systems. arXiv, 2025.
  3. Sourcegraph. Context Engineering: A Practical Guide for AI Agents. 2026.
  4. Anthropic. Effective Context Engineering for AI Agents. 2025.
  5. DataX Power. System Prompting as Engineering Practice in 2026. 2025.
  6. Paul, K. From Experimentation to Production: Managing the Prompt Engineering Lifecycle. Dev.to, 2025.
  7. ACM. A Systematic Prompt Template Analysis for Real-world LLM Apps. 2025.
  8. Anthropic. Prompting Best Practices — Claude API Documentation. 2025.

评论 0

0 / 1000