HYLOVEYOURSELF

小洋宝的进步史

导航

Datawhale组队学习 wow-agent 😀Task 3 Zigent搭建AI Agent😜

Datawhale组队学习 wow-agent

Task3 Zigent 搭建AI Agent

Datawhale项目链接:https://www.datawhale.cn/learn/summary/86

笔记作者:博客园-岁月月宝贝💫

微信名:有你在就不需要🔮给的勇气

冲啊冲啊冲啊冲啊!!!!!!!!!有时间一定做老师布置的附加题!!!啊啊啊啊啊啊!今天不能凌晨三点睡啦!!!有时间改改排版!!!加油小洋冲冲冲!!!!

*文中加🐛的都为源码的BUG哦

一、初识 Zigent:构建你的又一个智能搜索代理

Zigent是啥?

Zigent 是一个基于 Agentlite 框架(一个强大的 Agent 开发框架)定制化改进的智能代理开发框架,使其更适合特定场景的应用。

既然它是一个智能代理开发框架,那我们就用它创一个搜索代理!暂定它可以通过 🐤DuckDuckGo 搜索引擎查找信息并回答问题!

1️⃣pip导入必备库:

# 建议 Python > 3.8
pip install duckduckgo_search

2️⃣用老师给的免费大模型api_key

import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()
# 从环境变量中读取api_key
api_key = os.getenv('ZISHU_API_KEY')
base_url = "http://43.200.7.56:8008/v1"
chat_model = "glm-4-flash"

3️⃣引入 zigent 相关的方法:

from typing import List
from zigent.agents import ABCAgent, BaseAgent #Agent
from zigent.llm.agent_llms import LLM #LLM配置
from zigent.commons import TaskPackage
from zigent.actions.BaseAction import BaseAction #Action方法
from duckduckgo_search import DDGS #我们的搜索引擎
from zigent.logging.multi_agent_log import AgentLogger#🐛

4️⃣配置LLM与可用性测试:

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

🤖:我是一个人工智能助手,专门设计来帮助用户解答问题、提供信息以及执行各种任务。我的目标是成为您生活中的助手,帮助您更高效地获取所需信息。有什么我可以帮您的吗?

这里使用了 zigent 封装LLM加载和配置 LLM 服务,与上一个Task2Datawhale组队学习🔊wow-agent😀task02 Llama-index库搭建AI Agent - 岁月月宝贝 - 博客园有区别,我有去考古~

上一Task的”用Llama-index创建Agent“&”搜索引擎Agent“:

llm = OurLLM(api_key=api_key, base_url=base_url, model_name=chat_model)
response = llm.stream_complete("你是谁?")
for chunk in response:
    print(chunk, end="", flush=True)

数据库对话Agent“:

llm = OurLLM(api_key=api_key, base_url=base_url, model_name=chat_model)
# 测试对话模型
response = llm.complete("你是谁?")
print(response)

访问DuckDuckGo能力构建🔱!

*访问DuckDuckGo搜索引擎需要kexue上网~

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()
        super().__init__(
            action_name=action_name, 
            action_desc=action_desc, 
            params_doc=params_doc,
        )

    def __call__(self, query): #执行实际的搜索操作
        results = self.ddgs.chat(query)
        return results
    
#使用示例
search_action = DuckSearchAction()
results = search_action("什么是 agent")
print(results)

🤖:“Agent”这个词在不同的领域有不同的含义。以下是一些常见的解释:

  1. 一般意义:在日常用语中,agent指的是一个代理人或代表,负责代表他人进行某种活动或决策 。

  2. 计算机科学:在人工智能和计算机科学中,agent通常指的是一种能够感知其环境并采取行动以 实现特定目标的程序或系统。例如,智能代理可以在网络上自动执行任务。

  3. 商业:在商业领域,agent可以指代中介或代理商,他们代表公司或个人进行交易或谈判。

  4. 生物学:在生物学中,agent可以指代某种物质或生物体,能够引起特定的生物反应,例如病原 体。

具体的含义通常取决于上下文。如果你有特定的领域或上下文,请告诉我,我可以提供更详细的信息。

平替:访问Bocha能力构建⚜

*与上一节用一个API哦&不用kexue上网

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}")
   

#这个和上面访问DuckDuckGo的类很像
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 result
    
#使用示例
search_action = BochaSearchAction()
results = search_action("上海有哪些私立小学在招聘小学英语老师?")
print(results)

🤖:初中英语教师
06-24
15-21K/月
上海-普陀区 1年以上 全职
高老师021–56080869
初中物理教师
06-24
15-21K/月
上海-普陀区 1年以上 全职
高老师021–5608086...上海市七宝外国语小学现因学校发展需要,特招聘优秀的 语文、数学、英语老师 。
应聘条件
1.本科及以上学历,具有教师资格证者;
2.相关专业毕业,有教学经验者优先;
3.性格开朗、耐心细致、责任心强。
联系方式
潘老师:64195394-3207
邮箱地址: qbwgyxx@126.com (有意向的老师请将简历发至邮箱)
学校地址:闵行区新镇路79号
学校简介
上海市七宝外国语小学创办于2005年,属于民办非企业单位,是一所具有鲜明外语特色的优质民办学校,现为闵行区实验小学教育集团成员校。
学校现有30个教学班,一千三百余位学生,百余位教职工。学校以“助力每个孩子卓越成长”为核心理念,以养成教育、英语特色、思维培养、个性激发为着力点,通过精细化的管理为培养具有“家国情怀、世界眼光、知文达礼、卓立胜己”的卓越学生而竭智尽力,赢得了家长与社会的广泛赞誉。
多元的学习空间
丰富的校园活动
图文:上海市七宝外国语小学
转录编辑:吴王天呈(实习)
(点击图片查看)
上观号作者:今日闵行

真的超详细!好多好多!!!

赋予LLM访问DuckDuckGo能力🔯

*也叫创建搜索代理哈哈哈哈哈

#一个继承自 BaseAgent 的搜索代理类
class DuckSearchAgent(BaseAgent):
    def __init__(
        self,
        llm: LLM, #需要一个大语言模型 (llm)🐛
        actions: List[BaseAction] = [DuckSearchAction()],#一组动作(默认是 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,
            logger=agent_logger(),#🐛
        )
        
#执行我们创建的代理
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()

🤖:

Agent duck_search_agent receives the following TaskPackage:
[
        Task ID: 51c6eb6c-c544-4732-8765-982228f61d31
        Instruction: what is the found date of microsoft
]
====duck_search_agent starts execution on TaskPackage 51c6eb6c-c544-4732-8765-982228f61d31====
Agent duck_search_agent takes 0-step Action:
{
        name: DuckDuckGo_Search
        params: {'query': 'Microsoft founding date'}
}
Observation: Microsoft was founded on April 4, 1975.
Agent duck_search_agent takes 1-step Action:
{
        name: Finish
        params: {'response': 'Microsoft was founded on April 4, 1975.'}
}
Observation: Microsoft was founded on April 4, 1975.
=========duck_search_agent finish execution. TaskPackage[ID:51c6eb6c-c544-4732-8765-982228f61d31] status:
[
        completion: completed
        answer: Microsoft was founded on April 4, 1975.

]
==========

response: Microsoft was founded on April 4, 1975.

平替:赋予LLM访问Bocha能力✝

#搜索代理类
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():
    # 创建代理实例
    search_agent = BochaSearchAgent(llm=llm)

    # 创建任务
    task = "what is the found date of microsoft"
    task_pack = TaskPackage(instruction=task)

    # 执行任务并获取响应
    response = search_agent(task_pack)
    print("response:", response)
    
#执行我们创建的代理
do_search_agent()

🤖:

Agent bocha_search_agent receives the following TaskPackage:
[
	Task ID: 54eea4c0-3af8-4cce-9cdd-20e1e3f2ba36
	Instruction: what is the found date of microsoft
]
====bocha_search_agent starts execution on TaskPackage 54eea4c0-3af8-4cce-9cdd-20e1e3f2ba36====
Agent bocha_search_agent takes 0-step Action:
{
	name: Bocha_Search[{"query": "found date of Microsoft"}}
	params: {}
}
Observation: "This is the wrong action to call. Please check your available action list.
Agent bocha_search_agent takes 1-step Action:
{
	name: Action:Bocha_Search[{"query": "when was Microsoft founded"}]
	params: {}
}
Observation: "This is the wrong action to call. Please check your available action list.
Agent bocha_search_agent takes 2-step Action:
{
	name: Action:Bocha_Search[{"query": "when was Microsoft founded"}]
	params: {}
}
Observation: "This is the wrong action to call. Please check your available action list.

可以执行,但是貌似有些问题,后续还需要调试一下源代码?——Teacher

我这边感觉还OK哈😊,只不过是第一次就输出正确答案啦,然后无限次重复:

加油!!有空看看老师是否有更新💪

二、Zigent实现哲学家多智能体

大家平时是否想有一个吵架平替?那太好啦!我们让三个哲学家孔子、苏格拉底、亚里士多德作我们的最强辅助!!!

另外,大家是否好奇三位哲学家哪位辩论能力最强呀?👁本节,我们为他们构建一个“哲学家聊天室”,让他们对一个问题展开讨论!!!

准备工作

🐦用老师给的免费大模型api_key,完成LLM配置!

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 = "http://43.200.7.56:8008/v1"
chat_model = "glm-4-flash"

llm = LLM(api_key=api_key, base_url=base_url, model_name=chat_model)

创建哲学家👥

*也叫创建智能体

from typing import List
from zigent.actions.BaseAction import BaseAction
from zigent.agents import ABCAgent, BaseAgent #这个ABC很有意思
#from zigent.logging.multi_agent_log import AgentLogger#🐛

# 定义 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
        )

# 初始化哲学家对象(哲学家自己的名字+相同的llm=根据自己的哲学思想发表观点的llm)
Confucius = Philosopher(philosopher= "Confucius", llm = llm) # 孔子
Socrates = Philosopher(philosopher="Socrates", llm = llm) # 苏格拉底
Aristotle = Philosopher(philosopher="Aristotle", llm = llm) # 亚里士多德

"八股"回答模式设置

”八股“指我们通过编排动作设置了哲学家智能体的"示例任务"作答样板——包括设置示例问题、定义思考过程、应用到所有哲学家,并建立了一个"先思考,后总结"的回答模式

# 导入必要的模块
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."""
    },
)
# 第一个动作的观察结果(既然还有manager!是主持人嘛?)
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
)

创建辩论会主持人🕴

官方也叫”多智能体系统中的管理者代理(Manager Agent)“,或管理者

他负责协调孔子、苏格拉底和亚里士多德三位哲学家——依次询问各位哲学家的观点并总结

当然,我们也给了”主持人“主持的”八股“样板——ManagerAgent 中设置了"什么是生命的意义?"示例任务流程,包括思考如何处理任务询问哲学家的观点总结观点等步骤

# 定义管理者代理
from zigent.agents import ManagerAgent

# 1.设置管理者代理的基本信息
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." #依次询问观点并总结~
}

# 2.设置团队成员
team = [Confucius, Socrates, Aristotle]

# 3.创建管理者代理实例
manager_agent = ManagerAgent(name=manager_agent_info["name"], role=manager_agent_info["role"], llm=llm, TeamAgents=team)

# 4.为管理者代理添加示例任务"八股"

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?",
        },#这参数只有两类💫,一类是"INNER_ACT_KEY",一类是"AGENT_CALL_ARG_KEY"
)
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#一个是命令,一个是回答链!
)

结果showtime!!!

我们让主持人把”先有鸡还是先有蛋?“这个辩论任务布置下去啦!!!

from zigent.commons import AgentAct, TaskPackage

exp_task = "先有鸡还是先有蛋?"
exp_task_pack = TaskPackage(instruction=exp_task)
manager_agent(exp_task_pack)

🤖:

(辩论会超级精彩,我甚至把我跑出来的回答翻译了下,并且稍稍区分了下角色,这样就更好与上面代码设置的回答对应啦:)

D:\anaconda3\envs\wow-agent\python.exe D:\APP\Pycharm\MyPythonProject\wow-agent-main\Zigent-0119哲学家.py 
🍎Agent manager_agent receives the following TaskPackage:
[
    Task ID: ebcd2739-bfd3-4833-a80a-fb9e450d7cbd
    Instruction: 先有鸡还是先有蛋?
]
====🍎manager_agent starts execution on TaskPackage ebcd2739-bfd3-4833-a80a-fb9e450d7cbd====
🍎Agent manager_agent takes 0-step Action:
{
    name: Think
    params: {}
}
Observation: OK
🍎Agent manager_agent takes 1-step Action:
{
    name: Confucius
    params: {'Task': 'What is your opinion on the question of whether the chicken or the egg came first?'}
}
🍏Agent Confucius receives the following TaskPackage:
[
    Task ID: ebcd2739-bfd3-4833-a80a-fb9e450d7cbd
    Instruction: What is your opinion on the question of whether the chicken or the egg came first?
]
====🍏Confucius starts execution on TaskPackage ebcd2739-bfd3-4833-a80a-fb9e450d7cbd====
🍏Agent Confucius takes 0-step Action:
{
    name: Think
    params: {'response': '在思考先有鸡还是先有蛋这个问题时,重要的是要反思创造的本质以及生命的循环性。根据我的教导,世界是一个和谐的秩序,万物都有其位置和目的。鸡和蛋都是这个秩序中不可或缺的部分。有可能是蛋先出现,因为它是生命的自然产物,但鸡作为一种更复杂的形式,可能是从蛋进化而来的。在我看来,这种进化是生命不断进步和发展的证明。'}
}
Observation: OK
🍏Agent Confucius takes 1-step Action:
{
    name: Finish
    params: {'response': '因此,在我看来,先有鸡还是先有蛋这个问题并不是一个简单的因果关系问题,而是对生命复杂而持续循环的反映。它提醒我们,在理解世界时,必须超越简单的答案,考虑自然的复杂性。'}
}
Observation: Task Completed.
=========🍏Confucius finish execution. TaskPackage[ID:ebcd2739-bfd3-4833-a80a-fb9e450d7cbd] status:
[
    completion: completed
    answer: 因此,在我看来,先有鸡还是先有蛋这个问题并不是一个简单的因果关系问题,而是对生命复杂而持续循环的反映。它提醒我们,在理解世界时,必须超越简单的答案,考虑自然的复杂性。
]
==========
Observation: 因此,在我看来,先有鸡还是先有蛋这个问题并不是一个简单的因果关系问题,而是对生命复杂而持续循环的反映。它提醒我们,在理解世界时,必须超越简单的答案,考虑自然的复杂性。[TLDR]
🍎Agent manager_agent takes 2-step Action:
{
    name: Socrates
    params: {'Task': 'What is your opinion on the question of whether the chicken or the egg came first?'}
}
🍍Agent Socrates receives the following TaskPackage:
[
    Task ID: ebcd2739-bfd3-4833-a80a-fb9e450d7cbd
    Instruction: What is your opinion on the question of whether the chicken or the egg came first?
]
====🍍Socrates starts execution on TaskPackage ebcd2739-bfd3-4833-a80a-fb9e450d7cbd====
🍍Agent Socrates takes 0-step Action:
{
    name: Think
    params: {'response': '在思考先有鸡还是先有蛋这个问题时,我们必须考虑因果关系的性质以及生命的本质。根据苏格拉底的推理,这个问题的答案不在于经验观察,而在于理解“鸡”和“蛋”的定义。我们所理解的鸡是一种完全形成的有机体,而蛋是一个过程的产物。似乎可以合理推断,鸡必须先出现,因为它是从蛋开始的发育过程的结果。'}
}
Observation: OK
🍍Agent Socrates takes 1-step Action:
{
    name: Finish
    params: {'response': '因此,在苏格拉底哲学的语境中,合理地得出结论,鸡先出现,因为它代表了蛋的发育过程的最终结果。'}
}
Observation: Task Completed.
=========🍍Socrates finish execution. TaskPackage[ID:ebcd2739-bfd3-4833-a80a-fb9e450d7cbd] status:
[
    completion: completed
    answer: 因此,在苏格拉底哲学的语境中,合理地得出结论,鸡先出现,因为它代表了蛋的发育过程的最终结果。
]
==========
Observation: 因此,在苏格拉底哲学的语境中,合理地得出结论,鸡先出现,因为它代表了蛋的发育过程的最终结果。[TLDR]
🍎Agent manager_agent takes 3-step Action:
{
    name: Aristotle
    params: {'Task': 'What is your opinion on the question of whether the chicken or the egg came first?'}
}
🍑Agent Aristotle receives the following TaskPackage:
[
    Task ID: ebcd2739-bfd3-4833-a80a-fb9e450d7cbd
    Instruction: What is your opinion on the question of whether the chicken or the egg came first?
]
====🍑Aristotle starts execution on TaskPackage ebcd2739-bfd3-4833-a80a-fb9e450d7cbd====
🍑Agent Aristotle takes 0-step Action:
{
    name: Think
    params: {'response': '在考察先有鸡还是先有蛋这个问题时,我们必须考虑自然秩序以及发育过程。作为一名教育家和哲学家,我相信蛋必须先出现。这是因为生命源于男女元素的结合,而蛋是这种结合的自然产物。鸡作为一种完全形成的有机体,不可能从一个非生命的蛋中自发产生。因此,蛋作为鸡的血统的开端,必须先出现。'}
}
Observation: OK
🍑Agent Aristotle takes 1-step Action:
{
    name: Finish
    params: {'response': '综上所述,根据我的推理,在生物发育过程中,蛋必须先于鸡出现。'}
}
Observation: Task Completed.
=========🍑Aristotle finish execution. TaskPackage[ID:ebcd2739-bfd3-4833-a80a-fb9e450d7cbd] status:
[
    completion: completed
    answer: 综上所述,根据我的推理,在生物发育过程中,蛋必须先于鸡出现。
]
==========
Observation: 综上所述,根据我的推理,在生物发育过程中,蛋必须先于鸡出现。[TLDR]
🍎Agent manager_agent takes 4-step Action:
{
    name: Finish
    params: {'response': '先有鸡还是先有蛋这个问题已经从三个不同的角度进行了探讨。孔子强调了生命的循环性以及理解自然复杂性的重要性。苏格拉底认为作为最终结果的鸡先出现。而亚里士多德则指出,在生物发育过程中,蛋必须先于鸡出现。'}
}
Observation: Task Completed.
=========🍎manager_agent finish execution. TaskPackage[ID:ebcd2739-bfd3-4833-a80a-fb9e450d7cbd] status:
[
    completion: completed
    answer: 先有鸡还是先有蛋这个问题已经从三个不同的角度进行了探讨。孔子强调了生命的循环性以及理解自然复杂性的重要性。苏格拉底认为作为最终结果的鸡先出现。而亚里士多德则指出,在生物发育过程中,蛋必须先于鸡出现。
]
==========

进程已结束,退出代码为 0

三、Zigent实现教程编写智能体

喂!想给个主题,就让AI生成完整教科书嘛?

(我们都知道,现有的入GPT类的LLM生成长篇文章时,每个小节的内容总是生成不够完善,我们是否有办法让AI一次性生成各节完整&可读版教科书呐?)

设计思路

先通过 LLM 大模型生成教程的目录,再对目录按照二级标题进行分块,对于每块目录按照标题生成详细内容,最后再将标题和内容进行拼接

👍分块的设计,解决了 LLM 大模型长文本的限制问题。

准备工作

🐥用老师给的免费大模型api_key,完成LLM配置!

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 = "http://43.200.7.56:8008/v1"
chat_model = "glm-4-flash"

llm = LLM(api_key=api_key, base_url=base_url, model_name=chat_model)

🐤导入相关库!

from typing import List, Dict
from zigent.llm.agent_llms import LLM
from zigent.actions import BaseAction, ThinkAct, FinishAct
from zigent.agents import BaseAgent
from zigent.commons import TaskPackage, AgentAct
from zigent.actions.InnerActions import INNER_ACT_KEY
from datetime import datetime #生成命名教程目录😘
import json

🐣因为本文要访问文件路径,需要准备下面这些:

import sys

# 获取当前文件的绝对路径🐛
current_file_path = os.path.abspath(__file__)

# 获取当前文件所在目录的上一级目录
project_path = os.path.dirname(os.path.dirname(current_file_path))

# 将项目根目录添加到 sys.path
if project_path not in sys.path:
    sys.path.append(project_path)

"神笔马良"能力生成

*也叫定义生成教程内容行为~

目录生成部分

class WriteDirectoryAction(BaseAction):#🐛
    """Generate tutorial directory structure action"""

    def __init__(self) -> None:
        action_name = "WriteDirectory"
        action_desc = "Generate tutorial directory structure"
        params_doc = {
            "topic": "(Type: string): The tutorial topic name",
            "language": "(Type: string): Output language (default: 'Chinese')"
        }
        super().__init__(action_name, action_desc, params_doc)

    def __call__(self, **kwargs):
        topic = kwargs.get("topic", "")
        language = kwargs.get("language", "Chinese")

        directory_prompt = f"""
        请为主题"{topic}"生成教程目录结构,要求:
        1. 输出语言必须是{language}
        2. 严格按照以下字典格式输出: {{"title": "xxx", "directory": [{{"章节1": ["小节1", "小节2"]}}, {{"章节2": ["小节3", "小节4"]}}]}}
        3. 目录层次要合理,包含主目录和子目录
        4. 每个目录标题要有实际意义
        5. 不要有多余的空格或换行
        """

        # 调用 LLM 生成目录
        directory_data = llm.run(prompt=directory_prompt)  # 注意这里传入的是prompt参数
        try:
            directory_data = json.loads(directory_data)
        except:
            directory_data = {"title": topic, "directory": []}

        return {
            "topic": topic,
            "language": language,
            "directory_data": directory_data
        }

内容生成部分

class WriteContentAction(BaseAction):
    """Generate tutorial content action"""

    def __init__(self) -> None:
        action_name = "WriteContent"
        action_desc = "Generate detailed tutorial content based on directory structure"
        params_doc = {
            "title": "(Type: string): The section title",
            "chapter": "(Type: string): The chapter title",
            "directory_data": "(Type: dict): The complete directory structure",
            "language": "(Type: string): Output language (default: 'Chinese')"
        }
        super().__init__(action_name, action_desc, params_doc)

    def __call__(self, **kwargs):
        title = kwargs.get("title", "")#接收标题
        chapter = kwargs.get("chapter", "")#章节
        language = kwargs.get("language", "Chinese")#语言
        directory_data = kwargs.get("directory_data", {})#目录数据

        content_prompt = f"""
        请为教程章节生成详细内容:
        教程标题: {directory_data.get('title', '')}
        章节: {chapter}
        小节: {title}

        要求:
        1. 内容要详细且准确
        2. 如果需要代码示例,请按标准规范提供
        3. 使用 Markdown 格式
        4. 输出语言必须是{language}
        5. 内容长度适中,通常在500-1000字之间
        """

        # 调用 LLM 生成内容
        content = llm.run(prompt=content_prompt)  # 🐛
        return content

生成"生产线"设计🏭

这部分就像生成了一个生产线的指挥经理(^^ゞ,负责管理目录和内容的生成

#此类用于详细说明生成教程内容的流程,继承自BaseAgent
class TutorialAssistant(BaseAgent):
    """Tutorial generation assistant that manages directory and content creation"""#管理
    def __init__(
        self,
        llm: LLM,#🐛LLM
        language: str = "Chinese"
    ):
        name = "TutorialAssistant"
        role = """You are a professional tutorial writer. You can create well-structured, 
        comprehensive tutorials on various topics. You excel at organizing content logically 
        and explaining complex concepts clearly."""
        
        super().__init__(
            name=name,
            role=role,
            llm=llm,
        )
        
        self.language = language
        self.directory_action = WriteDirectoryAction()#初始化目录🐛(原文没有这个!!)
        self.content_action = WriteContentAction()#初始化内容生成动作
    
        # Add example for the tutorial assistant,为助手添加一个示例任务
        self._add_tutorial_example()
        
        
    def _generate_tutorial(self, directory_data: Dict) -> str:
        #根据目录数据生成完整的教程内容
        """Generate complete tutorial content based on directory structure"""
        full_content = []
        title = directory_data["title"] #标题
        full_content.append(f"# {title}\n") #添加一级标题内容(疑似总标题本身)
        
        # Generate table of contents,生成目录directory,目录中包含各chapter,chapter包含各section
        full_content.append("## 目录\n") #目录是二级标题内容
        for idx, chapter in enumerate(directory_data["directory"], 1):
            for chapter_title, sections in chapter.items():
                full_content.append(f"{idx}. {chapter_title}")
                for section_idx, section in enumerate(sections, 1):
                    full_content.append(f"   {idx}.{section_idx}. {section}")
        full_content.append("\n---\n")
        
        # Generate content for each section,生成每个章节的详细内容
        for chapter in directory_data["directory"]:
            for chapter_title, sections in chapter.items():
                for section in sections:#目录最小单位为section
                    content = self.content_action(#section里面填充的是内容
                        title=section,
                        chapter=chapter_title,
                        directory_data=directory_data,
                        language=self.language
                    )
                    full_content.append(content)#内容上下连接
                    full_content.append("\n---\n")
        
        return "\n".join(full_content)#返回总内容

    
    #处理生成教程的任务
    def __call__(self, task: TaskPackage):
        """Process the tutorial generation task"""
        # 1. Extract topic from task,从教程中节选出主题
        topic = task.instruction.split("Create a ")[-1].split(" tutorial")[0]
        if not topic:
            topic = task.instruction
            
        # 2. Generate directory structure,生成目录结构
        directory_result = self.directory_action(
            topic=topic,
            language=self.language
        )
        print(directory_result)
        
        # 3. Generate complete tutorial,依据生成完整教程
        tutorial_content = self._generate_tutorial(directory_result["directory_data"])

        # 4. Save the result,保存结果
        task.answer = tutorial_content
        task.completion = "completed"
        
        return task

    #为助手添加一个示例任务,展示如何生成一个 Python 教程的目录和内容
    def _add_tutorial_example(self):
        """Add an illustration example for the tutorial assistant"""
        exp_task = "Create a Python tutorial for beginners"
        exp_task_pack = TaskPackage(instruction=exp_task)
        topic = "Python基础教程"

        act_1 = AgentAct(#1.思考应该怎么做
            name=ThinkAct.action_name,
            params={INNER_ACT_KEY: """First, I'll create a directory structure for the Python tutorial, 
            then generate detailed content for each section."""}
        )
        obs_1 = "OK. I'll start with the directory structure."

        act_2 = AgentAct(#2.生成目录
            name=self.directory_action.action_name,
            params={
                "topic": topic, 
                "language": self.language
            }
        )
        obs_2 = """{"title": "Python基础教程", "directory": [
            {"第一章:Python介绍": ["1.1 什么是Python", "1.2 环境搭建"]},
            {"第二章:基础语法": ["2.1 变量和数据类型", "2.2 控制流"]}
        ]}"""

        act_3 = AgentAct(#3,生成各节内容
            name=self.content_action.action_name,
            params={
                "title": "什么是Python",
                "chapter": "第一章:Python介绍",
                "directory_data": json.loads(obs_2),
                "language": self.language
            }
        )
        obs_3 = """# 第一章:Python介绍\n## 什么是Python\n\nPython是一种高级编程语言..."""

        act_4 = AgentAct(#4.任务结束
            name=FinishAct.action_name,
            params={INNER_ACT_KEY: "Tutorial structure and content generated successfully."}
        )
        obs_4 = "Tutorial generation task completed successfully."

        exp_act_obs = [(act_1, obs_1), (act_2, obs_2), (act_3, obs_3), (act_4, obs_4)]
        #我发现Zigent都有这种结构
        self.prompt_gen.add_example(
            task=exp_task_pack,
            action_chain=exp_act_obs
        )

交互式教程生成

用户可以输入要创建的教程主题,我们的智能体TutorialAssistant可生成相应的教程内容,并将结果保存到本地文件

if __name__ == "__main__":
    
    #创建 `TutorialAssistant` 实例
    assistant = TutorialAssistant(llm=llm)

     # 调用其 `__call__` 方法,交互式生成教程
    FLAG_CONTINUE = True
    while FLAG_CONTINUE:
        input_text = input("What tutorial would you like to create?\n")
        task = TaskPackage(instruction=input_text)
        result = assistant(task)
        print("\nGenerated Tutorial:\n")
        print(result.answer)

        # 创建输出目录
        output_dir = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        os.makedirs(output_dir, exist_ok=True)
        
        # 保存文件
        output_file = os.path.join(output_dir, f"{input_text}.md")
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(result.answer)
        if input("\nDo you want to create another tutorial? (y/n): ").lower() != "y":
            FLAG_CONTINUE = False

😊预期结果会在当前目录生成一个时间戳目录(文件夹),目录下包含生成的教程文件。

🤖:

最重要的还有,我们亲爱的Agent教程诞生了!!!妈妈再也不用担心我的选修课大作业啦!!!

这个AI生成的Agent教程放到这里篇幅会很长,所以我可以为它(without任何修改)单开一篇博文,哈哈哈哈哈!

AI生成《Agent教程》的链接:Agent教程(内容均为本人操控AI生成🤖-原版) - 岁月月宝贝 - 博客园

今天终于可以早点交作业啦!开心开心!!!

posted on 2025-01-20 00:21  岁月月宝贝  阅读(101)  评论(0)    收藏  举报