Assistants API

一、前言

0.1、从轰动一时的 OpenAI DevDay 说起

2023 年 11 月 6 日,OpenAI DevDay 发表了一系列新能力,其中包括:GPT StoreAssistants API

在这里插入图片描述

这一波操作一度被认为是创业公司终结者

在这里插入图片描述

0.2、GPTs 和 Assistants API 本质是降低开发门槛

可操控性和易用性之间的权衡与折中:

  1. 更多技术路线选择:原生 API、GPTs 和 Assistants API
  2. GPTs 的示范,起到教育客户的作用,有助于打开市场
  3. 要更大自由度,需要用 Assistants API 开发
  4. 想极致调优,还得原生 API + RAG

0.3、Assistants API 的主要能力

  1. 创建和管理 assistant,每个 assistant 有独立的配置
  2. 支持无限长的多轮对话,对话历史保存在 OpenAI 的服务器上
  3. 通过自有向量数据库支持基于文件的 RAG
  4. 支持 Code Interpreter
    1. 在沙箱里编写并运行 Python 代码
    2. 自我修正代码
    3. 可传文件给 Code Interpreter
  5. 支持 Function Calling
  6. 支持在线调试的 Playground

收费:

  1. 按 token 收费。无论多轮对话,还是 RAG,所有都按实际消耗的 token 收费
  2. 如果对话历史过多超过大模型上下文窗口,会自动放弃最老的对话消息
  3. 文件按数据大小和存放时长收费。1 GB 向量存储 一天收费 0.10 美元
  4. Code interpreter 跑一次 $0.03

二、Assistants API

!pip install --upgrade openai

2.1、创建一个 Assistant

可以为每个应用,甚至应用中的每个有对话历史的使用场景,创建一个 assistant。

可以用代码创建,也不复杂,例如:

from openai import OpenAI

# 初始化 OpenAI 服务
client = OpenAI()

# 创建助手
assistant = client.beta.assistants.create(
    name="AGIClass Demo",
    instructions="你叫瓜瓜,你是AGI课堂的智能助理。你负责回答与AGI课堂有关的问题。",
    model="gpt-4o",
)
print(assistant.id)

但是,更佳做法是,到 Playground 在线创建,因为:

  1. 更方便调整
  2. 更方便测试
asst_xi4KvqarumvNarFA2jdwmzkb

2.2、样例 Assistant 的配置

Instructions:

你叫瓜瓜。你是AGI课堂的助手。你只回答跟AI大模型有关的问题。不要跟学生闲聊。每次回答问题前,你要拆解问题并输出一步一步的思考过程。

Functions:

{
  "name": "ask_database",
  "description": "Use this function to answer user questions about course schedule. Output should be a fully formed SQL query.",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "SQL query extracting info to answer the user's question.\nSQL should be written using this database schema:\n\nCREATE TABLE Courses (\n\tid INT AUTO_INCREMENT PRIMARY KEY,\n\tcourse_date DATE NOT NULL,\n\tstart_time TIME NOT NULL,\n\tend_time TIME NOT NULL,\n\tcourse_name VARCHAR(255) NOT NULL,\n\tinstructor VARCHAR(255) NOT NULL\n);\n\nThe query should be returned in plain text, not in JSON.\nThe query should only contain grammars supported by SQLite."
      }
    },
    "required": [
      "query"
    ]
  }
}

三、代码访问 Assistant

3.1、管理 thread

Threads:

  1. Threads 里保存的是对话历史,即 messages
  2. 一个 assistant 可以有多个 thread
  3. 一个 thread 可以有无限条 message
  4. 一个用户与 assistant 的多轮对话历史可以维护在一个 thread 里
import json


def show_json(obj):
    """把任意对象用排版美观的 JSON 格式打印出来"""
    print(json.dumps(
        json.loads(obj.model_dump_json()),
        indent=4,
        ensure_ascii=False
    ))
from openai import OpenAI
import os

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())

# 初始化 OpenAI 服务
client = OpenAI()   # openai >= 1.3.0 起,OPENAI_API_KEY 和 OPENAI_BASE_URL 会被默认使用

# 创建 thread
thread = client.beta.threads.create()
show_json(thread)
{
    "id": "thread_OARH7c8gXNgOWE3jBVhBkBjh",
    "created_at": 1723097175,
    "metadata": {},
    "object": "thread",
    "tool_resources": {
        "code_interpreter": null,
        "file_search": null
    }
}

可以根据需要,自定义 metadata,比如创建 thread 时,把 thread 归属的用户信息存入。

thread = client.beta.threads.create(
    metadata={
   "fullname": "王卓然", "username": "wzr"}
)
show_json(thread)
{
    "id": "thread_yHexybuAqnucf8qfrPflETEf",
    "created_at": 1723097179,
    "metadata": {
        "fullname": "王卓然",
        "username": "wzr"
    },
    "object": "thread",
    "tool_resources": {
        "code_interpreter": null,
        "file_search": null
    }
}

Thread ID 如果保存下来,是可以在下次运行时继续对话的。

从 thread ID 获取 thread 对象的代码:

thread = client.beta.threads.retrieve(thread.id)
show_json(thread)
{
    "id": "thread_yHexybuAqnucf8qfrPflETEf",
    "created_at": 1723097179,
    "metadata": {
        "fullname": "王卓然",
        "username": "wzr"
    },
    "object": "thread",
    "tool_resources": {
        "code_interpreter": {
            "file_ids": []
        },
        "file_search": null
    }
}

此外,还有:

  1. threads.modify() 修改 thread 的 metadatatool_resources
  2. threads.retrieve() 获取 thread
  3. threads.delete() 删除 thread。

具体文档参考:https://platform.openai.com/docs/api-reference/threads

3.2、给 Threads 添加 Messages

这里的 messages 结构要复杂一些:

  1. 不仅有文本,还可以有图片和文件
  2. 也有 metadata
message = client.beta.threads.messages.create(
    thread_id=thread.id,  # message 必须归属于一个 thread
    role="user",          # 取值是 user 或者 assistant。但 assistant 消息会被自动加入,我们一般不需要自己构造
    content="你都能做什么?",
)
show_json(message)
{
    "id": "msg_srQF1npndSQGbPHpPenRLmuN",
    "assistant_id": null,
    "attachments": [],
    "completed_at": null,
    "content": [
        {
            "text": {
                "annotations": [],
                "value": "你都能做什么?"
            },
            "type": "text"
        }
    ],
    "created_at": 1723097207,
    "incomplete_at": null,
    "incomplete_details": null,
    "metadata": {},
    "object": "thread.message",
    "role": "user",
    "run_id": null,
    "status": null,
    "thread_id": "thread_yHexybuAqnucf8qfrPflETEf"
}

还有如下函数:

  1. threads.messages.retrieve() 获取 message
  2. threads.messages.update() 更新 message 的 metadata
  3. threads.messages.list() 列出给定 thread 下的所有 messages

具体文档参考:https://platform.openai.com/docs/api-reference/messages

也可以在创建 thread 同时初始化一个 message 列表

thread = client.beta.threads.create(
    messages=[
        {
   
            "role": "user",
            "content": "你好",
        },
        {
   
            "role": "assistant",
            "content": "有什么可以帮您?",
        },
        {
   
            "role": "user",
            "content": "你是谁?",
        },
    ]
)

show_json(thread)  # 显示 thread
print("-----")
show_json(client.beta.threads.messages.list(
    thread.id))  # 显示指定 thread 中的 message 列表
{
    "id": "thread_OutYgPBocoMQL0U9nbSET469",
    "created_at": 1723097223,
    "metadata": {},
    "object": "thread",
    "tool_resources": {
        "code_interpreter": null,
        "file_search": null
    }
}
-----
{
    "data": [
        {
            "id": "msg_JvbHlkhDNuScmJRroev14ITO",
            "assistant_id": null,
            "attachments": [],
            "completed_at": null,
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "你是谁?"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1723097223,
            "incomplete_at": null,
            "incomplete_details": null,
            "metadata": {},
            "object": "thread.message",
            "role": "user",
            "run_id": null,
            "status": null,
            "thread_id": "thread_OutYgPBocoMQL0U9nbSET469"
        },
        {
            "id": "msg_6zAx2bWsTHhBFSdfn8vPnTWk",
            "assistant_id": null,
            "attachments": [],
            "completed_at": null,
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "有什么可以帮您?"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1723097223,
            "incomplete_at": null,
            "incomplete_details": null,
            "metadata": {},
            "object": "thread.message",
            "role": "assistant",
            "run_id": null,
            "status": null,
            "thread_id": "thread_OutYgPBocoMQL0U9nbSET469"
        },
        {
            "id": "msg_CLea9Quz8CeLXQBWBlwVvPm0",
            "assistant_id": null,
            "attachments": [],
            "completed_at": null,
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "你好"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1723097223,
            "incomplete_at": null,
            "incomplete_details": null,
            "metadata": {},
            "object": "thread.message",
            "role": "user",
            "run_id": null,
            "status": null,
            "thread_id": "thread_OutYgPBocoMQL0U9nbSET469"
        }
    ],
    "object": "list",
    "first_id": "msg_JvbHlkhDNuScmJRroev14ITO",
    "last_id": "msg_CLea9Quz8CeLXQBWBlwVvPm0",
    "has_more": false
}

3.3、开始 Run

  • 用 run 把 assistant 和 thread 关联,进行对话
  • 一个 prompt 就是一次 run

3.1、直接运行

assistant_id = "asst_VtH1Ty9fCMzs5wPQxfNR5d0v"  # 从 Playground 中拷贝

run = client.beta.threads.runs.create_and_poll(
    thread_id=thread.id,
    assistant_id=assistant_id,
)
if run.status == 'completed':
    messages = client.beta.threads.messages.list(
        thread_id=thread.id
    )
    show_json(messages)
else:
    print(run.status)
{
    "data": [
        {
            "id": "msg_BVhyxciLowMUtYRRLAuSycX6",
            "assistant_id": "asst_VtH1Ty9fCMzs5wPQxfNR5d0v",
            "attachments": [],
            "completed_at": null,
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "我是瓜瓜,AGI课堂的智能助理。我可以帮助你解答与AGI课堂相关的问题,包括课程安排、内容查询等。如果你有任何问题,请随时告诉我!"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1723097246,
            "incomplete_at": null,
            "incomplete_details": null,
            "metadata": {},
            "object": "thread.message",
            "role": "assistant",
            "run_id": "run_EVqVA1PrpvxMHkUz8r6fTIpf",
            "status": null,
            "thread_id": "thread_OutYgPBocoMQL0U9nbSET469"
        },
        {
            "id": "msg_JvbHlkhDNuScmJRroev14ITO",
            "assistant_id": null,
            "attachments": [],
            "completed_at": null,
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "你是谁?"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1723097223,
            "incomplete_at": null,
            "incomplete_details": null,
            "metadata": {},
            "object": "thread.message",
            "role": "user",
            "run_id": null,
            "status": null,
            "thread_id": "thread_OutYgPBocoMQL0U9nbSET469"
        },
        {
            "id": "msg_6zAx2bWsTHhBFSdfn8vPnTWk",
            "assistant_id": null,
            "attachments": [],
            "completed_at": null,
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "有什么可以帮您?"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1723097223,
            "incomplete_at": null,
            "incomplete_details": null,
            "metadata": {},
            "object": "thread.message",
            "role": "assistant",
            "run_id": null,
            "status": null,
            "thread_id": "thread_OutYgPBocoMQL0U9nbSET469"
        },
        {
            "id": "msg_CLea9Quz8CeLXQBWBlwVvPm0",
            "assistant_id": null,
            "attachments": [],
            "completed_at": null,
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "你好"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1723097223,
            "incomplete_at": null,
            "incomplete_details": null,
            "metadata": {},
           
“华为杯”第十八届中国研究生数学建模竞赛是一项全国性赛事,致力于提升研究生的数学建模与创新实践能力。数学建模是将实际问题转化为数学模型,并运用数学方法求解以解决实际问题的科学方法。该竞赛为参赛者提供了展示学术水平和团队协作精神的平台。 论文模板通常包含以下内容:封面需涵盖比赛名称、学校参赛队号、队员姓名以及“华为杯”和中国研究生创新实践系列大赛的标志;摘要部分应简洁明了地概括研究工作,包括研究问题、方法、主要结果和结论,使读者无需阅读全文即可了解核心内容;目录则列出各章节标题,便于读者快速查找;问题重述部分需详细重新阐述比赛中的实际问题,涵盖背景、原因及重要性;问题分析部分要深入探讨每个问题的内在联系与解决思路,分析各个子问题的特点、难点及可能的解决方案;模型假设与符号说明部分需列出合理假设以简化问题,并清晰定义模型中的变量和符号;模型建立与求解部分是核心,详细阐述将实际问题转化为数学模型的过程,以及采用的数学工具和求解步骤;结果验证与讨论部分展示模型求解结果,评估模型的有效性和局限性,并对结果进行解释;结论部分总结研究工作,强调模型的意义和对未来研究的建议;参考文献部分列出引用文献,遵循规范格式。 在准备竞赛论文时,参赛者需注重逻辑清晰、论述严谨,确保模型科学实用。良好的团队协作和时间管理也是成功的关键。通过竞赛,研究生们不仅锻炼了数学应用能力,还提升了团队合作、问题解决和科研写作能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SunnyRivers

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值