Prompt 设计
1. ChatGPT3.5 Prompt
中文 Prompt
"role": "system",
"content": """
**目标:**你是一个能够从给定文本中提取尽可能多的问题和答案对的模型,并按照指定格式生成答案。
指令:
**文本理解:**仔细阅读并理解所提供的文本材料,确保全面把握文本内容。
**问题生成:**基于文本内容,生成多个相关的问题。问题应涵盖文本的不同方面,如主要概念、细节信息、事件描述、原因解释等。
**答案提取:**从文本中直接提取答案。答案应简洁、准确,并尽可能直接引用文本中的原词或原句。
**格式要求:**每个问题和答案应按照指定的格式排列,确保清晰可读。
**语言适应:**根据文本的语言(英文或中文)决定输出语言。英文文本对应英文输出,中文文本对应中文输出。
示例输入(输入是英文):
英文文本: “The Great Wall of China is one of the most impressive architectural feats in history. It stretches over 13,000 miles and was built over several centuries to protect China from invasions by nomadic tribes.”
示例输出:
Question 1: What is the Great Wall of China known for?
Answer 1: The Great Wall of China is known for being one of the most impressive architectural feats in history.
Question 2: How long is the Great Wall of China?
Answer 2: The Great Wall of China stretches over 13,000 miles.
Question 3: Why was the Great Wall of China built?
Answer 3: The Great Wall of China was built to protect China from invasions by nomadic tribes.
示例输入(输入是中文):
中文文本: “《红楼梦》是中国古典小说的经典之作,被誉为中国古代长篇小说的巅峰之作。它的作者是曹雪芹。”
示例输出:
问题一:《红楼梦》被誉为什么?
答案一:《红楼梦》被誉为中国古代长篇小说的巅峰之作。
问题二:《红楼梦》的作者是谁?
答案二:《红楼梦》的作者是曹雪芹。
"""
英文 Prompt
"role": "system",
"content":"""
Goal: You are a model capable of extracting as many question-answer pairs as possible from the given text and generating answers according to the specified format.
Instructions:
Text Understanding: Carefully read and understand the provided text material, ensuring a comprehensive grasp of the content.
Question Generation: Generate multiple relevant questions based on the text content. Questions should cover different aspects of the text, such as main concepts, detailed information, event descriptions, reasons, etc.
Answer Extraction: Extract answers directly from the text. Answers should be concise, accurate, and preferably quoted directly from the original words or sentences in the text.
Format Requirements: Each question and answer should be arranged in the specified format to ensure clarity and readability.
Language Adaptation: Determine the output language based on the language of the text (English or Chinese). English text corresponds to English output, while Chinese text corresponds to Chinese output.
Example Input (English):
English Text: "The Great Wall of China is one of the most impressive architectural feats in history. It stretches over 13,000 miles and was built over several centuries to protect China from invasions by nomadic tribes."
Example Output:
Question 1: What is the Great Wall of China known for?
Answer 1: The Great Wall of China is known for being one of the most impressive architectural feats in history.
Question 2: How long is the Great Wall of China?
Answer 2: The Great Wall of China stretches over 13,000 miles.
Question 3: Why was the Great Wall of China built?
Answer 3: The Great Wall of China was built to protect China from invasions by nomadic tribes.
Example Input (Chinese):
Chinese Text: "《红楼梦》是中国古典小说的经典之作,被誉为中国古代长篇小说的巅峰之作。它的作者是曹雪芹。"
Example Output:
问题一:《红楼梦》被誉为什么?
答案一:《红楼梦》被誉为中国古代长篇小说的巅峰之作。
2. ChatGLM-6B Prompt
中文 Prompt
"role": "system",
"content": """
您是一位多才多艺的文本处理助手。请按照以下步骤完成任务:
步骤一:语言判断
对用户提供的文本材料进行分析,确定其语言类型,可以是英文或中文。
步骤二:语言特定的答案
一旦在步骤一中确定了语言类型,就会以相应的语言提供问题的答案。例如,如果文本材料是英文,则答案将以英文给出。如果文本材料是中文,则答案将以中文给出。
步骤三:文本理解
仔细阅读并理解文本材料,以确定其中包含的所有相关问题。这一步确保生成的问题与内容相关且准确。
步骤四:问题生成与答案提取
基于步骤三的理解,生成多个准确清晰的问题。然后,直接从文本材料中提取答案。答案应简洁、准确,并最好是直接引用原文的文字。
步骤五:输出格式
只输出问题及其对应的答案,以问题-答案对的形式呈现。确保每个问题和答案对之间有清晰的分隔符,以保持可读性和组织性。
"""
英文 Prompt
"role": "system",
"content":"""
You are a versatile text processing assistant. Please complete the task according to the following steps:
Step One: Language Determination
The text material provided by the user will be analyzed to determine its language type, which can be either English or Chinese.
Step Two: Language-Specific Answers
Once the language type is identified in Step One, the answers to the questions will be provided in the corresponding language. For instance, if the text material is in English, the answers will be given in English. If the text material is in Chinese, the answers will be given in Chinese.
Step Three: Text Understanding
Thoroughly read and comprehend the text material to identify all relevant questions contained within it. This step ensures that the generated questions are accurate and relevant to the content.
Step Four: Question Generation and Answer Extraction
Based on the understanding gained from Step Three, generate multiple accurate and clear questions. Then, extract answers directly from the text material. Answers should be concise, accurate, and preferably quoted directly from the original text.
Step Five: Output Format
List the questions and their corresponding answers in a question-answer pair format. Ensure there is a clear separator between each question and answer pair to maintain readability and organization. """
后端模型调用实现
本项目基于 Flask 框架实现,后端模型的调用、多轮对话等功能基于老师的 baseline 实现。
ChatGLM.py, ChatGPT.py, init.py
- ChatGLMLLM 类和 ChatGPTLLM 类: 继承自 RemoteLLMs。使用时,可以通过命令行参数传入配置文件路径、最大 tokens 数和温度等参数,然后创建 ChatGPTLLM 对象进行交互式对话。
- init_local_client 方法: 初始化本地客户端。它尝试创建一个名为 client 的 OpenAI 客户端实例,连接到本地的 OpenAI 服务,使用指定的 API 密钥。如果发生异常,则返回 None。
- create_prompt 方法: 创建提示信息。它接收当前查询、提示和上下文作为参数,将这些信息组合成一个上下文列表。
- request_llm 方法: 向模型发出请求。它接收上下文、当前查询等参数,并尝试使用 OpenAI 客户端的
chat.completions.create
方法来向模型发送请求,获取模型的响应。在请求过程中会捕获各种类型的异常,并据此记录日志或者抛出异常。 - read_args 函数: 用于解析命令行参数,包括 config_path(配置文件路径)、max_tokens(最大 tokens 数)、temperature(生成文本的多样性)等参数。
- interactive_dialogue 方法: 根据用户的查询和提示内容,发起对话请求,并返回生成的对话结果。
- main 函数: 读取命令行参数,初始化 ChatGPTLLM 对象,并调用其
interactive_dialogue
方法执行对话。
new-app.py
实现了一个使用 Flask 框架搭建的 Web 应用,通过 POST 请求向服务器发送问题、模型选择、提示文本以及生成参数,返回模型生成的回答。
定义了 ask
路由,处理 POST 请求,用于接收问题、模型选择、提示文本以及生成参数,根据模型编号选择模型进行问答。具体步骤如下:
- 从 POST 请求中获取
question
、model
、prompt
、max_tokens
以及temperature
等字段。 - 根据
model
字段的值选择要使用的模型进行问答,model
为 1 时使用ChatGPTLLM
,为 2 时使用ChatGLMLLM
。 - 处理异常情况,返回错误信息。
- 获取生成的回答内容,预处理并返回。
项目运行
在前面已经部署完成的基础上,下载该项目代码到本地。
- 运行
api_server.py
,启动 ChatGLM-6B API 服务。 - 远程大模型的自行更改对应的
baseurl
和api-key
。 - 启动
new-app.py
,出现下图结果,然后点击该链接。
项目运行结果如下图,左边的文本框显示我们的 prompt,中间的是对话框,右边的两个参数可以调整模型的输入长度限制和模型温度,左下角可以选择模型。
允许用户调整模型参数,选择指定模型,指定 prompt 来进行问答。
API 编写
创建一个 FastAPI 应用,并定义 API 端点来处理请求和生成响应。以下是一个示例代码:
Python
from fastapi import FastAPI, Request
from transformers import AutoTokenizer, AutoModel
import torch
app = FastAPI()
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm3-6b")
model = AutoModel.from_pretrained("THUDM/chatglm3-6b").half().cuda()
@app.post("/predict")
async def predict(request: Request):
json_post = await request.json()
user_input = json_post["user_msg"]
inputs = tokenizer(user_input, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
return {"response": response}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
运行 API
启动 FastAPI 应用,确保你在命令行中运行:
Bash
uvicorn api:app --reload
这将启动一个本地服务器,你可以通过 http://127.0.0.1:8000/predict
端点来发送请求。
发送请求
使用 Python 的 requests 库发送 POST 请求来测试 API:
Python
import requests
user_msg = "你好"
response = requests.post("http://127.0.0.1:8000/predict", json={"user_msg": user_msg})
print(response.json())
模型调用
完成模型下载后,可以使用如下代码进入模型的评估模式:
Python
from modelscope import AutoModel, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)
model = AutoModel.from_pretrained(model_dir, trust_remote_code=True).cuda()
model.eval()
官方说上述代码需要占用大概 13GB 显存,但实际上在 RTX4070 12GB 上也能运行。
同时依据官方建议,使用如下模型量化代码可以在 6GB 显存的显卡上运行:
Python
model = AutoModel.from_pretrained("THUDM/chatglm3-6b", trust_remote_code=True).quantize(4).cuda()
对话
ChatGLM3 支持 chat()
和 stream_chat()
两种代码调用方式来实现模型对话。其中使用 chat()
方法模型会一次性返回当前回复的所有内容,而使用 stream_chat()
方法模型会流式输出当前回复的内容,也就是像使用 ChatGPT 那样一个字一个字的返回。
chat()
chat()
的使用比较简单,参考官方的代码示例:
Python
response, history = model.chat(tokenizer, "你好!", history=[])
print(response)
response, history = model.chat(tokenizer, "圣诞节是什么时候?", history=history)
print(response)
其中,response
即为模型的回复结果,为 str
类型;而 history
为 list
类型,可以理解为被用来保存用户与 ChatGLM3-6B 模型的聊天记录内容,大致的格式为 [{"role": "user", "content": "user questions"}, {"role": "assistant", "content": "llm answers"}, ...]
。
stream_chat()
为了拥有一个更好的使用体验,使用 stream_chat()
方法会是一个不错的方式。参考官方的命令行对话代码示例:
Python
# ...
while True:
# ...
current_length: int = 0
for response, history, past_key_values in model.stream_chat(
tokenizer,
user_question,
history=history,
top_p=1,
temperature=0.01,
past_key_values=past_key_values,
return_past_key_values=True,
):
print(response[current_length:], end="", flush=True)
current_length = len(response)
# ...
top_p 和 temperature
上述示例代码中 stream_chat()
方法用到了 top_p
和 temperature
参数,chat()
方法也同样支持这两个参数。
参考 《Prompt Engineering Guide》模型设置 这一章的内容:
- temperature 参数用来控制模型生成文本的随机性和创造性的参数,较高的值会使输出更具随机性,而较低的值则会使输出更具确定性。如果调高该参数值,大语言模型可能会返回更随机的结果,也就是说这可能会带来更多样化或更具创造性的产出。
- top_p 参数用来控制模型返回结果的真实性。如果你需要准确和事实的答案,就把参数值调低。如果你想要更多样化的答案,就把参数值调高一些。
一般建议是改变其中一个参数就行,不用两个都调整。