如何使您的补全输出与新的 seed 参数保持一致

2023年11月6日
在 Github 中打开

TLDR:开发者现在可以在 Chat Completion 请求中指定 seed 参数,以接收(大部分)一致的输出。为了帮助您跟踪这些更改,我们公开了 system_fingerprint 字段。如果此值不同,您可能会看到不同的输出,这是由于我们在系统上所做的更改。请注意,此功能目前为 beta 版,并且目前仅支持 gpt-4-1106-previewgpt-3.5-turbo-1106

背景

在使用我们的 API 时,用户社区一直强烈要求可复现性。例如,当被授予获得可复现数值结果的能力时,用户可以解锁相当多的对数值变化敏感的用例。

模型级别实现一致性输出的功能

Chat Completions 和 Completions API 默认是非确定性的(这意味着模型输出可能因请求而异),但现在提供了一些使用一些模型级别控制来实现确定性输出的控制。

这可以解锁一致的补全,从而可以完全控制基于 API 构建的任何模型的行为,并且对于复现结果和测试非常有用,因此您可以确切地知道您会得到什么,从而安心无忧。

实现一致性输出

要接收 API 调用之间大部分确定性的输出

  • seed 参数设置为您选择的任何整数,但在所有请求中使用相同的值。例如,12345
  • 将所有其他参数(prompt、temperature、top_p 等)在所有请求中设置为相同的值。
  • 在响应中,检查 system_fingerprint 字段。系统指纹是 OpenAI 服务器用于生成补全的当前模型权重、基础设施和其他配置选项组合的标识符。当您更改请求参数或 OpenAI 更新服务我们模型的基础设施的数值配置时(每年可能会发生几次),它会发生变化。

如果您的请求中 seed、请求参数和 system_fingerprint 都匹配,则模型输出将基本相同。即使请求参数和 system_fingerprint 匹配,响应也可能会有所不同,这归因于我们模型固有的非确定性,但这种情况发生的几率很小。

模型级别实现一致性输出的控制 - seedsystem_fingerprint

seed

如果指定,我们的系统将尽最大努力确定性地采样,以便使用相同的 seed 和参数重复请求应返回相同的结果。不保证确定性,您应参考 system_fingerprint 响应参数来监控后端的变化。

system_fingerprint

此指纹代表模型运行的后端配置。它可以与 seed 请求参数结合使用,以了解何时进行了可能影响确定性的后端更改。这是用户是否应期望“几乎总是相同结果”的指标。

示例:使用固定 seed 生成短摘录

在此示例中,我们将演示如何使用固定 seed 生成短摘录。这在您需要为测试、调试或需要一致输出的应用程序生成一致结果的场景中特别有用。

Python SDK

注意 切换到最新版本的 SDK(撰写本文时为 1.3.3)。

!pip install --upgrade openai # Switch to the latest version of OpenAI (1.3.3 at time of writing)
import openai
import asyncio
from IPython.display import display, HTML

from utils.embeddings_utils import (
    get_embedding,
    distances_from_embeddings
)

GPT_MODEL = "gpt-3.5-turbo-1106"
async def get_chat_response(
    system_message: str, user_request: str, seed: int = None, temperature: float = 0.7
):
    try:
        messages = [
            {"role": "system", "content": system_message},
            {"role": "user", "content": user_request},
        ]

        response = openai.chat.completions.create(
            model=GPT_MODEL,
            messages=messages,
            seed=seed,
            max_tokens=200,
            temperature=temperature,
        )

        response_content = response.choices[0].message.content
        system_fingerprint = response.system_fingerprint
        prompt_tokens = response.usage.prompt_tokens
        completion_tokens = response.usage.total_tokens - response.usage.prompt_tokens

        table = f"""
        <table>
        <tr><th>Response</th><td>{response_content}</td></tr>
        <tr><th>System Fingerprint</th><td>{system_fingerprint}</td></tr>
        <tr><th>Number of prompt tokens</th><td>{prompt_tokens}</td></tr>
        <tr><th>Number of completion tokens</th><td>{completion_tokens}</td></tr>
        </table>
        """
        display(HTML(table))

        return response_content
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

def calculate_average_distance(responses):
    """
    This function calculates the average distance between the embeddings of the responses.
    The distance between embeddings is a measure of how similar the responses are.
    """
    # Calculate embeddings for each response
    response_embeddings = [get_embedding(response) for response in responses]

    # Compute distances between the first response and the rest
    distances = distances_from_embeddings(response_embeddings[0], response_embeddings[1:])

    # Calculate the average distance
    average_distance = sum(distances) / len(distances)

    # Return the average distance
    return average_distance

首先,让我们尝试在不使用 seed 参数的情况下生成几个不同版本的关于“火星之旅”的短摘录。这是默认行为

topic = "a journey to Mars"
system_message = "You are a helpful assistant."
user_request = f"Generate a short excerpt of news about {topic}."

responses = []


async def get_response(i):
    print(f'Output {i + 1}\n{"-" * 10}')
    response = await get_chat_response(
        system_message=system_message, user_request=user_request
    )
    return response


responses = await asyncio.gather(*[get_response(i) for i in range(5)])
average_distance = calculate_average_distance(responses)
print(f"The average similarity between responses is: {average_distance}")
Output 1
----------
响应“美国宇航局的火星任务进入关键阶段,航天器成功进入环绕这颗红色星球的轨道。这项历史性的旅程始于一年多前,吸引了全世界的目光,科学家和宇航员准备首次登陆火星。预计这项任务将为我们提供有关这颗行星的地质、大气层以及未来维持人类生命潜力的宝贵见解。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量76
Output 2
----------
响应“美国宇航局的毅力号探测器成功降落在火星上,标志着探索这颗红色星球的任务取得了重大里程碑。该探测器配备了先进的科学仪器,用于寻找古代微生物生命的迹象,并收集岩石和土壤样本以供未来返回地球。这一历史性成就为进一步探索和未来人类登陆火星的任务铺平了道路。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量76
Output 3
----------
响应“SpaceX 昨天成功发射了首次载人火星任务,标志着太空探索史上的一个历史性里程碑。由四名宇航员组成的机组人员将在接下来的六个月里前往这颗红色星球,在那里他们将进行开创性的研究和实验。这项任务代表着在火星上建立人类存在的重要一步,并为未来的行星际旅行铺平了道路。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量72
Output 4
----------
响应“美国宇航局最新的火星任务超出预期,毅力号探测器发现了关于这颗红色星球过去的诱人线索。科学家们对古代河床和沉积岩的发现感到兴奋,这提高了在火星上找到过去生命迹象的希望。随着这一激动人心的进展,将人类送往火星的梦想感觉比以往任何时候都更近了。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量72
Output 5
----------
响应“美国宇航局毅力号探测器成功登陆火星,开始探索任务。在太空探索史上的一个历史性时刻,美国宇航局的毅力号探测器已成功登陆火星表面。经过七个月的旅程,该探测器在耶泽罗陨石坑着陆,科学家们认为该地点可能曾经是一个湖泊,并可能包含古代微生物生命的迹象。该探测器的主要任务是寻找火星上过去生命的证据,并收集岩石和土壤样本以供未来返回地球。毅力号配备了先进的科学仪器,包括相机、光谱仪和钻头,将开始对火星表面进行探索,提供有关该行星地质和潜在宜居性的宝贵数据和见解。这次成功的着陆标志着人类探索红色星球的征程中的一个重要里程碑,并为未来载人登陆火星的任务铺平了道路。美国宇航局的毅力号探测器已准备好解开火星的奥秘并释放新的可能性”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量200
The average similarity between responses is: 0.1136714512418833

现在,让我们尝试使用常量 seed 123 和 temperature 0 运行相同的代码,并比较响应和 system_fingerprint

SEED = 123
responses = []


async def get_response(i):
    print(f'Output {i + 1}\n{"-" * 10}')
    response = await get_chat_response(
        system_message=system_message,
        seed=SEED,
        temperature=0,
        user_request=user_request,
    )
    return response


responses = await asyncio.gather(*[get_response(i) for i in range(5)])

average_distance = calculate_average_distance(responses)
print(f"The average distance between responses is: {average_distance}")
Output 1
----------
响应“美国宇航局毅力号探测器成功登陆火星。在一项历史性成就中,美国宇航局的毅力号探测器已成功登陆火星表面,标志着红色星球探索的一个重要里程碑。该探测器从地球行驶了超过 2.93 亿英里,配备了最先进的仪器,旨在寻找古代微生物生命的迹象,并收集岩石和土壤样本以供未来返回地球。这项任务代表着我们在理解火星以及未来人类探索这颗星球的潜力方面迈出了重要一步。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量113
Output 2
----------
响应“美国宇航局的毅力号探测器成功登陆火星,标志着太空探索史上的一个历史性里程碑。该探测器配备了先进的科学仪器,用于寻找古代微生物生命的迹象,并收集样本以供未来返回地球。这项任务为未来人类探索这颗红色星球铺平了道路,因为科学家和工程师不断突破太空旅行的界限,并扩展我们对宇宙的理解。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量81
Output 3
----------
响应“美国宇航局的毅力号探测器成功登陆火星,标志着太空探索史上的一个历史性里程碑。该探测器配备了先进的科学仪器,用于寻找古代微生物生命的迹象,并收集样本以供未来返回地球。这项任务为未来人类探索这颗红色星球铺平了道路,因为美国宇航局不断突破太空探索的界限。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量72
Output 4
----------
响应“美国宇航局的毅力号探测器成功登陆火星,标志着太空探索史上的一个历史性里程碑。该探测器配备了先进的科学仪器,用于寻找古代微生物生命的迹象,并收集样本以供未来返回地球。这项任务为未来人类探索这颗红色星球铺平了道路,因为科学家和工程师不断突破太空旅行的界限,并扩展我们对宇宙的理解。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量81
Output 5
----------
响应“美国宇航局的毅力号探测器成功登陆火星,标志着太空探索史上的一个历史性里程碑。该探测器配备了先进的科学仪器,用于寻找古代微生物生命的迹象,并收集样本以供未来返回地球。这项任务为未来人类探索这颗红色星球铺平了道路,因为科学家和工程师不断突破太空旅行的界限。”
系统指纹fp_772e8125bb
Prompt tokens 数量29
Completion tokens 数量74
The average distance between responses is: 0.0449054397632461

正如我们所观察到的,seed 参数允许我们生成更加一致的结果。

结论

我们演示了如何使用固定整数 seed 从我们的模型生成一致的输出。这在可复现性很重要的场景中特别有用。但是,重要的是要注意,虽然 seed 确保了一致性,但它不能保证输出的质量。请注意,当您想要使用可复现的输出时,您需要将 seed 在所有 Chat Completions 调用中设置为相同的整数。您还应该匹配任何其他参数,如 temperaturemax_tokens 等。可复现输出的进一步扩展可能是当对不同 prompt 或模型的性能进行基准测试/评估时,使用一致的 seed,以确保每个版本都在相同的条件下进行评估,从而使比较公平且结果可靠。