LLM 强大的语言、知识与推理能力在改变很多领域,也将持续、深入的改变更多领域。在软件领域,“Agent” 的编程模型已经是一种新的编程模式,通过这种“模式”可以将 LLM 的能力,软件提供商的领域知识,以及外部工具的能力很好的结合起来,形成“新的”软件产品。
(more…)知也无涯
吾生也有涯,而知也无涯,能学一点算一点…
-
在 \( \text{Attention} \) 机制(或 \( \text{Multi-Head Attention} \) )中我们会看到这样的变换:\( \text{Attention} = softmax(\frac{Q_iK_i^{T}}{\sqrt{d}}) \),其中这里 \( Q_i = XW_i^Q \) 那么如何理解这里的 \( XW_i^Q \) 呢? 该变换是向量空间内一个典型的线性变换,而这里的 \( W_i^Q \) 就是对应的线性变换矩阵,在早期 GPT 模型中该矩阵是一个\( 768 \times 64\) 的矩阵,研究该矩阵的典型方法就可以使用 \( \text{SVD} \) 分解,本文展示了简单的二维空间中 \( \text{SVD} \) 分解以及对应的几何意义,从而可以较好的帮助理解上述计算的深层次含义。
关于奇异值分解(\( \text{SVD} \))能够解决的问题这里不再详述。本文通过展示对于平面空间中的线性变换进行奇异值分解,从而观察该分解如何通过“几何”的方式描述一个线性变换,从而建立对线性变换的直观理解。本文的示例是一个\( 2 \times 2\)的矩阵,所以还补充了对该矩阵的特征值/特征向量的计算,从而对比这两种方法在处理“方阵”时的异同。
目录
1. 概述
本文通过对二维空间中的一个线性变换(满秩方阵) \( A = \begin{bmatrix} 1 & 2 \\ 2 & 1 \end{bmatrix} \) 进行 \( \text{SVD} \) 分析、特征值/特征向量分析,从而建立在平面空间中对于线性变换的直觉理解,更进一步的理解\( \text{SVD} \)和特征值/特征向量分别是如何描述一个线性变换的。具体的,这里观察了在该线性变换的作用下,一个点 \( (1,0) \) 是如何在两种矩阵变换下,映射到目标点的。
2. 奇异值分解
2.1 矩阵A的两种 SVD 分解
奇异值分解并不是唯一的。从几何的角度理解,一个二维空间的线性变换,是由旋转、反射、缩放组成,而先旋转、或先反射都是可以的,而这对应的就是不同的奇异值分解。考虑上述的矩阵 \( A = \begin{bmatrix} 1 & 2 \\ 2 & 1 \end{bmatrix} \) 进行 \( \text{SVD} \),我们有如下两种分解(关于具体的分解方法,本文并不详述)。
第一种分解:
$$ A = \begin{bmatrix}
1 & 2 \\
2 & 1
\end{bmatrix} = UΣV^T =\begin{bmatrix}
\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\
\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}
\end{bmatrix}\begin{bmatrix}
3 & 0 \\
0 & 1
\end{bmatrix}\begin{bmatrix}
\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\
\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}}
\end{bmatrix}
$$第二种分解如下:
$$ A = \begin{bmatrix}
1 & 2 \\
2 & 1
\end{bmatrix} = UΣV^T =\begin{bmatrix}
-\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\
-\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}
\end{bmatrix}\begin{bmatrix}
3 & 0 \\
0 & 1
\end{bmatrix}\begin{bmatrix}
-\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\
\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}}
\end{bmatrix} $$2.2 分解1的几何意义与图示
$$ A = \begin{bmatrix}
1 & 2 \\
2 & 1
\end{bmatrix} = U\Sigma V^T = \begin{bmatrix}
\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\
\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}
\end{bmatrix}\begin{bmatrix}
3 & 0 \\
0 & 1
\end{bmatrix}\begin{bmatrix}
\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\
\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}}
\end{bmatrix}
$$考虑:
\( V^T = \begin{bmatrix} \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}}\end{bmatrix} \) 形式与 \( \begin{bmatrix} \cos \varphi & \sin\varphi \\ \sin\varphi & -\cos \varphi \end{bmatrix} \) 相同,故,此为关于直线 \( y = (\tan\frac{\varphi}{2})x \) 的反射[附录1]。
\( \Sigma = \begin{bmatrix} 3 & 0 \\ 0 & 1 \end{bmatrix} \) 表示将点、向量的坐标进行缩放。
\( U = \begin{bmatrix} \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \end{bmatrix} \) 形式与 \( \begin{bmatrix} \cos \varphi & -\sin\varphi \\ \sin\varphi & \cos \varphi \end{bmatrix} \) 相同,故,此为一个逆时针 \( \varphi \) 度的旋转[附录1]。
即,上述的线性变换可以做这样的理解:
- 先将点以\( y=\tan\frac{45}{2}x = (\sqrt{2}-1)x \)为轴进行反射
- 然后将坐标第一个分量放大3倍
- 最后再逆时针旋转\( 45^{\circ} \)
考虑坐标上的点\( \alpha = \begin{pmatrix} 1 \\ 0 \end{pmatrix} \),我们看看如何经过该线性变换,映射到目标点:
右图反映了完整的过程:
- \( (1,0) \) 先经过按图中虚线为轴进行反射,到红点
- 然后,进行拉伸,第一个分量拉伸3倍,到绿色点
- 最后,再逆时针旋转\( 45^{\circ} \) 到黄色点
对应的矩阵计算如下:
\( \text{red} = V^T \alpha = \begin{bmatrix} \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}}\end{bmatrix} \begin{pmatrix} 1 \\ 0 \end{pmatrix} = \begin{pmatrix} \frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \end{pmatrix} \)
\( \text{green} = \Sigma V^T \alpha = \Sigma \, \text{red} = \begin{bmatrix} 3 & 0 \\ 0 & 1 \end{bmatrix} \begin{pmatrix} \frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \end{pmatrix} = \begin{pmatrix} \frac{3}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \end{pmatrix} \)
\( \text{yellow} = U\Sigma V^T \alpha = U \, \text{green} = \begin{bmatrix} \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \end{bmatrix} \begin{pmatrix} \frac{3}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \end{pmatrix} = \begin{pmatrix} 1 \\ 2 \end{pmatrix} \)

2.3 分解2的几何意义与图示
$$ A = \begin{bmatrix}
1 & 2 \\
2 & 1
\end{bmatrix} = UΣV^T =\begin{bmatrix}
-\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\
-\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}
\end{bmatrix}\begin{bmatrix}
3 & 0 \\
0 & 1
\end{bmatrix}\begin{bmatrix}
-\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\
\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}}
\end{bmatrix} $$考虑:
\( V^T = \begin{bmatrix}-\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \end{bmatrix} \) 形式与 \( \begin{bmatrix} \cos \varphi & -\sin\varphi \\ \sin\varphi & \cos \varphi \end{bmatrix} \)相同,故,此为一个逆时针 \( \varphi = 135^{\circ} \) 度的旋转[附录1]。
\( \Sigma = \begin{bmatrix} 3 & 0 \\ 0 & 1 \end{bmatrix} \) 表示将点、向量的坐标进行缩放。
\( U = \begin{bmatrix} -\frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} \\ -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \end{bmatrix} \) 形式与 \( \begin{bmatrix} \cos \varphi & \sin\varphi \\ \sin\varphi & -\cos \varphi \end{bmatrix} \) 相同,故,此为关于直线 \( y = (\tan\frac{\varphi}{2})x \) 的反射[附录1]。
即,上述的线性变换可以做这样的理解:
- 点\( (1,0) \) 先逆时针旋转\( \varphi = 135^{\circ} \)到达红色点
- 然后将坐标第一个分量放大3倍,成为绿色点
- 最后将点以\( y=\tan\frac{-135^{\circ}}{2}x \)为轴进行反射,到黄色点
具体可以参考右图,详细的计算这里不再给出。

3. 特征值与特征向量
因为这里的\( A \)是一个 \( 2 \times 2 \) 的方阵,故可以使用特征值与特征向量来洞察这个线性变换的本质。
对于该矩阵的特征值、对应的特征向量计算结果如下:
- 对于特征值 \( \lambda_1 = 3 \) 时,特征向量为 \( (\frac{1}{\sqrt{2}}, \frac{1}{\sqrt{2}}) \)
- 对于特征值 \( \lambda_2 = -1 \) 时,特征向量为 \( (\frac{1}{\sqrt{2}}, -\frac{1}{\sqrt{2}}) \)
依旧,这里我们来考虑向量 \( \alpha = \begin{pmatrix} 1 \\ 0 \end{pmatrix} \) 在这两个特征向量方向上作用后的效果。
右图已经比较直观的反应了如何从特征向量和特征值的角度去理解线性变换:
- 首先,先将向量 \( \alpha \) 在两个特征向量上进行分解,分解后的向量分别为 \( \alpha_1 \, \alpha_2 \)
- 然后再按照特征值进行缩放:
- \( \lambda_1 = 3 \) 故将 \( \alpha_1\)拉伸为 \( \beta_1 \)
- \( \lambda_2 = -1 \) 故将 \( \alpha_2\)反向为 \( \beta_2 \)
- 最后,\( \beta_1 \) 和 \( \beta_2 \) 合并为 \( \beta \)

4. 小结
在这种情况下(注:线性变换矩阵为一个 \( 2 \times 2 \)的满秩矩阵), 我们可以使用奇异值分解\( \text{SVD} \)、特征值计算的方式来洞察这个线性变换的“本质”。两种方法各有一些优缺点,大家可以自己去体会,这里小结一下我的理解。
奇异值分解\( \text{SVD} \)是一种“动态”的展示线性变换的方法,可以让你很清晰的了解这个线性变换是如何将空间中的“一个点”映射到“另一个点”的。例如在上述的例子中,则是先进行旋转、然后进行缩放、最后进行反射。
特征值/特征向量计算则是对线性变换的“静态”解释,使用静态的方式展现了线性变换如何将“一个点”映射到“另一个点”的。
5. 补充说明
- 实际应用中的奇异值分解通常是用于处理更高维的向量空间,所以通常没有这么直观的几何意义,但是依旧可以使用类比的“反射”、“旋转”、“拉伸/压缩”等概念去扩展的理解。
- 特征值/特征向量仅适用于处理方阵的场景,所以场景比较受限。
- 关于特特征值/特征向量计算,在实际中可能会更加复杂,例如,重根、复数根等情况,要想进一步理解,则需要做更深入的研究。
- 要进一步加深理解,则可以考虑,观察一个三维空间中变换的实例,有一些相同,也有一些不同:
- 反射,通常是基于某个平面(两个基张成的平面)的
- 选择,则是绕着某个直线(某个向量的方向上)
附录1 二维空间的正交变换
二维空间中,有两种正交变换,即旋转或反射。其对应的线性变换矩阵分别有如下的形式:\( \begin{bmatrix} \cos \varphi & \sin\varphi \\ \sin\varphi & -\cos \varphi \end{bmatrix} \) 与 \( \begin{bmatrix} \cos \varphi & -\sin\varphi \\ \sin\varphi & \cos \varphi \end{bmatrix} \) 。
附录2 三维空间的正交变换
在三维空间内,对于一组规范正交基 \( \{ \alpha_1,\alpha_2,\alpha_3 \} \) ,该空间下的正交变换矩阵总有如下形式:
$$
\begin{bmatrix}
\pm 1 & 0 & 0 \\
0 & a & b \\
0 & c & c
\end{bmatrix}
$$更为具体的为如下三种形态之一:
$$
A = \begin{bmatrix}
1 & 0 & 0 \\
0 & \cos\varphi & -\sin\varphi \\
0 & \sin\varphi & \cos\varphi
\end{bmatrix}
\quad
B = \begin{bmatrix}
-1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{bmatrix}
\\
\begin{aligned}
C & = \begin{bmatrix}
-1 & 0 & 0 \\
0 & \cos\varphi & -\sin\varphi \\
0 & \sin\varphi & \cos\varphi
\end{bmatrix} \\
& =
\begin{bmatrix}
1 & 0 & 0 \\
0 & \cos\varphi & -\sin\varphi \\
0 & \sin\varphi & \cos\varphi
\end{bmatrix}
\begin{bmatrix}
-1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{bmatrix}
\end{aligned}
$$这里的:
- 变换 \( A \) 为一个旋转,旋转轴为 \( \alpha_1 \) 所在的直线
- 变换 \( B \) 是一个反射,反射轴平面为 \( \mathscr{L}(\alpha_2,\alpha_3) \)
- 变换 \( C \) 是上述两个变换的组合
-
这大概是一个有趣、也略深刻的发现。
Word Embedding是比较抽象的,但是这些抽象背后是一些“具象”的含义的,本文通过一些简单的计算(变换)来将Embedding的某些维度/属性具象化。具体的,本文展示了在Embedding空间中,找到一个代表“动物”属性的方向。感兴趣的话,可以通过这个简单的方法,找到你感兴趣的属性方向。
TL;DR
通常,在某个具体的Word Embedding实现中,先给出一组具有“共同属性”的词语,然后计算这组词语Embedding向量的平均方向,就可以代表这个“共同属性”。
例如,找到一组“动物”,然后对这些词语的Embedding向量计算平均方向,那么这个方向就是“动物”这个属性的方向。
概述
如果你也尝试过去理解 Embedding 各个维度的含义的话,大概都听过这样一种说法:Embedding每个维度可以理解为这个词语的某种属性,例如,“性别属性”、“皇室相关度”等,这是最为经典的
man - woman = king - queue的例子中的一些解释。当你真的拿到一个词语的 Embedding 的时候,它可能有768维,但是,似乎没有一个维度有上述的清晰的属性含义。而实际上,这些属性含义是确实存在的,只是这些属性方向并不存在于“标准基”的方向上。
那如果存在,我们应该如何找到这个方向呢?本文展示并验证了一个非常简单的方法,让你快速找到某种属性的方向,并且进行一些验证。从而可以大大加深对于 Embedding 的理解。
寻找某个关心的方向
这里展示了以寻找“动物”属性方向为例,展示如何寻找并验证该方向。
列出最具代表性的词语
我们这样考虑这个问题,如果有一个方向表示一个词语的“动物”属性,那么这个方向会是哪个方向?这里以
all-MiniLM-L6-v2模型提供的Sentence Embedding为例,我看看如何找到该Embedding所处的向量空间中最可能代表“动物”属性的方向是哪个?具体的方法描述如下:- 首先,找到被认为最典型的与“动物”属性相关的词语\( n \)个,这里取\( n=50 \)
- 然后计算上述\( n \)个词语的平均方向
avg_vector,该方向则认为要寻找的方向
这里,给出的50个动物如下:
animals = [ "tiger", "lion", "elephant", "giraffe", "zebra", "rhinoceros", "hippopotamus","crocodile", "monkey", "panda", "koala", "kangaroo","whale", "dolphin", "seal", "penguin", "shark", "snake", "lizard", "turtle", "frog", "butterfly", "bee", "ant", "eagle", "sparrow", "pigeon", "parrot", "owl", "duck", "chicken", "dog", "cat", "pig", "cow", "sheep", "horse", "donkey", "rabbit", "squirrel", "fox", "wolf", "bear", "deer", "hedgehog", "bat", "mouse", "chameleon", "snail", "jellyfish" ]计算Embedding的平均方向
该平均方向,即为我们要寻找的“动物”属性方向。
animals_embeddings = model.encode(animals) avg_animals_embeddings = np.mean(animals_embeddings, axis=0)验证该方向
再选取两组词,一组认为是与“动物”非常相关的词,另一组则是与动物无关的词语。然后分别计算这两组词语在上述方向
avg_vector的投影值。观察投影值,是否符合预期。这里选择的两组词语分别是:
- 与动物非常相关的:”Camel”, “Gorilla”, “Cheetah”
- 与动物无关的:”Dream”, “Chair”, “Mathematics”
计算投影并可视化
具体的程序如下:
animals_words = ["Camel", "Gorilla", "Cheetah"] un_animals_words = ["Dream", "Chair", "Mathematics"] for word_list in (animals_words,un_animals_words): projection_scores = np.dot(model.encode(word_list), avg_animals_embeddings) results.update({word: score for word, score in zip(word_list, projection_scores)}) for word, score in results.items(): print(f"'{word}': {score:.4f}") print(np.round(avg_animals_embeddings[:10], 4))投影结果为:
'Camel': 0.3887 'Gorilla': 0.4186 'Cheetah': 0.3797 'Dream': 0.2450 'Chair': 0.2823 'Mathematics': 0.1972在实数轴上绘制上述两组词语的投影:

非常明显的可以看到,上述的
avg_vector方向某种程度上代表了一个词语的“动物”属性:即与动物属性相关的词语在该方向的投影大,无关的词语在该方向的投影小。原理解释
概述
事实上,一组词语Embedding的“平均向量”(centroids of word embeddings),则某种程度的代表这组词语的“语义中心”。如果这组词有某些共性,那么这个平均向量,则可能就是这个共性的代表。
在上述的例子中,刻意地给出的一组词语都是“动物”名称。那么,这个“平均向量”则比较有可能代表了这个向量空间中的“动物”属性。
数学推导
这样考虑这个问题:现在给出的 \( n \) 个向量 \( \alpha_1, \dots , \alpha_n \),找出一个单位向量 \( \xi \) 使得 \( n \) 个向量在 \( \xi \) 向量方向上的投影值的和最大。
这里取 \( \bar{\alpha} = \frac{\sum\limits_{i=1}^{n}\alpha_i}{n} \)
目标函数 \( S = \sum\limits_{i=1}^{n}(\alpha_i \cdot \xi ) = \sum\limits_{i=1}^{n}(\alpha_i) \cdot \xi = n \bar{\alpha} \cdot \xi = n \| \bar{\alpha}\| \| \xi \| \cos\theta \)
这里 \( n \)、\( \bar{\alpha} \)都是给定值,而 \( \| \xi \| = 1 \),所以这里 \( \cos\theta \) 取最大值时,上述的目标函数 \( S \) 取最大值。
即:\( \theta = 0 \) 时, \( S \) 取最大值。即当 \( \xi \) 与 \( \bar{\alpha} \) 方向相同时,即 \( \xi = \frac{\bar{\alpha}}{\|\bar{\alpha}\|} \) ,所有向量的投影值的和最大。
投影计算
太久不碰线性代数了,对于基本运算都不是很熟悉了。向量 \( \alpha \) 在 \( \beta \) 方向上的投影长度,计算公式如下:
$$ proj = \frac{\alpha \cdot \beta}{\|\beta\|} $$
证明比较简单,这里不再赘述。
向量的平均方向与主成分方向
当给出一组向量,面对上述问题,比较容易联想到这组向量的“主成分分析”的第一个维度。那么,上述的平均向量和主成分分析的第一个维度有什么关系呢?回答是:没有太大的关系。
可以看下面三个图:



上述三个二维平面中的点的平均方向均为红色,即(1,1);但是PCA的第一方向则各有不同,有时候与平均向量相同、有时候垂直,有时候相交。总之是没什么关系。
可以看到,平均向量时在当前的“基”下计算获得。而主方向分析的方向,则首先就与原点没有关系。
更深层次的理解
现在的Embedding算法,都是基于现实世界语料库训练而来,反应了人类认知中“语言”与现实世界的对应关系。而在人类的认知中,这个世界是有“维度”的,最为直白的例子就是:我们会将词语划分“褒义词”、“贬义词”。此外,可能还有:动物性、情感强烈度、词性等。那么,在人类认知中这种“认知”有多少个维度呢?这其实是未知的,而各种
Embedding算法则是在尝试使用量化的方式描述这些维度。但是,在实际训练出的各种Embedding实现,例如一个768维的Embedding,其单位向量方向,不太可能是上述的人类“认知”维度。如果把训练出来的Embedding的单位向量记为:\( \alpha_1, \dots , \alpha_n \),而把人类认知的维度记为: \( \beta_1, \dots , \beta_n \) 。
那么,则存在一个过渡矩阵 $T$,可以实现上述向量空间
基的变换。可是,现实世界没有那么理想。Embedding空间确实给出了一组正交基,但是人类认识却很难寻找这样的正交基,例如“动物”属性的词语,可能会带有“情感”属性,例如,“虎狼之词”等,都带有某种情感属性。
虽然,认知很难找到正交的“基”,但是找到某个具体的属性方向,则可以使用本书的方法。这正是本文所描述方法的局限性和价值所在。
补充说明
- 本文中,所说的Word Embedding,通常是指Sentence Embedding中的Token Embedding。在这里,无需区分两者。
- 实际的情况更加复杂,例如本文中的“动物”属性,只是这些词所代表的“动物”属性。什么是真正的“动物”属性,并不存在这样的精确概念。人类语言中的“动物”是一个抽象的,并没有数字化、数学化的精确定义。
- 完整的实现代码,参考:embedding_research_01.py。
-
上一次写DTCC已经是15年前了(参考:DTCC关于MySQL的未来),今天又有写一点什么的冲动了。因为要“练摊”,所以也只能是“部分”观察。
AI 到底会如何改变数据库领域
这次会场上,对于“佰晟智算”和“银联”在AI方向的一些探索关注的多一些,其他时间,则主要是在NineData展台“练摊”。说说一些感受吧。“佰晟科技”主要聚焦于国产化数据库的优化、监控管理等方向,最为亮眼的创新在于,将大模型的能力与“运维知识”深度的结合起来。白鳝很早就在给产品做市场预热了,所以,在产品推出比较短的时间能,就快速的获得了一些早期的种子客户。

“银联”则是在内部的数据库管理上,做了很多的探索。银联有非常强的自主研发能力,也做了很多的智能化探索,包括Text2SQL、SQL的性能诊断等。Text2SQL很多的企业做了探索,但由于表名、列名的识别对于大模型来说,是非常困难的(一方面由于列可能非常多、而且命名比较简短),会让大模型出现非常强的幻觉问题,这使得在复杂OLTP场景,Text2SQL依旧难以胜任。但对于一些较为简单的场景,例如比较比较少,表、列都使用非常规范的时候,对于部分开发者,依旧有帮助。也注意到,有很多的企业在BI或者“取数”、“报表”场景,做了非常多的探索。

在SQL优化的方向,AI的能力,已经得到了开发者比较一致的认可,大模型虽然可能会给出一些不太实用的建议,但是“正确”的优化建议,也总是在大模型给出的建议列表之中。这对于,DBA渐少的时代,对开发者来说,确实非常友好。
NineData 在这个方向上,也做了很多探索,从最早发布ChatDBA以来,后续持续在“DDL转换”、“SQL 优化”、“Text2SQL”、“国产化转换”等方向去尝试,这些功能随着基础大模型的增强,以及辅助以各种优化,确实可以让开发者的数据库管理变得简单一些。

Memobase
还听了一场 Memobase 的分享,是一个关于大模型“memroy”的产品。创始人非常技术,整个介绍听下来,如果稍不留神,甚至不知道演讲者是来介绍 Memobase 的,而是把业界的“memroy”产品以及相关的技术栈介绍了清楚。本以为这可能是一个略微冷门的话题,但从现场的问答环节来看,开发者们在这个方向上有很多的问题要解决。

这个是一个依旧在快速发展的方向。无论是Memobase还是Mem0,这类产品,与数据或者数据库的关系比较有趣的。简单的数据存储,即便是多模态存储,是无法简单的解决此类问题的。此类问题,当前,依旧是比较偏场景化的解决方案,例如,当天讨论的最多的,包括问答机器人、智能对话陪伴等。这些具体的场景下,产品需要深入到场景之中,才能解决开发者的问题。至于存储方案,可能不是当前最为紧迫的问题,所以存储上,可以用S3、也可以用“EloqData”、也可以考虑类似于MongoDB等其他的产品。
Memobase 比较强调自己在 Latency 方面的优势,但是,目前来看,在一个Chat的场景下,多个百毫秒的Latency,似乎并不是问题。
之所以,这里比较强调多模态的存储,主要在于:在这个场景中,通常会使用如下的方案,包括,使用 Graph 存储一些关联关系,例如一个人的朋友、“属性”等信息;还会大量使用json存储诸如profile、conversation 历史等信息。此外,这类方案,与RAG类似,也非常依赖注入Embedding、bm25等相似搜索,用于处理历史消息等。
总得来说,是一个场景化的,混合的存储方案,去应对业务场景。
创新与迭代是唯一出路
这次在现场也与很多朋友讨论了 AI 对数据库从业者(不限于)的影响,大家也都有着类似的看法,如果你不是做基础大模型的,那么,基本上,如果你能够更好的使用 AI,那么就有可能开发者出更好的产品;如果你的产品,能够更好的使用AI的能力,你的产品可能会在市场上有更强的竞争力。
对于开发者来说,确实应该更加积极、甚至激进的去拥抱 AI 技术。LLM从出圈到现在,一共也就两三年时间,所以,“大家的起点都一样,不要犹豫,往前跑就可以了”。
这个说法在当初ChatGPT刚出来时,Google也有类似的论断类似:““我们没有护城河,OpenAI也没有(We Have No Moat, And Neither Does OpenAI)”。事实上,经过也就两年的时间,Google Gemini 的能力、体验与市场,已经逐步在赶上ChatGPT。
另一方面,现在整个社会最多的风投资金、最聪明的人都聚集到了这个领域,这个领域的发展和变化,可以说是“日新月异”,这个领域一定会出现很多新的商业模式和企业。但如果,跑得晚了,后面的追赶会更加吃力。从最近的Zack如此大价钱的挖掘 AI 人才,也可能看出,即便是,最头部的厂商,在这个势头下,也是非常焦虑的。
向量数据库是AI还是数据库
向量存储在搜索在多个AI场景都有这广泛的使用,这次大会上,包括腾讯、华为、中兴、Oracle等厂商都介绍自己自己在这个方向的探索,包括海量存储下的性能优化、标量与向量混合查询的性能、面相RAG常见的效果优化、高效的向量缓存方案等。

最后
DTCC 是一年一度的数据库领域朋友聚会,非常开心。因为要“练摊”的原因,错过了很多的主题分享,今年的DTCC就简单记录如上。
-
大语言模型非常非常强大,但也有一些弱点。例如,需要精确推理与计算的场景、实时数据(如天气)获取等。MCP则是对这类外部能力扩展的一个接口,让大模型/Agent都能够便捷的接入外部工具解决此类问题。
本文通过演示创建一个外部计算24点的程序(MCP Server),让Cursor Agent访问LLM时具备快速的24点计算能力,从而帮助开发者快速了解如何构建一个MCP Server。该24点计算的MCP Server也已经在🤗 Hugging Face对外发布,你也可以接入你的Cursor(或其他MCP Host)进行测试(参考本文小结:在Cursor中配置MCP工具)[1]。
创建 MCP Server
现在各种工具框架已经把
MCP入门构建的门槛降低非常低了,这里将使用Gradio构建一个24点计算的程序,并以MCP Server的方式提供给各MCP Host(本文是Cursor)使用,同时将该MCP Server发布在🤗 Hugging Face的Space上,以供其他人测试和使用。创建24点计算的MCP Server
使用
Gradio创建MCP的代码如下:# # A project for mcp learning by orczhou # from solve_24_game import solve_24_game import gradio as gr def gradio_interface(a, b, c, d): return solve_24_game([a, b, c, d]) # Create the Gradio interface demo = gr.Interface( fn=gradio_interface, title="solve the 24 game/puzzle", inputs=[ gr.Number(label="Number 1", value=1), gr.Number(label="Number 2", value=2), gr.Number(label="Number 3", value=3), gr.Number(label="Number 4", value=4), ], outputs="text", flagging_mode="never", description="Solves the 24-point game. Given a list of four numbers, it attempts to find a mathematical expression using addition, subtraction, multiplication, and division that evaluates to 24. Each number must be used exactly once.", theme=gr.themes.Ocean() ) # Launch the interface and MCP server if __name__ == "__main__": demo.launch(mcp_server=True)Gradio 不仅可以快速构建可视化的交互界面(通常用于机器学习领域),还可以非常简单的构建起MCP Server,并将其托管于
🤗 Hugging Face:demo.launch(mcp_server=True)在启动时,新增
mcp_server=True即可以同时启动一个与此界面“相同”的MCP Server。左侧的代码首先创建了一个如下
Web服务:
在创建了上述的Web服务的同时,
Gradio还会同时创建了一个如下Endpoint的MCP Server:https://orczhou-solve-24-game.hf.space/gradio_api/mcp/sse如果是本地运行,
Endpoint则可能是:http://127.0.0.1:7860/gradio_api/mcp/这里解决24点问题的代码存储在文件
solve_24_game.py中,代码参考:solve_24_game.py。如何解决24点问题并不是本文的重点,这里不做详述。本地运行该MCP Server
在本地,则只需要使用
python3 app.py命令即可运行:python3 app.py * Running on local URL: http://127.0.0.1:7860 * To create a public link, set `share=True` in `launch()`. 🔨 Launching MCP server: ** Streamable HTTP URL: http://127.0.0.1:7860/gradio_api/mcp/ * [Deprecated] SSE URL: http://127.0.0.1:7860/gradio_api/mcp/sse在Hugging Face上发布 MCP Server
在
🤗 Hugging Face上可以非常方便的创建并托管简单的MCP Server。详细的介绍可以参考:Spaces as MCP servers。这里演示如何进行操作。前提要求
- 首先,你要有一个
🤗 Hugging Face的账号,注册即可 - (可选)可能还需要进行充值与信用卡绑定
- 准备好
🤗 Hugging Face的Token,并配置好权限
通常,Hugging Face运行程序的资源是需要付费的。但是也有部分免费资源,例如
MCP托管的时候,提供了一个免费的CPU Basic(2 vCPU 16 GB RAM)的免费资源(当前免费,未来也可能是计费的)。在本地代码向
Space上推送的时候,则需要通过Token的方式进行认证和权限管理。创建 Space
进入
🤗 Hugging Face,进入Space,点击“+ New Space”创建新的Space,则进入右侧的创建表单。注意到,在
Space Hardware选项中,这里的CPU Basic 2 vCPU 16GB是免费规格,这里用作个人测试故选择免费。此外,这里选择了
Gradio模板进行创建。可以看到,这里
🤗 Hugging Face把相关操作的入门门槛降到了非常低的程度,对初学者非常友好。提交代码
在完成创建后,可以使用
git想仓库中提交代码,Space则会根据代码架构,完全自动化的构建一个MCP Server向公网提供服务。代码提交可以参考如下命令:

git clone https://huggingface.co/spaces/orczhou/solve_24_game cd solve_24_game git add solve_24_game.py app.py git commit -m "mcp for 24 point game" git remote add origin https://huggingface.co/spaces/orczhou/solve_24_game git push -u origin main补充说明:首先在Hugging Face托管则需要把程序命名为
app.py,此外,还需要编写一个requirements.txt文件说明Pythone程序需要的一些模块,这里仅需要gradio[mcp]:cat requirements.txt gradio[mcp]调试
这里使用
Hugging Face和Gradio构建的MCP服务,可以非常方便的使用可视化的界面进行查看服务,例如,在这里可以通过,如下的URL来进行查看该服务是否正常:solve the 24 game/puzzle。此外,可以通过
curl命令进行调试,以确认MCP服务是否正常:
curl -X POST \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }' \ -L \ https://orczhou-solve-24-game.hf.space/gradio_api/mcp/data: { "jsonrpc":"2.0", "id":1, "result":{ "tools":[{ "name":"solve_24_game_gradio_interface", "description":"", "inputSchema":{ "type":"object", "properties":{ "a":{"type":"number", "default":1 }, "b":{"type":"number", "default":2 }, "c":{"type":"number", "default":3 }, "d":{"type":"number", "default":4 } } } }]}}在Cursor中配置该MCP服务
配置新的MCP服务
在
Cursor的Settings->Tools & Integrations中找到MCP Tools,就可以通过New MCP Server处编辑mcp.json,从而增加MCP Tools。具体的配置,参考如下:

{ "mcpServers": { "solve_24_game": { "type": "sse", "url": "https://orczhou-solve-24-game.hf.space/gradio_api/mcp/sse" } } }查看Cursor中MCP配置状态
首次测试和使用MCP时,还是比较容易出错的。可以通过上述的
MCP Tools处(右图)可以查看MCP的状态,已经该MCP中可用的工具。
在Cursor中使用该MCP服务
在
Agent模式下进行对话,Cursor背后的大模型就可以使用该MCP的能力。为了避免Agent生成代码(Cursor的Agent总是倾向于生成代码解决问题),故使用如下提示词提问:“不要生成任何代码,使用工具计算如下24点问题: 2 5 5 10”。
返回的结果如右图。可以看到,大模型拿到返回的结果
(5-(2/10))*5后,进行了必要的解释与回答。MCP详细的调用过程如下,包括了使用的参数、返回的结果:

在我的Cursor上使用该MCP
因为这里创建的
MCP Server是运行在公网环境,故在你本地的Cursor或者其他MCP Host上也可以配置和使用该MCP服务,配置的方法参考上述小结“配置新的MCP服务”,这里不再赘述。其他
更换Gradio的默认配色主题
可以使用
theme=gr.themes.Ocean()选项更改主题选项:# Create the Gradio interface demo = gr.Interface( ... theme=gr.themes.Ocean() )更多的配色主题可以参考:Theming Guide。
最后
大模型说:“我不需要帮助,愚蠢的人类!”
- 首先,你要有一个
-
MySQL的向量处理现状
向量数据库或者说向量处理是,个人认为,最为重要数据库
AI能力。目前,各个数据库都在围绕着向量数据库构建更为丰富的LLM/AI相关功能。而MySQL 9最为重要的特性之一就是新增了向量处理能力。当前的版本主要包括了:(a) 向量数据类型;(b) 简单的向量处理函数。其中部分向量处理函数放在了MySQL的企业版或云版本中。因为当前
MySQL 9系列的版本均为创新版(并不是稳定版),所以相关功能还会不断的迭代和发展。期待未来做出更多丰富功能:(a) 新增向量相似性搜索功能;(b) 并将完整的向量处理能力放到社区版中。后续依旧会持续关注这部分的产品能力。本文测试环境为
Oracle Cloud,你可以参考在 Oracle 云上免费测试数据库[3]文中创建一个免费的MySQL实例进行测试。MySQL中的向量数据类型
向量数据存储
在
MySQL 9中新增了数据类型vector用来存储向量数据[1],简单的使用方式如下:create table vector_t01 ( id int, s_v_01 vector(390), s_v_02 vector(390) );这里表示s_v_01、s_v_02均为390维的向量,每个维度在MySQL中使用
4 bytes的单精度浮点类型存储。写入向量数据
为了测试使用方便,这里使用
string_to_vector对向量进行转换并进行存储:insert into vector_t01 values (1,string_to_vector('[1,2,3]'),string_to_vector('[4,5,6]'));查询向量数据
使用 VECTOR_TO_STRING
使用
SELECT直接查询向量数据的话,则返回的是二进制形式,可以使用函数VECTOR_TO_STRING做一次转换:select id,VECTOR_TO_STRING(s_v_01),VECTOR_TO_STRING(s_v_02) FROM vector_t01; +------+---------------------------------------+---------------------------------------+ | id | VECTOR_TO_STRING(s_v_01) | VECTOR_TO_STRING(s_v_02) | +------+---------------------------------------+---------------------------------------+ | 1 | [1.00000e+00,2.00000e+00,3.00000e+00] | [4.00000e+00,5.00000e+00,6.00000e+00] | +------+---------------------------------------+---------------------------------------+如果不使用
VECTOR_TO_STRING则返回的是底层的二进制存储内容:select id,s_v_01,s_v_02 FROM vector_t01; +------+--------------+--------------+ | id | s_v_01 | s_v_02 | +------+--------------+--------------+ | 1 | �? @ @@ | �@ �@ �@ | +------+--------------+--------------+十六进制查询
如果使用十六进制展示,则有:
select id,hex(s_v_01),hex(s_v_02) FROM vector_t01; +------+--------------------------+--------------------------+ | id | hex(s_v_01) | hex(s_v_02) | +------+--------------------------+--------------------------+ | 1 | 0000803F0000004000004040 | 000080400000A0400000C040 | +------+--------------------------+--------------------------+这里的
0000803F0000004000004040一共是3个bytes,每个byte表示一个分量,例如:0000803F表示第一个分量,即为单精度浮点型的1.0(感兴趣的可以尝试做个转换,这里不再详述)。计算向量距离
目前,MySQL 支持最为常见的“距离”的计算,具体包括:点积(默认)、欧式距离、余弦距离的计算:
-- s_v_01: (1,2,3) -- s_v_01: (4,5,6) SELECT DISTANCE(s_v_01,s_v_02,"DOT") as dis_dot, DISTANCE(s_v_01,s_v_02,"COSINE") as dis_cos, DISTANCE(s_v_01,s_v_02,"EUCLIDEAN") as dis_ecu FROM vector_t01; +---------+----------------------+-------------------+ | dis_dot | dis_cos | dis_ecu | +---------+----------------------+-------------------+ | 32 | 0.025368213653564453 | 5.196152210235596 | +---------+----------------------+-------------------+需要注意的是,目前该距离计算函数(
DISTANCE[2])仅在Oracle Cloud或MySQL企业版本中提供。后续还将持续关注MySQL所提供的向量产品能力、以及其他GenAI相关功能。参考链接