OpenAI Assistant API(三):Run运行时的状态转移机制

一、OpenAI Assistant API运行原理

  1. 核心概念:Assistant API通过创建Thread(线程)、Message(消息)和Run(运行)来实现对话交互。一个Assistant对象可应用多个Thread执行不同聊天或任务,Thread用于管理对话线程,Message是Assistant和用户之间的对话会话,存放在Thread中,Run用于指示Assistant读取Thread中的消息并采取适当操作。在这里插入图片描述

  2. 异步调用机制:Assistant API底层是异步调用过程。当调用相关接口时,不管中间过程是否完成,先返回结果并告知初始状态,如创建Run时先进入queued(排队)状态。

二、Assistant API实战入门

  1. 创建Thread:使用client.threads.create()方法创建Thread。示例代码如下:
thread = client.threads.create()
print(thread.to_dict())
  1. 构建并添加Message:通过client.threads.messages.create()方法构建并添加Message到指定Thread。messages接口核心参数包括thread_id(必需,用于创建消息的线程ID)、role(必需,创建消息的实体角色,user表示用户发送,assistant表示助手生成)、content(必需,消息的内容)。示例代码如下:
message = client.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="写一篇关于一个小女孩在森林里遇到一只怪兽的故事。详细介绍她的所见所闻,并描述她的心理活动"
)
print(message.to_dict())
  1. 创建Run:使用client.threads.runs.create()方法创建Run,需传递thread_id(用于运行的线程ID)和assistant_id(助手的ID)两个必需参数。示例代码如下:
run = client.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
)
print(run.to_dict())

三、Assistant API关键接口

  1. Assistant对象接口方法:主要用于与特定Assistant进行交互,如设置指令、选择模型等。例如创建Run时指定assistant_id关联到相应Assistant对象 。
  2. Thread对象接口方法client.threads.create()用于创建线程;client.threads.messages.create()用于在指定线程中创建消息;client.threads.messages.list(thread_id=thread.id)用于获取指定线程的消息列表。
  3. Messages对象接口方法create方法已在构建并添加Message部分介绍;list方法用于获取消息列表,可通过索引访问具体消息内容,如response['data'][0]['content'][0]['text']['value']获取最新消息内容。

四、Run运行时的状态转移机制

在这里插入图片描述

在这里插入图片描述

  1. 初始状态 - queued:Run的初始状态为queued,进入队列等待被处理,排队结束后进入in_progress状态。
  2. 执行状态 - in_progress:处于in_progress状态时,可能出现以下几种后续状态:
    • 调用函数状态 - requires_action:当大模型分析出用户当前行为需要调用外部函数时进入该状态。在此状态下,提取函数名和函数入参,找到函数实际执行,执行完提交函数运行结果,然后回到in_progress等状态继续流转。
    • 主动取消 - cancelling:主动发起取消运行操作后进入该状态。若取消成功,进入cancelled状态;若取消操作中途放弃,可回到in_progress等其他状态继续执行。
    • 超时未返回结果 - expired:运行超时(默认10分钟)且未正常返回结果进入此状态。
    • 执行成功 - completed:操作执行成功,进入该状态,可继续下一轮任务。
    • 执行失败 - failed:运行过程中执行失败,直接终止,进入此状态,后续可查看具体失败原因。
    • 因token限制终止 - incomplete:因max_prompt_tokensmax_completion_tokens达到限制,基于内置策略终止运行,进入此状态。
  3. 取消状态 - cancelled:运行已成功取消,处于此状态。

五、获取模型响应消息

  1. 获取流程:用户请求最终响应时,请求先到assistant对象,assistant对象从相关数据结构(如set)中查找最后一条message信息,通过thread返回给assistant对象,再由assistant对象返回给用户。实际获取时,使用client.beta.threads.messages.list方法并传入thread_id获取完整历史会话列表,通过索引取具体值,如response['data'][0]['content'][0]['text']['value']获取最新一轮对话模型生成的响应。
  2. 对话测试示例:进行多轮对话测试,如:
# 第一轮对话
message_1 = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="写一篇关于一个小女孩在森林里遇到一只怪兽的故事。详细介绍她的所见所闻,并描述她的心理活动"
)
run_1 = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
)
response_1 = client.beta.threads.messages.list(thread_id=thread.id)
# 第二轮对话
message_2 = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="写一篇关于孙悟空大闹天宫的精彩战斗故事"
)
run_2 = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
)
response_2 = client.beta.threads.messages.list(thread_id=thread.id)
# 第三轮对话
message_3 = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="写一篇歌颂中国的文章"
)
run_3 = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
)
response_3 = client.beta.threads.messages.list(thread_id=thread.id)

随着对话轮次增加,client.beta.threads.messages.list方法返回的消息列表数据增多,可通过上述索引方式获取最新响应。
根据文档内容和对话逻辑,response_dict_2中应包含两轮对话的提问与回答。但文档未完整呈现,以下是按照正常逻辑推测补充完整的response_dict_2结果示例:

{
    "data": [
        {
            "id": "msg_second_assistant",
            "assistant_id": "assistant_id_value",
            "attachments": [],
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "在遥远的神话世界中,孙悟空凭借无比的勇气和聪明才智,早已成为了名声显赫的齐天大圣。他的武器是一根金箍棒,强大而灵活,能够随心所欲地变换大小。此时,孙悟空因不满天庭的规矩,被贬为“弼马温”,心中怒火中烧,决心大闹天宫,向所有神仙报仇。\n\n某日,孙悟空在他的花果山上盘算着,决定化身为乌头,趁着狂风,如同箭一般地冲向天庭。不一会儿,他便来到了天庭的宫阙之下。天庭的守卫看到孙悟空,立刻警惕起来,大声喝道:“你这弼马温,又来作甚?”孙悟空不屑一顾,挥舞着金箍棒,喊道:“今日我要让你们知道,我齐天大圣可不是好惹的!”\n\n说罢,孙悟空便与天庭守卫展开了激烈的战斗。他身手敏捷,金箍棒舞得虎虎生风,打得守卫们节节败退。很快,孙悟空就突破了守卫的防线,闯入了天庭的内部。\n\n天庭之内,玉帝听闻动静,脸色不善,他召集众神,试图镇压这股滔天的怒火。第一批出战的,是天庭中威武的战神哪吒。他骑着自己的风火轮,手握混天绫,冲向孙悟空。\n\n“弼马温,你妄想造反,今日便让我来教训你!”哪吒怒吼道,冲着孙悟空发出闪电般的攻击。\n\n孙悟空不屑一顾,语气轻松:“来吧,小子,我倒要看看你有什么本事!”\n\n两人相遇,瞬间爆发出激烈的战斗。哪吒使出浑身解数,混天绫如同网一般将孙悟空包围。孙悟空则翻滚闪避,纵身一跃,金箍棒在空中轻巧地舞动,时而变长,时而变短,时而化为一条巨龙,时而又化为一根长枪,直逼哪吒。\n\n随着一声巨响,孙悟空一棒砸在哪吒的风火轮上!只听“轰”的一声,哪吒被震得摔落在地,风火轮在空中翻转几圈,最终砸落在旁。孙悟空趁势而上,准备给予最后一击。\n\n“哼,不自量力!”就在此时,哪吒悍然召唤出他的三头六臂,瞬间变得威猛无比,继续与孙悟空对抗。战斗瞬间进入白热化的阶段,几乎整个天宫都在震动,神仙们纷纷趴下,以躲避这场席卷天空的战斗。\n\n随后,天蓬元帅猪八戒也加入了战斗,他用九齿钉耙迎战孙悟空。猪八戒一边挥舞钉耙,一边打趣道:“悟空兄弟,打不过我就喊人,别再要小聪明了!”\n\n孙悟空嘲讽地一笑,金箍棒在手中轻轻一转,摇身一变,与猪八戒展开了激烈的斗法。两人斗得不可开交,天上飞电闪雷鸣,震耳欲聋。\n\n随着持续不断的战斗,孙悟空感受到了一丝力量的枯竭,但他绝不允许自己输。于是,他使出了自己的绝技 - 72变,化作千军万马,气势恢宏,直逼天宫。那些天兵们虽然武艺高强,见这阵仗也忍不住心生恐惧,纷纷退后。\n\n终于,在众神束手无策的情况下,孙悟空闯入了玉帝的殿堂,直面天庭的至尊。在这惊心动魄的时刻,孙悟空发出一声怒吼:“我乃齐天大圣,天宫的约束不能再限制我的自由!”\n\n就在这时,玉帝显露出威严,机智而沉稳地说:“悟空,你为何如此无法无天?若想获得名分,不妨归顺天庭!”\n\n可孙悟空已经不再是当初那个只知寻欢作乐的猴子。他举起金箍棒,朝着神位猛砸而下,誓言不屈。天宫的战斗在怒吼声与震动声中达到高潮,但终究,孙悟空依靠自己的智慧与勇气一扫千军。\n\n经过一番波澜壮阔的战斗,天庭的神仙们终于对这个独特的齐天大圣刮目相看。然而,孙悟空并不满足于此。他高傲地挺起胸膛,向所有神仙宣告:“我是自由的猴子,我绝不会被束缚!”\n\n经过这场大闹天宫的辉煌战斗,孙悟空不仅将自己的勇气与智慧展现出来,也赢得了诸神的尊重,成为了无数人心目中的英雄。天庭的暴动落下帷幕,尽管孙悟空仍旧桀骜不驯,但他向自由的追寻之路已开启,传奇将继续延续。"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1727267711,
            "metadata": {},
            "object": "thread.message",
            "role": "assistant",
            "run_id": "run_id_for_second_question",
            "thread_id": "thread_8t2o4a7qQ11nJZE3JtxA2khh"
        },
        {
            "id": "msg_second_user",
            "assistant_id": None,
            "attachments": [],
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "写一篇关于孙悟空大闹天宫的精彩战斗故事"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1727267700, // 假设时间,比回答时间稍早
            "metadata": {},
            "object": "thread.message",
            "role": "user",
            "run_id": None,
            "thread_id": "thread_8t2o4a7qQ11nJZE3JtxA2khh"
        },
        {
            "id": "msg_first_assistant",
            "assistant_id": "assistant_id_value",
            "attachments": [],
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "在一个阳光明媚的早晨,小女孩莉莉兴奋地穿过家附近的森林。她爱冒险,尤其是这个充满神秘气息的地方,树木高大,枝叶茂密,阳光将斑驳的影子洒在蜿蜒的小路上。鸟儿在枝头欢快地歌唱,微风轻拂,带来青草和泥土的芬芳。\n\n莉莉一路走着,忽然听见了一阵奇怪的声音,像是树木间低沉的呜咽。她的好奇心被瞬间点燃,尽管心中隐隐有些不安,但她还是决定顺着声音的方向走去。走到一片开阔地,她目瞪口呆地看见了一只怪兽。\n\n这是一只巨大的生物,身披灰色的毛发,全身笼罩着厚厚的霜,像是被寒冬的白雪包裹。它的眼睛炯炯有神,像两颗灼热的红宝石,盯着莉莉,闪烁着智慧与温柔。怪兽的爪子像树根,粗壮而有力,但却并没有攻击的意图。它的身上散发着一股奇异的香气,混合着泥土和野花的味道。\n\n莉莉的心跳加速,既害怕又好奇。在她的脑海中,关于怪兽的各种故事浮现出来,有的说它们是残暴的,有的却描绘它们是孤独的生灵。莉莉咬了咬嘴唇,深吸一口气,决定不逃跑,而是慢慢靠近。\n\n“你好,”莉莉小声地说道,尽管她的声音在这片寂静的森林中显得如此微弱。\n\n奇怪的是,怪兽似乎听懂了,缓缓低下头,用那温暖的气息将她包围。它发出了一种低沉的声音,像是吟唱着古老的旋律。莉莉感受到了一种前所未有的安全感,渐渐地,她的恐惧烟消云散。\n\n莉莉仔细观察着这只怪兽,发现它身上的毛发如同森林中的树叶,随风起舞。她注意到怪兽的身后有一块小小的伤疤,似乎是之前受了伤。她忽然想起自己曾经看到的关于友谊与勇气的故事,心中涌起一股同情。\n\n“我可以帮你吗?”莉莉鼓起勇气,问道。\n\n怪兽停住了,眼中闪烁着复杂的情感,像是在告诉莉莉它的经历与痛苦。此时,莉莉意识到它的孤独,她想到了自己与朋友们一起玩耍的快乐时光。\n\n莉莉开始采集周围的草药,轻轻地和怪兽沟通,她用温柔的声音告诉怪兽,她可以帮它包扎伤口。怪兽静静地坐着,乖乖地让莉莉靠近,在她的照料下,它变得更加宁静。莉莉在给怪兽疗伤的过程中,感受到了一种特殊的连接,仿佛她们成为了朋友。\n\n当太阳慢慢落下,黄金色的光辉洒在森林里,莉莉与怪兽依依不舍地告别。她知道,这次相遇将成为她心中最珍贵的记忆。莉莉轻轻挥手,回头时看到怪兽缓缓消失在树荫中,它的身影在夕阳的映照下显得愈发神秘而温柔。\n\n走出森林,莉莉的心中不仅带走了一份勇敢的记忆,还有一种对未知世界的好奇与敬畏。她相信,每一个看似可怕的外表下,都隐藏着不为人知的故事。"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1727266561,
            "metadata": {},
            "object": "thread.message",
            "role": "assistant",
            "run_id": "run_id_for_first_question",
            "thread_id": "thread_8t2o4a7qQ11nJZE3JtxA2khh"
        },
        {
            "id": "msg_first_user",
            "assistant_id": None,
            "attachments": [],
            "content": [
                {
                    "text": {
                        "annotations": [],
                        "value": "写一篇关于一个小女孩在森林里遇到一只怪兽的故事。详细介绍她的所见所闻,并描述她的心理活动"
                    },
                    "type": "text"
                }
            ],
            "created_at": 1727266550, // 假设时间,比回答时间稍早
            "metadata": {},
            "object": "thread.message",
            "role": "user",
            "run_id": None,
            "thread_id": "thread_8t2o4a7qQ11nJZE3JtxA2khh"
        }
    ],
    "object": "list"
}

在上述示例中,response_dict_2data列表里按顺序包含了第二轮对话的回答、提问,以及第一轮对话的回答、提问。每个消息都有对应的idassistant_iduser提问时assistant_idNone )、content(包含具体文本内容)、created_at(创建时间)、metadata(当前为空)、object(固定为thread.message)、role(区分userassistant)、run_iduser提问时run_idNone )和thread_id

六、异常机制

Assistant API存在线程锁,同一时刻处于活跃状态的信息仅支持一条。当一个run还在执行(未完成)时,向同一thread追加新信息会抛出异常,提示不能在运行ID处于活跃状态时添加新信息到线程中。例如:

# 先提交一个问题并运行
message_4 = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="请介绍一下中国国庆节的由来"
)
run_4 = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
)
# 未等run_4执行完,马上提交新问题
message_5 = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="请你介绍一下中国中秋节的由来"
)

此时会抛出异常。等待前一个run完成后,再次执行相同操作则不会报错。

七、监控Run状态的需求及实现思路

  1. 需求:为实时获取结果,需要监控Run的状态。
  2. 实现思路:理论上,在Run进入queued状态后,不断监控status关键词。当状态达到completed时,打印最后结果,就能确保当前轮次的对话或任务已成功完成。OpenAI Assistant API提供了retrieve方法,可借助该方法及相关框架实现此需求。

八、Run运行时的状态转移机制总结

  1. 需求:为实时获取结果,需要监控Run的状态。
  2. 实现思路:理论上,在Run进入queued状态后,不断监控status关键词。当状态达到completed时,打印最后结果,就能确保当前轮次的对话或任务已成功完成。OpenAI Assistant API提供了retrieve方法,可借助该方法及相关框架实现此需求。

八、Run运行时的状态转移机制总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值