提示工程 | | 约 23 分钟 | 9,122 字

Prompt 优化实战:从 60 分到 90 分

系统化的 Prompt 优化方法论:基线建立、A/B 测试、指标驱动迭代

大多数人优化 Prompt 的方式

“试试改个词?""加个例子?""换个说法?”

这种凭感觉的优化方式,就像蒙着眼睛调参——偶尔能碰对,但大多数时候在原地打转。

我们需要一套系统化的方法论,让 Prompt 优化变得可衡量、可复现、可持续。


优化方法论:四步循环

建立基线 → 定义指标 → 迭代优化 → 验证效果
    ↑                                    ↓
    └────────────────────────────────────┘

第一步:建立基线

在优化之前,先搞清楚现在的 Prompt 表现如何。

import json
import time

def establish_baseline(prompt: str, test_cases: list[dict]) -> dict:
    """建立 Prompt 的基线表现"""

    results = {
        "prompt_version": "v1.0",
        "timestamp": time.strftime("%Y-%m-%d %H:%M"),
        "total_cases": len(test_cases),
        "passed": 0,
        "failed": 0,
        "details": []
    }

    for case in test_cases:
        output = call_llm(f"{prompt}\n\n输入:{case['input']}")

        passed = case["evaluate"](output)
        results["passed" if passed else "failed"] += 1

        results["details"].append({
            "input": case["input"],
            "output": output[:200],
            "expected": case.get("expected", ""),
            "passed": passed,
            "notes": ""
        })

    results["score"] = results["passed"] / results["total_cases"]
    return results

测试用例设计

好的测试用例是优化的基础。覆盖以下几类:

类型说明占比建议
正常用例典型的、预期的输入40%
边界用例极端情况、空输入、超长输入20%
对抗用例容易出错的、有歧义的输入20%
格式用例验证输出格式是否正确20%
test_cases = [
    # 正常用例
    {
        "input": "用户无法登录,提示密码错误",
        "expected": "包含:复现步骤、可能原因、解决方案",
        "evaluate": lambda x: all(k in x for k in ["步骤", "原因", "方案"])
    },
    # 边界用例
    {
        "input": "",
        "expected": "应该提示输入为空",
        "evaluate": lambda x: "请提供" in x or "输入" in x
    },
    # 对抗用例
    {
        "input": "这不是一个 Bug,我只是想聊天",
        "expected": "应该礼貌引导回正题",
        "evaluate": lambda x: "Bug" in x or "问题" in x
    },
    # 格式用例
    {
        "input": "页面加载很慢,大概要 10 秒",
        "expected": "输出应该是结构化的",
        "evaluate": lambda x: "##" in x or "1." in x
    },
]

第二步:定义成功指标

不同任务需要不同的评估指标:

分类任务

def evaluate_classification(output: str, expected: str) -> dict:
    """评估分类任务"""
    predicted = output.strip().lower()
    expected = expected.strip().lower()

    return {
        "accuracy": predicted == expected,
        "predicted": predicted,
        "expected": expected
    }

生成任务

生成任务的评估更复杂,通常需要多个维度:

def evaluate_generation(output: str, criteria: dict) -> dict:
    """评估生成任务"""

    scores = {}

    # 1. 完整性:是否包含所有必要部分
    required_sections = criteria.get("required_sections", [])
    present = sum(1 for s in required_sections if s in output)
    scores["completeness"] = present / len(required_sections) if required_sections else 1.0

    # 2. 长度:是否在合理范围内
    word_count = len(output)
    min_len = criteria.get("min_length", 100)
    max_len = criteria.get("max_length", 2000)
    scores["length"] = 1.0 if min_len <= word_count <= max_len else 0.5

    # 3. 格式:是否符合要求的格式
    format_checks = criteria.get("format_checks", [])
    format_passed = sum(1 for check in format_checks if check(output))
    scores["format"] = format_passed / len(format_checks) if format_checks else 1.0

    # 4. 用 LLM 评估质量(1-10 分)
    quality_score = llm_evaluate_quality(output, criteria.get("task_description", ""))
    scores["quality"] = quality_score / 10

    # 加权总分
    weights = {"completeness": 0.3, "length": 0.1, "format": 0.2, "quality": 0.4}
    scores["total"] = sum(scores[k] * weights[k] for k in weights)

    return scores

def llm_evaluate_quality(output: str, task_description: str) -> int:
    """用 LLM 评估输出质量"""
    response = call_llm(f"""请评估以下输出的质量(1-10 分)。

任务描述:{task_description}
输出内容:{output}

评分标准:
- 1-3 分:质量差,有明显错误或不相关
- 4-6 分:质量一般,基本完成但有改进空间
- 7-8 分:质量好,准确且有用
- 9-10 分:质量优秀,超出预期

请只输出一个数字。""")

    import re
    match = re.search(r'\d+', response)
    return int(match.group()) if match else 5

第三步:迭代优化

有了基线和指标,就可以开始系统性优化了。

常见优化模式

优化模式适用场景效果
添加角色定义输出风格不对
添加 Few-Shot 示例格式不对或理解有偏差
细化约束条件输出超出范围
添加 CoT 指令推理类任务准确率低
拆分为多步单个 Prompt 太复杂
调整输出格式后续处理困难
添加负面示例特定错误反复出现

A/B 测试框架

def ab_test(prompt_a: str, prompt_b: str, test_cases: list[dict]) -> dict:
    """A/B 测试两个 Prompt"""

    results_a = {"scores": [], "total_time": 0}
    results_b = {"scores": [], "total_time": 0}

    for case in test_cases:
        # 测试 Prompt A
        start = time.time()
        output_a = call_llm(f"{prompt_a}\n\n输入:{case['input']}")
        results_a["total_time"] += time.time() - start
        results_a["scores"].append(1 if case["evaluate"](output_a) else 0)

        # 测试 Prompt B
        start = time.time()
        output_b = call_llm(f"{prompt_b}\n\n输入:{case['input']}")
        results_b["total_time"] += time.time() - start
        results_b["scores"].append(1 if case["evaluate"](output_b) else 0)

    # 计算统计数据
    avg_a = sum(results_a["scores"]) / len(results_a["scores"])
    avg_b = sum(results_b["scores"]) / len(results_b["scores"])

    return {
        "prompt_a_score": avg_a,
        "prompt_b_score": avg_b,
        "winner": "A" if avg_a > avg_b else "B" if avg_b > avg_a else "平局",
        "improvement": f"{(avg_b - avg_a) / avg_a * 100:+.1f}%" if avg_a > 0 else "N/A",
        "prompt_a_avg_time": results_a["total_time"] / len(test_cases),
        "prompt_b_avg_time": results_b["total_time"] / len(test_cases),
    }

第四步:验证效果

优化后要在独立的测试集上验证,避免过拟合。

def validate_optimization(
    old_prompt: str,
    new_prompt: str,
    validation_cases: list[dict]  # 不同于优化时用的测试用例
) -> dict:
    """在独立验证集上验证优化效果"""

    old_results = establish_baseline(old_prompt, validation_cases)
    new_results = establish_baseline(new_prompt, validation_cases)

    return {
        "old_score": old_results["score"],
        "new_score": new_results["score"],
        "improvement": new_results["score"] - old_results["score"],
        "regression_cases": [
            d for d_old, d_new in zip(old_results["details"], new_results["details"])
            if (d := d_old)["passed"] and not d_new["passed"]
        ]
    }

注意 regression_cases——这些是优化后反而变差的用例。如果回归太多,说明优化方向有问题。


实战案例:优化一个 Bug 分类 Prompt

初始 Prompt(v1.0,得分 60%)

请将以下 Bug 报告分类为:UI、API、数据库、性能、安全。

Bug 报告:{input}

问题:分类不准确,经常把性能问题归为 API 问题。

优化 1:添加分类定义(v1.1,得分 72%)

请将以下 Bug 报告分类为以下类别之一:

- UI:界面显示、样式、交互相关的问题
- API:接口调用、请求响应、状态码相关的问题
- 数据库:数据存储、查询、迁移相关的问题
- 性能:加载速度、响应时间、资源占用相关的问题
- 安全:认证、授权、数据泄露相关的问题

Bug 报告:{input}

请只输出类别名称。

提升了 12%,但还不够。

优化 2:添加 Few-Shot 示例(v1.2,得分 85%)

请将 Bug 报告分类为:UI、API、数据库、性能、安全。

示例:
Bug:页面加载需要 15 秒 → 性能
Bug:按钮点击没反应 → UI
Bug:POST /users 返回 500 → API
Bug:用户密码明文存储 → 安全
Bug:查询超时,SQL 执行慢 → 数据库

Bug 报告:{input}
类别:

又提升了 13%。Few-Shot 示例的效果非常明显。

优化 3:添加 CoT + 边界处理(v1.3,得分 91%)

请将 Bug 报告分类为:UI、API、数据库、性能、安全。

分类规则:
- 如果涉及多个类别,选择根本原因所在的类别
- "慢"不一定是性能问题,要看原因(SQL 慢→数据库,接口慢→API)
- 如果无法确定,选择最可能的类别并说明原因

示例:
Bug:页面加载需要 15 秒 → 分析:加载慢是性能问题 → 性能
Bug:POST /users 返回 500 → 分析:接口错误 → API
Bug:查询用户列表很慢,SQL 执行了 30 秒 → 分析:虽然表现为慢,但根因是 SQL → 数据库

Bug 报告:{input}

请先简要分析,然后给出分类。
格式:
分析:[一句话分析]
类别:[类别名]

最终得分 91%,从 60% 提升了 31 个百分点。

优化过程总结

版本改动得分提升
v1.0初始版本60%-
v1.1添加分类定义72%+12%
v1.2添加 Few-Shot85%+13%
v1.3添加 CoT + 边界规则91%+6%

优化清单

当你的 Prompt 效果不好时,按这个清单逐项检查:

准确性问题

  • 任务描述是否足够清晰?
  • 是否提供了足够的上下文?
  • 是否需要添加 Few-Shot 示例?
  • 是否需要 CoT 推理?
  • 是否有歧义的表述?

格式问题

  • 输出格式是否明确定义?
  • 是否提供了格式示例?
  • 是否需要 JSON/XML 等结构化输出?

一致性问题

  • 多次运行结果是否一致?
  • 是否需要降低 temperature?
  • 是否需要 Self-Consistency?

边界问题

  • 空输入如何处理?
  • 超长输入如何处理?
  • 不相关输入如何处理?
  • 多类别/多答案如何处理?

记录优化历史

每次优化都要记录,方便回溯和团队协作:

optimization_log = {
    "task": "Bug 报告分类",
    "versions": [
        {
            "version": "v1.0",
            "date": "2026-03-01",
            "prompt": "...",
            "score": 0.60,
            "changes": "初始版本",
            "notes": "分类不准确,性能和 API 经常混淆"
        },
        {
            "version": "v1.1",
            "date": "2026-03-05",
            "prompt": "...",
            "score": 0.72,
            "changes": "添加了每个分类的定义",
            "notes": "定义帮助区分了大部分情况,但边界 case 仍有问题"
        },
        {
            "version": "v1.2",
            "date": "2026-03-08",
            "prompt": "...",
            "score": 0.85,
            "changes": "添加了 5 个 Few-Shot 示例",
            "notes": "示例效果显著,特别是对边界 case"
        },
        {
            "version": "v1.3",
            "date": "2026-03-10",
            "prompt": "...",
            "score": 0.91,
            "changes": "添加 CoT 和边界处理规则",
            "notes": "CoT 让模型先分析再分类,减少了冲动判断"
        }
    ]
}

总结

Prompt 优化不是玄学,而是工程。关键是:

  1. 有基线:知道现在多少分
  2. 有指标:知道什么算”好”
  3. 有方法:知道往哪个方向改
  4. 有验证:知道改了之后是否真的变好了

大多数 Prompt 通过 3-5 轮迭代就能从 60 分提升到 85-90 分。剩下的 10 分往往需要更高级的技巧(Chaining、Self-Consistency 等)或者更多的测试数据。

优化 Prompt 就像优化代码:先让它跑起来,再让它跑得好,最后让它跑得快。不要试图一步到位,迭代才是王道。

评论

加载中...

相关文章

分享:

评论

加载中...