Redis作者antirez谈LLM和编程

13 篇文章 15 订阅 ¥9.90 ¥99.00
12 篇文章 0 订阅

文章主要内容来自Redis之神(作者)antirez对于使用LLM后的“获奖感言”

文章要点

0、与大型语言模型(LLM)协作,学会让其为简单问题提供答案,这样可以更高效地利用时间。
1、正确地向LLM提问是一项基本技能。
2、在与他人交流时,提高描述问题的能力同样重要,因为不仅LLM,有时不是每个人都明白我们的意图。
3、搜索引擎可能会被LLM替代,因此在寻求信息时,首先应咨询LLM,但同样需要有辨别能力。
4、哲学观点:相信亲眼所见似乎是一个明智的方法。

文章内容

我首先要说的是,这篇文章并不是对 LLM 的回顾。很明显,2023 年对人工智能来说是特殊的一年:重申这一点似乎毫无意义。相反,这篇文章旨从人程序员角度提供一些LLM的使用心得体会。自从 ChatGPT 出现以来,以及后来通过使用在本地运行的 LLM,我广泛使用了这项新技术。目标是提高我编写代码的能力,但这不是唯一的目的。还有一个意图是不要在不值得付出努力的编程方面浪费精力。例如:花了无数时间搜索关于奇特的、智力上无趣的方面的文档;努力学习过于复杂的 API,通常没有充分的理由;编写立即可用的程序,几个小时后我会丢弃这些程序——这些都是我不想做的事情,尤其是现在,谷歌已经变成了一个垃圾邮件的海洋,在其中寻找一些有用的东西变成了一件极具挑战的事情。

同时,我当然不是编程新手。我能够在没有任何帮助的情况下编写代码,事实上,我经常这样做。随着时间的流逝,我越来越多地使用 LLM 来编写高级代码,尤其是在 Python 中,而在 C 中则更少。我个人对 LLM 的体验让我印象深刻的是,我已经准确地学会了何时使用它们以及何时使用它们只会减慢我的速度。我还了解到,LLM有点像维基百科和散落在YouTube上的所有视频课程:它们帮助那些有意愿、有能力和纪律的人,但对那些落后的人却是微不足道的。我担心至少在最初,它们只会使那些已经拥有优势的人受益。

但是,让我们一步一步来。

1 无所不知还是鹦鹉学舌

机器学习新浪潮中最令人担忧的现象之一是人工智能专家接受其有限知识的能力有限(能力有限的ai专家接受了他们只掌握了有限的、关于LLM的知识)。人类发明了神经网络,然后,更关键的是,发明了一种自动优化神经网络参数的算法。硬件已经能够训练越来越大的模型,并且利用有关要处理的数据(先验)的统计知识,并通过对连续近似的大量试验和错误,已经发现比其他架构工作得更好。但总而言之,神经网络仍然相当不透明。

面对这种无法解释LLM的某些新兴能力,人们本来希望科学家更加谨慎。相反,许多人严重低估了LLM,说它们毕竟只不过是某种程度上先进的马尔可夫链,最多能够鹦鹉学舌般复述他们在训练集中看到的极其有限的变化。然后,在证据面前,鹦鹉的这种概念几乎被普遍撤回。

与此同时,许多热情的群众将LLM归因于现实中不存在的超自然力量。不幸的是,LLM 最多只能在它们在训练期间看到的数据所表示的空间中进行插值:这已经很多了。实际上,它们的插值能力是有限的(但仍然令人惊讶,也出乎意料)。(译者:请注意这个说法,人类是不是也是在有限的语言空间中插值呢,我的所组织出的语言或者想法其实一直局限在有限的空间,甚至所谓的创新也是差值而已,想到这里竟有一丝感慨!)哦,要是今天最大的 LLM 能在他们所看到的所有代码所限制的空间中连续插值就好了!即使他们无法产生真正的新奇事物,他们也能够取代 99% 的程序员。现实情况更为温和,几乎总是如此。LLM当然能够以这种确切的形式编写它从未见过的程序,显示出一定的能力,可以以一定的频率混合训练集中出现的不同想法。同样明显的是,目前这种能力有很深的局限性,每当需要微妙的推理时,LLM就会灾难性地失败。然而,它们代表了人工智能从诞生到今天的最大成就。这似乎是不可否认的。

2 愚蠢但无所不知

这是真的:LLM最多只能进行基本的推理,通常不准确,很多时候充满了对不存在的事实的幻觉。但他们拥有广阔的知识。在编程领域,以及其他有高质量数据的领域,LLM就像愚蠢的学者,知道很多事情。与这样的伙伴进行结对编程是很糟糕的(对我来说,即使在最一般的术语中,结对编程也是可怕的):他们会有荒谬的想法,我们将不得不不断努力强加我们自己的想法。但是,如果这个博学的傻瓜随时待命并回答了向他们提出的所有问题,事情就会改变。目前的LLM不会把我们带到知识的道路上,但如果我们想解决一个我们不太了解的话题,它们通常可以把我们从绝对的无知中提升到我们有足够的知识来自己前进的地步。

在编程领域,也许直到二三十年前,他们的能力都很少引起人们的兴趣。那时候,你必须知道几种编程语言、经典算法和这十个基本库。剩下的你必须加上你自己,你自己的智慧、专业知识、设计技能。如果你具备这些要素,你就是一个专业的程序员,能够或多或少地做任何事情。随着时间的流逝,我们目睹了框架、编程语言和各种库的爆炸式增长。复杂性的爆炸往往是完全不必要和不合理的,但事实是,事情就是这样。而在这样的背景下,一个无所不知的白痴,却是宝贵的盟友。

让我举个例子:我的机器学习实验使用 Keras 进行了至少一年。然后出于各种原因,我切换到了 PyTorch。我已经知道什么是嵌入或残差网络,但我不想一步一步地研究 PyTorch 的文档(就像我对 Keras 所做的那样,我在 ChatGPT 还不存在时学到了这一点)。使用 LLM,编写使用 Torch 的 Python 代码非常容易。我只需要对我想组合的模型有清晰的想法,并提出正确的问题。

3 是时候举例了

我不是在谈论简单的事情,比如:“嘿,X类做Y的方法是什么”?如果只是为了这个,人们可能会同意那些对 LLM 持怀疑态度的人。更复杂的模型能够做什么,这要复杂得多。直到几年前,这还是纯粹的魔法。我可以告诉 GPT4:看,这是我在 PyTorch 中实现的神经网络模型。这些是我的批次。我想调整张量的大小,以便发出批处理的函数与神经网络的输入兼容,我想用这种特殊的方式表示事物。你能告诉我进行重塑所需的代码吗?GPT4 编写代码,我所要做的就是在 Python CLI 中测试张量是否真的具有对我有用的维度以及数据布局是否正确。

这是另一个例子。前段时间,我不得不为某些基于 ESP32 的设备实现 BLE 客户端。经过一番研究,我意识到多平台蓝牙编程绑定或多或少都无法使用。解决方案很简单,使用 macOS 的原生 API 在 Objective C 中编写代码。因此,我发现自己必须同时处理两个问题:学习目标 C 中繁琐的 BLE API,其中充满了我认为荒谬的模式(我是一个极简主义者,这种 API 与我认为的“好设计”处于光谱的另一端),同时记住如何在目标 C 中编程。我上一次用 Objective C 编写程序是在十年前:我不记得事件循环、内存管理等细节。

最终的结果是这里的这段代码,虽然不算很漂亮,但它做了它必须做的事情。我在极短的时间内写完了它。否则是不可能的。

https://github.com/antirez/freakwan/blob/main/osx-bte-cli/SerialBTE.m

代码主要是通过在 ChatGPT 上剪切和粘贴我想做的事情来编写的,但不太知道如何做,所以它们无法正常工作。让LLM向我解释问题是什么以及如何解决它。的确,LLM没有编写太多代码,但它也确实大大加快了编写速度。如果没有 ChatGPT,我能做到吗?当然是的,但最有趣的是,它不需要我更长的时间:事实是我甚至不会尝试,因为这不值得。这一事实至关重要。编写这样一个程序的努力和收益之间的比例,次要于我的项目,会很不方便。此外,这比程序本身具有更有用的次要附带效应:对于该项目,我修改了线噪声(我的线编辑库之一),使其在多路复用中工作。

另一个例子,这次不是关于代码编写,而是关于数据解释。我想使用我在网上找到的卷积神经网络来设置一个 Python 脚本,但它缺乏文档。该网络的优点是采用 ONNX 格式,因此我可以轻松提取输入和输出列表及其分配的名称。关于这个卷积网络,我只知道一件事:它检测图像中的某些特征。我不知道输入图像的格式和大小,特别是,网络的输出比我想象的要复杂得多(我以为这是一个二元分类器:观察到的图像是好的还是有问题的?两个输出,但有数百个)。我首先将 ONNX 网络元数据输出复制粘贴到 ChatGPT 中。我向助手解释我对网络知之甚少。ChatGPT 假设输入是如何组织的,并且输出可能是归一化的框,表示与潜在缺陷相对应的图像部分,而其他输出则表示这些缺陷的可能性。经过几分钟的来回奔波,我得到了一个能够进行网络推理的 Python 脚本,以及将起始图像转换为适合输入的张量的必要代码,依此类推。那次会议让我印象深刻的是,ChatGPT 在观察测试图像上的原始输出值(基本上是 logits)后,终于“理解”了网络是如何运作的:一系列浮点数字提供了识别确切输出细节的上下文、归一化、框是否居中或是否指定了左上角, 等等。

4 一次性程序

我可以记录我上面叙述的几十个这样的案例。这将是毫无意义的,因为它是同一个故事或多或少以相同的方式重复。我有一个问题,我需要快速知道一些事情,*我可以验证*LLM是否在胡说八道。好吧,在这种情况下,我使用LLM来加速我对知识的需求。

但是,在不同的情况下,我让 LLM 编写所有代码。例如,每当我需要编写一个或多或少的一次性程序时。像这样:

https://github.com/antirez/simple-language-model/blob/main/plot.py

我需要在学习小型神经网络的过程中可视化损失曲线。我在学习过程中向 GPT4 展示了 PyTorch 程序生成的 CSV 文件的格式,然后我要求如果我在命令行上指定了多个 CSV 文件,我不再想要同一个实验的训练和验证损失曲线,而是不同实验的验证损失曲线的比较。以上是 GPT4 生成的结果。总共三十秒。

同样,我需要一个程序来阅读 AirBnB CSV 报告,并按月和年对我的公寓进行分组。然后,考虑到清洁成本和每次预订的晚数,它将对一年中不同月份的平均租金价格进行统计。这个程序对我来说非常有用。同时,写它是致命的无聊:没有什么有趣的。所以我拿了一个很好的 CSV 文件,并在 GPT4 上进行了复制粘贴。我写信给LLM要解决的问题:程序在第一次尝试时就起作用了。我在下面完整地向您展示。

```python

import pandas as pd

pd.set_option('display.max_rows', None)

df = pd.read_csv('listings.csv')

reservations = df[df['Type'] == 'Reservation']

reservations['Start Date'] = pd.to_datetime(reservations['Start Date'])

reservations['Year'] = reservations['Start Date'].dt.year

reservations['Month'] = reservations['Start Date'].dt.month

reservations['Nightly Rate'] = (reservations['Amount'] - reservations['Cleaning Fee']) / reservations['Nights']

all_listings = reservations['Listing'].unique()

all_years = reservations['Year'].unique()

all_months = range(1, 13)

index = pd.MultiIndex.from_product([all_listings, all_years, all_months], names=['Listing', 'Year', 'Month'])

all_data = pd.DataFrame(index=index).reset_index()

merged_data = pd.merge(all_data, reservations, on=['Listing', 'Year', 'Month'], how='left')

average_nightly_rates = merged_data.groupby(['Listing', 'Year', 'Month'])['Nightly Rate'].mean().fillna(0)

print(average_nightly_rates)

```

要确切地理解如何对数据进行分组,这些数据本来是相当分散和无序的,需要一些简单的推理:这不是一个LLM可以简单地通过反刍近似于它所看到的语言来解决的问题。GPT4 在训练期间肯定观察到过类似的程序,但几乎可以肯定的是,没有看到一个程序必须按照我要求的确切方式和具有该特定格式的 CSV 文件对事物进行分组。这表明(在我看来)LLM 可以在某种程度上在训练集中不同程序概述的空间内进行插值。

在我看来,编写这种类型的程序是轻率地使用我的时间。LLM可以为我做这件事,这无疑加快了我以一种相当直接的方式生成代码的能力:我可以专注于重要的事情。

5 当事情没有按预期进行时: 系统编程

尽管我在 LLM 和编程方面取得了成功,但当我用 C 语言编写程序时,我几乎总是只将 LLM 作为一种更方便的文档形式。我是系统编程方面的专家,在这种情况下,只有当LLM能够进行复杂的推理时,它们才会对我有用:在这种情况下,它们几乎总是失败。

让我们从这个实验的提示开始:

概述一个漂亮、小而有效的 Bloom 过滤器的 C 实现的要求。重点关注哈希函数的重要方面。然后用高质量的 C 写它。

此外,请考虑示例实现的大小应为存储 100,000 个元素,误报概率最多为 5%。添加的元素是以 null 结尾的字符串。

```c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <math.h>

#define N 100000  // Number of elements

#define P 0.05    // False positive probability

#define M (int)(-(N * log(P)) / (log(2) * log(2)))  // Size of bit array

#define K (int)(M / N * log(2))  // Number of hash functions

unsigned char bitArray[M / 8 + 1];

void setBit(int n) {

    bitArray[n / 8] |= 1 << (n % 8);

}

int getBit(int n) {

    return bitArray[n / 8] & (1 << (n % 8));

}

// Basic hash functions (for demonstration purposes)

int hash1(char *str) {

    int hash = 5381;

    int c;

    while ((c = *str++))

        hash = ((hash << 5) + hash) + c;

    return abs(hash % M);

}

int hash2(char *str) {

    unsigned long hash = 0;

    int c;

    while ((c = *str++))

        hash = c + (hash << 6) + (hash << 16) - hash;

    return abs(hash % M);

}

void add(char *str) {

    setBit(hash1(str));

    setBit(hash2(str));

    // Add more hash functions if needed

}

int is_in(char *str) {

    return getBit(hash1(str)) && getBit(hash2(str));

    // Check more hash functions if used

}

int main() {

    char *testStr = "testString";

    add(testStr);

    if (is_in(testStr)) {

        printf("%s is probably in the set.\n", testStr);

    } else {

        printf("%s is definitely not in the set.\n", testStr);

    }

    return 0;

}

```

GPT4 产生的实现并不完全出色。布隆过滤器非常普遍。它不是一种奇特的数据结构。然而,很明显,编写一个像样的布隆过滤器需要更大的抽象能力:例如,存在一个问题,即找到一种有效的方法来对同一个字符串进行 N 次哈希处理,并确保哈希值充分去相关。

然而,如果你明确要求 GPT4 修改哈希函数,使其产生 N 个去相关输出,它提出的解决方案要容易得多:

```c

unsigned int hash(const char* str, unsigned int hash_id) {

    unsigned int hash = 5381;

    int c;

    while ((c = *str++)) {

        hash = ((hash << 5) + hash) + c + hash_id;

    }

    return hash % BF_SIZE;

}

```

如果它自己想出这个想法,它会以不同的方式编写布隆过滤器,使用单个哈希函数一次设置 K 位。

GPT4 能够单独执行编写适当且更通用的哈希函数的任务。但是在编写 Bloom 过滤器的更大项目中,它没有表现出足够的推理能力,而是吐出了两个不同但相似的哈希函数:这就是人们所预期到的一篇关于 Bloom 过滤器的粗浅文章示例。

目前大型语言模型的推理能力较弱,再加上该主题可能缺乏资源,更糟糕的是,可能存在许多低质量资源,共同导致了这种微薄的结果。然而,这并不是一个孤立的案例。我尝试在算法或系统编程领域使用 LLM 的几次,结果都非常糟糕,即使预期的推理能力并不大于 LLM 在 Python 编程等上下文中似乎拥有的能力。

同时,GPT-4 能够反编译它生成的功能(在单独的会话中),并且还能精确地理解其目的:

https://chat.openai.com/share/f54b64d7-d19a-4be4-8f10-08553aa812f1

因此,说在系统编程上下文中没有用途肯定是不准确的。

一件有趣且几乎令人期待的事情是,在这些情况下,较小和较大的模型之间的差异确实很大。让我们看看两种本地模型的表现如何。

例如Mixtral, the MoE of Mistral对同样的问题做出了如下回答:

```c

unsigned int hash(const char* str, unsigned int hash_id) {

    unsigned int hash = 5381;

    int c;

    while ((c = *str++)) {

        hash = ((hash << 5) + hash) + c;

    }

    return hash + hash_id;

}

```

显然,只在末尾添加“hash_id”是一个非常糟糕的解决方案。Mixtral 在许多用途上都是一个很好的模型,但至于 LLM 已经很弱的推理能力,到目前为止的规则肯定是:越大越好。

这是与本地 LLM deepseek 编码器的聊天,量化为 4 位,因为我没有足够的 RAM 来以更高的精度使用该模型。然而,由于有340亿个参数,它在这个问题上的推理能力似乎相当先进。以下是聊天记录(与llama.cpp一起进行):

> 我有一个哈希函数,它应该为相同的数据输出 N 个不同的哈希值。但是,当我更改 hash_id 的值时,我看到生成的哈希值分布非常差:

unsigned int hash(const char* str, unsigned int hash_id) {

    unsigned int hash = 5381;

    int c;

    while ((c = *str++)) {

        hash = ((hash << 5) + hash) + c;

    }

    return hash + hash_id;

}

也许我使用的加盐策略很差?我该如何更改它?

[Deep-seek coder 回复]

实现的一个可能问题是,您只是在哈希末尾添加了“hash_id”。这可能会导致分布不良,尤其是在“hash_id”太大或分布不均匀的情况下。

考虑使用按位运算将“hash_id”混合在一起。下面是 XOR 的示例:

```c

unsigned int hash(const char* str, unsigned int hash_id) {

    unsigned int hash = 5381;

    int c;

    while ((c = *str++)) {

        hash = ((hash << 5) + hash) ^ c + hash_id; // Using XOR to mix in the hash_id

     }

    return (hash ^ hash_id); // Mixing the hash_id one more time at the end

}

```

这将在整个哈希中传播“hash_id”,而不是简单地添加它,这可能会导致分布不那么均匀。[剪下...实际的回复包含更多信息]

对于在我的 MacBook M1 Max 上运行的型号来说还不错。它还将总和与异或混合在一起。在这种情况下,我提供了有关要解决的问题的线索这一事实无疑对模型有所帮助,但正是模型确定了问题的真正根源是什么,并且提出的替代方案是有效的。类似上述内容的内容在任何书籍、文档或 Google 搜索的范围内都无法实现。作为原始的,插值的结果,或者你想怎么看,模型已经执行了某种形式的推理,如果通过推理,在这种特定情况下,我们接受对问题起源及其潜在解决方案的识别。然而,人们想考虑 LLM,说它们对程序员没有帮助是非常轻率的。

然而,与此同时,我过去几个月的经验表明,如果你已经是一个有经验的程序员,对于系统编程,LLM几乎永远不会提供可接受的解决方案。让我再举一个真实的例子。我目前的项目 ggufflib 涉及编写一个读取和写入 GGUF 格式文件的库,这是llama.cpp加载量化模型的格式。最初,为了了解量化编码的工作原理(出于速度原因,每个量化的位都以花哨的方式存储),我尝试使用 ChatGPT,但后来我决定对 llama.cpp 的代码进行逆向工程:它要快得多。如果一个能够很好地帮助系统程序员的 LLM,如果它看到数据编码“struct”声明和解码函数,应该能够重建数据格式文档。llama.cpp的功能足够小,可以完全适应 GPT4 的上下文,但输出完全没用。在这些情况下,事情就像过去一样:纸和笔,读取代码,并查看解码器提取的位的注册位置。

让我更好地解释上面的用例,以便您可以自己尝试一下,如果您愿意。我们从llama.cpp实现中就有了这个结构。

```

// 6-bit quantization

// weight is represented as x = a * q

// 16 blocks of 16 elements each

// Effectively 6.5625 bits per weight

typedef struct {

    uint8_t ql[QK_K/2];      // quants, lower 4 bits

    uint8_t qh[QK_K/4];      // quants, upper 2 bits

    int8_t  scales[QK_K/16]; // scales, quantized with 8 bits

    ggml_fp16_t d;           // super-block scale

} block_q6_K;

Then there is this function that is used to perform the dequantization:

void dequantize_row_q6_K(const block_q6_K * restrict x, float * restrict y, int k) {

    assert(k % QK_K == 0);

    const int nb = k / QK_K;

    for (int i = 0; i < nb; i++) {

        const float d = GGML_FP16_TO_FP32(x[i].d);

        const uint8_t * restrict ql = x[i].ql;

        const uint8_t * restrict qh = x[i].qh;

        const int8_t  * restrict sc = x[i].scales;

        for (int n = 0; n < QK_K; n += 128) {

            for (int l = 0; l < 32; ++l) {

                int is = l/16;

                const int8_t q1 = (int8_t)((ql[l +  0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32;

                const int8_t q2 = (int8_t)((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32;

                const int8_t q3 = (int8_t)((ql[l +  0]  >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32;

                const int8_t q4 = (int8_t)((ql[l + 32]  >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32;

                y[l +  0] = d * sc[is + 0] * q1;

                y[l + 32] = d * sc[is + 2] * q2;

                y[l + 64] = d * sc[is + 4] * q3;

                y[l + 96] = d * sc[is + 6] * q4;

            }

            y  += 128;

            ql += 64;

            qh += 32;

            sc += 8;

        }

    }

}

```

如果我要求 GPT4 写一个所用格式的大纲,它很难清楚地解释块是如何存储在“ql”的下/上 4 位上,具体取决于权重位置。在这篇博文中,我还尝试让它编写一个更简单的函数来显示数据是如何存储的(也许它不能用文字来解释,但可以用代码来解释)。生成的函数在许多方面都损坏了,索引错误,6 位 -> 8 位符号扩展错误(它只是转换为uint8_t),等等。

顺便说一句,这是我结束自己编写的代码:

```

} else if (tensor->type == GGUF_TYPE_Q6_K) {

        uint8_t *block = (uint8_t*)tensor->weights_data;

        uint64_t i = 0; // i-th weight to dequantize.

        while(i < tensor->num_weights) {

            float super_scale = from_half(*((uint16_t*)(block+128+64+16)));

            uint8_t *L = block;

            uint8_t *H = block+128;

            int8_t *scales = (int8_t*)block+128+64;

            for (int cluster = 0; cluster < 2; cluster++) {

                for (uint64_t j = 0; j < 128; j++) {

                    f[i] = (super_scale * scales[j/16]) *

                           ((int8_t)

                            ((((L[j%64] >> (j/64*4)) & 0xF) |

                             (((H[j%32] >> (j/32*2)) & 3) << 4)))-32);

                    i++;

                    if (i == tensor->num_weights) return f;

                }

                L += 64;

                H += 32;

                scales += 8;

            }

            block += 128+64+16+2; // Go to the next block.

        }

   }

```

从上面的函数中,我删除了这段代码的实际贡献:记录llama.cpp Q6_K编码使用的确切格式的长注释。现在,如果 GPT 能为我做到这一点,那将是非常有用的,我敢打赌这只是几个月的事情,因为这些任务在没有任何突破的情况下可以达到,只是稍微扩展一下。

6 正确看待LLM

我很遗憾地说,但这是真的:今天的大多数编程都是以略有不同的形式复制粘贴相同的东西。不需要高水平的推理。LLM 非常擅长做到这一点,尽管它们仍然受到其上下文最大大小的强烈限制。这真的应该让程序员思考。值得编写这种程序吗?当然,你会得到报酬,而且相当可观,但如果llm可以做其中的一部分,也许它不是五年或十年内值得继续的最好的地方。

然后,LLM 是否具有一些推理能力,还是完全是虚张声势?也许有时,他们似乎只是因为,正如符号学家所说,“指”给人的印象是实际上并不存在的意义。那些在LLM上工作了足够多的人,虽然接受了他们的局限性,但肯定知道不可能是这样:他们融合他们以前看到的东西的能力远远超出了随机反刍的单词。尽管他们的训练主要是在预训练期间进行的,但在预测下一个标记时,这个目标迫使模型创建某种形式的抽象模型。这个模型是薄弱的、不完整的和不完美的,但如果我们观察我们观察到的东西,它就必须存在。如果我们的数学确定性是值得怀疑的,而最伟大的专家往往站在相反的立场上,那么相信亲眼所见似乎是一个明智的方法

最后,今天不使用 LLM 进行编程有什么意义?向 LLM 提出正确的问题是一项基本技能。实践得越少,由于人工智能,人们就越无法改进他们的工作。然后,在与其他人交谈时,培养对问题的描述能力也很有用。LLM并不是唯一一个有时不明白我们想说什么的人。沟通不畅是一个很大的局限性,许多程序员尽管在他们的特定领域非常有能力,但沟通却很差。现在 Google 已经无法使用:即使只是将 LLM 用作压缩形式的文档也是一个好主意。就我而言,我将继续广泛使用它们。我从来不喜欢学习晦涩难懂的通信协议的细节,也不喜欢学习那些想要展示自己有多好的人编写的库的复杂方法。对我来说,这似乎是“垃圾知识”。LLMs每天都在越来越多地将我从这一切中拯救出来。

祝看到最后的程序员们,开工大吉,龙年吉祥,一顺百顺千日顺,顺风顺水顺长生,生财生福生长寿,好年好景好前程!

mark!20240222

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只要开始永远不晚

谢谢打赏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值