第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

如何用LangGraph、Qwen和Streamlit構(gòu)建一個(gè)多代理健康助手系統(tǒng)

AI生成的照片

代理是自主代理,能够感知环境并行动以实现特定的目标。在我的先前文章中,我探讨了AI代理的基础知识及其功能。在本文中,我们更进一步,深入探讨一下多代理系统(Multi-Agent Systems,MAS)。

当我们无法用单个智能体处理复杂任务时,我们就会构建多智能体系统,可以将它们定义为一个协同解决问题的智能体网络。存在多种智能体架构,对于我们实现的系统,我们将专注于监督架构。为了驱动我们的智能体,我们将使用Qwen,一个本地的大规模语言模型(LLM)。

在这份教程中,我们将构建一个AI健康助手平台,该平台包含三个代理——健身代理、营养代理和心理健康代理。这三个代理将会协同工作,帮助用户提升体能、营养和身心健康。系统将由一个监督代理协调,该监督代理将任务分配给每个代理并监督他们的进展。

监督架构

系统的核心是监督代理,它扮演协调者的角色。它接收用户的指令或输入,识别出适合处理任务各部分的适当代理,并将任务分配给他们。例如,如果用户说:“我想变得健康并且吃得更健康”,监督代理会将此请求交给健身代理和营养师代理。然后,它会收集这些代理的回复,并给出连贯的反馈给用户。在下面的图表中,我们可以看到每个代理如何向监督代理汇报。

现在我们已经讨论了多代理监督系统的概念和架构,让我们来看看具体怎么实现吧。请按照下面的步骤来。

第一步:安装

在我们能够在本地使用Qwen之前,我们需要先安装Ollama,它允许我们在本地机器上直接运行大模型

1)下载然后安装Ollama

要下载Ollama,请访问他们的官网并下载适合您操作系统的版本。

2) 检查安装

ollama -v

ii) 获取Qwen模型

ollama pull qwen2.5:14b

接下来,设置你的 API 密钥

我们的系统将会使用外部API来获取真实世界的数据。这些健康助手会从各自的API获取运动和营养信息。

用到的 API:

i) 获取你的API密钥

在两个平台上免费注册,然后免费获取你的API密钥。

ii)保存密钥:

为了确保凭证的安全并方便访问,我们将凭证存放在 .env 文件中。

.env文件将会是这样的:

运动API密钥 =xxxxxxxx   
饮食API密钥 =xxxxxxxxxxxx
步骤 3:创建程序运行的状态

当我们构建我们的AI健康助手时,我们需要首先设置的是状态信息。状态信息在帮助代理们记录对话历史方面起着至关重要的作用,特别是在它们在整个流程中互相交流并传递任务时。这样可以帮助代理们记录对话历史。

为了管理这个,我们将使用LangGraph自带的MessagesState类。这个类提供了一种方便的方式来存储和管理消息。我们的自定义状态类将继承MessagesState类以利用其内置功能。

    从langchain_core.messages导入HumanMessage, AIMessage
    从langgraph.prebuilt导入create_react_agent
    从langgraph.graph导入StateGraph, MessagesState, START, END
    从langgraph.checkpoint.memory导入MemorySaver
    从langchain.prompts导入PromptTemplate
    从IPython.display导入display, Image
    从typing导入Annotated, Literal
    从langchain_ollama导入ChatOllama

    从typing_extensions导入TypedDict
    从langchain.tools导入tool
    从langgraph.types导入Command
    导入requests
    导入random
    导入uuid
    导入os

    fitness_api_key = os.getenv("EXERCISE_API_KEY")
    diet_api_key = os.getenv("DIET_API_KEY")

    类State(MessagesState):
        next: str
步骤 4:创建自己的工具

之前,我们从API-Ninjas(用于运动数据)和Spoonacular(用于食物和营养数据)获取了API密钥。现在是时候把这些密钥派上用场了,为我们的代理制作自定义工具。这些工具就是代理人完成任务时会用到的。

i)健身器材

我们将使用这个endpoint来获取各种锻炼类型,并为用户制定个性化的锻炼计划。代码如下所示。

    class FitnessData:  

        def __init__(self):  
            self.base_url = "https://api.api-ninjas.com/v1/exercises"  
            self.api_key = fitness_api_key  

        def get_muscle_groups_and_types(self):  

            muscle_targets = {  
                    'full_body': ["abdominals", "biceps", "calves", "chest", "forearms", "glutes",  
                        "hamstrings", "lower_back", "middle_back", "quadriceps",  
                        "traps", "triceps", "adductors"  
                        ],  
                    'upper_body': ["biceps", "chest", "forearms", "lats", "lower_back", "middle_back", "neck", "traps", "triceps" ],  
                    'lower_body': ["adductors", "calves", "glutes", "hamstrings", "quadriceps"]  
                }  
            exercise_types = {'types':["powerlifting","strength", "stretching", "strongman"]}  

            return muscle_targets, exercise_types  

        def fetch_exercises(self, type, muscle, difficulty):  
            headers = {  
                'X-Api-Key':self.api_key  
            }  
            params= {  
                'type': type,  
                'muscle': muscle,  
                'difficulty': difficulty  
                }  
            try:  
                response = requests.get(self.base_url, headers=headers,params=params)  
                result = response.json()  
                if not result:  
                    print(f"没有找到针对 {muscle} 的运动")  
                return result  
            except requests.RequestException as e:  
                print(f"请求失败:{e}")  
                return []  

        def generate_workout_plan(self, query='full_body', difficulty='intermediate'):  
            output=[]  
            muscle_targets, exercise_types = self.get_muscle_groups_and_types()  
            muscle = random.choice(muscle_targets.get(query))  
            type = random.choice(exercise_types.get('types'))  
            result = self.fetch_exercises('拉伸', muscle, difficulty)  
            print(result)  
            limit_plan = result[:3]  
            for i, data in enumerate(limit_plan):  
                if data not in output:  
                    output.append(f"运动 {i+1}:{data['name']}")  
                    output.append(f"锻炼部位:{data['muscle']}")  
                    output.append(f"说明:{data['instructions']}")  

            return output

之后,我们通过创建类的实例来调用 generate_workout_plan 函数,从而建立了一个健身自定义工具。此函数允许用户根据特定类别(比如全身、上半身或下半身)来定制锻炼计划。请注意,该函数带有 @tool 装饰器;这个装饰器就是将函数转变成 LangChain 自定义工具的关键。

    @工具注解  
    def fitness_data_tool(query: Annotated[str, "此输入应为 full_body、upper_body 或 lower_body 中的一种"]):  
        """此工具用于为用户提供健身或锻炼计划。  
        输入的锻炼类型(full_body、upper_body 或 lower_body)将作为您的输入。  
        """  
        fitness_tool = FitnessData()  
        result = fitness_tool.generate_workout_plan(query)  
        return result

饮食营养师工具

对于营养师助手的数据来源,我们将利用Spoonacular API,并利用其生成饮食计划获取食谱信息端点。通过这种方式,助手可以根据用户的饮食偏好(如素食、纯素食或标准饮食等)生成个性化的饮食计划。用户可以看到包含每日营养成分明细(如蛋白质、脂肪和碳水化合物)的饮食计划。

    class 营养师类:  

        def __init__(self):  
            self.base_url = "https://api.spoonacular.com"  
            self.api_key = diet_api_key  

        def 获取餐食(self, 时间范围="day", 饮食="无"):  

            url = f"{self.base_url}/mealplanner/generate"  
            params = {  
                "timeFrame": 时间范围,  
                "diet": 饮食,  
                "apiKey": self.api_key  
            }  

            response = requests.get(url, params=params)  
            if not response:  
                print('未找到餐计划,请检查输入参数')  
            return response.json()  

        def 获取食谱信息(self, 食谱ID):  

            url = f"{self.base_url}/recipes/{食谱ID}/information"  
            params = {"apiKey": self.api_key}  
            response = requests.get(url, params=params)  
            if not response:  
                print("未找到食谱,请检查 API 密钥和输入参数")  
            return response.json()  

        def 生成餐计划(self, 查询):  
            处理餐食 = []  
            餐计划 = self.获取餐食(查询)  
            print(餐计划)  

            餐食 = 餐计划.get('meals')  
            营养成分 = 餐计划.get('nutrients')  

            for i, 餐食项 in enumerate(餐食):  
                食谱信息 = self.获取食谱信息(餐食项.get('id'))  
                食材 = [食材['original'] for 食材 in 食谱信息.get('extendedIngredients')]  

                处理餐食.append(f"🍽️ 餐点 {i+1}: {餐食项.get('title')}")  
                处理餐食.append(f"准备时间 (分钟): {餐食项.get('readyInMinutes')}")  
                处理餐食.append(f"份量 (人): {餐食项.get('servings')}")  

                处理餐食.append("食材:\n" + "\n".join(食材))  
                处理餐食.append(f"指南:\n {食谱信息.get('instructions')}")  

            处理餐食.append(   
            "\n每日营养:\n"  
            f"蛋白质: {营养成分.get('protein', 'N/A')} g\n"  
            f"脂肪: {营养成分.get('fat', 'N/A')} g\n"  
            f"碳水化合物: {营养成分.get('carbohydrates', 'N/A')} g"  
            )  

            return 处理餐食  

接下来,我们来创建自己的工具。

    @工具装饰器  
    def diet_tool(query: Annotated[str, "输入可以是 None、素食或纯素食"]):  
        """使用此工具为用户提供饮食计划。  
        输入的饮食类型会生成相应的饮食计划  
        """  
        营养师工具 = Dietitian()  
        结果 = 营养师工具.generate_meal_plan(query)  

        return result
步骤 5:给 LLM 下定义

在这里,我们将定义这个大型语言模型,名为Qwen2.5:14b。该模型非常适合用于构建智能助手。

    llm = ChatOllama(model="qwen2.5:14b")  # 创建一个名为llm的ChatOllama对象,使用模型"qwen2.5:14b"
    memory = MemorySaver()  # 创建一个名为memory的MemorySaver对象
步骤六:创建代理和节点:

在这一步,我们将创建节点以及代理,我们将使用 LangGraph 中预构建的create_react_agent工具。

i) 健身教练

对于健身代理程序,我们将以下三个关键组件传递给 create_react_agent 函数:LLM、我们自定义的用于获取运动数据的工具(fitness_data_tool)和健身代理提示(fitness_agent_prompt)。

接下来,在我们的健身任务节点中,该节点代表LangGraph工作流中的健身任务。我们通过传递当前状态中的消息(即用户的输入信息)来调用代理。处理完成后,我们使用命令对象传递结果。这让我们能够用输出更新状态,并指示其返回主管代理。一旦任务完成,我们就指示健身节点返回主管代理。

    fitness_agent_prompt = """  
    你只能回答关于健身的问题。  
    """  

    fitness_agent = create_react_agent(  
        llm,  
        tools = [fitness_data_tool],  
        prompt = fitness_agent_prompt)  

    def fitness_node(state: State) -> Command[Literal["supervisor"]]:  
        result = fitness_agent.invoke(state)  
        return Command(  
            update={  
                "messages": [  
                    AIMessage(content=result["messages"][-1].content, name="健身消息")  
                ]  
            },  
            goto="supervisor",  
        )

ii) 营养师代理
在创建营养师代理及其节点的过程中,我们遵循了同样的步骤。

    dietitian_system_prompt = """  
    你只能回答关于饮食和餐计划安排的问题。  
    """  
    dietitian_agent = create_react_agent(  
        llm,  
        tools = [diet_tool],  
        prompt = dietitian_system_prompt)  

    def dietitian_node(state: State) -> Command[Literal["supervisor"]]:  
        result = dietitian_agent.invoke(state)  
        return Command(  
            update={  
                "messages": [  
                    AIMessage(content=result["messages"][-1].content, name="dietitian")  
                ]  
            },  
            goto="supervisor",  
        )

iii) 心理健康辅导员

为了创建我们的心理健康代理,我们定义了一个 mental_health_node,它包含一个自定义提示来引导大语言模型完成任务,并告知其预期结果。任务完成后,该节点使用 Command 对象来更新对话状态以反映当前情况,然后将控制权交回 Supervisor Agent

     def 心理健康节点(state: State) -> Command[Literal["supervisor"]]:  
        提示模板 = PromptTemplate.from_template(  
            """你是一位支持性的心理健康教练。  
            你的任务是:  
            - 提供一个独特的心理健康建议或减压练习。  
            - 使其简单、亲切且实用。避免重复建议。"""  
        )  

        链 = 提示模板 | llm  
        回复 = 链.invoke(state)  
        return Command(  
            update={  
                "messages": [  
                    AIMessage(content=f"这是你的健康贴士:{回复.content}", name="wellness")  
                ]  
            },  
            goto="supervisor",  
        )

iv) 主管代理

在创建监督代理的过程中,我们定义了一个系统提示,在其中明确代理的角色并介绍它将管理的团队成员,包括健身代理、营养师代理和心理健康代理这三名成员。我们还定义了一个路由器类,用以规范监督代理的输出,作为监督代理输出的结构化模板。

然后,我们实现了监控节点,设置了消息的流程,并定义了代理之间路由的消息逻辑。这包括如何将消息路由到下一个任务以及何时结束会话。

    members = ["fitness", "dietitian", "wellness"]  
    options = members + ["FINISH"]  

    system_prompt = (  
        "你是负责管理以下员工之间的对话的主管:\n"  
        f"{members}。在收到用户的请求后,\n"  
        "请回复接下来应由哪个员工行动。每个员工将执行一项任务并回复他们的结果和状态。任务完成后,\n"  
        "请回复 FINISH。\n"  

        "指南:\n"  
        "1. 请检查对话中的最后一条消息,确定任务是否已完成。\n"  
        "2. 如果您已经得到了最终答案或结果,请回复 'FINISH'。\n"  

    )  

    class Router(TypedDict):  
        """如果没有需要处理的工作人员,请回复 FINISH。"""  

        next: Literal[*options]  

    def supervisor_node(state: State)-> Command[Literal[*members, "__end__"]]:  
        messages = [  
            {"role": "system", "content": system_prompt},  
        ] + state["messages"]  
        response = llm.with_structured_output(Router).invoke(messages)  
        goto = response["next"]  
        if goto == "FINISH":  
            goto = END  

        return Command(goto=goto, update={"next": goto})
第7步:构建多代理图

现在,我们构建工作流图,将主管节点作为执行的起点。接着,我们再添加其他的代理节点。

builder = StateGraph(状态)  
builder.add_edge(开始, "supervisor")  
builder.add_node("supervisor", 监督节点)  # 监督节点指的是负责监督的节点  
builder.add_node("fitness", 健身节点)  # 健身节点指的是与健身相关的节点  
builder.add_node("dietitian", 营养师节点)  # 营养师节点指的是与营养师相关的节点  
builder.add_node("wellness", 心理健康节点)  # 心理健康节点指的是与心理健康相关的节点  
graph = builder.compile(checkpointer=memory)

步骤八:测试这个多代理系统的功能

在这个阶段,我们的多代理系统已经完全准备好,准备好接收用户的输入。发送输入之前,我们先定义一个帮助函数来提取代理的输出。

    def 解析语言图输出(stream):  # 解析语言图输出
        结果 = []  # 结果列表
        for 键, 值 in stream.items():  # 遍历键值对
            if 键 == "supervisor":  # 如果键是"supervisor",继续下一个循环
                continue
            消息 = 值.get("messages", [])  # 获取消息列表
            for 消息项 in 消息:  # 遍历消息列表
                if isinstance(消息项, str):  # 判断是否为字符串
                    结果.append((键, 消息项))  # 添加键值对到结果列表
                elif isinstance(消息项, AIMessage):  # 判断是否为AIMessage
                    结果.append((键, 消息项.content))  # 添加键值对到结果列表
        return 结果  # 返回结果列表

我们将用户的输入输入到系统中。


    # 获取流的最终事件
    final_event = None
    config = {"configurable": {"thread_id": "1", "recursion_limit": 10}}    
    inputs = {  
                    "messages": [  
                        HumanMessage(  
                            content="给我一些关于这个月的健康建议?"  
                        )  
                    ],  
                }  

    for step in graph.stream(inputs, config=config):  
        final_event = step  # 始终使用最新的事件
        输出当前事件:final_event  

        response_message = parse_langgraph_output(final_event)  
        for agent, content in response_message:  
            显示 "**Agent :** `{agent}`\n\n{content}"  
            显示 "="*50

这是在Streamlit应用中显示的结果。

查看这个GitHub仓库的完整代码。

谢谢你的阅读!下回见,。

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫(xiě)下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專(zhuān)欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢(xún)優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消