项目链接:
https://github.com/openai/swarm
1.流式输出
在Swarm-01-初体验中,已经成功利用Swarm框架进行Agent的调用和切换。接下来要研究的问题与流式输出和多轮对话相关。
❗ 经过个人不完全测试,仅有OpenAI发行的模型(例如gpt-4o)可以成功实现流式输出,采用其他模型会报错。
延续之前张飞的例子,将原有的client中Stream参数修改为True。
response = swarm_client.run(
agent=agent_a,
messages=[{"role": "user", "content": "我心情不好,我想和智能体B说话"}],
model_override="gpt-4o",
# model_override="qwen-plus",
stream=True
)
for chunk in response:
print(chunk)
# print(response.messages)
获得的回复如下:
# 流式回复:
# {'delim': 'start'}
# {'content': None, 'function_call': None, 'refusal': None, 'role': 'assistant', 'tool_calls': [{'index': 0, 'id': 'call_ueAo2o1pYJzGnrLCGZP15oxa', 'function': {'arguments': '', 'name': 'transfer_to_agent_b'}, 'type': 'function'}], 'sender': 'Agent A'}
# {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '{}', 'name': None}, 'type': None}]}
# {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'delim': 'end'}
# {'delim': 'start'}
# {'content': '', 'function_call': None, 'refusal': None, 'role': 'assistant', 'tool_calls': None, 'sender': 'Agent B'}
# {'content': '啊', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': ',', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '兄', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '弟', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '!', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '汝', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '心', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '情', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '不', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '佳', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': ',是', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '何', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '事', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '困', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '扰', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '耶', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '?', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '尽', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '管', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '与', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '我', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '张', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '飞', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '言', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '之', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': ',我', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '这', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '生', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '来', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '就是', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '个', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '直', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '脾', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '气', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': ',', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '愿', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '助', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '汝', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '一', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '解', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '烦', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '忧', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '!', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '来', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '来', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '尽', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '言', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '无', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '妨', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': '!', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}
# {'delim': 'end'}
# {'response': Response(messages=[{'content': '', 'sender': 'Agent A', 'role': 'assistant', 'function_call': None, 'tool_calls': [{'function': {'arguments': '{}', 'name': 'transfer_to_agent_b'}, 'id': 'call_ueAo2o1pYJzGnrLCGZP15oxa', 'type': 'function'}]}, {'role': 'tool', 'tool_call_id': 'call_ueAo2o1pYJzGnrLCGZP15oxa', 'tool_name': 'transfer_to_agent_b', 'content': '{"assistant": "Agent B"}'}, {'content': '啊,兄弟!汝心情不佳,是何事困
# 扰耶?尽管与我张飞言之,我这生来就是个直脾气,愿助汝一解烦忧!来来尽言无妨!', 'sender': 'Agent A', 'role': 'assistant', 'function_call': None, 'tool_calls': None}], agent=Agent(name='Agent B', model='gpt-4o', instructions='你是智能体B,你自称张飞,用张飞的口吻回复', functions=[], tool_choice=None, parallel_tool_calls=True), context_variables={})}
首先可以注意到的是,整个流式输出的内容以{'delim': 'start'}与{'delim': 'start'}作为流式输出开始和结束的标志,最后再跟进一个完整的response。并且,由于中间进行了智能体的切换,因此整个响应过程中这两个标志出现了两次,且第一次出现时,content为None。
因此如果想要在终端实现逐字打印,可以通过函数对chunk进行处理。
def stream_print(response):
for chunk in response:
if 'content' in chunk and chunk['content'] is not None:
print(chunk['content'], end='', flush=True)
stream_print(response)
获得的回复如下(再次生成,所以回复内容不同):
# 哈哈哈,你找我,张飞,有什么事尽管说!心里不痛快,咱们就痛痛快快地说出来!说不定,咱也能给你劈开一道痛快的路子!你碰上什么烦心事啦?
2.多轮对话
截至本文发布时间,Swarm框架还未添加历史消息列表的保存和管理方式。可以通过尝试手动添加messages来增添历史记录。
为了增加辨识度,更改智能体创建时的instructions部分,同时在初次输入messages时告诉它名字。
# 创建Agent A,设置其名称、指令和功能
agent_a = Agent(
name="Agent A",
instructions="你是一个优秀的人工智能助手,你的所有回复开头加上【A】。",
functions=[transfer_to_agent_b],
)
# 创建Agent B,设置其名称和指令
agent_b = Agent(
name="Agent B",
instructions="你自称张飞,你用张飞的口吻回复,你的所有回复开头加上【B】。",
)
# 初始化消息列表,包含用户的初始消息
messages = [{"role": "user", "content": "我叫ArtemisYi,我想和智能体B说话"}]
# 进入主循环,处理用户输入和AI回复
while True:
# 运行Swarm客户端,使用Agent A处理消息
response = swarm_client.run(
agent=agent_a,
messages=messages,
model_override="gpt-4o",
)
# 获取AI的回复并打印
reply = response.messages[-1]["content"]
print(f"AI {reply}")
# 将AI的回复添加到消息列表中
messages.append({"role": "assistant", "content": reply})
# 获取用户输入并添加到消息列表中
user_input = input("User: ")
# 输入"exit"或"quit"退出循环
if user_input.lower() in ["exit", "quit"]:
break
messages.append({"role": "user", "content": user_input})
获得的回复如下:
# 初始输入内容:我叫ArtemisYi,我想和智能体B说话
# AI 【B】哎,尔等休要慌张,就是我张翼德。在此,有何话快讲!
# User: 我刚刚说我叫什么来着
# AI 【A】你刚刚说你叫ArtemisYi。
# User: 你是谁?
# AI 【A】我是一个优秀的人工智能助手,专门用来帮助回答问题并提供信息。你可以问我各类问题或者请求我提供帮助!
# User: 我想和智能体B沟通
# AI 【B】哈哈,又是俺张飞,是想和俺聊些什么呢?快快说来无妨!
# User: 我叫什么?
# AI 【B】你刚才说你叫ArtemisYi,不知道对不对?有何事尽管说!
可以看到,尽管两个智能体都记住了名字,但在第一次提问时,Swarm在重新调用智能体A回复时,即使它拥有历史记录,却没有实现我最初想和智能体B对话的功能。但是第二次我再提问时,它却又继续沿用了张飞的口吻。这是Swarm框架目前还存在的问题,对于用户意图的识别并没有达到最优。
当下的解决方法,或许可以选择在输出时获取当前的agent,然后在循环中改变调用模型,来确保自己在切换和交流时不会出错,但这仅是从开发者角度出发的考量,个人希望Swarm框架能够在后续版本中优化相关的问题。
Comments
评论
Loading comments...
登录后可以评论。 Login