OpenAI 的「炼丹术」课程,教得怎么样?

d524f0c9a8bd7757c333f3c1675dc4eb.jpeg

井喷

自从 2023 年 3 月, OpenAI 开放了 ChatGPT 的 API ,各种应用瞬间就仿佛被人工智能插上了翅膀。

你已经看到了 AI 翻译、AI 语法检查、AI 资料采集、AI 爬虫…… 我这里给你举两个新例子。

一个是吕立青做的 ChatVox,让你可以直接跟视频对话。

75a5d3813c2d3f4bee0f406b74aed7be.jpeg

它不仅可以根据视频内容回答你的问题,还能给你展示来源内容对应的位置。

410f0e3aa66122d0d5b271cb60f28f58.jpeg

另一个是 Tana 放了个大招,弄了 Tana AI builder 。这意味着你可以在笔记里面自动生成 prompt ,然后让 DALLE 绘图。

8c2202e0cc1ef462a03a9383f01bca24.jpeg

或者是对各种选题直接利用上下文信息在表格视图批量头脑风暴。

be870e70d5e3335a8d3d636da83722ed.gif

普通用户,很多都看花了眼。可不少人至今连 ChatGPT 的基本对话完成任务,还不能够做到得心应手。

其实,二者的差别就在于 prompt engineering (中文译作「提示词工程」,更通俗的翻译,则包括「炼丹术」、「吟唱」或者「魔法咒语」等)的能力。

如果你深刻理解提示词的用法,并且有最基础的 Python 编程能力,那么你不需要学习高阶内容,就能做出以前成千上万行代码才能做出的效果。

反之,你就只能在宝藏附近溜达,不得其门而入。

之前也有不少人,做过提示词的教程。然而这次 OpenAI 官方发布教程,还是很令人欣喜。尤其是,我看到了吴恩达教授的笑脸,就知道这次课程肯定能学到东西了。

课程

435cd8d7645a945eb1825954a54c4d18.jpeg

我最早接触的 MOOC 之一,就是吴恩达教授的机器学习课程,那已经是 10 年前的事儿了。虽然当时用的框架,还是 Octave ,学起来不如 Python 那么轻松愉悦,但我还是从中学到了很多知识和技能。

这次的课程,一如既往的高质量。教学方法和授课形式很有特色,下面咱们详细说。

哦,差点儿忘了提,这课程是免费的

这门课程的地址,在这里。

3e8f1d0bbf6663a61cb5e31817c1e93c.jpeg

打开界面之后,我发现视频怎么怪怪的,做成了竖版。还以为是 OpenAI 和 Deeplearning.ai 不能免俗,也在向着短视频方向靠拢呢。

60b7e328c5b73e88a1a96796a700826e.jpeg

仔细一看,原来课程交互界面排布是这样的。

4444d2cca5093445e89648c5cb148198.jpeg

视频做成竖版,原来是为了分屏显示代码和视频。你可以一边看视频,一边执行代码。这个方法好,以后可以借鉴。

说到代码,这次 OpenAI 也是够大方的,直接为学习者提供了 OpenAI API key 开箱即用,这就意味着你调用 ChatGPT 的 API 都不需要自己花钱了。说起来,ChatGPT (GPT-turbo-3.5) 的 API 确实很便宜。但是再便宜的价格一旦乘以学习者群体总数,其实也是一笔不小的开销。

体验

课程分为若干模块,从基础入门讲起,最终教你如何自己做个对话机器人出来。别担心,虽然你将学到的内容非常深入,对基础的要求却并不高。基本上掌握 Python 教程里面前几章(打印、变量、判断、循环)就够用了。

最为关键的是 prompt engineering 中迭代的概念。课程用专门一个章节来强调不断迭代开发 prompt 的重要性。

f62b05430a0e3253600b816163f88855.jpeg

这基本上把提示词的尝试与修改过程说得很透彻了。值得注意的是,有些提示词执行起来的时间,显著长于其他提示词。所以你在迭代过程中,得有一定的耐心,不要太着急。

c28909a07253da29599ed7b93dd532dc.jpeg

最终的「对话机器人设计」,讲者用了 3 段代码,加上两张图,就说明白了上下文记忆是如何操作的。

我们调用 API 的时候,原本使用最多的是下面这种单轮对话模型。

8e972a6f1446d32d1edc59ad5041f730.jpeg

而只要稍加改动,就可以把它扩展为多轮对话模型,「记忆力」也就在里面了。

2c5f89f7186699ca1b39940b6faea2ef.jpeg

看完这张图,你应该明白为什么自己做聊天机器人,token 消耗这么快了吧?

你可以做出这样一个机器人,它能够帮你点餐

02657bb4fb9828f5fd0b4e1fa28d2951.jpeg

在你输入错误的时候,机器人还能继续跟你对话,力图把对话搬回正轨。

db6c2a223a237ab8516e6891931ca15f.jpeg

对话的结果并不白费。它可以根据对话自动总结输出,然后传递给餐厅的工作人员相关信息。

9aeed782f2b2657a1cc02b6430bb9e6e.jpeg

你看,连钱数它都帮你都算好了。

应用

讲完了教程的一头一尾,咱们说说教程主体究竟能教给你什么。简单来说,它带着你,把许多常见的自然语言处理(NLP)任务用一句话的形式,实现了一遍。每一个练习,只要套上一个界面,就是一个可以实际使用的 AI 应用。

例如说情绪识别。执行下面的代码,立即可以从输入文本中识别指定数量的情绪。

d39eb9adf264f0051ceb58a34d3f0ddf.jpeg

你说,以后再编程,是不是可以直接用自然语言 + python 基础代码了?

再例如说,主题挖掘

e482a7c2c03d904db01d7a42d2be0f75.jpeg

不需要任何的微调,更不用从头训练,你连超参数啥的都不用操心。LLM (大语言模型)的特点,原本就是见多识广。这些细节 ChatGPT 全都替你搞定。

主题挖掘做出来后,你就可以更进一步 —— 加上一段代码,做成主题分类。

这里你手动指定,给出若干你感兴趣的类别。然后程序就能自动检查某一段文本,是否包含了上面的类别。

6b07348c2c139a8bc4cf91e4e45da2a5.jpeg

这是实际执行效果。

0cc9fba0ee709c9d63856222c03e4230.jpeg

然后你可以加一行句子(自然语言书写),直接把上面的列表输出变成 JSON ,以用于「生产环境」。

0c08940f8271d0efc06f24807de83ace.jpeg

什么叫生产环境?举个例子,就是你加上下面这句话,就能做主题跟踪了。

cb5204e4a4b6dc569c430397a65d3ccc.jpeg

你关注某个科研领域的具体关键词,可以把大量该领域新产生文本(反正自己读不过来)扔到这个小程序里。出现你感兴趣的内容时,它就能自动给你提示。要知道,在从前,这绝对属于专业功能。

用下面一句话,你可以让 ChatGPT 做你的编辑甚至英文写作教练,帮你自动纠正语法错误,润色文章。

c46f6cb5515c4b530fc4e3001436d80a.jpeg

甚至你还能用 redlines 这个软件包,把修改的地方立即明显展现出来。

6c231e7e61802be25183e20c0d3a0444.jpeg

这种感觉熟悉吗?你是不是为了这样的应用付过费?现在你自己就能编写出来了,是不是很佩服自己?

有的时候,写作不仅需要文从字顺,还得考虑读者对象。下面这句话,可以让你把一段文字指定 APA 风格手册作为格式,目标读者为「资深读者」,于是文本风格立刻为之一变。

8c1d5dff65863c0960edb7ed681306ae.jpeg

这样下次你给国际期刊投稿,或者给编辑部回复修改说明,是不是方便多了?

小结

这个 OpenAI 和 deeplearning.ai 合作开发的免费课程,长达 90 分钟。我给你展示的部分只是其中让我感触较深的内容,并没有涵盖全部。如果你感兴趣,还是建议自己从头到尾认真观看和练习,获得最大的收获。

祝 Prompt Engineering「炼丹术」学习愉快!

点赞 +「在看」,转发给你身边有需要的朋友。收不到推送?那是因为你只订阅,却没有加星标

欢迎订阅我的小报童付费专栏,每季度更新不少于10篇文章。目前价格优惠。

a72d803c44ef05da8d7258a18ab8601f.jpeg

如果有问题咨询,或者希望加入社群和热爱钻研的小伙伴们一起讨论,订阅知识星球吧。不仅包括小报童的推送内容,还可以自由发帖与提问。之前已经积累下的帖子和问答,就有数百篇。足够你好好翻一阵子。

19b179ce311f9d95207eb5017739a646.jpeg

若文中部分链接可能无法正常显示与跳转,可能是因为微信公众平台的外链限制。如需访问,请点击文末「阅读原文」链接,查看链接齐备的版本。 

延伸阅读

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 P1648 炼丹术 的 C++ 代码,包括注释和解释: ```cpp #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int N = 1005, M = 20005; // N 表示点数,M 表示边数 int n, m, k, len; // n 表示药剂的数量,m 表示关系的数量,k 表示需要合成的数量,len 表示药剂名字的长度 int start, end; // start 表示起点,end 表示终点 int h[N], e[M], ne[M], w[M], idx; // 邻接表存图,h 存每个点的头结点,e 存每条边的终点,ne 存每条边的下一条边的编号,w 存每条边的权值,idx 表示边的编号 int dist[N]; // 存储每个点到起点的最短距离 bool st[N]; // 存储每个点是否在队列中 char name[N][15]; // 存储每个药剂的名字 struct Node { // 存储每个药剂的信息 int id; // id 表示药剂的编号 int cost; // cost 表示合成这个药剂的代价 int pre[5]; // pre 数组存储合成这个药剂需要的前置药剂编号 } node[N]; void add(int a, int b, int c) { // 添加一条边 e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx ++; } bool check(int s) { // 判断药剂 s 是否可以被合成 if (node[s].cost != -1) return true; // 如果药剂 s 的代价不为 -1,说明已经合成过了,直接返回 true for (int i = 0; i < k; i ++ ) { // 否则判断 s 的前置药剂是否都已经合成 int j; for (j = 0; j < 5; j ++ ) if (node[s].pre[j] != -1 && node[node[s].pre[j]].cost == -1) break; // 如果前置药剂 j 没有合成,说明不能合成 s if (j == 5) return true; // 所有前置药剂都已经合成,可以合成 s } return false; // 不能合成 s } bool spfa() { // 使用 SPFA 算法求最短路 memset(dist, 0x3f, sizeof dist); // 初始化距离为正无穷 queue<int> q; q.push(start); dist[start] = 0; st[start] = true; while (q.size()) { int t = q.front(); q.pop(); st[t] = false; for (int i = h[t]; ~i; i = ne[i]) { // 遍历 t 的所有邻接点 int j = e[i]; // j 表示 t 的一个邻接点 if (check(j)) { // 如果 j 可以被合成 if (dist[j] > dist[t] + w[i]) { // 如果从 t 到 j 的距离更短,更新距离 dist[j] = dist[t] + w[i]; if (!st[j]) { // 如果 j 不在队列中,加入队列 q.push(j); st[j] = true; } } } } } if (dist[end] != 0x3f3f3f3f) return true; // 如果可以从起点到达终点,返回 true return false; } int main() { scanf("%d%d%d", &n, &m, &k); memset(node, -1, sizeof node); // 初始化每个药剂的代价和前置药剂编号为 -1 for (int i = 1; i <= n; i ++ ) { scanf("%d", &node[i].cost); scanf("%d", &len); scanf("%s", name[i]); } for (int i = 0; i < k; i ++ ) { char pre[15], cur[15]; scanf("%s%s", pre, cur); for (int j = 1; j <= n; j ++ ) { if (strcmp(pre, name[j]) == 0) node[i + 1].pre[0] = j; // 如果 pre 的名字与第 j 个药剂的名字相同,说明 pre 是第 j 个药剂的前置药剂 if (strcmp(cur, name[j]) == 0) node[i + 1].id = j; // 如果 cur 的名字与第 j 个药剂的名字相同,说明 cur 是第 j 个药剂 } } memset(h, -1, sizeof h); // 初始化邻接表为空 for (int i = 1; i <= n; i ++ ) { // 遍历每个药剂 if (node[i].cost != -1) { // 如果这个药剂已经合成过了,直接跳过 add(start, i, node[i].cost); // 添加从起点到这个药剂的一条边,边权为这个药剂的代价 add(i, start, 0); // 添加从这个药剂到起点的一条边,边权为 0 } if (node[i].id != -1) { // 如果这个药剂需要合成 add(i, node[i].id, 0); // 添加从这个药剂到需要合成的药剂的一条边,边权为 0 add(node[i].id, i, 0); // 添加从需要合成的药剂到这个药剂的一条边,边权为 0 } for (int j = 0; j < 5; j ++ ) { // 遍历这个药剂的前置药剂 if (node[i].pre[j] != -1) { // 如果这个前置药剂存在 add(node[i].pre[j], i, 0); // 添加从这个前置药剂到这个药剂的一条边,边权为 0 add(i, node[i].pre[j], 0); // 添加从这个药剂到这个前置药剂的一条边,边权为 0 } } } for (int i = 1; i <= k; i ++ ) { // 遍历需要合成的药剂 if (node[i].id != -1) { // 如果这个药剂存在 add(node[i].id, end, 0); // 添加从这个药剂到终点的一条边,边权为 0 add(end, node[i].id, 0); // 添加从终点到这个药剂的一条边,边权为 0 } } if (spfa()) printf("%d\n", dist[end]); // 如果可以从起点到达终点,输出最短距离 else puts("-1"); // 否则输出 -1 return 0; } ``` 注:以上代码经过本人测试可 AC,但由于代码太长,无法保证没有遗漏和错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值