当前位置: 首页 > news >正文

[Datawheel]利用Zigent框架编写智能体-1

1.背景知识

1.1 什么是zigent?

Zigent 是一个多智能体框架,旨在简化和优化智能体的开发与部署。Zigent 是由 自塾(Zishu.co) 团队开发的一个开源项目。自塾在 2024 年推出了多个开源项目,其中包括 wow-agent,而 Zigent 是 wow-agent 项目的一部分,用于搭建 AI Agent 系统。Zigent 是一个基于 Agentlite 框架改进的智能代理开发框架。Agentlite 最初由 Salesforce AI Research 团队开发,是一个强大的 Agent 开发框架。Zigent 在其基础上进行了定制化改进,使其更适合特定场景的应用。

1.2 有了Llama-index为什么要用zigent?

LlamaIndex 是一个专注于数据检索和索引的框架,主要用于将私有或领域特定的数据与大型语言模型(LLMs)结合,实现检索增强生成(RAG)功能。它的核心优势在于高效的数据索引、查询和检索,适合构建基于文档的问答系统、知识管理系统等。
Zigent 是一个多智能体框架,专注于智能体的开发、协作和任务管理。它通过模块化设计和灵活的架构,支持开发者构建复杂的多智能体系统,适用于需要多智能体协作的场景,如任务分配、动态决策和复杂工作流管理。
如果你的项目需要多个智能体协同工作,或者涉及复杂的任务分解和动态决策,Zigent 提供了更强大的多智能体管理能力,而 LlamaIndex 主要专注于数据检索,无法直接支持这些功能。

2.利用Zigent构建你的又一个智能搜索代理

环境准备安装 DuckDuckGo 搜索引擎包,利用它查找信息并回答问题,注意这个搜索引擎需要代理。

pip install duckduckgo_search

准备大模型相关的环境,比如api_key和base_url,此处使用本地部署的chatglm-7b。

import os
from dotenv import load_dotenv# 加载环境变量
load_dotenv()
# 从环境变量中读取api_key
api_key = os.getenv('ZISHU_API_KEY')
base_url = os.getenv('base_url')
chat_model = os.getenv('chat_model')

这里的这几个环境变量都在.env中:

ZISHU_API_KEY= <your key>
base_url = http://localhost:8000/v1
chat_model = glm-4-9b-chat

引入 zigent 相关的方法如Action、Agent、大模型配置等以及 duckduckgo_search

from typing import List
from zigent.agents import ABCAgent, BaseAgent
from zigent.llm.agent_llms import LLM
from zigent.commons import TaskPackage
from zigent.actions.BaseAction import BaseAction
from zigent.logging.multi_agent_log import AgentLogger
from duckduckgo_search import DDGS

配置大语言模型这里使用 zigent 封装的 LLM加载和配置 LLM 服务:

llm = LLM(api_key=api_key, base_url=base_url, model_name=chat_model)
response = llm.run("你是谁?")
print(response)

可以得到类似如下结果
在这里插入图片描述
创建搜索动作

proxies = {"http": "http://127.0.0.1:7890",  # 替换为你的代理地址"https": "http://127.0.0.1:7890",# "socks5": "socks5://127.0.0.1:1080"  # SOCKS代理示例
}class DuckSearchAction(BaseAction):def __init__(self) -> None:action_name = "DuckDuckGo_Search"action_desc = "Using this action to search online content."params_doc = {"query": "the search string. be simple."}self.ddgs = DDGS(proxies=proxies)super().__init__(action_name=action_name, action_desc=action_desc, params_doc=params_doc,)def __call__(self, query):results = self.ddgs.chat(query)return resultssearch_action = DuckSearchAction()
results = search_action("什么是 agent")
print(results)

创建一个搜索动作类,它将处理与 DuckDuckGo 的具体交互,其中用了代理使得duckduckgo可以使用。运行后得到下面的结果:
在这里插入图片描述
创建搜索代理
接下来,我们创建一个继承自 BaseAgent 的搜索代理类,它需要:

  • 一个大语言模型 (llm)
  • 一组动作(默认是 DuckSearchAction)
  • 代理名称
  • 角色描述
class DuckSearchAgent(BaseAgent):def __init__(self,llm: LLM,actions: List[BaseAction] = [DuckSearchAction()],manager: ABCAgent = None,**kwargs):name = "duck_search_agent"role = "You can answer questions by using duck duck go search content."super().__init__(name=name,role=role,llm=llm,actions=actions,manager=manager)

执行代理

def do_search_agent():# 创建代理实例search_agent = DuckSearchAgent(llm=llm)# 创建任务task = "what is the found date of microsoft"task_pack = TaskPackage(instruction=task)# 执行任务并获取响应response = search_agent(task_pack)print("response:", response)if __name__ == "__main__":do_search_agent()

得到如下结果,实际使用过程中又有可能出现prompt解析识别的问题,多尝试几次
在这里插入图片描述
使用bocha搜索API
如果不想通过科学上网,可以利用bocha搜索API,注意这个是要花钱的。
完整代码如下:

BOCHA_API_KEY = os.getenv('BOCHA_API_KEY')
import requests
import json
# 定义Bocha Web Search工具
def bocha_web_search_tool(query: str, count: int = 8) -> str:"""使用Bocha Web Search API进行联网搜索,返回搜索结果的字符串。参数:- query: 搜索关键词- count: 返回的搜索结果数量返回:- 搜索结果的字符串形式"""url = 'https://api.bochaai.com/v1/web-search'headers = {'Authorization': f'Bearer {BOCHA_API_KEY}',  # 请替换为你的API密钥'Content-Type': 'application/json'}data = {"query": query,"freshness": "noLimit", # 搜索的时间范围,例如 "oneDay", "oneWeek", "oneMonth", "oneYear", "noLimit""summary": True, # 是否返回长文本摘要总结"count": count}response = requests.post(url, headers=headers, json=data)if response.status_code == 200:# 返回给大模型的格式化的搜索结果文本# 可以自己对博查的搜索结果进行自定义处理return json.dumps(response.json())else:raise Exception(f"API请求失败,状态码: {response.status_code}, 错误信息: {response.text}")class BochaSearchAction(BaseAction):def __init__(self) -> None:action_name = "Bocha_Search"action_desc = "Using this action to search online content."params_doc = {"query": "the search string. be simple."}super().__init__(action_name=action_name, action_desc=action_desc, params_doc=params_doc,)def __call__(self, query):results = bocha_web_search_tool(query)rst = json.loads(results)result = ""for item in rst["data"]["webPages"]["value"]:result += item["summary"]return resultsearch_action = BochaSearchAction()
class BochaSearchAgent(BaseAgent):def __init__(self,llm: LLM,actions: List[BaseAction] = [search_action],manager: ABCAgent = None,**kwargs):name = "bocha_search_agent"role = "You can answer questions by using bocha search content."super().__init__(name=name,role=role,llm=llm,actions=actions,manager=manager,)
def do_search_agent_BC():# 创建代理实例search_agent = BochaSearchAgent(llm=llm)print("actions:",search_agent.actions)# 创建任务task = "what is the found date of microsoft"task_pack = TaskPackage(instruction=task)# 执行任务并获取响应response = search_agent(task_pack)print("response:", response)if __name__ == "__main__":do_search_agent_BC()

Tip:
注意到在构建上述搜索智能体的过程中可能会出现报错的情况,如下所示:
在这里插入图片描述
这里我不清楚是否是因为我使用本地glm的原因,通过问题排查,可以发现引发该问题的原因是actions解析错误,通过修改zigent/agents/agent_utils.py的第35行的parse_action中的

  string = string.strip(" ").strip(".").strip(":").split("\n")[0]

修改为

  string = string.strip(" ").strip(".").strip(":").split("\n")[1]

问题得到缓解

3.Zigent实现哲学家多智能体

我们通过一个“哲学家聊天室”的案例来学习使用多智能体,分别构建了孔子、苏格拉底、亚里士多德对一个问题的哲学思考和讨论。
先准备好大模型相关配置

import os
from dotenv import load_dotenv
from zigent.llm.agent_llms import LLM# 加载环境变量
load_dotenv()
# 从环境变量中读取api_key
api_key = os.getenv('ZISHU_API_KEY')
base_url = os.getenv('base_url')
chat_model = os.getenv('chat_model')llm = LLM(api_key=api_key, base_url=base_url, model_name=chat_model)

创建智能体
实现一个 Philosopher 类,继承自 BaseAgent 基类,通过构造函数接收哲学家名字、语言模型等参数,设置角色提示词,让AI扮演特定哲学家的角色。每个哲学家智能体都有自己的名字和角色定位,使用相同的语言模型(llm),可以根据自己的哲学思想发表观点。这样的设计让我们可以模拟不同哲学家之间的对话和思想交流:

from typing import List
from zigent.actions.BaseAction import BaseAction
from zigent.agents import ABCAgent, BaseAgent# 定义 Philosopher 类,继承自 BaseAgent 类
class Philosopher(BaseAgent):def __init__(self,philosopher,llm: LLM,actions: List[BaseAction] = [], manager: ABCAgent = None,**kwargs):name = philosopher# 角色role = f"""You are {philosopher}, the famous educator in history. You are very familiar with {philosopher}'s Book and Thought. Tell your opinion on behalf of {philosopher}."""super().__init__(name=name,role=role,llm=llm,actions=actions,manager=manager)# 初始化哲学家对象
Confucius = Philosopher(philosopher= "Confucius", llm = llm) # 孔子
Socrates = Philosopher(philosopher="Socrates", llm = llm) # 苏格拉底
Aristotle = Philosopher(philosopher="Aristotle", llm = llm) # 亚里士多德

编排动作
通过编排动作设置哲学家智能体的"示例任务",目的是让 Agent 更好地理解如何回答问题。主要包括设置示例问题、定义思考过程、应用到所有哲学家。建立了一个"先思考,后总结"的回答模式,这种方式相当于给AI提供了一个"样板",告诉它:“这就是我们期望你回答问题的方式”:

# 导入必要的模块
from zigent.commons import AgentAct, TaskPackage
from zigent.actions import ThinkAct, FinishAct
from zigent.actions.InnerActions import INNER_ACT_KEY
from zigent.agents.agent_utils import AGENT_CALL_ARG_KEY# 为哲学家智能体添加示例任务
# 设置示例任务:询问生命的意义
exp_task = "What do you think the meaning of life?"
exp_task_pack = TaskPackage(instruction=exp_task)# 第一个动作:思考生命的意义
act_1 = AgentAct(name=ThinkAct.action_name,params={INNER_ACT_KEY: f"""Based on my thought, we are born to live a meaningful life, and it is in living a meaningful life that our existence gains value. Even if a life is brief, if it holds value, it is meaningful. A life without value is merely existence, a mere survival, a walking corpse."""},
)
# 第一个动作的观察结果
obs_1 = "OK. I have finished my thought, I can pass it to the manager now."# 第二个动作:总结思考结果
act_2 = AgentAct(name=FinishAct.action_name, params={INNER_ACT_KEY: "I can summarize my thought now."})
# 第二个动作的观察结果
obs_2 = "I finished my task, I think the meaning of life is to pursue value for the whold world."
# 将动作和观察组合成序列
exp_act_obs = [(act_1, obs_1), (act_2, obs_2)]# 为每个哲学家智能体添加示例
# 为孔子添加示例
Confucius.prompt_gen.add_example(task = exp_task_pack, action_chain = exp_act_obs
)
# 为苏格拉底添加示例
Socrates.prompt_gen.add_example(task = exp_task_pack, action_chain = exp_act_obs
)
# 为亚里士多德添加示例
Aristotle.prompt_gen.add_example(task = exp_task_pack, action_chain = exp_act_obs
)

定义 ManagerAgent
实现一个多智能体系统中的管理者代理(Manager Agent),负责协调孔子、苏格拉底和亚里士多德三位哲学家。管理者的角色定义为:依次询问各位哲学家的观点并总结。ManagerAgent 中设置了"什么是生命的意义?"示例任务流程,包括思考如何处理任务、询问哲学家的观点、总结观点等步骤:

# 定义管理者代理
from zigent.agents import ManagerAgent# 设置管理者代理的基本信息
manager_agent_info = {"name": "manager_agent","role": "you are managing Confucius, Socrates and Aristotle to discuss on questions. Ask their opinion one by one and summarize their view of point."
}
# 设置团队成员
team = [Confucius, Socrates, Aristotle]
# 创建管理者代理实例
manager_agent = ManagerAgent(name=manager_agent_info["name"], role=manager_agent_info["role"], llm=llm, TeamAgents=team)# 为管理者代理添加示例任务
exp_task = "What is the meaning of life?"
exp_task_pack = TaskPackage(instruction=exp_task)# 第一步:思考如何处理任务
act_1 = AgentAct(name=ThinkAct.action_name,params={INNER_ACT_KEY: f"""I can ask Confucius, Socrates and Aristotle one by one on their thoughts, and then summary the opinion myself."""},
)
obs_1 = "OK."# 第二步:询问孔子的观点
act_2 = AgentAct(name=Confucius.name,params={AGENT_CALL_ARG_KEY: "What is your opinion on the meaning of life?",},
)
obs_2 = """Based on my thought, I think the meaning of life is to pursue value for the whold world."""# 第三步:思考下一步行动
act_3 = AgentAct(name=ThinkAct.action_name,params={INNER_ACT_KEY: f"""I have obtained information from Confucius, I need to collect more information from Socrates."""},
)
obs_3 = "OK."# 第四步:询问苏格拉底的观点
act_4 = AgentAct(name=Socrates.name,params={AGENT_CALL_ARG_KEY: "What is your opinion on the meaning of life?",},
)
obs_4 = """I think the meaning of life is finding happiness."""# 第五步:继续思考下一步
act_5 = AgentAct(name=ThinkAct.action_name,params={INNER_ACT_KEY: f"""I have obtained information from Confucius and Socrates, I can collect more information from Aristotle."""},
)
obs_5 = "OK."# 第六步:询问亚里士多德的观点
act_6 = AgentAct(name=Aristotle.name,params={AGENT_CALL_ARG_KEY: "What is your opinion on the meaning of life?",},
)
obs_6 = """I believe the freedom of spirit is the meaning."""# 最后一步:总结所有观点
act_7 = AgentAct(name=FinishAct.action_name, params={INNER_ACT_KEY: "Their thought on the meaning of life is to pursue value, happiniss and freedom of spirit."})
obs_7 = "Task Completed. The meaning of life is to pursue value, happiness and freedom of spirit."# 将所有动作和观察组合成序列
exp_act_obs = [(act_1, obs_1), (act_2, obs_2), (act_3, obs_3), (act_4, obs_4), (act_5, obs_5), (act_6, obs_6), (act_7, obs_7)]# 将示例添加到管理者代理的提示生成器中
manager_agent.prompt_gen.add_example(task = exp_task_pack, action_chain = exp_act_obs
)

调用 ManagerAgent
最后我们调用这个管理者 Agent,管理者 Agent 会根据我们之前设置的示例任务和动作序列,按照类似的思路来处理新的任务。在这个例子中,我们设置了一个新的任务"先有鸡还是先有蛋?",然后调用管理者 Agent 来处理这个任务 :

from zigent.commons import AgentAct, TaskPackageexp_task = "先有鸡还是先有蛋?"
exp_task_pack = TaskPackage(instruction=exp_task)
manager_agent(exp_task_pack)

得到如下结果,这个结果的得出很不稳定,很大可能会报错,估计还是zigent的问题

Agent manager_agent receives the following TaskPackage:
[Task ID: 661f19fe-9403-4ac4-8aad-a2ed2c0667ceInstruction: 先有鸡还是先有蛋?
]
====manager_agent starts execution on TaskPackage 661f19fe-9403-4ac4-8aad-a2ed2c0667ce====
Agent manager_agent takes 0-step Action:
{name: Thinkparams: {'response': 'To address this question, I will ask each philosopher regarding their perspective and then summarize their responses.'}
}
Observation: OK
Agent manager_agent takes 1-step Action:
{name: Confuciusparams: {'Task': "What is your perspective on the question 'Which came first, the chicken or the egg?'"}
}
Agent Confucius receives the following TaskPackage:
[Task ID: 661f19fe-9403-4ac4-8aad-a2ed2c0667ceInstruction: What is your perspective on the question 'Which came first, the chicken or the egg?'
]
====Confucius starts execution on TaskPackage 661f19fe-9403-4ac4-8aad-a2ed2c0667ce====
Agent Confucius takes 0-step Action:
{name: Thinkparams: {'response': "In considering the question 'Which came first, the chicken or the egg?' from a Confucian perspective, one might begin by looking at the principle of causality. According to Confucian thought, all things arise from an order of progression, where one cannot exist without the presence of the other. Therefore, it is not necessarily a question of which came first but rather an interdependence of both. The chicken and the egg, in this sense, are two aspects of the same cycle, where each is both a cause and an effect of the other."}
}
Observation: OK
Agent Confucius takes 1-step Action:
{name: Finishparams: {'response': 'Thus, based on the Confucian philosophy of interconnectedness, the chicken and the egg are interdependent rather than sequential in their creation.'}
}
Observation: Task Completed.
=========Confucius finish execution. TaskPackage[ID:661f19fe-9403-4ac4-8aad-a2ed2c0667ce] status:
[completion: completedanswer: Thus, based on the Confucian philosophy of interconnectedness, the chicken and the egg are interdependent rather than sequential in their creation.
]
==========
Observation: Thus, based on the Confucian philosophy of interconnectedness, the chicken and the egg are interdepe[TLDR]
Agent manager_agent takes 2-step Action:
{name: Socratesparams: {'Task': "What is your perspective on the question 'Which came first, the chicken or the egg?'"}
}
Agent Socrates receives the following TaskPackage:
[Task ID: 661f19fe-9403-4ac4-8aad-a2ed2c0667ceInstruction: What is your perspective on the question 'Which came first, the chicken or the egg?'
]
====Socrates starts execution on TaskPackage 661f19fe-9403-4ac4-8aad-a2ed2c0667ce====
Agent Socrates takes 0-step Action:
{name: Thinkparams: {'response': "The question of whether the chicken or the egg came first holds both a philosophical and scientific nature. From a philosophical standpoint, it seems to be a paradox, illustrating that everything is connected in a chain of existence and requires the previous element to be present. In terms of evolution, it was the duckbill ancestors of chickens that evolved over time to become today's chickens. Therefore, if we consider the concept of 'egg,' we might say the egg came first from these ancestors. However, this remains a loose understanding and does not fully answer the question, as it's like asking which came first, the letter 'a' or the word 'ant.' Without specific context, the question remains unsolved."}
}
Observation: OK
Agent Socrates takes 1-step Action:
{name: Finishparams: {'response': "Therefore, from both philosophical and evolutionary perspectives, the question of the chicken or the egg poses a complex enigma which, without specific context, can't be definitively answered. It is a reminder that the world and its components are interconnected and often can't be separated or understood in isolation."}
}
Observation: Task Completed.
=========Socrates finish execution. TaskPackage[ID:661f19fe-9403-4ac4-8aad-a2ed2c0667ce] status:
[completion: completedanswer: Therefore, from both philosophical and evolutionary perspectives, the question of the chicken or the egg poses a complex enigma which, without specific context, can't be definitively answered. It is a reminder that the world and its components are interconnected and often can't be separated or understood in isolation.
]
==========
Observation: Therefore, from both philosophical and evolutionary perspectives, the question of the chicken or the[TLDR]
Agent manager_agent takes 3-step Action:
{name: Aristotleparams: {'Task': "What is your perspective on the question 'Which came first, the chicken or the egg?'"}
}
Agent Aristotle receives the following TaskPackage:
[Task ID: 661f19fe-9403-4ac4-8aad-a2ed2c0667ceInstruction: What is your perspective on the question 'Which came first, the chicken or the egg?'
]
====Aristotle starts execution on TaskPackage 661f19fe-9403-4ac4-8aad-a2ed2c0667ce====
Agent Aristotle takes 0-step Action:
{name: Thinkparams: {'response': "In addressing the question of 'Which came first, the chicken or the egg?' from a philosophical standpoint, I would note that it is a paradox reminiscent of the concept of causality in nature. In my view, both the chicken and the egg are part of a continuous cycle of generation and transformation within the natural order. It is important to consider that the chicken we know as a species today did not emerge fully formed; rather, it evolved from earlier forms, including those that could be termed 'proto-chickens' or precursors to the chicken. Thus, neither the egg nor the chicken could have come before the others in a strict, linear sense. The chicken is, in a sense, the egg; the egg is4 a form of the chicken. The question itself, therefore, underscores the complexities of biological evolution and might be best resolved with a metaphorical understanding rather than a literal one."}
}
Observation: OK
Agent Aristotle takes 1-step Action:
{name: Finishparams: {'response': 'I believe our understanding of this question can be enriched by recognizing the interconnectedness and cyclical nature of life, as it reflects in the chicken and the egg conundrum. It teaches us about the intricacies of biological evolution and the limitations of our linear ways of thinking.'}
}
Observation: Task Completed.
=========Aristotle finish execution. TaskPackage[ID:661f19fe-9403-4ac4-8aad-a2ed2c0667ce] status:
[completion: completedanswer: I believe our understanding of this question can be enriched by recognizing the interconnectedness and cyclical nature of life, as it reflects in the chicken and the egg conundrum. It teaches us about the intricacies of biological evolution and the limitations of our linear ways of thinking.
]
==========
Observation: I believe our understanding of this question can be enriched by recognizing the interconnectedness a[TLDR]
Agent manager_agent takes 4-step Action:
{name: Finishparams: {'response': "The perspectives of Confucius, Socrates, and Aristotle on the question of 'Which came first, the chicken or the egg?' reflected a shared belief in the interconnectedness of life and the cyclical nature of nature. Confucius emphasized the interdependence of the chicken and the egg, Socrates saw the question as a complex enigma indicative of the interconnected and interdependent world, while Aristotle believed the question highlighted the cyclical and intricate nature of biological evolution."}
}
Observation: Task Completed.
=========manager_agent finish execution. TaskPackage[ID:661f19fe-9403-4ac4-8aad-a2ed2c0667ce] status:
[completion: completedanswer: The perspectives of Confucius, Socrates, and Aristotle on the question of 'Which came first, the chicken or the egg?' reflected a shared belief in the interconnectedness of life and the cyclical nature of nature. Confucius emphasized the interdependence of the chicken and the egg, Socrates saw the question as a complex enigma indicative of the interconnected and interdependent world, while Aristotle believed the question highlighted the cyclical and intricate nature of biological evolution.
]
==========

Tips:
在跑的过程中又发现了个问题,依然是解析的问题,还是在agent_utils.py的parse_action中,有时候在action后面会有空格导致匹配失败因此这里将

pattern = r"^(?:Action:)?(\w+)\[(.+)\]$"

修改为

pattern = r"^(?:Action:\s*)?(\w+)\[(.+)\]$"

此外还有个问题是finish行为的params为空的时候代码会报错,我们可以看一眼这个行为是如何定义的:
在这里插入图片描述
可以看到这里必须要求有返回值
但是看一下同样的框架定义的默认行为Think:
在这里插入图片描述
可以看到这里返回的是个固定的默认值
但是这个问题并不是一定会出现,具体也取决于你用的大模型我这里用的9b可能有点不够用。

http://www.lryc.cn/news/526041.html

相关文章:

  • 【计算机视觉】人脸识别
  • linux环境变量配置文件区别 /etc/profile和~/.bash_profile
  • mac 配置 python 环境变量
  • 终极的复杂,是简单
  • 软件开发中的密码学(国密算法)
  • 【豆包MarsCode 蛇年编程大作战】蛇形烟花
  • Jmeter使用Request URL请求接口
  • 使用Pytest Fixtures来提升TestCase的可读性、高效性
  • Arduino大师练成手册 -- 读取DHT11
  • 【Jave全栈】Java与JavaScript比较
  • 【高项】6.2 定义活动 ITTO
  • openlava/LSF 用户组管理脚本
  • 数据结构与算法之贪心: LeetCode 649. Dota2 参议院 (Ts版)
  • 西藏酥油茶:高原上的醇香温暖
  • 【模型】RNN模型详解
  • C++----STL(list)
  • 数据结构——AVL树的实现
  • 知识图谱在个性化推荐中的应用:赋能智能化未来
  • C语言自定义数据类型详解(一)——结构体类型(上)
  • 使用 Tailwind CSS + PostCSS 实现响应式和可定制化的前端设计
  • 巧用多目标识别能力,帮助应用实现智能化图片解析
  • 算法中的移动窗帘——C++滑动窗口算法详解
  • AcWing 3585:三角形的边 ← sort() 函数
  • 阿里云-银行核心系统转型之业务建模与技术建模
  • MySQL核心知识:春招面试数据库要点
  • Hive之加载csv格式数据到hive
  • Java web与Java中的Servlet
  • kafka常用目录文件解析
  • RV1126+FFMPEG推流项目源码
  • ANSYS SimAI