LangGraph之Multi-Agent-Systems开发实战
本节课我们将围绕 LangGraph 框架中的多智能体系统Multi-Agent Systems展开学习和应用的实践。
Agent到底应该如何去定义? 什么样的应用程序能算的上一个Agent? 到现在仍然没有特别一个明确的说法和界定。有的人认为只要应用程序中集成了能够处理全领域知识查询的大模型,它就可被视为一个Agent,而更多的一部人则认为这还远不够,他们会觉得只有当一个应用程序能像人类一样思考并自主处理复杂任务时,才真正符合 Agent 的标准。大家应该都听过这样一种观点:大模型的发展使得人工通用智能(AGI)在未来成为现实的可能性也越来越大。在这个过程中,基础的Agent扮演关键角色。那么,什么样的Agent最符合未来的发展趋势呢?
我们来看看大模型行业巨头OpenAI对AI Agent的理解。
在2024年7月初,OpenAI 的领导层在全体内部员工会议上的分享中,定义了 AI 的五个不同阶段,共同去努力实现构建通用人工智能的最终目标。这五个阶段涵盖了从基本的聊天机器人到能够完成整个组织工作的高级系统,而第五个阶段所需要具备的能力就是可以构造出一种智能且能够执行与人类相同的所有工作的 AI 。各个阶段如下所示:
- Stage 1. Chatbots
AI的第一阶段称为聊天机器人。OpenAI 自己的 ChatGPT 就是这个阶段的最佳例子,它在 2022 年底发布时以其用自然语言交谈的能力震惊了世界。我们可以使用聊天机器人来提高其内部生产力,这些聊天机器人乍一看似乎非常聪明,但是通常会充满信心地编造和呈现虚假信息,所以如果它们不能有效的融入私人/企业的数据,没有太多的商业用途。
- Stage 2: Reasoners
OpenAI 定义的AI第二阶段为推理者。推理者是可以完成基本问题解决任务的系统,不需要借助任何工具,通过改进推理增强大模型处理各种任务的能力,这包括从做出重大科学发现到规划和构建新的软件应用程序。正如 OpenAI 发布的 o1-preview。
- Stage 3: Agents
AI的第三个阶段,OpenAI 认为是AI Agent,它是可以代表用户采取行动的系统。而这个阶段也就是我们目前一直在学习的相关内容,如LangGraph的Router Agent、Tool Calling Agent以及ReAct,我们通过工作流的编排去让应用程序自主完成一些特定的用户需求和任务目标,整个过程不需要任何的人工介入。
- Stage 4: Innovators
第四个阶段的创新者是指:可以帮助发明的人工智能。这类应用帮助人们产生想法、编写代码和进行创作,它们以专门开发的 AI 系统的形式出现,以帮助原型、构建和制造物理产品。
- Stage 5: Organizations
在 OpenAI 提出的人工智能的最后阶段:AI 系统将变得足够先进和智能,可以完成整个组织的工作,并将组织归类为智能路线图的最后一步。
随着本期课程中Agent模块学习进度的推进,大家已经顺利的迈入了Stage 3: Agents 阶段。无论是从零到一去构建ReAct,还是借助Assistant API、langGraph框架去实现完全自主循环代理,大家已经能够借助大模型的能力,让其在个人的工作/学习中解放人力的同时提升效率。而接下来的Stage 4 ~ Stage 5 两个阶段,我可能有一万种理由去解释为什么现在学习到的知识点还不能够去匹配和适应这两个更高阶段的需求。
1、Single-Agent架构的局限
就我们目前正在探讨的LangGraph框架,Stage 5:Organizations 阶段特别强调的AI是一个组织,组织的概念大家应该都比较清楚,它大到一个国家,小到两个人的团队,但它绝不仅仅是一个个体。但我们之前所学习的,强如完全自主循环代理ReAct,它其实做的都是在尝试去打造更强的独立个体,我们通过给它传递更多工具(Tool Calling),赋予上下文的记忆(Memory)等等多种方式让其能够处理越来越发展的任务需求。但随着需求越来越复杂,能够预想到的以下几个非常关键的问题是:
Agent有太多工具可供使用,会导致对下一步调用哪个工具做出了混乱的决定。- 上下文变得过于复杂,无法清晰的跟踪并传递有效信息。
- 系统中需要多个专业领域(例如规划师、研究人员、数学专家等),单一的角色背景设定没有办法匹配不同的需求。
上面这三个问题很现实的摆在我们面前,行之有效的解决的办法就是:调整 Agent 的架构。变成如下图所示的一样:
多代理系统其实就可以非常简单的理解为:将原本的应用程序拆分成多个较小的独立代理,从而组合而成的系统。这些小的独立代理可以是简单的大模型交互代理,也可以是复杂的 ReAct 代理。举个比较热门的案例,假设我们需要建立一个用于数据分析的Agent,则可以设计代理配置:Agent 1作为用户意图识别代理,集成大模型用来解析用户的查询和指令,理解其意图和需求,并将用户输入转化为具体的任务。Agent 2作为数据分析代理,集成大模型并绑定若干个处理不同数据和需求的工具,提供统计分析、趋势预测和数据可视化服务。当任务涉及到代码生成时,Agent 3,即代码执行代理,会接收用户输入的代码,在安全的Python环境中执行这些代码,并返回运行结果,用于代码测试、执行特定算法或自动化任务。
由此能感受到的是多智能体系统 (MAS) 是通过多个单代理之间的协作来解决复杂的任务,其中多代理系统中集成的每个单代理,都有特定的背景身份和独有的技能。其显著的优势则包含如下三个方面:
- 专业化:当一个系统中可以创建多个专注于特定领域的专家代理,能实现处理更复杂的应用的
AI系统。 - 模块化:单独的代理开发模式对于开发、测试和维护完整代理系统是更加容易的。
- 控制度:显式地控制代理的通信方式,而不仅仅是依赖函数调用。
通过langGraph前面知识点的学习,我们已经完全掌握了构建Multi-Agent Systems三个优势点中的前两个中涉及的方法,即专业化和模块化。我们知道如何去在langGraph中给某个节点(Node)中的大模型赋予特殊的身份背景,这可以通过SystemMessage来做到。同样也知道如何去基于Router Agent、 ToolCalling Agent 或者ReAct去构建具备诸如数据分析代理、代码执行代理等完整的构建思路和流程。
唯一还欠缺的知识点只有:如何去建立起不同Agent之间的通信连接。在Single-Agent架构中,我们是通过节点和边去构建图的结构,但在Multi-Agent,当简单的节点由复杂的Agent来替代,那么如何去建立起不同Agent之间的通信关系,就是我们在构建多代理系统时唯一需要关注的事情。如下图所示 👇
在多代理架构中,对于子代理的数量以及应如何连接它们时,没有严格的规则或准则,可以完全依赖开发者的思路和实际的业务场景进行自定义编排。我们要做的是:在功能设计上将较大的目标分解为较小的任务,并创建单独的代理来处理这些任务中的每一个。每个代理都拥有自己的系统提示和身份设定、大模型的接入支持、工具和自定义代码,从而形成多智能实体的协作交互。
2、Multi-agent architectures架构
继续深入探讨 Multi-Agent概念。LangGraph利用基于图的结构来定义代理并在它们之间建立连接。在此框架中,每个代理都表示为图中的一个节点,并通过边链接到其它代理。每个代理通过接收来自其他代理的输入并将控制权传递给下一个代理来执行其指定的操作。在LangGraph 框架的设计中,主要通过如下几种方法来建立各个子代理之间的通信连接:
- NetWork(网络):每个代理都可以与其他每个代理通信。任何代理都可以决定接下来要呼叫哪个其他代理。
- Supervisor(主管):每个代理都与一个
Supervisor代理通信。由Supervisor代理决定接下来应调用哪个代理。 - Supervisor (tool-calling):
Supervisor架构的一个特例。每个代理都是一个工具。由Supervisor代理通过工具调用的方式来决定调用哪些子代理执行任务,以及要传递给这些代理程序的参数 - Hierarchical(分层):定义具有
supervisor嵌套supervisor多代理系统。这是Supervisor架构的一种泛化,允许更复杂的控制流。
各个多代理架构的通信方式如下图所示 👇 :
LangGraph 非常适合创建多代理工作流,因为它允许将两个或多个代理作为图连接。每个代理都是一个独立的参与者,代理之间的连接由边表示。每个连接边都可以有一个控制条件,用于将信息从一个代理中引导到另一个代理中,并且每个代理都有一个状态,可以在每个流期间使用信息进行更新。
但是,在具体实践各个不同多代理架构下的具体应用方法之前,我们需要结合LangGraph构建图的机制去思考一个问题:通过State可以让一个图中的所有节点共享全局的信息,那么在多代理架构中,当每一个图变成了一个节点,那么不同图之间的状态,应该怎么传递?
在上图所示的架构中,每个子代理(例如Agent 1、Agent 2、Agent 3)由多个内部节点组成,各自通过独立的State维护内部节点间的消息传递。举个例子,假设Agent 1是一个数据分析师,负责接收并整理关键数据;Agent 2则负责进行精细化的计算。在这个过程中,如何有效地在Agent 1和Agent 2之间传递数据成为了一个关键问题。Agent 1需要将数据传递给Agent 2进行处理,之后Agent 2需要将计算结果返回给Agent 1。但是当前的涉及是不支持在代理间传递状态的,即在Agent 2的执行过程中无法访问Agent 1中的状态。
因此,如果想让不同Agent之间能够做到消息共享,则需要了解 LangGraph框架中的Subgraphs(子图)相关的概念和使用方法。
3、Subgraphs
Subgraphs(子图)指的是能够用作另一个图中的节点的图。简单理解就是:把一个已经编译好的图,嵌入到另一个已经编译好的图中,并且两个独立图的中的状态可以信息共享。一个典型的应用就是构建多代理系统架构。它所做的事情是:当把每个独立的Agent图结构定义为一个子图时,只要遵守子图的接口(输入和输出模式)规范,那么子图中定义的共享状态就可以在父图中进行使用。如下图所示:
添加子图主要解决的问题就是解决各Single-Agent之间的通信问题,即它们如何在图执行期间在彼此之间传递状态。这主要有两种情况:
- 父、子图的状态模式中有共同的键(通道)。
- 父、子图的状态模式中没有共同的键。(通道)
如何理解这两种情况?我们就分别用实际的案例来帮助大家理解这个过程。首先来看第一种情况:如果父、子图节点中定义的状态模式有共同的键,比如下述情况所示:
在这个图结构中,final_answer作为父图的全局共享状态,被Sub Graph 子图访问。这个子图通过共享状态键final_answer进行交互,同时各自自己独立的内部状态键summary_answer。这种设计允许父图与子图之间通过共享状态键final_answer进行通信,同时保持各自的状态独立性,实现数据隔离与信息共享的平衡。
接下来我们设计一个实际应用场景去构建如上图所示的父图与子图相结合的状态图系统。具体来说,我们设计一个评分系统,分为两个主要部分:父图负责处理初步的用户输入,并生成响应,而子图则进一步处理这些响应,进行内容精简和质量评估。以下是具体的代码实现:
- Step 1. 定义用于构建Agent的大模型实例
之前的案例中我们一直使用GPT模型构建Agent,当然LangGraph也支持本地开源模型的接入,所以接下来我们提供两种模型的接入代码供大家结合自己的实际情况进行选择。首先,如果大家在实践时仍然选用GPT模型,依然使用如下代码进行GPT模型的实例化。
1 | import getpass |
而如何想要使用本地部署的开源大模型,可以用LangChain进行高效的接入。如下代码所示,我们使用langChain的ChatOllama第三方的集成方法接入本地启动的Qwen-2.5:72B模型。
注意:在执行如下代码之前,需要在本地/云服务器上使用Ollama部署并启动对应的模型,如下所示:
1 | # ! pip install langchain-ollama |
1 | # 如果用开源模型,可以用Ollama 接入 |
测试一下 qwen2.5:72b 模型的连通性,代码如下:
1 | print(llm.invoke("你好,请你介绍一下你自己。").content) |
你好!我是Qwen,我是阿里云开发的超大规模语言模型,我能够生成各种类型的文本,如文章、故事、诗歌等,并能根据不同的场景和需求进行调整和优化。我的目标是帮助用户更高效地创作内容,同时也能在对话中提供有用的信息和支持。很高兴认识你,有什么我可以帮到你的吗?
- Step 2. 定义父图的状态模式
父图的作用是接收来自用户的输入,这些输入可能是问题、请求或任何形式的查询,使用大模型处理用户输入,生成一个详细的响应。所以涉及两个状态键:用户的输入和大模型针对用户输入的响应。因此定义如下:
1 | from typing import TypedDict |
- Step 3. 定义父图的节点逻辑
节点的功能就是使用大模型处理用户输入,并生成响应。
1 | def parent_node(state: ParentState): |
- Step 4. 定义子图的状态模式
对于子图来说,父图生成的响应会传递到子图,子图的第一个节点负责将这个响应缩减为一个简洁的总结。然后在子图的第二个节点,对完整的响应及其总结进行评分。因此涉及的状态模式就如下图所示:
1 | # 定义子图中的状态 |
其中final_answer用来接收父图传递过来的响应,summary_answer用来接收子图对父图传递过来的响应的总结。
- Step 5. 定义子图的节点逻辑
第一个节点用来将 父图生成一个不超过10个单词的简短总结,第二个节点根据完整的响应及其总结进行综合的评分,代码如下:
1 | from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage, AIMessage |
1 | def subgraph_node_2(state: SubgraphState): |
接下来要明确的是:如果我们希望子图与父图在共享状态键的情况下可以进行通信,需要执行如下两个步骤:
定义子图工作流程并对其进行编译。
在定义父图工作流时,将编译的子图传递给
.add_node方法。
- Step 6. 定义子图的图结构并且进行编译
1 | from langgraph.graph import START, StateGraph |
- Step 7. 定义父图的图结构,并将子图作为节点添加至父图
1 | builder = StateGraph(ParentState) |
- Step 8. 可视化完整的图结构
1 | from IPython.display import Image, display |
1 | async for chunk in graph.astream({"user_input": "我现在想学习大模型,应该关注哪些技术?"}, stream_mode='values'): |
{'user_input': '我现在想学习大模型,应该关注哪些技术?'}
{'user_input': '我现在想学习大模型,应该关注哪些技术?', 'final_answer': AIMessage(content='如果你对大模型感兴趣并希望深入学习,可以关注以下几个方面的技术和概念:\n\n1. **自然语言处理(NLP)**:这是大模型应用最广泛的领域之一。了解词嵌入、序列到序列模型、注意力机制等基础概念对于理解大模型的工作原理非常重要。\n\n2. **深度学习框架**:熟悉至少一个深度学习框架,如TensorFlow、PyTorch或PaddlePaddle等。这些工具是构建和训练大型神经网络的基础。\n\n3. **Transformer架构**:目前大多数先进的大模型都基于Transformer架构。深入理解其工作原理(包括自注意力机制)对于掌握如何设计和优化大模型至关重要。\n\n4. **模型压缩与加速技术**:虽然大模型具有强大的性能,但它们往往需要大量的计算资源。学习如何通过量化、剪枝等方法来减少模型大小而不显著牺牲准确性是非常有用的技能。\n\n5. **微调(Fine-tuning)与迁移学习**:了解如何基于预训练的大模型进行特定任务的微调,是快速提高模型在具体应用场景中表现的有效途径。\n\n6. **评估指标和验证技术**:掌握准确评估大模型性能的方法和技术,包括常见的评价指标如精确率、召回率等,以及如何设置合理的测试集来避免过拟合等问题。\n\n7. **伦理与隐私问题**:随着AI技术的发展,数据安全和个人隐私保护成为越来越重要的议题。了解相关法律法规和最佳实践有助于确保你的项目既创新又负责任。\n\n8. **持续学习和社区参与**:AI领域发展迅速,新的研究和技术不断涌现。通过阅读论文、参加线上课程或加入专业论坛等方式保持对最新进展的关注非常重要。\n\n希望这些建议对你有所帮助!如果你有更具体的学习目标或者遇到任何技术难题,也欢迎随时提问。', additional_kwargs={}, response_metadata={'model': 'qwen2.5:72b', 'created_at': '2024-11-15T08:56:41.373140529Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 25588340376, 'load_duration': 63230315, 'prompt_eval_count': 40, 'prompt_eval_duration': 122000000, 'eval_count': 375, 'eval_duration': 25382000000}, id='run-a9a4968b-44ba-4580-9620-66cbe6f99303-0', usage_metadata={'input_tokens': 40, 'output_tokens': 375, 'total_tokens': 415})}
{'user_input': '我现在想学习大模型,应该关注哪些技术?', 'final_answer': '8'}
当一个图中添加了子图,按照常规的调用方法可以看到父图的最终输出包括子图调用的结果(即字符串 “final_answer”)。如果想进一步查看子图的输出,可以在流式传输时指定 subgraphs=True。如下代码所示:
1 | async for chunk in graph.astream({"user_input": "如何理解RAG?"}, stream_mode='values', subgraphs=True): |
((), {'user_input': '如何理解RAG?'})
((), {'user_input': '如何理解RAG?', 'final_answer': AIMessage(content='RAG(Retrieval-Augmented Generation)是一种结合了检索和生成模型的技术,旨在提高自然语言处理任务的准确性和相关性。在传统的生成式模型中,如基于Transformer的语言模型(例如GPT系列),模型通常是通过从大量文本数据中学习来预测或生成文本,但这些模型可能缺乏最新的信息、特定领域的知识或是对事实细节的记忆。\n\nRAG方法的核心思想是在生成过程中引入一个检索组件,该组件可以从外部数据库或者文档集合中查找相关信息。具体来说,在面对一个输入请求时,系统首先使用检索模块从大量的候选文档中找到最相关的几段文本(称为“上下文”或“证据”),然后将这些文本与原始输入一起作为条件传递给生成模型,最后由生成模型根据提供的信息生成最终答案。\n\n这样的机制有几个明显的优势:\n1. **增强相关性**:通过检索来获取特定于问题的相关背景资料,可以显著提高回答的准确性和针对性。\n2. **保持更新**:由于可以从最新的数据源中检索信息,RAG系统能够提供更加及时和准确的答案。\n3. **节省计算资源**:相比于直接训练一个包含所有可能知识的大模型,使用现有知识库进行检索并结合生成模型的方法在效率上更有优势。\n\n总之,RAG是一种将传统检索技术和现代深度学习技术相结合的创新方法,它使得机器能够更好地理解和回应人类的需求。', additional_kwargs={}, response_metadata={'model': 'qwen2.5:72b', 'created_at': '2024-11-15T08:57:27.553914678Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 27792811420, 'load_duration': 65937389, 'prompt_eval_count': 34, 'prompt_eval_duration': 86000000, 'eval_count': 294, 'eval_duration': 27620000000}, id='run-2e783027-2927-49ca-b34f-c69c6e56f495-0', usage_metadata={'input_tokens': 34, 'output_tokens': 294, 'total_tokens': 328})})
(('node_2:85cb8695-6705-749a-be86-8cd1aafca032',), {'final_answer': AIMessage(content='RAG(Retrieval-Augmented Generation)是一种结合了检索和生成模型的技术,旨在提高自然语言处理任务的准确性和相关性。在传统的生成式模型中,如基于Transformer的语言模型(例如GPT系列),模型通常是通过从大量文本数据中学习来预测或生成文本,但这些模型可能缺乏最新的信息、特定领域的知识或是对事实细节的记忆。\n\nRAG方法的核心思想是在生成过程中引入一个检索组件,该组件可以从外部数据库或者文档集合中查找相关信息。具体来说,在面对一个输入请求时,系统首先使用检索模块从大量的候选文档中找到最相关的几段文本(称为“上下文”或“证据”),然后将这些文本与原始输入一起作为条件传递给生成模型,最后由生成模型根据提供的信息生成最终答案。\n\n这样的机制有几个明显的优势:\n1. **增强相关性**:通过检索来获取特定于问题的相关背景资料,可以显著提高回答的准确性和针对性。\n2. **保持更新**:由于可以从最新的数据源中检索信息,RAG系统能够提供更加及时和准确的答案。\n3. **节省计算资源**:相比于直接训练一个包含所有可能知识的大模型,使用现有知识库进行检索并结合生成模型的方法在效率上更有优势。\n\n总之,RAG是一种将传统检索技术和现代深度学习技术相结合的创新方法,它使得机器能够更好地理解和回应人类的需求。', additional_kwargs={}, response_metadata={'model': 'qwen2.5:72b', 'created_at': '2024-11-15T08:57:27.553914678Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 27792811420, 'load_duration': 65937389, 'prompt_eval_count': 34, 'prompt_eval_duration': 86000000, 'eval_count': 294, 'eval_duration': 27620000000}, id='run-2e783027-2927-49ca-b34f-c69c6e56f495-0', usage_metadata={'input_tokens': 34, 'output_tokens': 294, 'total_tokens': 328})})
(('node_2:85cb8695-6705-749a-be86-8cd1aafca032',), {'final_answer': AIMessage(content='RAG(Retrieval-Augmented Generation)是一种结合了检索和生成模型的技术,旨在提高自然语言处理任务的准确性和相关性。在传统的生成式模型中,如基于Transformer的语言模型(例如GPT系列),模型通常是通过从大量文本数据中学习来预测或生成文本,但这些模型可能缺乏最新的信息、特定领域的知识或是对事实细节的记忆。\n\nRAG方法的核心思想是在生成过程中引入一个检索组件,该组件可以从外部数据库或者文档集合中查找相关信息。具体来说,在面对一个输入请求时,系统首先使用检索模块从大量的候选文档中找到最相关的几段文本(称为“上下文”或“证据”),然后将这些文本与原始输入一起作为条件传递给生成模型,最后由生成模型根据提供的信息生成最终答案。\n\n这样的机制有几个明显的优势:\n1. **增强相关性**:通过检索来获取特定于问题的相关背景资料,可以显著提高回答的准确性和针对性。\n2. **保持更新**:由于可以从最新的数据源中检索信息,RAG系统能够提供更加及时和准确的答案。\n3. **节省计算资源**:相比于直接训练一个包含所有可能知识的大模型,使用现有知识库进行检索并结合生成模型的方法在效率上更有优势。\n\n总之,RAG是一种将传统检索技术和现代深度学习技术相结合的创新方法,它使得机器能够更好地理解和回应人类的需求。', additional_kwargs={}, response_metadata={'model': 'qwen2.5:72b', 'created_at': '2024-11-15T08:57:27.553914678Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 27792811420, 'load_duration': 65937389, 'prompt_eval_count': 34, 'prompt_eval_duration': 86000000, 'eval_count': 294, 'eval_duration': 27620000000}, id='run-2e783027-2927-49ca-b34f-c69c6e56f495-0', usage_metadata={'input_tokens': 34, 'output_tokens': 294, 'total_tokens': 328}), 'summary_answer': AIMessage(content='RAG结合了检索和生成模型,通过从外部数据库查找相关信息来增强文本生成的准确性和相关性,特别适合需要最新信息或特定领域知识的任务。', additional_kwargs={}, response_metadata={'model': 'qwen2.5:72b', 'created_at': '2024-11-15T08:57:31.639350874Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 4068289804, 'load_duration': 69716776, 'prompt_eval_count': 319, 'prompt_eval_duration': 94000000, 'eval_count': 37, 'eval_duration': 3876000000}, id='run-6f38f9dc-b683-48d2-bb32-48939c5a0828-0', usage_metadata={'input_tokens': 319, 'output_tokens': 37, 'total_tokens': 356})})
(('node_2:85cb8695-6705-749a-be86-8cd1aafca032',), {'final_answer': '8', 'summary_answer': AIMessage(content='RAG结合了检索和生成模型,通过从外部数据库查找相关信息来增强文本生成的准确性和相关性,特别适合需要最新信息或特定领域知识的任务。', additional_kwargs={}, response_metadata={'model': 'qwen2.5:72b', 'created_at': '2024-11-15T08:57:31.639350874Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 4068289804, 'load_duration': 69716776, 'prompt_eval_count': 319, 'prompt_eval_duration': 94000000, 'eval_count': 37, 'eval_duration': 3876000000}, id='run-6f38f9dc-b683-48d2-bb32-48939c5a0828-0', usage_metadata={'input_tokens': 319, 'output_tokens': 37, 'total_tokens': 356})})
((), {'user_input': '如何理解RAG?', 'final_answer': '8'})
这个案例实现的工作流就让父图和子图借助共享的状态键(通道)进行通信,这是非常常见的一种多代理架构的底层构建模式,这种通信模式要关注的点就是如何设计自己的工作流以通过父图的全局状态键进行各个子图(子代理)的有效交互和信息传递。
接下来我们看第二种情况:父、子图节点中定义的状态模式没有共同的键的时候,怎么做?这种情况如下图所示:
如果父图与子图是完全不同的架构,则会出现上图中无共同键可用的情况。在这种情况下如果仍然想让父图与子图之间能够以某种方式进行通信,则需要定义一个调用子图的 node 函数,其作用是:在调用子图之前将输入(父)状态转换为子图状态,并在从节点返回状态更新之前将结果转换回父状态。 我们来看下面这个案例:
1 | # import getpass |
父图的状态和节点的逻辑均布发生变化,如下所示:
1 | from typing import TypedDict |
子图中专注于处理自己内部的逻辑,无需关心父图中的状态中都定义了哪些键,如下代码所示:
1 | from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage, AIMessage |
正常定义子图并编译。
1 | subgraph_builder = StateGraph(SubgraphState) |
接下来的j这个函数是关键。**parent_node_2用来连接父图与子图之间的网络通信,它通过将父节点与子节点的状态做转化来达到此目的**。代码如下:
1 | def parent_node_2(state: ParentState): |
1 | builder = StateGraph(ParentState) |
1 | from IPython.display import Image, display |
1 | async for chunk in graph.astream({"user_input": "我现在想学习大模型,应该关注哪些技术?"}, stream_mode='values'): |
{'user_input': '我现在想学习大模型,应该关注哪些技术?'}
{'user_input': '我现在想学习大模型,应该关注哪些技术?', 'final_answer': AIMessage(content='想要深入学习大型语言模型(简称“大模型”),您需要掌握和了解多个方面的技术和知识。以下是一些关键领域的概述:\n\n1. **机器学习基础**:在开始研究大模型之前,拥有扎实的机器学习基础知识是非常重要的。这包括理解监督学习、无监督学习和强化学习等基本概念。\n\n2. **深度学习**:深入理解和实践神经网络的设计与训练是构建大型语言模型的核心。重点掌握卷积神经网络(CNNs)、循环神经网络(RNNs)及其变体如长短期记忆网络(LSTMs)和门控循环单元(GRUs),以及变压器架构(Transformers)。\n\n3. **自然语言处理(NLP)**:了解文本表示方法,例如词嵌入(Word Embeddings)、TF-IDF、GloVe等。掌握序列到序列模型(Seq2Seq models)及其在翻译、对话系统中的应用。\n\n4. **变压器架构(Transformers)**:当前大多数先进的大模型都基于变压器技术。深入学习自我注意机制(Self-Attention Mechanism)、多头注意力(Multi-head Attention)、位置编码(Positional Encoding)等核心技术。\n\n5. **大规模数据处理与优化算法**:了解如何高效地训练大型神经网络,包括但不限于批量归一化、梯度裁剪、学习率调度策略。同时,熟悉使用并行计算和分布式系统来加速模型的训练过程。\n\n6. **框架和技术工具**:熟练掌握至少一种深度学习框架,如TensorFlow, PyTorch等,并了解相关的库和工具,例如Hugging Face Transformers库,它提供了很多预训练模型的访问接口。\n\n7. **伦理与安全问题**:随着大模型的应用越来越广泛,对于模型输出的内容生成、隐私保护等方面也提出了新的挑战。学习如何构建负责任的人工智能系统也是十分必要的。\n\n8. **实践项目和论文阅读**:通过参与实际项目或竞赛来应用所学知识,并定期阅读最新的研究文献以保持对领域发展的了解。\n\n希望这些方向能帮助您更好地规划自己的学习路径!', additional_kwargs={}, response_metadata={'model': 'qwen2.5:72b', 'created_at': '2024-11-15T08:59:10.11718449Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 40626413319, 'load_duration': 63246082, 'prompt_eval_count': 40, 'prompt_eval_duration': 121000000, 'eval_count': 437, 'eval_duration': 40422000000}, id='run-51578955-0791-47ec-9929-bc78a4dd2819-0', usage_metadata={'input_tokens': 40, 'output_tokens': 437, 'total_tokens': 477})}
{'user_input': '我现在想学习大模型,应该关注哪些技术?', 'final_answer': '8'}
1 | all_chunk = [] |
1 | all_chunk[-1][1]["final_answer"] |
'8'
在上面的案例中,subgraph state 完全独立于父 graph state,即两者之间没有重叠的键(通道)是最常见的,也是灵活性最高的。其中的关键点在于:需要在调用子图之前将其输入转换为子图,然后在返回之前转换其输出,即可正常完成父、子图之间的通信。
在LangGraph中,子图的应用主要用于多代理系统的构建,而如果理解了上面两个案例中通信状态的传递方式,就基本具备了构建多代理系统的必要条件。接下来,我们就针对LangGraph框架下的不同多代理架构依次展开详细的探讨和实践。
4、基于Network(网络)的多代理架构
Single-Agent可以在单个图结构运行工具,但即使使用像 gpt-4 这样的强大模型,当工具特别多的时候也会经常出现问题。处理复杂任务的一种方法是通过 “分而治之” 的方法:为每个任务或领域创建一个专门的代理,并将任务路由到正确的 “专家”。这是多代理网络架构的一个核心思想。那对于NetWork(网络)代理来说,它的架构是:每个代理都可以与其他代理通信,且任何代理都可以决定接下来要呼叫哪个其他代理。 正如下图所示:
1 | # pip install -U langchain langchain_openai langsmith pandas langchain_experimental matplotlib langgraph langchain_core |
接下来,我们尝试用上图中的网络架构去构建多代理系统。我们选择一个商业智能(BI)用于数据分析的落地场景的案例。商业智能(BI)应用于各种行业的数据分析过程,它主要是通过将数据转换为有价值的洞察力,帮助企业做出更好的决策,比如销售和市场分析、客户关系管理(CRM)、库存管理、财务分析等等。这些场景在不同行业的具体应用可能有所差异,但核心都是通过数据分析来提高效率、降低成本、增强客户满意度和优化决策过程。
这里我们就尝试来实现一个销售和市场分析场景的简化案例。完整设计思路及构建流程如下:
- Stage 1. 定义大模型实例
我们使用 gpt-4o-mini 作为数据库管理员db_agent, 根据用户的需求操作数据库,提取出核心的数据信息。 使用最新开源的Qwen 2.5-Coder:32b模型作为数据分析师code_agent,根据db_agent传递过来的数据生成对应的代码,并在本地的Python解释器进行自动化的数据分析,并生成可视化图表。
首先来接入 gpt-4o-mini 模型,代码如下:
1 | import getpass |
测试一下 gpt-4o-mini 模型的连通性,如下:
1 | print(db_llm.invoke("你好,测试连通性。").content) |
你好!我能听到你说的话。请问有什么我可以帮助你的吗?
如果能够成功收到回复,则说明gpt-4o-mini模型服务正常。接下来,我们使用Ollama启动刚刚开源的Qwen-2.5-Coder:32模型,用来生成代码。
这里我们使用LangChain来进行接入。
1 | # ! pip install langchain-ollama |
1 | from langchain_ollama import ChatOllama |
测试一下 qwen2.5-coder:0.5b 模型的连通性,代码如下:
1 | from langchain_core.messages import AIMessage |
当然可以!下面是一个简单的贪吃蛇游戏的Python实现,使用了Pygame库。请确保你已经安装了Pygame库,如果没有安装,可以通过以下命令进行安装:
1
pip install pygame
以下是完整的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import pygame
import time
import random
# 初始化Pygame
pygame.init()
# 定义颜色
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)
# 定义游戏窗口大小
dis_width = 800
dis_height = 600
# 创建游戏窗口
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('贪吃蛇游戏')
# 定义时钟
clock = pygame.time.Clock()
# 定义蛇的大小和速度
snake_block = 10
snake_speed = 15
# 设置字体
font_style = pygame.font.SysFont(None, 50)
score_font = pygame.font.SysFont(None, 35)
def our_snake(snake_block, snake_list):
for x in snake_list:
pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])
def message(msg, color):
mesg = font_style.render(msg, True, color)
dis.blit(mesg, [dis_width / 6, dis_height / 3])
def gameLoop():
game_over = False
game_close = False
x1 = dis_width / 2
y1 = dis_height / 2
x1_change = 0
y1_change = 0
snake_List = []
Length_of_snake = 1
foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
while not game_over:
while game_close == True:
dis.fill(blue)
message("You Lost! Press Q-Quit or C-Play Again", red)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
gameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x1_change = -snake_block
y1_change = 0
elif event.key == pygame.K_RIGHT:
x1_change = snake_block
y1_change = 0
elif event.key == pygame.K_UP:
y1_change = -snake_block
x1_change = 0
elif event.key == pygame.K_DOWN:
y1_change = snake_block
x1_change = 0
if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
game_close = True
x1 += x1_change
y1 += y1_change
dis.fill(blue)
pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
snake_Head = []
snake_Head.append(x1)
snake_Head.append(y1)
snake_List.append(snake_Head)
if len(snake_List) > Length_of_snake:
del snake_List[0]
for x in snake_List[:-1]:
if x == snake_Head:
game_close = True
our_snake(snake_block, snake_List)
pygame.display.update()
if x1 == foodx and y1 == foody:
foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
Length_of_snake += 1
clock.tick(snake_speed)
pygame.quit()
quit()
gameLoop()
这段代码创建了一个简单的贪吃蛇游戏。游戏中,玩家通过键盘的方向键控制蛇的移动,吃到绿色的食物后蛇会变长。如果玩家撞到墙壁或自己的身体,游戏结束,并提示“Game Over”。玩家可以按Q退出游戏,按C重新开始游戏。
希望你喜欢这个简单的贪吃蛇游戏!如果有任何问题或需要进一步的功能,请告诉我。
- Stage 2:定义工具
这里我们为db_agent配置的能力是操作数据库权限,以下是我们即将构建的数据模型(SalesData, CustomerInformation, ProductInformation, CompetitorAnalysis)表的描述,用来构成销售和市场分析核心数据的存储。如下所示:
SalesData 表:
| 字段名 | 类型 | 描述 |
|---|---|---|
| sales_id | Integer | 销售记录的唯一标识符(主键) |
| product_id | Integer | 产品ID,与产品信息表关联(外键) |
| employee_id | Integer | 员工ID,假设已有员工表(此例未创建员工表) |
| customer_id | Integer | 客户ID,与客户信息表关联(外键) |
| sale_date | String | 销售日期 |
| quantity | Integer | 销售数量 |
| amount | Float | 销售额(总金额) |
| discount | Float | 折扣率 |
CustomerInformation 表:
| 字段名 | 类型 | 描述 |
|---|---|---|
| customer_id | Integer | 客户的唯一标识符(主键) |
| customer_name | String | 客户姓名 |
| contact_info | String | 客户联系方式 |
| region | String | 客户所在地区 |
| customer_type | String | 客户类别 |
ProductInformation 表:
| 字段名 | 类型 | 描述 |
|---|---|---|
| product_id | Integer | 产品的唯一标识符(主键) |
| product_name | String | 产品名称 |
| category | String | 产品类别 |
| unit_price | Float | 单位价格 |
| stock_level | Integer | 库存水平 |
CompetitorAnalysis 表:
| 字段名 | 类型 | 描述 |
|---|---|---|
| competitor_id | Integer | 竞争对手的唯一标识符(主键) |
| competitor_name | String | 竞争对手名称 |
| region | String | 竞争对手所在地区 |
| market_share | Float | 市场份额 |
使用如下代码进行表结构的创建:
1 | from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey |
创建完成后,可以使用可视化工具进行验证,我这里使用Navicat:
接下来,创建模拟数据。我们使用 Python 的 faker 库来生成模拟数据,并构建插入数据的代码。(faker 是一个 Python 库,用于创建假数据,非常适合在开发和测试阶段填充数据库。)
1 | # ! pip install faker |
1 | # 插入模拟数据 |
执行结束后,可以进行数据验证,如下所示:
准备好数据以后,接下来给db_agent配置工具用来执行数据的增删改查操作,具体如下:
1 | from pydantic import BaseModel, Field |
然后,第二个数据分析师(code_agent)在需要的时候,接收db_agent的数据,生成可视化的图表,这里我们给他配置一个本地的Python代码解释器。这里我们使用Python REPL 工具,它是LangChian封装的一个工具,作用是先让大模型生成代码,然后再运行该代码来获取答案,且仅返回打印的内容。使用的方式非常简单,代码如下:
1 | from typing import Annotated |
定义工具列表,并使用ToolNode进行构建。
1 | from langgraph.prebuilt import ToolNode |
- Stage 3. 创建代理
要通过图状态进行通信,需要将单个代理定义为图节点,在图执行的每个步骤中,代理节点接收图的当前状态,执行代理代码,然后将更新的状态传递给下一个节点。代理节点是共享单个状态架构的。这里我们定义一个辅助函数create_agent,用来帮助我们创建多代理系统中的每一个子代理。每个子代理可以通过llm参数定义其使用的大模型,system_message用于定义其每个代理独有的背景信息,而tools则可以给不同的子代理绑定特有的工具。具体函数代码如下:
1 | from langchain_core.messages import BaseMessage, HumanMessage, ToolMessage |
对应的中文Prompt 解释:
1 | prompt = """ |
然后,我们根据create_agent辅助函数依次去创建db_agent和code_agent两个代理,分别赋予它们不同的身份设定、基座模型和所能使用的工具。
1 | # 数据库管理员 |
1 | db_agent |
ChatPromptTemplate(input_variables=['messages'], input_types={'messages': list[typing.Annotated[typing.Union[typing.Annotated[langchain_core.messages.ai.AIMessage, Tag(tag='ai')], typing.Annotated[langchain_core.messages.human.HumanMessage, Tag(tag='human')], typing.Annotated[langchain_core.messages.chat.ChatMessage, Tag(tag='chat')], typing.Annotated[langchain_core.messages.system.SystemMessage, Tag(tag='system')], typing.Annotated[langchain_core.messages.function.FunctionMessage, Tag(tag='function')], typing.Annotated[langchain_core.messages.tool.ToolMessage, Tag(tag='tool')], typing.Annotated[langchain_core.messages.ai.AIMessageChunk, Tag(tag='AIMessageChunk')], typing.Annotated[langchain_core.messages.human.HumanMessageChunk, Tag(tag='HumanMessageChunk')], typing.Annotated[langchain_core.messages.chat.ChatMessageChunk, Tag(tag='ChatMessageChunk')], typing.Annotated[langchain_core.messages.system.SystemMessageChunk, Tag(tag='SystemMessageChunk')], typing.Annotated[langchain_core.messages.function.FunctionMessageChunk, Tag(tag='FunctionMessageChunk')], typing.Annotated[langchain_core.messages.tool.ToolMessageChunk, Tag(tag='ToolMessageChunk')]], FieldInfo(annotation=NoneType, required=True, discriminator=Discriminator(discriminator=<function _get_type at 0x000002009215E520>, custom_error_type=None, custom_error_message=None, custom_error_context=None))]]}, partial_variables={'system_message': "You should provide accurate data for the code_generator to use. and source code shouldn't be the final answer", 'tool_names': 'add_sale, delete_sale, update_sale, query_sales'}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=['system_message', 'tool_names'], input_types={}, partial_variables={}, template="You are a helpful AI assistant, collaborating with other assistants. Use the provided tools to progress towards answering the question. If you are unable to fully answer, that's OK, another assistant with different tools will help where you left off. Execute what you can to make progress. If you or any of the other assistants have the final answer or deliverable, prefix your response with FINAL ANSWER so the team knows to stop. You have access to the following tools: {tool_names}.\n{system_message}"), additional_kwargs={}), MessagesPlaceholder(variable_name='messages')])
| RunnableBinding(bound=ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x00000200B01722D0>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x00000200B0171BD0>, root_client=<openai.OpenAI object at 0x00000200ADEAAE90>, root_async_client=<openai.AsyncOpenAI object at 0x00000200ADEAAFD0>, model_name='gpt-4o-mini', model_kwargs={}, openai_api_key=SecretStr('**********')), kwargs={'tools': [{'type': 'function', 'function': {'name': 'add_sale', 'description': 'Add sale record to the database.', 'parameters': {'properties': {'product_id': {'type': 'integer'}, 'employee_id': {'type': 'integer'}, 'customer_id': {'type': 'integer'}, 'sale_date': {'type': 'string'}, 'quantity': {'type': 'integer'}, 'amount': {'type': 'number'}, 'discount': {'type': 'number'}}, 'required': ['product_id', 'employee_id', 'customer_id', 'sale_date', 'quantity', 'amount', 'discount'], 'type': 'object'}}}, {'type': 'function', 'function': {'name': 'delete_sale', 'description': 'Delete sale record from the database.', 'parameters': {'properties': {'sales_id': {'type': 'integer'}}, 'required': ['sales_id'], 'type': 'object'}}}, {'type': 'function', 'function': {'name': 'update_sale', 'description': 'Update sale record in the database.', 'parameters': {'properties': {'sales_id': {'type': 'integer'}, 'quantity': {'type': 'integer'}, 'amount': {'type': 'number'}}, 'required': ['sales_id', 'quantity', 'amount'], 'type': 'object'}}}, {'type': 'function', 'function': {'name': 'query_sales', 'description': 'Query sale record from the database.', 'parameters': {'properties': {'sales_id': {'type': 'integer'}}, 'required': ['sales_id'], 'type': 'object'}}}]}, config={}, config_factories=[])
接下来,将Agent去定义成节点。如下代码所示:
1 | import functools |
1 | db_node |
functools.partial(<function agent_node at 0x00000200ADEFDE40>, agent=ChatPromptTemplate(input_variables=['messages'], input_types={'messages': list[typing.Annotated[typing.Union[typing.Annotated[langchain_core.messages.ai.AIMessage, Tag(tag='ai')], typing.Annotated[langchain_core.messages.human.HumanMessage, Tag(tag='human')], typing.Annotated[langchain_core.messages.chat.ChatMessage, Tag(tag='chat')], typing.Annotated[langchain_core.messages.system.SystemMessage, Tag(tag='system')], typing.Annotated[langchain_core.messages.function.FunctionMessage, Tag(tag='function')], typing.Annotated[langchain_core.messages.tool.ToolMessage, Tag(tag='tool')], typing.Annotated[langchain_core.messages.ai.AIMessageChunk, Tag(tag='AIMessageChunk')], typing.Annotated[langchain_core.messages.human.HumanMessageChunk, Tag(tag='HumanMessageChunk')], typing.Annotated[langchain_core.messages.chat.ChatMessageChunk, Tag(tag='ChatMessageChunk')], typing.Annotated[langchain_core.messages.system.SystemMessageChunk, Tag(tag='SystemMessageChunk')], typing.Annotated[langchain_core.messages.function.FunctionMessageChunk, Tag(tag='FunctionMessageChunk')], typing.Annotated[langchain_core.messages.tool.ToolMessageChunk, Tag(tag='ToolMessageChunk')]], FieldInfo(annotation=NoneType, required=True, discriminator=Discriminator(discriminator=<function _get_type at 0x000002009215E520>, custom_error_type=None, custom_error_message=None, custom_error_context=None))]]}, partial_variables={'system_message': "You should provide accurate data for the code_generator to use. and source code shouldn't be the final answer", 'tool_names': 'add_sale, delete_sale, update_sale, query_sales'}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=['system_message', 'tool_names'], input_types={}, partial_variables={}, template="You are a helpful AI assistant, collaborating with other assistants. Use the provided tools to progress towards answering the question. If you are unable to fully answer, that's OK, another assistant with different tools will help where you left off. Execute what you can to make progress. If you or any of the other assistants have the final answer or deliverable, prefix your response with FINAL ANSWER so the team knows to stop. You have access to the following tools: {tool_names}.\n{system_message}"), additional_kwargs={}), MessagesPlaceholder(variable_name='messages')])
| RunnableBinding(bound=ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x00000200B01722D0>, async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x00000200B0171BD0>, root_client=<openai.OpenAI object at 0x00000200ADEAAE90>, root_async_client=<openai.AsyncOpenAI object at 0x00000200ADEAAFD0>, model_name='gpt-4o-mini', model_kwargs={}, openai_api_key=SecretStr('**********')), kwargs={'tools': [{'type': 'function', 'function': {'name': 'add_sale', 'description': 'Add sale record to the database.', 'parameters': {'properties': {'product_id': {'type': 'integer'}, 'employee_id': {'type': 'integer'}, 'customer_id': {'type': 'integer'}, 'sale_date': {'type': 'string'}, 'quantity': {'type': 'integer'}, 'amount': {'type': 'number'}, 'discount': {'type': 'number'}}, 'required': ['product_id', 'employee_id', 'customer_id', 'sale_date', 'quantity', 'amount', 'discount'], 'type': 'object'}}}, {'type': 'function', 'function': {'name': 'delete_sale', 'description': 'Delete sale record from the database.', 'parameters': {'properties': {'sales_id': {'type': 'integer'}}, 'required': ['sales_id'], 'type': 'object'}}}, {'type': 'function', 'function': {'name': 'update_sale', 'description': 'Update sale record in the database.', 'parameters': {'properties': {'sales_id': {'type': 'integer'}, 'quantity': {'type': 'integer'}, 'amount': {'type': 'number'}}, 'required': ['sales_id', 'quantity', 'amount'], 'type': 'object'}}}, {'type': 'function', 'function': {'name': 'query_sales', 'description': 'Query sale record from the database.', 'parameters': {'properties': {'sales_id': {'type': 'integer'}}, 'required': ['sales_id'], 'type': 'object'}}}]}, config={}, config_factories=[]), name='db_manager')
- Stage 4. 定义路由
在多代理系统中,路由器的功能是根据从代理收到的消息确定接下来要执行的流程,用于路由调用工具、结束流程或继续下一步,具体取决于消息的内容和代理做出的决策。如下所示的router 函数,将图的当前状态作为输入,从状态中提取消息,重点关注列表中的最后一条消息。如果最后一条消息的附加参数中包含 tool_calls,则表示前一个代理调用了工具。在这种情况下,路由器决定继续执行图形中的 call_tool 节点。如果最后一条消息的内容包括 FINAL ANSWER,则表示所有代理都已决定完成工作。在这种情况下,路由器将工作流定向到终端节点,指示进程的终止。如果上述条件均未满足,则路由器将返回 continue,指示工作流应继续执行图中的下一步。
1 | # 任何一个代理都可以决定结束 |
- Stage 5. 定义状态和图
在初始化 StateGraph 对象之前,我们首先定义 AgentState。AgentState定义在图中的节点之间传递的对象的结构。在这里,它包括消息列表和要执行任务的代理名称(sender)。代码如下:
1 | import operator |
- Stage 5. 构建图结构
一切准备就绪后,我们在在下面的代码中构建管理多智能体工作流的流程。通过网络代理的多代理架构,它是每一个代理之间都可以构建互相的连接关系,所以我们就需要在定义图结构的时候,将需要进行通行的代理通过条件边来互相建立联系。
1 | from langgraph.graph import END, StateGraph |
- Stage 6. 可视化图结构
1 | from IPython.display import Image, display |
- Stage 6. 调用测试
完成图表的编译后,我们就可以进行功能测试了。
1 | for chunk in graph.stream( |
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={})]}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN')], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'function': {'arguments': '{"sales_id": 2}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'function': {'arguments': '{"sales_id": 3}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'function': {'arguments': '{"sales_id": 4}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'function': {'arguments': '{"sales_id": 5}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 380, 'total_tokens': 456, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-f9974e83-6e55-442d-9adb-51ebf7a6ec43-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 2}, 'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 3}, 'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 4}, 'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 5}, 'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 380, 'output_tokens': 76, 'total_tokens': 456, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'function': {'arguments': '{"sales_id": 2}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'function': {'arguments': '{"sales_id": 3}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'function': {'arguments': '{"sales_id": 4}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'function': {'arguments': '{"sales_id": 5}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 380, 'total_tokens': 456, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-f9974e83-6e55-442d-9adb-51ebf7a6ec43-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 2}, 'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 3}, 'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 4}, 'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 5}, 'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 380, 'output_tokens': 76, 'total_tokens': 456, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 2, "product_id": 13, "employee_id": 5, "customer_id": 2, "sale_date": "2023-11-16", "quantity": 8, "amount": 2315.86, "discount": 0.0620275}', name='query_sales', tool_call_id='call_5YrNGeiscbbgVFo7SrVNXH1f'), ToolMessage(content='{"sales_id": 3, "product_id": 12, "employee_id": 10, "customer_id": 17, "sale_date": "2024-09-14", "quantity": 7, "amount": 808.775, "discount": 0.0783529}', name='query_sales', tool_call_id='call_4WuNHVDKcsRkd6Z1NSEZIXyi'), ToolMessage(content='{"sales_id": 4, "product_id": 9, "employee_id": 7, "customer_id": 11, "sale_date": "2024-08-01", "quantity": 1, "amount": 3248.92, "discount": 0.00331112}', name='query_sales', tool_call_id='call_fKuNAUgGYzaVY8sdcl89Wyeg'), ToolMessage(content='{"sales_id": 5, "product_id": 11, "employee_id": 8, "customer_id": 8, "sale_date": "2024-11-08", "quantity": 9, "amount": 4020.69, "discount": 0.119492}', name='query_sales', tool_call_id='call_lKJRJougLHCgiWvyRQAxrGUb')], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'function': {'arguments': '{"sales_id": 2}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'function': {'arguments': '{"sales_id": 3}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'function': {'arguments': '{"sales_id": 4}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'function': {'arguments': '{"sales_id": 5}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 380, 'total_tokens': 456, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-f9974e83-6e55-442d-9adb-51ebf7a6ec43-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 2}, 'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 3}, 'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 4}, 'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 5}, 'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 380, 'output_tokens': 76, 'total_tokens': 456, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 2, "product_id": 13, "employee_id": 5, "customer_id": 2, "sale_date": "2023-11-16", "quantity": 8, "amount": 2315.86, "discount": 0.0620275}', name='query_sales', tool_call_id='call_5YrNGeiscbbgVFo7SrVNXH1f'), ToolMessage(content='{"sales_id": 3, "product_id": 12, "employee_id": 10, "customer_id": 17, "sale_date": "2024-09-14", "quantity": 7, "amount": 808.775, "discount": 0.0783529}', name='query_sales', tool_call_id='call_4WuNHVDKcsRkd6Z1NSEZIXyi'), ToolMessage(content='{"sales_id": 4, "product_id": 9, "employee_id": 7, "customer_id": 11, "sale_date": "2024-08-01", "quantity": 1, "amount": 3248.92, "discount": 0.00331112}', name='query_sales', tool_call_id='call_fKuNAUgGYzaVY8sdcl89Wyeg'), ToolMessage(content='{"sales_id": 5, "product_id": 11, "employee_id": 8, "customer_id": 8, "sale_date": "2024-11-08", "quantity": 9, "amount": 4020.69, "discount": 0.119492}', name='query_sales', tool_call_id='call_lKJRJougLHCgiWvyRQAxrGUb'), AIMessage(content='我已经获得了前5名销售的销售记录。以下是每个销售的销售总额:\n\n1. Sales ID 1: Amount = 1193.36\n2. Sales ID 2: Amount = 2315.86\n3. Sales ID 3: Amount = 808.775\n4. Sales ID 4: Amount = 3248.92\n5. Sales ID 5: Amount = 4020.69\n\n接下来,我将计算这些销售的总额,并准备数据以生成折线图。 \n\n总额计算如下:\n- 1193.36 + 2315.86 + 808.775 + 3248.92 + 4020.69 = 11687.625\n\n现在,我将准备数据以生成折线图。以下是数据点:\n\n- Sales ID 1: 1193.36\n- Sales ID 2: 2315.86\n- Sales ID 3: 808.775\n- Sales ID 4: 3248.92\n- Sales ID 5: 4020.69\n\n请使用这些数据生成折线图。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 242, 'prompt_tokens': 728, 'total_tokens': 970, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-6933dec1-2efc-43d8-9493-8c502e362f2c-0', usage_metadata={'input_tokens': 728, 'output_tokens': 242, 'total_tokens': 970, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'function': {'arguments': '{"sales_id": 2}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'function': {'arguments': '{"sales_id": 3}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'function': {'arguments': '{"sales_id": 4}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'function': {'arguments': '{"sales_id": 5}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 380, 'total_tokens': 456, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-f9974e83-6e55-442d-9adb-51ebf7a6ec43-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 2}, 'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 3}, 'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 4}, 'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 5}, 'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 380, 'output_tokens': 76, 'total_tokens': 456, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 2, "product_id": 13, "employee_id": 5, "customer_id": 2, "sale_date": "2023-11-16", "quantity": 8, "amount": 2315.86, "discount": 0.0620275}', name='query_sales', tool_call_id='call_5YrNGeiscbbgVFo7SrVNXH1f'), ToolMessage(content='{"sales_id": 3, "product_id": 12, "employee_id": 10, "customer_id": 17, "sale_date": "2024-09-14", "quantity": 7, "amount": 808.775, "discount": 0.0783529}', name='query_sales', tool_call_id='call_4WuNHVDKcsRkd6Z1NSEZIXyi'), ToolMessage(content='{"sales_id": 4, "product_id": 9, "employee_id": 7, "customer_id": 11, "sale_date": "2024-08-01", "quantity": 1, "amount": 3248.92, "discount": 0.00331112}', name='query_sales', tool_call_id='call_fKuNAUgGYzaVY8sdcl89Wyeg'), ToolMessage(content='{"sales_id": 5, "product_id": 11, "employee_id": 8, "customer_id": 8, "sale_date": "2024-11-08", "quantity": 9, "amount": 4020.69, "discount": 0.119492}', name='query_sales', tool_call_id='call_lKJRJougLHCgiWvyRQAxrGUb'), AIMessage(content='我已经获得了前5名销售的销售记录。以下是每个销售的销售总额:\n\n1. Sales ID 1: Amount = 1193.36\n2. Sales ID 2: Amount = 2315.86\n3. Sales ID 3: Amount = 808.775\n4. Sales ID 4: Amount = 3248.92\n5. Sales ID 5: Amount = 4020.69\n\n接下来,我将计算这些销售的总额,并准备数据以生成折线图。 \n\n总额计算如下:\n- 1193.36 + 2315.86 + 808.775 + 3248.92 + 4020.69 = 11687.625\n\n现在,我将准备数据以生成折线图。以下是数据点:\n\n- Sales ID 1: 1193.36\n- Sales ID 2: 2315.86\n- Sales ID 3: 808.775\n- Sales ID 4: 3248.92\n- Sales ID 5: 4020.69\n\n请使用这些数据生成折线图。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 242, 'prompt_tokens': 728, 'total_tokens': 970, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-6933dec1-2efc-43d8-9493-8c502e362f2c-0', usage_metadata={'input_tokens': 728, 'output_tokens': 242, 'total_tokens': 970, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), AIMessage(content="以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>", additional_kwargs={}, response_metadata={'model': 'qwen2.5-coder:32b', 'created_at': '2024-11-15T09:20:24.33453634Z', 'message': {'role': 'assistant', 'content': "以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>"}, 'done_reason': 'stop', 'done': True, 'total_duration': 9535302748, 'load_duration': 91459758, 'prompt_eval_count': 1100, 'prompt_eval_duration': 1118000000, 'eval_count': 165, 'eval_duration': 8112000000}, name='code_generator', id='run-82746b12-8518-4ecb-b644-1eac2a6fd81b-0', usage_metadata={'input_tokens': 1100, 'output_tokens': 165, 'total_tokens': 1265})], 'sender': 'code_generator'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'function': {'arguments': '{"sales_id": 2}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'function': {'arguments': '{"sales_id": 3}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'function': {'arguments': '{"sales_id": 4}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'function': {'arguments': '{"sales_id": 5}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 380, 'total_tokens': 456, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-f9974e83-6e55-442d-9adb-51ebf7a6ec43-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 2}, 'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 3}, 'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 4}, 'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 5}, 'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 380, 'output_tokens': 76, 'total_tokens': 456, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 2, "product_id": 13, "employee_id": 5, "customer_id": 2, "sale_date": "2023-11-16", "quantity": 8, "amount": 2315.86, "discount": 0.0620275}', name='query_sales', tool_call_id='call_5YrNGeiscbbgVFo7SrVNXH1f'), ToolMessage(content='{"sales_id": 3, "product_id": 12, "employee_id": 10, "customer_id": 17, "sale_date": "2024-09-14", "quantity": 7, "amount": 808.775, "discount": 0.0783529}', name='query_sales', tool_call_id='call_4WuNHVDKcsRkd6Z1NSEZIXyi'), ToolMessage(content='{"sales_id": 4, "product_id": 9, "employee_id": 7, "customer_id": 11, "sale_date": "2024-08-01", "quantity": 1, "amount": 3248.92, "discount": 0.00331112}', name='query_sales', tool_call_id='call_fKuNAUgGYzaVY8sdcl89Wyeg'), ToolMessage(content='{"sales_id": 5, "product_id": 11, "employee_id": 8, "customer_id": 8, "sale_date": "2024-11-08", "quantity": 9, "amount": 4020.69, "discount": 0.119492}', name='query_sales', tool_call_id='call_lKJRJougLHCgiWvyRQAxrGUb'), AIMessage(content='我已经获得了前5名销售的销售记录。以下是每个销售的销售总额:\n\n1. Sales ID 1: Amount = 1193.36\n2. Sales ID 2: Amount = 2315.86\n3. Sales ID 3: Amount = 808.775\n4. Sales ID 4: Amount = 3248.92\n5. Sales ID 5: Amount = 4020.69\n\n接下来,我将计算这些销售的总额,并准备数据以生成折线图。 \n\n总额计算如下:\n- 1193.36 + 2315.86 + 808.775 + 3248.92 + 4020.69 = 11687.625\n\n现在,我将准备数据以生成折线图。以下是数据点:\n\n- Sales ID 1: 1193.36\n- Sales ID 2: 2315.86\n- Sales ID 3: 808.775\n- Sales ID 4: 3248.92\n- Sales ID 5: 4020.69\n\n请使用这些数据生成折线图。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 242, 'prompt_tokens': 728, 'total_tokens': 970, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-6933dec1-2efc-43d8-9493-8c502e362f2c-0', usage_metadata={'input_tokens': 728, 'output_tokens': 242, 'total_tokens': 970, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), AIMessage(content="以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>", additional_kwargs={}, response_metadata={'model': 'qwen2.5-coder:32b', 'created_at': '2024-11-15T09:20:24.33453634Z', 'message': {'role': 'assistant', 'content': "以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>"}, 'done_reason': 'stop', 'done': True, 'total_duration': 9535302748, 'load_duration': 91459758, 'prompt_eval_count': 1100, 'prompt_eval_duration': 1118000000, 'eval_count': 165, 'eval_duration': 8112000000}, name='code_generator', id='run-82746b12-8518-4ecb-b644-1eac2a6fd81b-0', usage_metadata={'input_tokens': 1100, 'output_tokens': 165, 'total_tokens': 1265}), AIMessage(content="由于我无法执行图形绘制代码,我将提供代码供您在本地环境中运行。您可以复制并粘贴到您的Python环境中,确保您已经安装了`matplotlib`库。\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n请运行此代码以生成折线图。如果您需要进一步的帮助,请告诉我!", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 196, 'prompt_tokens': 1137, 'total_tokens': 1333, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-dc8232a2-6340-4c3c-9931-eb415c1eb278-0', usage_metadata={'input_tokens': 1137, 'output_tokens': 196, 'total_tokens': 1333, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'function': {'arguments': '{"sales_id": 2}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'function': {'arguments': '{"sales_id": 3}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'function': {'arguments': '{"sales_id": 4}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'function': {'arguments': '{"sales_id": 5}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 380, 'total_tokens': 456, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-f9974e83-6e55-442d-9adb-51ebf7a6ec43-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 2}, 'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 3}, 'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 4}, 'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 5}, 'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 380, 'output_tokens': 76, 'total_tokens': 456, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 2, "product_id": 13, "employee_id": 5, "customer_id": 2, "sale_date": "2023-11-16", "quantity": 8, "amount": 2315.86, "discount": 0.0620275}', name='query_sales', tool_call_id='call_5YrNGeiscbbgVFo7SrVNXH1f'), ToolMessage(content='{"sales_id": 3, "product_id": 12, "employee_id": 10, "customer_id": 17, "sale_date": "2024-09-14", "quantity": 7, "amount": 808.775, "discount": 0.0783529}', name='query_sales', tool_call_id='call_4WuNHVDKcsRkd6Z1NSEZIXyi'), ToolMessage(content='{"sales_id": 4, "product_id": 9, "employee_id": 7, "customer_id": 11, "sale_date": "2024-08-01", "quantity": 1, "amount": 3248.92, "discount": 0.00331112}', name='query_sales', tool_call_id='call_fKuNAUgGYzaVY8sdcl89Wyeg'), ToolMessage(content='{"sales_id": 5, "product_id": 11, "employee_id": 8, "customer_id": 8, "sale_date": "2024-11-08", "quantity": 9, "amount": 4020.69, "discount": 0.119492}', name='query_sales', tool_call_id='call_lKJRJougLHCgiWvyRQAxrGUb'), AIMessage(content='我已经获得了前5名销售的销售记录。以下是每个销售的销售总额:\n\n1. Sales ID 1: Amount = 1193.36\n2. Sales ID 2: Amount = 2315.86\n3. Sales ID 3: Amount = 808.775\n4. Sales ID 4: Amount = 3248.92\n5. Sales ID 5: Amount = 4020.69\n\n接下来,我将计算这些销售的总额,并准备数据以生成折线图。 \n\n总额计算如下:\n- 1193.36 + 2315.86 + 808.775 + 3248.92 + 4020.69 = 11687.625\n\n现在,我将准备数据以生成折线图。以下是数据点:\n\n- Sales ID 1: 1193.36\n- Sales ID 2: 2315.86\n- Sales ID 3: 808.775\n- Sales ID 4: 3248.92\n- Sales ID 5: 4020.69\n\n请使用这些数据生成折线图。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 242, 'prompt_tokens': 728, 'total_tokens': 970, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-6933dec1-2efc-43d8-9493-8c502e362f2c-0', usage_metadata={'input_tokens': 728, 'output_tokens': 242, 'total_tokens': 970, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), AIMessage(content="以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>", additional_kwargs={}, response_metadata={'model': 'qwen2.5-coder:32b', 'created_at': '2024-11-15T09:20:24.33453634Z', 'message': {'role': 'assistant', 'content': "以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>"}, 'done_reason': 'stop', 'done': True, 'total_duration': 9535302748, 'load_duration': 91459758, 'prompt_eval_count': 1100, 'prompt_eval_duration': 1118000000, 'eval_count': 165, 'eval_duration': 8112000000}, name='code_generator', id='run-82746b12-8518-4ecb-b644-1eac2a6fd81b-0', usage_metadata={'input_tokens': 1100, 'output_tokens': 165, 'total_tokens': 1265}), AIMessage(content="由于我无法执行图形绘制代码,我将提供代码供您在本地环境中运行。您可以复制并粘贴到您的Python环境中,确保您已经安装了`matplotlib`库。\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n请运行此代码以生成折线图。如果您需要进一步的帮助,请告诉我!", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 196, 'prompt_tokens': 1137, 'total_tokens': 1333, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-dc8232a2-6340-4c3c-9931-eb415c1eb278-0', usage_metadata={'input_tokens': 1137, 'output_tokens': 196, 'total_tokens': 1333, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), AIMessage(content='\n', additional_kwargs={}, response_metadata={'model': 'qwen2.5-coder:32b', 'created_at': '2024-11-15T09:20:29.497282633Z', 'message': {'role': 'assistant', 'content': '\n'}, 'done_reason': 'stop', 'done': True, 'total_duration': 890283741, 'load_duration': 69585538, 'prompt_eval_count': 1467, 'prompt_eval_duration': 348000000, 'eval_count': 2, 'eval_duration': 203000000}, name='code_generator', id='run-7b5eae2b-af25-4262-86a2-72fb2b41efb5-0', usage_metadata={'input_tokens': 1467, 'output_tokens': 2, 'total_tokens': 1469})], 'sender': 'code_generator'}
{'messages': [HumanMessage(content='根据sales_id使用折线图显示前5名销售的销售总额', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'function': {'arguments': '{"sales_id":1}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 289, 'total_tokens': 304, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-1f0240b2-685f-4a98-8560-ab3af10d6ff8-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 1}, 'id': 'call_6bAhCyRVEjGzzhwX9zNWstwN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 289, 'output_tokens': 15, 'total_tokens': 304, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}', name='query_sales', tool_call_id='call_6bAhCyRVEjGzzhwX9zNWstwN'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'function': {'arguments': '{"sales_id": 2}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'function': {'arguments': '{"sales_id": 3}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'function': {'arguments': '{"sales_id": 4}', 'name': 'query_sales'}, 'type': 'function'}, {'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'function': {'arguments': '{"sales_id": 5}', 'name': 'query_sales'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 380, 'total_tokens': 456, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-f9974e83-6e55-442d-9adb-51ebf7a6ec43-0', tool_calls=[{'name': 'query_sales', 'args': {'sales_id': 2}, 'id': 'call_5YrNGeiscbbgVFo7SrVNXH1f', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 3}, 'id': 'call_4WuNHVDKcsRkd6Z1NSEZIXyi', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 4}, 'id': 'call_fKuNAUgGYzaVY8sdcl89Wyeg', 'type': 'tool_call'}, {'name': 'query_sales', 'args': {'sales_id': 5}, 'id': 'call_lKJRJougLHCgiWvyRQAxrGUb', 'type': 'tool_call'}], usage_metadata={'input_tokens': 380, 'output_tokens': 76, 'total_tokens': 456, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"sales_id": 2, "product_id": 13, "employee_id": 5, "customer_id": 2, "sale_date": "2023-11-16", "quantity": 8, "amount": 2315.86, "discount": 0.0620275}', name='query_sales', tool_call_id='call_5YrNGeiscbbgVFo7SrVNXH1f'), ToolMessage(content='{"sales_id": 3, "product_id": 12, "employee_id": 10, "customer_id": 17, "sale_date": "2024-09-14", "quantity": 7, "amount": 808.775, "discount": 0.0783529}', name='query_sales', tool_call_id='call_4WuNHVDKcsRkd6Z1NSEZIXyi'), ToolMessage(content='{"sales_id": 4, "product_id": 9, "employee_id": 7, "customer_id": 11, "sale_date": "2024-08-01", "quantity": 1, "amount": 3248.92, "discount": 0.00331112}', name='query_sales', tool_call_id='call_fKuNAUgGYzaVY8sdcl89Wyeg'), ToolMessage(content='{"sales_id": 5, "product_id": 11, "employee_id": 8, "customer_id": 8, "sale_date": "2024-11-08", "quantity": 9, "amount": 4020.69, "discount": 0.119492}', name='query_sales', tool_call_id='call_lKJRJougLHCgiWvyRQAxrGUb'), AIMessage(content='我已经获得了前5名销售的销售记录。以下是每个销售的销售总额:\n\n1. Sales ID 1: Amount = 1193.36\n2. Sales ID 2: Amount = 2315.86\n3. Sales ID 3: Amount = 808.775\n4. Sales ID 4: Amount = 3248.92\n5. Sales ID 5: Amount = 4020.69\n\n接下来,我将计算这些销售的总额,并准备数据以生成折线图。 \n\n总额计算如下:\n- 1193.36 + 2315.86 + 808.775 + 3248.92 + 4020.69 = 11687.625\n\n现在,我将准备数据以生成折线图。以下是数据点:\n\n- Sales ID 1: 1193.36\n- Sales ID 2: 2315.86\n- Sales ID 3: 808.775\n- Sales ID 4: 3248.92\n- Sales ID 5: 4020.69\n\n请使用这些数据生成折线图。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 242, 'prompt_tokens': 728, 'total_tokens': 970, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-6933dec1-2efc-43d8-9493-8c502e362f2c-0', usage_metadata={'input_tokens': 728, 'output_tokens': 242, 'total_tokens': 970, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), AIMessage(content="以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>", additional_kwargs={}, response_metadata={'model': 'qwen2.5-coder:32b', 'created_at': '2024-11-15T09:20:24.33453634Z', 'message': {'role': 'assistant', 'content': "以下是Python代码:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n现在,我将执行这段代码以生成折线图。\n<|im_start|>"}, 'done_reason': 'stop', 'done': True, 'total_duration': 9535302748, 'load_duration': 91459758, 'prompt_eval_count': 1100, 'prompt_eval_duration': 1118000000, 'eval_count': 165, 'eval_duration': 8112000000}, name='code_generator', id='run-82746b12-8518-4ecb-b644-1eac2a6fd81b-0', usage_metadata={'input_tokens': 1100, 'output_tokens': 165, 'total_tokens': 1265}), AIMessage(content="由于我无法执行图形绘制代码,我将提供代码供您在本地环境中运行。您可以复制并粘贴到您的Python环境中,确保您已经安装了`matplotlib`库。\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n请运行此代码以生成折线图。如果您需要进一步的帮助,请告诉我!", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 196, 'prompt_tokens': 1137, 'total_tokens': 1333, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-dc8232a2-6340-4c3c-9931-eb415c1eb278-0', usage_metadata={'input_tokens': 1137, 'output_tokens': 196, 'total_tokens': 1333, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), AIMessage(content='\n', additional_kwargs={}, response_metadata={'model': 'qwen2.5-coder:32b', 'created_at': '2024-11-15T09:20:29.497282633Z', 'message': {'role': 'assistant', 'content': '\n'}, 'done_reason': 'stop', 'done': True, 'total_duration': 890283741, 'load_duration': 69585538, 'prompt_eval_count': 1467, 'prompt_eval_duration': 348000000, 'eval_count': 2, 'eval_duration': 203000000}, name='code_generator', id='run-7b5eae2b-af25-4262-86a2-72fb2b41efb5-0', usage_metadata={'input_tokens': 1467, 'output_tokens': 2, 'total_tokens': 1469}), AIMessage(content="FINAL ANSWER\n以下是Python代码,用于生成显示前5名销售的销售总额的折线图:\n\n```python\nimport matplotlib.pyplot as plt\n\n# Data points\nsales_ids = [1, 2, 3, 4, 5]\namounts = [1193.36, 2315.86, 808.775, 3248.92, 4020.69]\n\n# Plotting the line chart\nplt.figure(figsize=(10, 6))\nplt.plot(sales_ids, amounts, marker='o', linestyle='-')\nplt.title('Total Sales Amount for Top 5 Sales IDs')\nplt.xlabel('Sales ID')\nplt.ylabel('Total Sales Amount')\nplt.grid(True)\nplt.show()\n```\n\n请在您的Python环境中运行此代码以查看折线图。如果您需要进一步的帮助,请告诉我!", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 180, 'prompt_tokens': 1347, 'total_tokens': 1527, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 1024}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-455a67e7-e5ac-4ba5-815c-853af3d34a27-0', usage_metadata={'input_tokens': 1347, 'output_tokens': 180, 'total_tokens': 1527, 'input_token_details': {'audio': 0, 'cache_read': 1024}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'sender': 'db_manager'}
1 | for chunk in graph.stream( |
{'messages': [HumanMessage(content='帮我删除销售id 是 20 的这名销售信息', additional_kwargs={}, response_metadata={})]}
{'messages': [HumanMessage(content='帮我删除销售id 是 20 的这名销售信息', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'function': {'arguments': '{"sales_id":20}', 'name': 'delete_sale'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 288, 'total_tokens': 303, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-dde39d3a-1633-4a9e-a6f2-8272cd7a8024-0', tool_calls=[{'name': 'delete_sale', 'args': {'sales_id': 20}, 'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'type': 'tool_call'}], usage_metadata={'input_tokens': 288, 'output_tokens': 15, 'total_tokens': 303, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='帮我删除销售id 是 20 的这名销售信息', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'function': {'arguments': '{"sales_id":20}', 'name': 'delete_sale'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 288, 'total_tokens': 303, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-dde39d3a-1633-4a9e-a6f2-8272cd7a8024-0', tool_calls=[{'name': 'delete_sale', 'args': {'sales_id': 20}, 'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'type': 'tool_call'}], usage_metadata={'input_tokens': 288, 'output_tokens': 15, 'total_tokens': 303, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"messages": ["销售记录删除成功。"]}', name='delete_sale', tool_call_id='call_ypbaeza31dC6JIfIHGWBFgIj')], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='帮我删除销售id 是 20 的这名销售信息', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'function': {'arguments': '{"sales_id":20}', 'name': 'delete_sale'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 288, 'total_tokens': 303, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-dde39d3a-1633-4a9e-a6f2-8272cd7a8024-0', tool_calls=[{'name': 'delete_sale', 'args': {'sales_id': 20}, 'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'type': 'tool_call'}], usage_metadata={'input_tokens': 288, 'output_tokens': 15, 'total_tokens': 303, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"messages": ["销售记录删除成功。"]}', name='delete_sale', tool_call_id='call_ypbaeza31dC6JIfIHGWBFgIj'), AIMessage(content='销售ID为20的销售信息已成功删除。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 325, 'total_tokens': 339, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-36b7b21a-470a-477b-94c7-834b955a9ec5-0', usage_metadata={'input_tokens': 325, 'output_tokens': 14, 'total_tokens': 339, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'sender': 'db_manager'}
{'messages': [HumanMessage(content='帮我删除销售id 是 20 的这名销售信息', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'function': {'arguments': '{"sales_id":20}', 'name': 'delete_sale'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 288, 'total_tokens': 303, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'tool_calls', 'logprobs': None}, name='db_manager', id='run-dde39d3a-1633-4a9e-a6f2-8272cd7a8024-0', tool_calls=[{'name': 'delete_sale', 'args': {'sales_id': 20}, 'id': 'call_ypbaeza31dC6JIfIHGWBFgIj', 'type': 'tool_call'}], usage_metadata={'input_tokens': 288, 'output_tokens': 15, 'total_tokens': 303, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content='{"messages": ["销售记录删除成功。"]}', name='delete_sale', tool_call_id='call_ypbaeza31dC6JIfIHGWBFgIj'), AIMessage(content='销售ID为20的销售信息已成功删除。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 325, 'total_tokens': 339, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_0ba0d124f1', 'finish_reason': 'stop', 'logprobs': None}, name='db_manager', id='run-36b7b21a-470a-477b-94c7-834b955a9ec5-0', usage_metadata={'input_tokens': 325, 'output_tokens': 14, 'total_tokens': 339, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), AIMessage(content='如果没有其他任务需要完成,我们可以结束这次操作。\n\nFINAL ANSWER: 销售ID为20的销售信息已成功删除。', additional_kwargs={}, response_metadata={'model': 'qwen2.5-coder:32b', 'created_at': '2024-11-15T09:21:04.832697148Z', 'message': {'role': 'assistant', 'content': '如果没有其他任务需要完成,我们可以结束这次操作。\n\nFINAL ANSWER: 销售ID为20的销售信息已成功删除。'}, 'done_reason': 'stop', 'done': True, 'total_duration': 1826702566, 'load_duration': 65437951, 'prompt_eval_count': 358, 'prompt_eval_duration': 147000000, 'eval_count': 30, 'eval_duration': 1504000000}, name='code_generator', id='run-fb85e579-32db-40fe-94d2-aee5f283acaa-0', usage_metadata={'input_tokens': 358, 'output_tokens': 30, 'total_tokens': 388})], 'sender': 'code_generator'}
1 | for chunk in graph.stream( |
================================[1m Human Message [0m=================================
帮我根据前10名的 销售记录id,生成对应的销售额柱状图
==================================[1m Ai Message [0m==================================
Name: db_manager
Tool Calls:
query_sales (call_6DJz9lCACEoG9uvP284r1Da3)
Call ID: call_6DJz9lCACEoG9uvP284r1Da3
Args:
sales_id: 1
=================================[1m Tool Message [0m=================================
Name: query_sales
{"sales_id": 1, "product_id": 18, "employee_id": 2, "customer_id": 38, "sale_date": "2024-05-18", "quantity": 6, "amount": 1193.36, "discount": 0.00735418}
==================================[1m Ai Message [0m==================================
Name: db_manager
Tool Calls:
query_sales (call_g7hwUx6XNjV6kvOtkGzTvORI)
Call ID: call_g7hwUx6XNjV6kvOtkGzTvORI
Args:
sales_id: 2
query_sales (call_TYcQRQauS6xVNkjrNIvvBtcf)
Call ID: call_TYcQRQauS6xVNkjrNIvvBtcf
Args:
sales_id: 3
query_sales (call_jCKkW6XpohuhGB11FUfFYMp4)
Call ID: call_jCKkW6XpohuhGB11FUfFYMp4
Args:
sales_id: 4
query_sales (call_wZXNf3lbxgJecksj9bH8m1CW)
Call ID: call_wZXNf3lbxgJecksj9bH8m1CW
Args:
sales_id: 5
query_sales (call_8GZ40gRHuLXH6a1b5AR2nWIC)
Call ID: call_8GZ40gRHuLXH6a1b5AR2nWIC
Args:
sales_id: 6
query_sales (call_5zfVi3zcR7LQxUWfUja5pYWp)
Call ID: call_5zfVi3zcR7LQxUWfUja5pYWp
Args:
sales_id: 7
query_sales (call_hvyAc5HN5mDcDAZsqwwRl2MH)
Call ID: call_hvyAc5HN5mDcDAZsqwwRl2MH
Args:
sales_id: 8
query_sales (call_CFjYYj6IC1hqPqnZqZS08OKw)
Call ID: call_CFjYYj6IC1hqPqnZqZS08OKw
Args:
sales_id: 9
query_sales (call_zTHEbaswGZCq5Iy8B0VOEcUO)
Call ID: call_zTHEbaswGZCq5Iy8B0VOEcUO
Args:
sales_id: 10
=================================[1m Tool Message [0m=================================
Name: query_sales
{"sales_id": 10, "product_id": 16, "employee_id": 7, "customer_id": 33, "sale_date": "2024-07-13", "quantity": 1, "amount": 2247.41, "discount": 0.00544484}
==================================[1m Ai Message [0m==================================
Name: db_manager
我从数据库中获取了前10名的销售记录。这些记录的销售额如下:
1. 销售记录ID 1: 销售额 $1193.36
2. 销售记录ID 2: 销售额 $2315.86
3. 销售记录ID 3: 销售额 $808.78
4. 销售记录ID 4: 销售额 $3248.92
5. 销售记录ID 5: 销售额 $4020.69
6. 销售记录ID 6: 销售额 $3519.43
7. 销售记录ID 7: 销售额 $2286.76
8. 销售记录ID 8: 销售额 $3024.09
9. 销售记录ID 9: 销售额 $1334.56
10. 销售记录ID 10: 销售额 $2247.41
现在可以使用这些数据生成对应的销售额柱状图。以下是生成图表的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt
# 销售记录ID
sales_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 销售额
amounts = [1193.36, 2315.86, 808.78, 3248.92, 4020.69, 3519.43, 2286.76, 3024.09, 1334.56, 2247.41]
plt.bar(sales_ids, amounts, color='blue')
plt.xlabel('销售记录ID')
plt.ylabel('销售额 ($)')
plt.title('前10名销售记录的销售额')
plt.xticks(sales_ids)
plt.show()
您可以将上述代码复制到Python环境中运行,以生成柱状图。
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 38144 (\N{CJK UNIFIED IDEOGRAPH-9500}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 21806 (\N{CJK UNIFIED IDEOGRAPH-552E}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 39069 (\N{CJK UNIFIED IDEOGRAPH-989D}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 21069 (\N{CJK UNIFIED IDEOGRAPH-524D}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 21517 (\N{CJK UNIFIED IDEOGRAPH-540D}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 35760 (\N{CJK UNIFIED IDEOGRAPH-8BB0}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 24405 (\N{CJK UNIFIED IDEOGRAPH-5F55}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
C:\ProgramData\anaconda3\envs\agent\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 30340 (\N{CJK UNIFIED IDEOGRAPH-7684}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
==================================[1m Ai Message [0m==================================
Name: code_generator
Tool Calls:
python_repl (f85395e4-1e87-421c-b2dc-ebc359d970fc)
Call ID: f85395e4-1e87-421c-b2dc-ebc359d970fc
Args:
code: import matplotlib.pyplot as plt
# 销售记录ID
sales_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 销售额
amounts = [1193.36, 2315.86, 808.78, 3248.92, 4020.69, 3519.43, 2286.76, 3024.09, 1334.56, 2247.41]
plt.bar(sales_ids, amounts, color='blue')
plt.xlabel('销售记录ID')
plt.ylabel('销售额 ($}')
plt.title('前10名销售记录的销售额')
plt.xticks(sales_ids)
plt.show()
python_repl (5d59745f-d55f-436e-921e-7da101d15fd2)
Call ID: 5d59745f-d55f-436e-921e-7da101d15fd2
Args:
code: import matplotlib.pyplot as plt
# 销售记录ID
sales_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 销售额
amounts = [1193.36, 2315.86, 808.78, 3248.92, 4020.69, 3519.43, 2286.76, 3024.09, 1334.56, 2247.41]
plt.bar(sales_ids, amounts, color='blue')
plt.xlabel('销售记录ID')
plt.ylabel('销售额 ($)')
plt.title('前10名销售记录的销售额')
plt.xticks(sales_ids)
plt.show()
在基于网络代理构建的多智能体系统中,每个代理都可以与其他每个代理通信(多对多连接),并可以决定接下来要调用哪个代理。虽然非常灵活,但这个体系结构不能随着代理数量的增加而很好地扩展,比如很难强制执行接下来应该调用哪个代理,很难确定应该在代理之间传递多少信息等多种问题。这是NetWork通信方式的优劣势所在。
除此以外,LangGraph中可以构建的Supervisor与Hierarchical多智能体系统,我们在下节课给大家展开详细的介绍。