CH2 - SunXiaoXiang/learn_wowagent GitHub Wiki
conda create -n wowAgent python=3.10 -y
conda activate wowAgent
pip install openai python-dotenv
国内模型可以是智谱、Yi、千问deepseek等等。KIMI是不行的,因为Kimi家没有嵌入模型。
新建.env文件,并在其中添加你需要的大模型的 API 环境
# ZHIPU
base_url = "https://open.bigmodel.cn/api/paas/v4/"
chat_model = "glm-4-flash"
#Qwen
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
chat_model = "qwen-plus"
#zhishu
base_url = "http://43.200.7.56:8008/v1"
chat_model = "glm-4-flash"
#Deepseek
base_url = "https://api.deepseek.com"
chat_model = "deepseek-chat"
import os
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 从环境变量中读取api_key
api_key = os.getenv('ZISHU_API_KEY')
base_url = "http://43.200.7.56:8008/v1"
chat_model = "glm-4-flash"
构造 client
from openai import OpenAI
client = OpenAI(
api_key = api_key,
base_url = base_url
)
尝试向大模型提问
def get_completion(prompt):
response = client.chat.completions.create(
model="glm-4-flash", # 填写需要调用的模型名称
messages=[
{"role": "user", "content": prompt},
],
)
return response.choices[0].message.content
听听看,他怎么回答你
response = get_completion("你是谁?")
print(response)
实际使用
import os
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 从环境变量中读取api_key
api_key = os.getenv('DEEPSEEK_API_KEY')
base_url = "https://api.deepseek.com"
chat_model = "deepseek-chat"
from openai import OpenAI
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)
智能体需要大量的prompt工程。代码是调用机器能力的工具, Prompt 是调用大模型能力的工具。Prompt 越来越像新时代的编程语言。让我们来学习一下著名的LangGPT。
参考:https://github.com/EmbraceAGI/LangGPT
结构化的思想很普遍,结构化内容也很普遍,我们日常写作的文章,看到的书籍都在使用标题、子标题、段落、句子等语法结构。结构化 Prompt 的思想通俗点来说就是像写文章一样写 Prompt。
为了阅读、表达的方便,我们日常有各种写作的模板,用来控制内容的组织呈现形式。例如古代的八股文、现代的简历模板、学生实验报告模板、论文模板等等模板。所以结构化编写 Prompt 自然也有各种各样优质的模板帮助你把 Prompt 写的更轻松、性能更好。所以写结构化 Prompt 可以有各种各样的模板,你可以像用 PPT 模板一样选择或创造自己喜欢的模板。
我们发现 ChatGPT 可以识别各种良好标记的层级结构内容。大模型可以识别文章的标题,段落名,段落正文等层级结构,如果我们告诉他标题,模型知道我们指的是标题以及标题下的正文内容。
这意味着我们将 prompt 的内容用结构化方式呈现,并设置标题即可方便的引用,修改,设置 prompt 内容。可以直接使用段落标题来指代大段内容,也可以告诉ChatGPT修改调整指定内容。这类似于编程中的变量,因此我们可以将这种标题当做变量使用。
Markdown 的语法层级结构很好,适合编写 prompt,因此 LangGPT 的变量基于 markdown语法。实际上除 markdown外各种能实现标记作用,如 json,yaml, 甚至好好排版好格式 都可以。
变量为 Prompt 的编写带来了很大的灵活性。使用变量可以方便的引用角色内容,设置和更改角色属性。这是一般的 prompt 方法实现起来不方便的。
ChatGPT 十分擅长角色扮演,大部分优质 prompt 开头往往就是 “我希望你作为xxx”,“我希望你扮演xxx” 的句式定义一个角色,只要提供角色说明,角色行为,技能等描述,就能做出很符合角色的行为。
如果你熟悉编程语言里的 “对象”,就知道其实 prompt 的“角色声明”和类声明很像。因此 可以将 prompt 抽象为一个角色 (Role),包含名字,描述,技能,工作方法等描述,然后就得到了 LangGPT 的 Role 模板。
使用 Role 模板,只需要按照模板填写相应内容即可。
除了变量和模板外,LangGPT 还提供了命令,记忆器,条件句等语法设置方法。
标识符:#, <> 等符号(-, []也是),这两个符号依次标识标题,变量,控制内容层级,用于标识层次结构。
属性词:Role, Profile, Initialization 等等,属性词包含语义,是对模块下内容的总结和提示,用于标识语义结构。
使用分隔符清晰标示输入的不同部分,像三重引号、XML标记、节标题等分隔符可以帮助标示需要以不同方式处理的文本部分。
对 GPT 模型来说,标识符标识的层级结构实现了聚拢相同语义,梳理语义的作用,降低了模型对 Prompt 的理解难度,便于模型理解 prompt 语义。
属性词实现了对 prompt 内容的语义提示和归纳作用,缓解了 Prompt 中不当内容的干扰。 使用属性词与 prompt 内容相结合,实现了局部的总分结构,便于模型提纲挈领的获得 prompt 整体语义。
一个好的结构化 Prompt 模板,某种意义上是构建了一个好的全局思维链。 如 LangGPT 中展示的模板设计时就考虑了如下思维链:
Role (角色) -> Profile(角色简介)—> Profile 下的 skill (角色技能) -> Rules (角色要遵守的规则) -> Workflow (满足上述条件的角色的工作流程) -> Initialization (进行正式开始工作的初始化准备) -> 开始实际使用
构建 Prompt 时,不妨参考优质模板的全局思维链路,熟练掌握后,完全可以对其进行增删改留调整得到一个适合自己使用的模板。例如当你需要控制输出格式,尤其是需要格式化输出时,完全可以增加 Ouput 或者 OutputFormat 这样的模块
保持上下文语义一致性
包含两个方面,一个是格式语义一致性,一个是内容语义一致性。
-
格式语义一致性是指标识符的标识功能前后一致。 最好不要混用,比如 # 既用于标识标题,又用于标识变量这种行为就造成了前后不一致,这会对模型识别 Prompt 的层级结构造成干扰。
-
内容语义一致性是指思维链路上的属性词语义合适。 例如 LangGPT 中的 Profile 属性词,原来是 Features,但实践+思考后我更换为了 Profile,使之功能更加明确:即角色的简历。结构化 Prompt 思想被诸多朋友广泛使用后衍生出了许许多多的模板,但基本都保留了 Profile 的诸多设计,说明其设计是成功有效的。
为什么前期会用 Features 呢? 因为 LangGPT 的结构化思想有受到 AI-Tutor[7] 项目很大启发,而 AI-Tutor 项目中并无 Profile 一说,与之功能近似的是 Features。但 AI-Tutor 项目中的提示词过于复杂,并不通用。为形成一套简单有效且通用的 Prompt 构建方法,我参考 AutoGPT 中的提示词,结合自己对 Prompt 的理解,提出了 LangGPT 中的结构化思想,重新设计了并构建了 LangGPT 中的结构化模板。
内容语义一致性还包括属性词和相应模块内容的语义一致。 例如 Rules 部分是角色需要遵守规则,则不宜将角色技能、描述大量堆砌在此。
- Author: YZFly
- Version: 0.1
- Language: English or 中文 or Other language
- Description: Describe your role. Give an overview of the character's characteristics and skills
1.技能描述1 2.技能描述2
1.技能描述1 2.技能描述2
- Don't break character under any circumstance.
- Don't talk nonsense and make up facts.
- First, xxx
- Then, xxx
- Finally, xxx
As a/an < Role >, you must follow the < Rules >, you must talk to user in default < Language >,you must greet the user. Then introduce yourself and introduce the < Workflow >.
Prompt Chain 将原有需求分解,通过用多个小的 Prompt 来串联/并联,共同解决一项复杂任务。
Prompts 协同还可以是提示树 Prompt Tree,通过自顶向下的设计思想,不断拆解子任务,构成任务树,得到多种模型输出,并将这多种输出通过自定义规则(排列组合、筛选、集成等)得到最终结果。 API 版本的 Prompt Chain 结合编程可以将整个流程变得更加自动化
- 数据准备。收集高质量的案例数据作为后续分析的基础。
- 模型选择。根据具体创作目的,选择合适的大语言模型。
- 提示词设计。结合案例数据,设计初版提示词;注意角色设置、背景描述、目标定义、约束条件等要点。
- 测试与迭代。将提示词输入 GPT 进行测试,分析结果;通过追问、深度交流、指出问题等方式与 GPT 进行交流,获取优化建议。
- 修正提示词。根据 GPT 提供的反馈,调整提示词的各个部分,强化有效因素,消除无效因素。
- 重复测试。输入经修正的提示词重新测试,比较结果,继续追问GPT并调整提示词。
- 循环迭代。重复上述测试-交流-修正过程,直到结果满意为止。
- 总结提炼。归纳提示词优化过程中获得的宝贵经验,形成设计提示词的最佳实践。
- 应用拓展。将掌握的方法论应用到其他创意内容的设计中,不断丰富提示词设计的技能。
让我们为本课的智能体定义各种prompt。
sys_prompt = """你是一个聪明的客服。您将能够根据用户的问题将不同的任务分配给不同的人。您有以下业务线:
1.用户注册。如果用户想要执行这样的操作,您应该发送一个带有"registered workers"的特殊令牌。并告诉用户您正在调用它。
2.用户数据查询。如果用户想要执行这样的操作,您应该发送一个带有"query workers"的特殊令牌。并告诉用户您正在调用它。
3.删除用户数据。如果用户想执行这种类型的操作,您应该发送一个带有"delete workers"的特殊令牌。并告诉用户您正在调用它。
"""
registered_prompt = """
您的任务是根据用户信息存储数据。您需要从用户那里获得以下信息:
1.用户名、性别、年龄
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,您需要提示用户提供。如果用户提供了此信息,则需要将此信息存储在数据库中,并告诉用户注册成功。
存储方法是使用SQL语句。您可以使用SQL编写插入语句,并且需要生成用户ID并将其返回给用户。
如果用户没有新问题,您应该回复带有 "customer service" 的特殊令牌,以结束任务。
"""
query_prompt = """
您的任务是查询用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
如果用户没有提供此信息,则需要提示用户提供。如果用户提供了此信息,那么需要查询数据库。如果用户ID和密码匹配,则需要返回用户的信息。
如果用户没有新问题,您应该回复带有 "customer service" 的特殊令牌,以结束任务。
"""
delete_prompt = """
您的任务是删除用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,则需要提示用户提供该信息。
如果用户提供了这些信息,则需要查询数据库。如果用户ID和密码匹配,您需要通知用户验证码已发送到他们的电子邮件,需要进行验证。
如果用户没有新问题,您应该回复带有 "customer service" 的特殊令牌,以结束任务。
"""
定义一个智能客服智能体。
class SmartAssistant:
def __init__(self):
self.client = client
self.system_prompt = sys_prompt
self.registered_prompt = registered_prompt
self.query_prompt = query_prompt
self.delete_prompt = delete_prompt
# Using a dictionary to store different sets of messages
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}]
}
# Current assignment for handling messages
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=chat_model,
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):
while True:
user_input = input("User: ")
if user_input.lower() in ['exit', 'quit']:
print("Exiting conversation.")
break
response = self.get_response(user_input)
print("Assistant:", response)
来运用一下这个Agent。
assistant = SmartAssistant()
assistant.start_conversation()
使用 deepseek api 重写这个例子
import os
from dotenv import load_dotenv
from openai import OpenAI
# 加载环境变量
load_dotenv()
def create_openai_client():
"""
从环境变量中加载 api_key 并创建 OpenAI 客户端。
"""
# 从环境变量中读取 api_key
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
raise ValueError("请确保 .env 文件中已设置 DEEPSEEK_API_KEY")
base_url = "https://api.deepseek.com"
# 创建 OpenAI 客户端
client = OpenAI(
api_key=api_key,
base_url=base_url
)
return client
class SmartAssistant:
def __init__(self, client):
# 初始化 OpenAI 客户端
self.client = client
# 定义系统提示词
self.sys_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.sys_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:
# 调用 OpenAI API 获取响应
response = self.client.chat.completions.create(
model="deepseek-chat", # 使用正确的模型名称
messages=self.messages[self.current_assignment],
temperature=0.7,
stream=False,
max_tokens=2000,
)
# 提取 AI 响应内容
ai_response = response.choices[0].message.content
# 根据 AI 响应内容切换任务
if "registered workers" in ai_response:
self.current_assignment = "registered"
print("意图识别:", ai_response)
print("切换到 <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("切换到 <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("切换到 <delete> 任务")
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "customer service" in ai_response:
print("意图识别:", ai_response)
print("切换到 <customer service> 任务")
self.messages["system"] += self.messages[self.current_assignment]
self.current_assignment = "system"
return ai_response
else:
# 如果没有切换任务,将 AI 响应添加到消息历史并返回
self.messages[self.current_assignment].append({"role": "assistant", "content": ai_response})
return ai_response
def start_conversation(self):
# 启动对话循环
while True:
user_input = input("User: ")
if user_input.lower() in ['exit', 'quit']:
print("退出对话。")
break
response = self.get_response(user_input)
print("Assistant:", response)
# 创建 OpenAI 客户端
client = create_openai_client()
# 创建 SmartAssistant 实例并启动对话
assistant = SmartAssistant(client)
assistant.start_conversation()
运行程序,并测试部分例子: