ChatGPT-Next-Web icon indicating copy to clipboard operation
ChatGPT-Next-Web copied to clipboard

Zero, One and Few Shot Prompting

Open realskyrin opened this issue 1 year ago • 47 comments

Few-show 可以简单的理解为在发送 prompt 时提前做一个 context mock,通过少量引导可以显著提升 AI 回复质量的技巧。

例如这个查单词小工具

#!/usr/bin/env python3
# This is an English word search assistant.

import json
import requests
import sys
import os

OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY')
OPENAI_BASE_URL = os.environ.get('OPENAI_BASE_URL')


def query(message):
    message = json.dumps(message)

    if len(sys.argv) > 1:
        prompt = "你是一个英语单词查询助手,每当用户发送一个英语单词给你,你都要以固定格式响应用户," \
                 "如果用户发给你的不是一个单词,回复 'invalid token'"

        response_few_shot_text = "run [/rʌn/]" \
                                 "\n\nn. 奔跑;竞赛;连续的演出\nHe went for a run after work. (他下班后去跑步了)" \
                                 "\n\nv. 奔跑;运行\nI like to run in the park every morning. (我喜欢每天早上在公园里跑步)" \
                                 "\n\nadj. 连续的;流畅的\nThis printer is really fast and runs smoothly. (这台打印机速度非常快,而且运行流畅)"
    else:
        print("This is an English word search assistant")
        print("Usage: qr word")
        return

    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {OPENAI_API_KEY}"
    }

    data = {
        "model": "gpt-3.5-turbo",
        "temperature": 0,
        "top_p": 1,
        "frequency_penalty": 1,
        "presence_penalty": 1,
        "stream": False,
        "messages": [
            {"role": "system", "content": prompt},
            {"role": "user", "content": "run"},
            {"role": "assistant", "content": response_few_shot_text},
            {"role": "user", "content": message}
        ]
    }

    response = requests.post(OPENAI_BASE_URL, headers=headers, data=json.dumps(data))

    answer = json.loads(response.content)["choices"][0]["message"]["content"].strip()
    print("\033[32m---🤖---------\033[0m")
    print(answer)
    print("\033[32m--------------\033[0m")


if __name__ == "__main__":
    query(" ".join(sys.argv[1:]))

我在 request message 中 mock 了 system prompt、user 发送的第一个 prompt 以及 assistant 的一个 response

"messages": [
    {"role": "system", "content": prompt},
    {"role": "user", "content": "run"},
    {"role": "assistant", "content": response_few_shot_text},
    {"role": "user", "content": message}
]

那么我之后再发送任何单词,它都会很规范的返回结果 (返回单词的所有词性并造句),因为 context 里已经 mock 了它返回的第一个结果,它知道接下来该怎么回复,而无需向它解释过多的东西 image

如果直接给它发消息作为 prompt 也就是直接一条 user prompt,效果就会差很多,有时候每个词性给出多条例句,或者就只给一个词性的例句

image image

这是 openai-cookbook 中关于 Few shot 的介绍:https://github.com/openai/openai-cookbook/blob/main/techniques_to_improve_reliability.md#few-shot-examples

除此之外,Few-shot 也有助于 AI 进行链式思维以提升结果的准确率,可以应用到很多场景。

我的想法是,可以给每个可以给每个 chat 单独设置 system、user、assistant 这些预设,简单一点的做法是给一个输入框,可以填入整个 request message 部分的 json :

"messages": [
    {"role": "system", "content": sys_prompt},
    {"role": "user", "content": "user_prompt"},
    {"role": "assistant", "content": response_few_shot_text},
    {"role": "user", "content": user_message}
]

请求的时候直接带上这个预设的 message。而且每次 request 仅带这个 message,不需要传入其它上下文,这样一来这个 chat 就变成一个相当稳定且节省 Token 的小工具了。

总之,这个项目非常很赞,只可惜自己不会前端所以以上想法没法直接提 PR,今天现在开始学前端 😂

支持一波 4321680072417_ pic

realskyrin avatar Mar 29 '23 06:03 realskyrin

Prompt 列表是刚加的功能,后期会允许用户编辑单个对话的预设 prompt,和你说的功能应该是一致的,可以耐心等待。

Yidadaa avatar Mar 29 '23 06:03 Yidadaa

学到了,Few-show 确实很有用 😌

tisfeng avatar Mar 29 '23 16:03 tisfeng

一点UX构思 228723779-70159680-c0a1-494c-9043-452813908f6a

228725778-8ce2bc1c-ad77-48d8-8c27-72b5f5085cb3

后续如果可能的话,可以把全局设置中的模型、随机性那部分挪到 Chat 设置的层级,使每个 Chat 的定义更灵活

realskyrin avatar Mar 30 '23 04:03 realskyrin

赞,很有用的技巧

Cranberrycrisp avatar Mar 31 '23 08:03 Cranberrycrisp

Prompt 列表是刚加的功能,后期会允许用户编辑单个对话的预设 prompt,和你说的功能应该是一致的,可以耐心等待。

如果用户每次对话都单独预设system role感觉有些繁琐,看到chatgpt-vercel这个项目里面是直接加到系统设置里面的。应该也是一种可以参考的方式

tiwentichat avatar Mar 31 '23 15:03 tiwentichat

Prompt 列表是刚加的功能,后期会允许用户编辑单个对话的预设 prompt,和你说的功能应该是一致的,可以耐心等待。

如果用户每次对话都单独预设system role感觉有些繁琐,看到chatgpt-vercel这个项目里面是直接加到系统设置里面的。应该也是一种可以参考的方式

这是可选的而不是强制的,如果不给对话设置 system、user、assistant 这些 in-context,那它就只是一个普通会话,不影响其原有属性。

realskyrin avatar Apr 01 '23 01:04 realskyrin

另外多普及一点,in-context 中的 user、assistant prompt 和 system prompt 一样重要,要不然它们也没必要出现在 API 的示例中。OpenAI 的论文里有很多试验结果已经表明了 Few-shot 可以提升模型解决针对性问题的能力,一个 shot 其实就是 in-context 中的一个 user + assistant 的一问一答,给的例子越多它越准。

比如我上面给出的英语查单词小程序就是 1 shot,针对更复杂的应用场景你可以做 8 shot、25 shot。比较遗憾的是,目前我看到的所有套壳,都没有自定义 Few-shot 的功能,都是 0 shot,可能是觉得这样更方便使用?或者是大家不了解 Few-shot 这个概念,这无疑是把这条强大 API 的能力给绑起来了。我认为一个好的 AI 工具是给 AI 松绑而不是相反。

realskyrin avatar Apr 01 '23 01:04 realskyrin

感谢提供信息,我会考虑在单个对话页加入更详细的 few shot 编辑界面,让用户提供更丰富的预设上下文信息。

Yidadaa avatar Apr 01 '23 05:04 Yidadaa

realskyrin你的想法非常棒,经过你的启发,我是这么思考这一功能的。以函数的形式封装每一个功能,比如翻译,英文纠正。在用户选择初始化页面的时候,选择需要导入的function。类似我们coding时候的import。下面我给出几个例子,这些例子,我在3.5测试过,没有问题。如果是4的话效果更佳。

首先需要给GPT定义函数的prompt。

Hello, ChatGPT! I hope you are doing well. I am reaching out to you for assistance with a specific function. I understand that you have the capability to process information and perform various tasks based on the instructions provided. In order to help you understand my request more easily, I will be using a template to describe the function, input, and instructions on what to do with the input. Please find the details below:

function_name: [Function Name]
input: [Input]
rule: [Instructions on how to process the input]

I kindly request you to provide the output for this function, based on the details I have provided. Your assistance is greatly appreciated. Thank you!
I will replace the text inside the brackets with the relevant information for the function I want you to perform. This detailed introduction should help you understand my request more efficiently and provide the desired output. The format is function_name(input) If you understand, just answer one word with ok.

然后编写函数trans_word(这是一个可以输入中文,翻译成英语的function)

function_name: [trans_word]
input: ["text"]
rule: [I want you to act as an English translator, spelling corrector and improver. I will provide you with input forms including "text" in any language and you will detect the language, translate it and answer in the corrected of my text, in English.]

然后编写函数expand_word(输入英文,扩充文本)

function_name: [expand_word]
input: ["text"]
rule: [Please serve as a Chatterbox, spelling corrector, and language enhancer. I will provide you with input forms including "text" in any language, and output the original language.I want you to Keep the meaning same, but make them more literary.]

然后编写函数fix_english(输入英文,修改美化文本)

function_name: [fix_english]
input: ["text"]
rule: [Please serve as an English translator, spelling corrector, and language enhancer. I will provide you with input forms including "text", I want you to improve the text's vocabulary and sentences with more natural and native. Keep the meaning same.]

finally, 到了最终的时候了, 调用函数、甚至可以链式调用。

trans_word('婆罗摩火山处于享有“千岛之国”美称的印度尼西亚。多岛之国印尼有4500座之多的火山,世界著名的十大活火山有三座在这里。')
fix_english('Act as an English Translator and Improver')
fix_english(expand_word(trans_word('婆罗摩火山处于享有“千岛之国”美称的印度尼西亚。多岛之国印尼有4500座之多的火山,世界著名的十大活火山有三座在这里。')))

多参数的function也不在话下,可以省略参数名,也可以显式指定

function_name: [pg]
input: ["length", "capitalized", "lowercase", "numbers", "special"]
what to do with input: [I want you to act as a password generator for individuals in need of a secure password. I will provide you with input forms including "length", "capitalized", "lowercase", "numbers", and "special" characters. Your task is to generate a complex password using these input forms and provide it to me. Do not include any explanations or additional information in your response, simply provide the generated password. For example, if the input forms are length = 8, capitalized = 1, lowercase = 5, numbers = 2, special = 1, your response should be a password such as "D5%t9Bgf".]

pg(length = 10, capitalized = 1, lowercase = 5, numbers = 2, special = 1)
pg(10,1,5,2,1)

畅想,最后可以积木式调用,形成无限扩展。还可以形成指定领域的package,供别人使用。面向GPT编程, 哈哈哈。如果大家觉得这个想法不错,可以一起搞搞事情。

xiaodi007 avatar Apr 02 '23 02:04 xiaodi007

畅想,最后可以积木式调用,形成无限扩展。还可以形成指定领域的package,供别人使用。面向GPT编程, 哈哈哈。如果大家觉得这个想法不错,可以一起搞搞事情。

你这个思路很好,事实上很多基于 GPT 做的复杂应用也是这个路子(巨硬家的各种 Copilot),把需求进行无限拆解,拆到能被 GPT 稳定完成的一个个 function,因为 API 是可以并发去 call 的。所以在这些 function call 完之后把结果再组装回来,就能搞出很惊艳的效果。OpenAI 的这条 completion API 真的是有无限可能,值得好好学习。

realskyrin avatar Apr 02 '23 03:04 realskyrin

@xiaodi007 langchain 正在做这个事情,官方的 chatgpt plugin 应该也是类似的思路。

Yidadaa avatar Apr 02 '23 12:04 Yidadaa

目前已经增加 contextual prompt 自定义功能,可以自行指定前置对话列表,可以尝试一下,入口:

  • 对话框顶部 toast
  • header 记忆 button

Yidadaa avatar Apr 02 '23 18:04 Yidadaa

目前已经增加 contextual prompt 自定义功能,可以自行指定前置对话列表,可以尝试一下,入口:

  • 对话框顶部 toast
  • header 记忆 button

@Yidadaa 试了一下,设计的非常棒,基本上就是这个效果了,辛苦了☕️

我用了 3 shot 让它实现 Grammarly 的功能。前面的 response 看起来还可,后面问了句重复的,它说它前面翻译过了😂,看起来它还是记忆了预设 context 之外的信息,这种进行过 Few-shot 的工具不需要任何除预设 context 之外的信息,可以给个 CheckBox 让用户勾选是否记住上下文,否则会影准确性。

Context prompt WeChat58dabcb6050fca19304252c1004c036a

WeChatfe5f6403ab638ef3acd0252b100088e4

使用示例 WeChat66fe2b3488c77520c937b5e2d81772c8

WeChat9c917ff3307882c7b0e1af290a61fa80

realskyrin avatar Apr 03 '23 03:04 realskyrin

66666,好用

tiwentichat avatar Apr 03 '23 03:04 tiwentichat

@realskyrin

在设置里把历史消息数量设置为 0 就行。

Yidadaa avatar Apr 03 '23 03:04 Yidadaa

@realskyrin

在设置里把历史消息数量设置为 0 就行。

👍👍👍 可以了

realskyrin avatar Apr 03 '23 03:04 realskyrin

@realskyrin

在设置里把历史消息数量设置为 0 就行。

但是现在的版本里面如果这么做的话,会不太方便。 所以建议:

  1. 能否增加记忆的模板管理,并选择对应的记忆模板。(默认新聊天不使用记忆模板)
  2. 记忆模板,无法快速粘贴导入,建议增加支持

第一个需求的实现的话,就可以满足重复使用记忆的能力了。(不然对话删除了就得重新再添加记忆)

zealotCE avatar Apr 03 '23 08:04 zealotCE

@realskyrin 在设置里把历史消息数量设置为 0 就行。

但是现在的版本里面如果这么做的话,会不太方便。 所以建议:

  1. 能否增加记忆的模板管理,并选择对应的记忆模板。(默认新聊天不使用记忆模板)
  2. 记忆模板,无法快速粘贴导入,建议增加支持

第一个需求的实现的话,就可以满足重复使用记忆的能力了。(不然对话删除了就得重新再添加记忆)

@zealotCE Json 模版导入导出这个功能确实刚需,便于小工具分享和导入,不过这是个新需求了,可以新开 issues 进行讨论

realskyrin avatar Apr 03 '23 08:04 realskyrin

@zealotCE 这个建议,其实和 prompt store 的思路是相通的。我的想法是用 json 导入导出,包括自定义提示词、如果以后有在线导入都遵循这个规范:

  1. 一组 Few-show ,其实就是 messages 中的多组 content 预设。
{"messages": [
  {"role": "system","content": "Role definition"},
  {"role": "user","content": "Input"},
  {"role": "assistant","content": "Output"}
]}
  1. 单个 prompt,其实就是一个 user content 预设
{"messages": [
  {"role": "user","content": "prompt"},
]}

这样就打通了前置上下文提示词的功能。同样,希望能单独设置 前置上下文 Chat 自定义历史消息,很多时候用前置上下文并不需要历史消息,但又希望不影响其他对话。

我已经把 ChatGPT 集成到程序里,审核中文内容(能理解含义,其他AI无法做到)、做心理咨询,都是通过固定的 Json 格式输出,方便程序进一步处理。按这样 ChatGPT 能扩展出很多功能,不仅仅是聊天AI。

Cp0204 avatar Apr 03 '23 09:04 Cp0204

是的,确实是这样。 另外,这里面还需要增加一个需求,就是关闭记忆,仅使用预设的 Few-show 来进行。不然,连续的对话,会导致模型不按照最早的预期走。

zealotCE avatar Apr 03 '23 09:04 zealotCE

是的,确实是这样。 另外,这里面还需要增加一个需求,就是关闭记忆,仅使用预设的 Few-show 来进行。不然,连续的对话,会导致模型不按照最早的预期走。

确实需要一个 Chat 级别的 CheckBox 开关来控制是否携带出预设之外的 Context。全局的那个设置为 0 之后,新建的其它普通 Chat 就没有上下文了

realskyrin avatar Apr 03 '23 10:04 realskyrin

@Yidadaa ,另外发现两个小问题,通过 Request Payload 看到请求 Message 中携带了一个 system 角色的历史记忆总结,这个会影响 Few-shot 的稳定,建议在 Chat 级别的开关去掉。还有个问题是 \n 换行符在 Payload 中被转成 \\n 不知道这是不是预期的情况,从返回结果中看这回导致它直接返回 \n\n在消息中,而不是两个换行。

WeChat9ca5dc03d7de70cb8fc86ef1f84fccf1

realskyrin avatar Apr 03 '23 11:04 realskyrin

@realskyrin

在设置里把历史消息数量设置为 0 就行。

请问作者能否每个 chat 单独设置历史消息数量呢?

ClarenceYk avatar Apr 04 '23 05:04 ClarenceYk

之后会更新此功能。

Yidadaa avatar Apr 04 '23 06:04 Yidadaa

感觉目前这种添加Few-show的方式太容易被清除破坏了 对不不想变动、固定格式的对话,不太方便 有没有更好的法子Yidadaa

asaketsu avatar Apr 08 '23 03:04 asaketsu

@asaketsu 重置对话或者清除,并不会清理前置上下文,你升级最新版看看

realskyrin avatar Apr 08 '23 07:04 realskyrin

目前已经增加 contextual prompt 自定义功能,可以自行指定前置对话列表,可以尝试一下,入口:

  • 对话框顶部 toast
  • header 记忆 button

@Yidadaa 试了一下,设计的非常棒,基本上就是这个效果了,辛苦了☕️

我用了 3 shot 让它实现 Grammarly 的功能。前面的 response 看起来还可,后面问了句重复的,它说它前面翻译过了😂,看起来它还是记忆了预设 context 之外的信息,这种进行过 Few-shot 的工具不需要任何除预设 context 之外的信息,可以给个 CheckBox 让用户勾选是否记住上下文,否则会影准确性。

Context prompt

WeChat58dabcb6050fca19304252c1004c036a WeChatfe5f6403ab638ef3acd0252b100088e4

使用示例

WeChat66fe2b3488c77520c937b5e2d81772c8 WeChat9c917ff3307882c7b0e1af290a61fa80

试了下,并不会保留用删除线标记的单词,只能对订正后的单词保留标记

hostemail avatar Apr 14 '23 14:04 hostemail

大家好,

经过几天的开发,2.0 版本的重磅功能“预设角色”将于这两天上线,我将其命名为“面具”功能,基于此功能,各位可以十分方便地创建、调试、分享本 issue 提到的 zero/one/few shot prompting,以此来充分定制化大语言模型的能力。

在推送到主线之前,特来邀请各位试用此功能,试用链接:v2.0 试用地址

各位在试用过程中遇到任何问题,都可以在此处回帖,我会一一解答。

下面是一些截图:

image

image

image

Yidadaa avatar Apr 27 '23 03:04 Yidadaa

image image

设置的上下文如下:

image

看起来逃逸了

selfboot avatar Apr 27 '23 03:04 selfboot

@selfboot 比较考验 prompt 质量,需要反复强调不要尝试理解用户说的话的内容,然后在模型设置里关闭历史消息数、关闭历史消息压缩。不过我自己测下来,还是会有逃逸的情况。

Yidadaa avatar Apr 27 '23 03:04 Yidadaa