今日主题:我们来手把手,嘴对嘴的手搓一个幼儿版的Agent
书接上文,我们梳理一个Agent的定义,也梳理了什么LLM和Agents的区别,看不到的小伙伴可以点击链接传送门:从零到手搓一个Agent:AI Agents新手入门精通(一)。现在我们开始我们第二个学习。
温馨提醒:本系列的初衷是为了从原理去理解Agents,所以我们会用python代码去手搓一个Agent,而不是通过coze,腾讯元器这一些平台去调用工作流。所以可能会有点难度,我们到后面会做一些工作流等一些节点的学习。
现在,我们来手搓一个,智能客服的Agent(只要跟着过程一步一步的操作,一定能手搓一个小Agents出来的,遇到报错的问题,可以评论区留言)
一、准备好API与环境
①我们先安装好环境
pip install openai python-dotenv
②准备好四样东西
国内模型可以是智谱、Yi、千问deepseek等等。KIMI是不行的,因为Kimi家没有嵌入模型。 要想用openai库对接国内的大模型,对于每个厂家,我们都需要准备四样前菜:
在这三样东西里面,第一个api_key你要好好保密,不要泄露出去。免得被人盗用,让你的余额用光光。
后面两样东西都是公开的。在这里,我推荐智谱的模型,因为他免费
我们也以智谱为例子
我们来一步步创建一个项目目录,并配置 .env 文件。
首先,我们需要创建一个新的项目目录。在命令行中执行以下命令:
mkdir my_project
cd my_project
在项目的根目录下创建一个名为 .env 的文件。可以使用以下命令:
echo "ZHIPU_API_KEY=你的api_key" > .env
确保将 你的api_key 替换为您实际的 API 密钥。
现在,我们的项目目录结构应该如下:
4. 安装必要的库
在项目目录中,安装 openai 和 python-dotenv 库:
pip install openai python-dotenv
在项目目录中创建一个 Python 脚本文件,例如 main.py,并添加以下内容:
import os
from dotenv import load_dotenv
from openai import OpenAI
# 加载环境变量
load_dotenv()
# 从环境变量中读取API密钥
api_key = os.getenv('ZHIPU_API_KEY')
# 基础配置
base_url = "https://open.bigmodel.cn/api/paas/v4/"
chat_model = "glm-4-flash"
# 创建客户端
client = OpenAI(
api_key=api_key,
base_url=base_url
)
def get_completion(prompt):
response = client.chat.completions.create(
model=chat_model,
messages=[
{"role": "user", "content": prompt},
],
)
return response.choices[0].message.content
# 测试调用
response = get_completion("你好,世界!")
print(response)
在命令行中运行您的 Python 脚本:
python main.py
得到输出
这将使用您在 .env 文件中配置的 API 密钥与智谱AI进行交互。通过这些步骤,您已经成功创建了一个简单的项目,并配置了与智谱AI的连接。
如果到这里没有问题,那可太棒了,来休息一下,奖励一下自己
我们现在来手搓一个智能客服的智能体
1、创建一个智能体客服的类
class SmartAssistant:
def __init__(self, client):
self.client = client
# 定义不同场景的提示词
self.system_prompt = """你是一个聪明的客服。您将能够根据用户的问题将不同的任务分配给不同的人。您有以下业务线:
1.用户注册。如果用户想要执行这样的操作,您应该发送一个带有"registered workers"的特殊令牌。并告诉用户您正在调用它。
2.用户数据查询。如果用户想要执行这样的操作,您应该发送一个带有"query workers"的特殊令牌。并告诉用户您正在调用它。
3.删除用户数据。如果用户想执行这种类型的操作,您应该发送一个带有"delete workers"的特殊令牌。并告诉用户您正在调用它。
"""
self.registered_prompt = """
您的任务是根据用户信息存储数据。您需要从用户那里获得以下信息:
1.用户名、性别、年龄
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,您需要提示用户提供。如果用户提供了此信息,则需要将此信息存储在数据库中,并告诉用户注册成功。
存储方法是使用SQL语句。您可以使用SQL编写插入语句,并且需要生成用户ID并将其返回给用户。
如果用户没有新问题,您应该回复带有 "customer service" 的特殊令牌,以结束任务。
"""
self.query_prompt = """
您的任务是查询用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
如果用户没有提供此信息,则需要提示用户提供。如果用户提供了此信息,那么需要查询数据库。如果用户ID和密码匹配,则需要返回用户的信息。
如果用户没有新问题,您应该回复带有 "customer service" 的特殊令牌,以结束任务。
"""
self.delete_prompt = """
您的任务是删除用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,则需要提示用户提供该信息。
如果用户提供了这些信息,则需要查询数据库。如果用户ID和密码匹配,您需要通知用户验证码已发送到他们的电子邮件,需要进行验证。
如果用户没有新问题,您应该回复带有 "customer service" 的特殊令牌,以结束任务。
"""
# 使用字典存储不同场景的消息
self.messages = {
"system": [{"role": "system", "content": self.system_prompt}],
"registered": [{"role": "system", "content": self.registered_prompt}],
"query": [{"role": "system", "content": self.query_prompt}],
"delete": [{"role": "system", "content": self.delete_prompt}]
}
# 当前处理的任务
self.current_assignment = "system"
def get_response(self, user_input):
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
while True:
response = self.client.chat.completions.create(
model="glm-4",
messages=self.messages[self.current_assignment],
temperature=0.9,
stream=False,
max_tokens=2000,
)
ai_response = response.choices[0].message.content
if "registered workers" in ai_response:
self.current_assignment = "registered"
print("意图识别:", ai_response)
print("switch to <registered>")
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "query workers" in ai_response:
self.current_assignment = "query"
print("意图识别:", ai_response)
print("switch to <query>")
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "delete workers" in ai_response:
self.current_assignment = "delete"
print("意图识别:", ai_response)
print("switch to <delete>")
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "customer service" in ai_response:
print("意图识别:", ai_response)
print("switch to <customer service>")
self.messages["system"] += self.messages[self.current_assignment]
self.current_assignment = "system"
return ai_response
else:
self.messages[self.current_assignment].append({"role": "assistant", "content": ai_response})
return ai_response
def start_conversation(self):
print("智能客服助手已启动,请输入您的问题(输入 'exit' 或 'quit' 退出)")
while True:
user_input = input("User: ")
if user_input.lower() in ['exit', 'quit']:
print("感谢使用智能客服系统,再见!")
break
response = self.get_response(user_input)
print("Assistant:", response)
在我们的main.p文件中,去调用这个类,也就是调用这个客服
if __name__ == "__main__":
assistant = SmartAssistant(client)
assistant.start_conversation()
确保您的 .env 文件中有正确的 API 密钥,然后在命令行中运行:
python main.py
我忘记我的账号密码了
PS D:\agent> python main.py
你好🌏!很高兴见到你,有什么可以帮助你的吗?
智能客服助手已启动,请输入您的问题(输入 'exit' 或 'quit' 退出)
User: 我的账号密码忘记了
意图识别: 1.用户注册
```python
tool_call(token='registered workers')
```
switch to <registered>
意图识别: 如果您忘记了自己的账号密码,您可以按照以下步骤来重置或找回密码:
1. **找到重置密码选项**:在登录界面通常会有“忘记密码”、“重置密码”或类似的选项。
2. **验证身份**:点击该选项后,系统会要求您提供一些信息来 验证您的身份,这通常是通过电子邮件地址或者手机号码来完成的。
3. **检查您的邮箱或手机**:根据您提供的联系方式,系统会发 送一个重置密码的链接或验证码。
4. **按照指引操作**:通过邮箱中的链接或者输入手机收到的验 证码进入密码重置页面。
5. **设置新密码**:在密码重置页面,输入新的密码,并确认密 码。
6. **完成重置**:按照页面的提示完成密码重置流程。
如果您在找回密码的过程中遇到任何问题,可以联系客服帮助解决。
但是,由于我是一个虚拟助手,我无法直接帮您处理忘记密码的问题,也无法访问实际的数据库来存储或检索信息。不过,我可以提供一个SQL插入语句的示例,帮助理解这个过程:
```sql
-- 假设我们有一个用户表 `users`,字段包括:user_id, username, gender, age, password, email
-- 插入用户数据的SQL语句
INSERT INTO users (username, gender, age, password, email)
VALUES ('张三', '男', 25, 'hashed_password', 'zhangsan@example.com');
-- hashed_password 是指加密后的密码,实际操作中不应存储明 文密码。
-- 生成用户ID的SQL语句,这通常是在插入数据之前完成的,取决于数据库的设计
-- 假设用户ID是自动增长的,下面这条语句可能不是必须的
SELECT LAST_INSERT_ID(); -- 在MySQL中这样获取最后一个插入 记录的自增ID
```
对于找回密码的问题,您应该联系实际的客户服务部门或者使用网站提供的帮助工具。
如果您不需要进一步的帮助,请告诉我“customer service”,我会结束这个任务。
switch to <customer service>
Assistant: 如果您忘记了自己的账号密码,您可以按照以下步骤 来重置或找回密码:
1. **找到重置密码选项**:在登录界面通常会有“忘记密码”、“重置密码”或类似的选项。
2. **验证身份**:点击该选项后,系统会要求您提供一些信息来 验证您的身份,这通常是通过电子邮件地址或者手机号码来完成的。
3. **检查您的邮箱或手机**:根据您提供的联系方式,系统会发 送一个重置密码的链接或验证码。
4. **按照指引操作**:通过邮箱中的链接或者输入手机收到的验 证码进入密码重置页面。
5. **设置新密码**:在密码重置页面,输入新的密码,并确认密 码。
6. **完成重置**:按照页面的提示完成密码重置流程。
如果您在找回密码的过程中遇到任何问题,可以联系客服帮助解决。
但是,由于我是一个虚拟助手,我无法直接帮您处理忘记密码的问题,也无法访问实际的数据库来存储或检索信息。不过,我可以提供一个SQL插入语句的示例,帮助理解这个过程:
```sql
-- 假设我们有一个用户表 `users`,字段包括:user_id, username, gender, age, password, email
-- 插入用户数据的SQL语句
INSERT INTO users (username, gender, age, password, email)
VALUES ('张三', '男', 25, 'hashed_password', 'zhangsan@example.com');
-- hashed_password 是指加密后的密码,实际操作中不应存储明 文文密码。
-- 生成用户ID的SQL语句,这通常是在插入数据之前完成的,取决于数据库的设计
-- 假设用户ID是自动增长的,下面这条语句可能不是必须的
SELECT LAST_INSERT_ID(); -- 在MySQL中这样获取最后一个插入记 录的自增ID
```
对于找回密码的问题,您应该联系实际的客户服务部门或者使用网站提供的帮助工具。
如果您不需要进一步的帮助,请告诉我“customer service”,我会结束这个任务。
User: gis
User: 我需要注册一个账号,怎么注册
意图识别: 好的,为了帮您注册账号,我需要收集以下信息:
1. 用户名
2. 性别
3. 年龄
4. 密码
5. 电子邮件地址
请提供以上信息,以便我为您创建账号。在您提供这些信息后,我会生成一个用户ID,并将其返回给您。同时,我会发送一个"registered workers"的特殊令牌给相关部门,以便他们知道有新的注册请求。
现在,您可以开始提供这些信息了。
switch to <registered>
Assistant: 为了注册账号,请您提供以下信息:
1. 用户名
2. 性别
3. 年龄
4. 您希望设置的密码
5. 您的电子邮件地址
请您提供这些信息,以便我可以帮您完成注册并存储数据到数据库中。例如:
- 用户名:张三
- 性别:男
- 年龄:28
- 密码:(请提供一个您希望的密码)
- 电子邮件地址:zhangsan@example.com
您只需提供上述信息,我会为您生成一个用户ID,然后模拟执行SQL 插入语句以存储信息。请注意,在实际应用中,密码不应该以明文形式存储,而是经过加密处理。以下是模拟的SQL插入语句的示例:
```sql
INSERT INTO users (username, gender, age, password, email)
VALUES ('张三', '男', 28, 'your_password_here', 'zhangsan@example.com');
```
在您提供信息后,我会“执行”这个语句,并告诉您注册成功,同时提供给您一个生成的用户ID。请提供您的注册信息吧。
User:
①注册:当用户输入注册相关信息时,智能体会提示用户提供必要的注册信息。
②查询:当用户输入查询相关信息时,智能体会提示用户提供用户ID和密码。
③删除:当用户输入删除相关信息时,智能体会提示用户提供用户ID、密码和电子邮件。
通过这些步骤,您将能够创建一个简单的智能客服智能体,并与之进行交互。您可以根据需要进一步扩展和完善智能体的功能
让我们分析一下这个智能体的表现:
①意图识别正确
1、成功识别了"忘记密码"的场景
2、正确识别了"注册账号"的需求
3、准确识别了"查询用户"的请求
②状态切换正常
1、从 system -> registered -> customer service 的切换正确
2、从 system -> query 的切换也正确
3、每次切换都有清晰的提示("switch to <xxx>")
③ 提示词执行到位
1、按照预设的 prompt 给出相应的回答
④要求用户提供必要的信息
1、给出了具体的SQL示例
2、交互流畅
3、对话自然
4、回答详细
5、引导清晰
在某些回答中出现了重复的内容,比如SQL语句示例重复出现状态管理,在处理"靓仔"这个简单回答时,可能切换状态过于频繁,从 registered 直接切换到 customer service 可能过早
2、信息收集
可以更有条理地一步步收集用户信息,增加信息验证的环节
增加渐进式信息收集
def collect_user_info(self):
info = {}
fields = ['username', 'gender', 'age', 'password', 'email']
for field in fields:
info[field] = self.ask_for_field(field)
return inf
优化状态切换逻辑
def should_switch_state(self, current_state, response):
总的来说,这个智能体实现了基本功能,但还可以在用户体验和功能完整性上进行优化。下次我们继续搞一个大的