【Langchain Agent研究】SalesGPT项目介绍(四)

【Langchain Agent研究】SalesGPT项目介绍(三)-CSDN博客

  github地址:GitHub - jerry1900/SalesGPT: Context-aware AI Sales Agent to automate sales outreach.      

        上节课,我们主要介绍了SalesGPT的类属性和它最重要的类方法from_llm()。因为SalesGPT没有构造器方法,所以类方法from_llm()方法就是这个类的构造方法,所以这个类方法很重要。

        第二节课的时候我们讲过(【Langchain Agent研究】SalesGPT项目介绍(二)-CSDN博客),这个项目的运行代码是run.py,但是在我仔细研究项目的逻辑后发现,run.py的代码是有很明显的逻辑错误的,应该压根就跑不起来、或者会进死循环的,所以没有办法,我自己写了一个test方法来把这个项目跑起来,然后我把运行过程拆开,方便我们用debug来看一下代码运行过程中的中间变量。在介绍我们自己的test方法的过程中,我会顺便介绍SalesGPT其他几个重要的方法 step(), human_step(),_call(),determine_conversation_stage(),基本上掌握了这些方法就能够运行整个项目了。

run.py运行代码有逻辑问题

        首先跟大家说一下,我仔细研究了项目自带的run.py方法,感觉不太对头,就是它的这个方法里少了关键的调用determine_conversation_stage()方法,我们来看一下:

    sales_agent.seed_agent()print("=" * 10)cnt = 0while cnt != max_num_turns:cnt += 1if cnt == max_num_turns:print("Maximum number of turns reached - ending the conversation.")breaksales_agent.step()# end conversationif "<END_OF_CALL>" in sales_agent.conversation_history[-1]:print("Sales Agent determined it is time to end the conversation.")breakhuman_input = input("Your response: ")sales_agent.human_step(human_input)print("=" * 10)

        这块代码之前没有啥问题,但是在seed_agent()之后,从来没有调用过determine_conversation_stage()这个方法,这个在逻辑上是不对的,我们回忆一下我们第一课上讲的东西,整个业务逻辑是这样的:

        注意在用户输入之后、在Agent响应之前,每次都是要做阶段判断的,如果不判断对话阶段,是根本无法正确地和用户交互的,相当于整个逻辑链少了一个关键环节,这是一个很明显的错误,希望大家也能发现这个问题。

我们自己构造一个运行程序my_test.py

        我们自己尝试构造一个运行程序,去把这个项目跑起来,因为有很多问题只有把代码跑起来才能发现其中的问题:

import osfrom dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from salesgpt.agents import SalesGPTload_dotenv()print(os.getenv("OPENAI_API_KEY"))llm = ChatOpenAI(temperature=0,openai_api_key = os.getenv("OPENAI_API_KEY"),base_url = os.getenv("OPENAI_BASE_URL")
)

        这里注意一下,我对项目用的ChatLiteLLM不太熟悉,不知道他怎么设置base_url的,因为我用的是国内openai节点,所以我索性不用ChatLiteLLM了,我直接用咱们以前项目用过的ChatOpenAI包装器,方便我修改base_url。

sales_agent = SalesGPT.from_llm(llm,verbose=True,use_tools=False,salesperson_name="Ted Lasso",salesperson_role="Sales Representative",company_name="Sleep Haven",company_business="""Sleep Haven is a premium mattress company that providescustomers with the most comfortable andsupportive sleeping experience possible. We offer a range of high-quality mattresses,pillows, and bedding accessories that are designed to meet the unique needs of our customers.""",)sales_agent.seed_agent()
sales_agent.determine_conversation_stage()

        到这里,我们要注意一下,由于我换了模型,直接运行会报错:

        看报错位置和报错提示,大概能猜出来,由于我换了模型,ChatOpenAI这个模型缺少model这个参数,所以就报错了(ChatLiteLLM模型有这个参数)。因为我们之前研究过SalesGPT的构造方法:

def from_llm(cls, llm: ChatLiteLLM, verbose: bool = False, **kwargs) -> "SalesGPT":

        不难看出,这个model_name并非构造SalesGPT的必要参数,是放在kwargs里面的东西,所以干脆注销掉就好了。由于我是改的项目源代码,所以在这里要注释一下,免得以后忘了为啥要把这行代码注释掉。 我们注释掉之后再跑一下,我建议大家用pycharm的debug一步一步地跑,这样可以清晰地看到里面的运行过程、线程和参数:

        OK,到这里,项目开始跑起来了,这里看到已经开始构造StageAnalyzerChain了,我们继续往下看看,可以看到历史记录是空的,我们和openai的交互也成功了,也正确输出了:

prompt提示词调整 

        虽然项目跑起来了,但是仔细检查里面的过程,还是有问题:

        可以看到这里出了问题,我们第一次跑这个项目,之前是没有历史聊天记录的,但是在第一次做阶段判断的时候,直接stage分析的时候直接判定到了第二个阶段,这个是有问题的。解决方法有两个,一个是换更好用、逻辑推理能力更强的GPT-4模型,还有一个办法就是对项目自带的prompt提示词进行修改和优化如下:

 

Current Conversation stage is: {conversation_stage_id}check conversation history step by step,if converssation history is null,output 1.The answer needs to be one number only, no words.
Do not answer anything else nor add anything to you answer."""# If there is no conversation history, output 1

         “If there is no conversation history, output 1”是原来项目里的提示词,感觉不太好用,我们用我自己写的提示词“check conversation history step by step,if converssation history is null,output 1.”,这里应用了提示词工程的小技巧(思维链),让大模型在检查这里的时候不要给我糊弄,好好看,我们再运行一下项目:

        可以看到,我们换了提示词之后,大模型终于把这块整明白了,阶段输出也正确了。

不断向agent提问,理解整个业务逻辑 ,查看中间过程

        我们下面可以不断地向用户提问,其实就是不断重复这个流程:

sales_agent.determine_conversation_stage()
sales_agent.step()
agent_output = sales_agent.conversation_history[-1]human_input = input('say something')
sales_agent.human_step(human_input)

        先进行阶段判断,然后根据阶段判断agent先进行输出,然后用户再进行输出,你可以用pycharm的debug功能清晰看到中间过程:

        输出结果和日志在console里看,线程和参数在threads&variables里看: 

        在这里点开,你可以看到你代码构造的实例和变量,里面的东西太多了,大家自己点进去看吧,有助于你里面代码背后的东西。

 seed_agent()方法

        我们之前已经介绍了SalesGPT最重要的from_llm()类方法,这个方法同时也是这个类的构造方法,我们继续来看一下我们demo用到的SalesGPT的其他方法,注意,这些方法都不是类方法,都是实例方法,他们都是我们在实例化获得了一个sales_agent之后调用的。第一个是seed_agent()方法:

    @time_loggerdef seed_agent(self):# Step 1: seed the conversationself.current_conversation_stage = self.retrieve_conversation_stage("1")self.conversation_history = []

        这个方法的上面加了一个装饰器,用于计时的,代码里面的内容就是初始化一下,没啥好说的。

determine_conversation_stage()方法

        调用类的实例属性stage_analyzer_chain来进行阶段判断,输入的参数有三个如下,这里要对内容做一些格式上的调整,函数的输出就是把类的conversation_stage_id,current_conversation_stage这个两个值属性进行了对应的修改:

    @time_loggerdef determine_conversation_stage(self):self.conversation_stage_id = self.stage_analyzer_chain.run(conversation_history="\n".join(self.conversation_history).rstrip("\n"),conversation_stage_id=self.conversation_stage_id,conversation_stages="\n".join([str(key) + ": " + str(value)for key, value in CONVERSATION_STAGES.items()]),)print(f"Conversation Stage ID: {self.conversation_stage_id}")self.current_conversation_stage = self.retrieve_conversation_stage(self.conversation_stage_id)print(f"Conversation Stage: {self.current_conversation_stage}")

step()方法和_call()方法

        step()方法里面做了一个简单判断,因为我们不需要stream的输出样式,所以就是去调用_call()方法,这个方法是一个类内部方法:

    @time_loggerdef step(self, stream: bool = False):"""Args:stream (bool): whether or not returnstreaming generator object to manipulate streaming chunks in downstream applications."""if not stream:self._call(inputs={})else:return self._streaming_generator()

         _call()方法:

    def _call(self, inputs: Dict[str, Any]) -> Dict[str, Any]:"""Run one step of the sales agent."""# override inputs temporarilyinputs = {"input": "","conversation_stage": self.current_conversation_stage,"conversation_history": "\n".join(self.conversation_history),"salesperson_name": self.salesperson_name,"salesperson_role": self.salesperson_role,"company_name": self.company_name,"company_business": self.company_business,"company_values": self.company_values,"conversation_purpose": self.conversation_purpose,"conversation_type": self.conversation_type,}# Generate agent's utteranceif self.use_tools:ai_message = self.sales_agent_executor.invoke(inputs)output = ai_message["output"]else:ai_message = self.sales_conversation_utterance_chain.invoke(inputs)output = ai_message["text"]# Add agent's response to conversation historyagent_name = self.salesperson_nameoutput = agent_name + ": " + outputif "<END_OF_TURN>" not in output:output += " <END_OF_TURN>"self.conversation_history.append(output)print(output.replace("<END_OF_TURN>", ""))return ai_message

        注意,这里的input是空的:

        因为系统输出只依赖于现在对话处于哪个阶段,并不依赖于用户输入的具体内容!这里困扰了我好久,我当时一直和我自己之前写的agent做比较,我还纳闷呢,为啥这个agent输入没有用户的Input呢?现在我明白了,用户的输入就是用来帮助进行阶段判断的,系统的输出只依赖于现在处于哪个阶段。

        继续往下看,如果使用了tools就用sales_agent_executor,否则就用sales_conversation_utterrance_chain,因此我们之前的demo运行都用的sales_conversation_utterrance_chain,下节课我们来用sales_agent_executor。

        # Generate agent's utteranceif self.use_tools:ai_message = self.sales_agent_executor.invoke(inputs)output = ai_message["output"]else:ai_message = self.sales_conversation_utterance_chain.invoke(inputs)output = ai_message["text"]

                最后要把大模型给的输出结果包装一下,放到conversation_history里,ai_message作为函数的返回结果:

        # Add agent's response to conversation historyagent_name = self.salesperson_nameoutput = agent_name + ": " + outputif "<END_OF_TURN>" not in output:output += " <END_OF_TURN>"self.conversation_history.append(output)print(output.replace("<END_OF_TURN>", ""))return ai_message

human_step()

        这个就更简单了,不说了。

    def human_step(self, human_input):# process human inputhuman_input = "User: " + human_input + " <END_OF_TURN>"self.conversation_history.append(human_input)

        至此,我们就把如何把这个项目跑起来展示了一遍,我们对项目源码做了两处修改,大家注意要同样修改源码之后才能运行我们自己的代码,我贴一下整个my_test整体代码:

import osfrom dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from salesgpt.agents import SalesGPTload_dotenv()print(os.getenv("OPENAI_API_KEY"))llm = ChatOpenAI(temperature=0,openai_api_key = os.getenv("OPENAI_API_KEY"),base_url = os.getenv("OPENAI_BASE_URL")
)sales_agent = SalesGPT.from_llm(llm,verbose=True,use_tools=False,salesperson_name="Ted Lasso",salesperson_role="Sales Representative",company_name="Sleep Haven",company_business="""Sleep Haven is a premium mattress company that providescustomers with the most comfortable andsupportive sleeping experience possible. We offer a range of high-quality mattresses,pillows, and bedding accessories that are designed to meet the unique needs of our customers.""",)sales_agent.seed_agent()
sales_agent.determine_conversation_stage()sales_agent.step()
agent_output = sales_agent.conversation_history[-1]
assert agent_output is not None, "Agent output cannot be None."
assert isinstance(agent_output, str), "Agent output needs to be of type str"
assert len(agent_output) > 0, "Length of output needs to be greater than 0."human_input = input('say something')
sales_agent.human_step(human_input)sales_agent.determine_conversation_stage()
sales_agent.step()
agent_output = sales_agent.conversation_history[-1]human_input = input('say something')
sales_agent.human_step(human_input)sales_agent.determine_conversation_stage()
sales_agent.step()
agent_output = sales_agent.conversation_history[-1]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/682997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【教学类-47-01】20240206UIBOT+IDM下载儿童古诗+修改文件名

背景需求&#xff1a; 去年12月&#xff0c;我去了其他幼儿园参观&#xff0c;这是一个传统文化德育教育特色的学校&#xff0c;在“古典集市”展示活动中&#xff0c;小班中班大班孩子共同现场念诵《元日》《静夜思》包含了演唱版本和儿歌念诵版本。 我马上也要当班主任了&a…

微信小程序开发学习笔记《17》uni-app框架-tabBar

微信小程序开发学习笔记《17》uni-app框架-tabBar 博主正在学习微信小程序开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读uni-app对应官方文档 一、创建tabBar分支 运行如下的命令&#xff0c;基于master分支在本地创建tabBar子分支&#x…

Netty Review - 服务端channel注册流程源码解析

文章目录 PreNetty主从Reactor线程模型服务端channel注册流程源码解读入口 serverBootstrap.bind(port)执行队列中的任务 &#xff1a; AbstractUnsafe#register0注册 doRegister() 源码流程图 Pre Netty Review - ServerBootstrap源码解析 Netty Review - NioServerSocketCh…

TCP高频知识点

本篇文章主要讲述一下在面试过程中TCP的高频知识点 1.TCP三次握手流程图: 客户端发送一个SYN&#xff08;同步&#xff09;报文段给服务器&#xff0c;选择一个初始序列号&#xff0c;并设置SYN标志位为1。服务器接收到客户端的SYN报文段后&#xff0c;回复一个ACK&#xff08…

OJ刷题:杨氏矩阵【建议收藏】

看见这个题目&#xff0c;很多人的第一反应是遍历整个数组查找数字&#xff0c;但是这种方法不仅效率低&#xff0c;而且远远不能满足题目要求。下面介绍一种高效的查找方法&#xff1a; 代码实现&#xff1a; #include <stdio.h>int Yang_Find_Num(int arr[][3], int …

steam游戏搬砖项目靠谱吗?有没有风险?

作为一款fps射击游戏&#xff0c;csgo在近几年可谓是火出圈&#xff0c;作为一款全球竞技游戏&#xff0c;深受玩家喜爱追捧&#xff0c;玩家追求的就是公平公正&#xff0c;各凭本事&#xff0c;像其他游戏可能还会有皮肤等装备属性加成&#xff0c;在csgo里面是不存在的。 纯…

K8sGPT 的使用

K8sGPT 介绍 k8sgpt 是一个扫描 Kubernetes 集群、诊断和分类问题的工具。它将 SRE 经验编入其分析器中&#xff0c;并帮助提取最相关的信息&#xff0c;通过人工智能来丰富它。它还可以与 OpenAI、Azure、Cohere、Amazon Bedrock 和本地模型结合使用。 K8sGPT Github 地址 …

Vue插槽

Vue插槽 一、插槽-默认插槽1.作用2.需求3.问题4.插槽的基本语法5.代码示例6.总结 二、插槽-后备内容&#xff08;默认值&#xff09;1.问题2.插槽的后备内容3.语法4.效果5.代码示例 三、插槽-具名插槽1.需求2.具名插槽语法3.v-slot的简写4.代码示例5.总结 四、作用域插槽1.插槽…

安卓价值1-如何在电脑上运行ADB

ADB&#xff08;Android Debug Bridge&#xff09;是Android平台的调试工具&#xff0c;它是一个命令行工具&#xff0c;用于与连接到计算机的Android设备进行通信和控制。ADB提供了一系列命令&#xff0c;允许开发人员执行各种操作&#xff0c;包括但不限于&#xff1a; 1. 安…

在python中JSON数据格式的使用

什么是JSON&#xff1f; JSON是一种数据格式&#xff0c;由美国程序设计师DouglasCrockford创建的&#xff0c;JSON全名是JavaScript Object Notation,由JSON英文全文字义我们可以推敲JSON的缘由&#xff0c;最初是为JavaScript开发的。这种数据格式由于简单好用被大量应用在We…

DS Wannabe之5-AM Project: DS 30day int prep day15

Q1. What is Autoencoder? 自编码器是什么&#xff1f; 自编码器是一种特殊类型的神经网络&#xff0c;它通过无监督学习尝试复现其输入数据。它通常包含两部分&#xff1a;编码器和解码器。编码器压缩输入数据成为一个低维度的中间表示&#xff0c;解码器则从这个中间表示重…

数据库被人破解,删除数据,勒索

事情是这样的&#xff0c;我买了一台服务器自己部署项目玩儿玩儿&#xff0c;我的数据库运行在3306端口&#xff0c;密码没改&#xff0c;就是默认的123456&#xff0c;诡异的事情发生了&#xff0c;用了一段时间之后&#xff0c;数据库突然连接不上了&#xff0c;我一通操作猛…

Python爬虫——解析库安装(1)

目录 1.lxml安装2.Beautiful Soup安装3.pyquery 的安装 我创建了一个社区&#xff0c;欢迎大家一起学习交流。社区名称&#xff1a;Spider学习交流 注&#xff1a;该系列教程已经默认用户安装了Pycharm和Anaconda&#xff0c;未安装的可以参考我之前的博客有将如何安装。同时默…

【开源】SpringBoot框架开发企业项目合同信息系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 合同审批模块2.3 合同签订模块2.4 合同预警模块2.5 数据可视化模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 合同审批表3.2.2 合同签订表3.2.3 合同预警表 四、系统展示五、核心代码5.1 查询合同…

Linux多线程[二]

引入知识 进程在线程内部执行是OS的系统调度单位。 内核中针对地址空间&#xff0c;有一种特殊的结构&#xff0c;VM_area_struct。这个用来控制虚拟内存中每个malloc等申请的空间&#xff0c;来区别每个malloc的是对应的堆区哪一段。OS可以做到资源的精细度划分。 对于磁盘…

嵌入式软件设计入门:从零开始学习嵌入式软件设计

&#xff08;本文为简单介绍&#xff0c;个人观点仅供参考&#xff09; 首先,让我们了解一下嵌入式软件的定义。嵌入式软件是指运行在嵌入式系统中的特定用途软件,它通常被用来控制硬件设备、处理实时数据和实现特定功能。与桌面应用程序相比,嵌入式软件需要具备更高的实时性、…

反无人机系统技术分析,无人机反制技术理论基础,无人机技术详解

近年来&#xff0c;经过大疆、parrot、3d robotics等公司不断的努力&#xff0c;具有强大功能的消费级无人机价格不断降低&#xff0c;操作简便性不断提高&#xff0c;无人机正快速地从尖端的军用设备转入大众市场&#xff0c;成为普通民众手中的玩具。 然而&#xff0c;随着消…

Python算法题集_翻转二叉树

Python算法题集_翻转二叉树 题226&#xff1a;翻转二叉树1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【DFS递归】2) 改进版一【BFS迭代&#xff0c;节点循环】3) 改进版二【BFS迭代&#xff0c;列表循环】 4. 最优算法 本文为Python算法题集…

Spring Boot 笔记 019 创建接口_文件上传

1.1 创建阿里OSS bucket OSS Java SDK 兼容性和示例代码_对象存储(OSS)-阿里云帮助中心 (aliyun.com) 1.2 编写工具类 package com.geji.utils;import com.aliyun.oss.ClientException; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun…

加速创新如何先从创意管理开始?

文章详细介绍了什么是创意管理以及它在组织中的重要性和最佳实践。创意管理是指在组织内捕捉、组织、评估和实施创意的过程。它通过建立一个结构化的系统&#xff0c;从员工、客户或其他利益相关者那里收集创意&#xff0c;并系统地审查和选择最有前景的创意进行进一步的开发或…