“AI书法”的原理
AI书法不使用图像生成 AI,而是用语言模型来书写书法。
一般的图像生成 AI 直接输出完成的图像。然而书法是一门重视过程的艺术:笔落在何处、按下多重、如何运行又如何收住。图像生成 AI 没有这一过程,因此无法表现书法的本质。
而语言模型虽然无法输出图像,却能把运笔的过程生成为数据。也就是说,借助语言模型,可以模拟“书写”这一行为本身,有可能做出更接近书法本质的表现。
语言模型 × 书法引擎
语言模型会收到以下信息作为输入。
- 系统提示词:
- 书法引擎的规格:输入数据的格式、纸张与坐标的定义、笔画的写法、毛笔与墨的机制
- 书法心得:运笔原则,露锋、转折、钩、撇捺等笔法的示例,“永”字的写法示例(永字八法),写好书法的诀窍与心态
- 题目文本:指示写什么的文字。(例:“请用楷书写『春風』”)
语言模型根据这两项信息,把实际的运笔输出为数据。把这些数据变成实际图像的,是书法引擎 sho.js。sho.js 是再现毛笔特性的原创程序,通过再现毛笔与纸张的物理规律来完成书法作品。
- 系统提示词引擎规格与书法心得题目文本(例)用楷书写“春風”
- 语言模型构思运笔
- 运笔数据
{"p":[[377,327,0.06,null,0.8],[418,352,1],… - 书法引擎sho.js
- 作品

模型的个性
sho.js 只负责毛笔与纸张的物理再现。如何运笔、写成什么字形、如何布局整张纸面等表现上的判断,全部交给语言模型的能力。因此作品中会鲜明地表现出各个模型的特征。对比作品,可以观察到各模型在对书法的理解深度、笔顺正误、技术高低、字形习惯等方面的个性差异。
sho.js 的规格
下面结合可实际运行的示例,说明运笔数据的形式、各数值的含义,以及 sho.js 如何把数据变成线条。同样的内容也写在交给语言模型的系统提示词中。(系统提示词全文见这里,为日文)
数据格式
数据为 JSON Lines 格式,即每行一个 JSON 对象。sho.js 从上到下依次处理这些数据。
{"t":"brush","size":58}
{"c":"永"}
{"p":[[377,327,0.06,null,0.8],[418,352,1],[434,376,2.0,null,0.3,0.12],[430,372,0.06,null,0.4]]}
{"p":[[311,528,0.1,null,0.5],[317,534,1.1,null,0.4], …]}
…
{"comment":"把右捺的收尾稍微拉长了一些。"}| 行 | 含义 |
|---|---|
{"t":"brush","size":58} | 声明所用的毛笔。size 是笔压为 1 时的线宽。 也可以指定 ink_tone(墨的浓淡)和 ink_load(墨量)。 书写表情符号时可以更换一次毛笔。 |
{"c":"永"} | 声明接下来要写的字。此时毛笔会蘸墨(蘸墨)。若不蘸墨,写作 {"c":"永","no_dip":true}。 |
{"p":[[x,y,…],…]} | 一笔的数据。是点的序列,毛笔依次经过这些点。 |
{"dip":0.6} | 蘸墨的量。 |
{"comment":"…"} | 写完作品后的感想。 |
纸张为竖长的半纸,宽 1000 × 高 1376。左上角为 (0, 0),右下角为 (1000, 1376)。
“笔画”数据的表示
笔画由点的序列表示,每个点写作 [x, y, 笔压, 角度, 速度, 停顿]。不写或写 null 即可省略该值。 加入 "k" 则该点成为转角。
| 值 | 范围 | 含义 | 省略时 |
|---|---|---|---|
| x, y | 纸张坐标 | 笔尖的位置 | (不可省略) |
| 笔压 | 0〜2 | 毛笔压入纸面的深度。1 时线宽等于笔的粗细,2 时为两倍。接近 0 时只有笔尖接触,线条尖细 | 由前后的点插值(全部省略则为 1) |
| 角度 | 度 | 从笔尖指向笔腹的方向 | 保持前一个点的角度(最初为 42) |
| 速度 | 0.05〜6 | 运笔的速度。1 为每秒“笔的粗细 × 20” | 由前后的点插值(全部省略则为 1) |
| 停顿 | 秒 | 毛笔在该点停留的时间。越长,墨越浓,轮廓越圆润鼓胀 | 0 |
| "k" | — | 该点不平滑连接,而是成为转角(转折) | 平滑 |
书法引擎用平滑曲线(centripetal Catmull-Rom)连接各点,笔压、角度、速度也在点与点之间插值。
笔:笔尖与笔腹
毛笔是数百根毛的束(粗细 60 的笔约 300 根,笔越粗越多),形如水滴,笔尖细、笔腹粗。点所在的位置是笔尖, 线条从笔尖沿角度的方向展开,宽度为笔压 × 笔的粗细。 压得越深,笔腹越多地落在纸上,线越粗;提起时则收缩回笔尖,线条变细变尖。
角度是笔的倾斜。默认的 42 时,笔腹落在笔尖的右下方(侧锋),粗的部分偏向点的右下方。 当角度与前进方向一致时,笔尖走在线条的中心(中锋),笔沿笔轴前进,线条较细。 当笔横切笔轴前进时,线条最粗。
墨:浓淡与墨量
墨由浓淡和墨量两个值决定,都在毛笔声明中指定。省略时两者均为 1,即蘸满浓墨的笔。 这两个值彼此独立,组合使用。
墨的浓淡 ink_tone(0〜1)决定颜色的深浅和洇染的难易。1 是浓墨的黑色,调低则变成淡墨的灰色。 淡墨含水多,会向线外洇开,外缘留下一圈略深的水痕。洇染在书写较慢处更宽,飞白处不会出现。
墨量 ink_load(0.2〜1.5)是毛笔蘸的墨量。不改变颜色,只决定是否容易出现飞白。
墨:飞白与停顿
每一根毛都含有墨,随着在纸上行进而逐渐失去墨。有墨时线条连贯,墨用尽之处则沿着纸的纹理断开, 形成条状的飞白。墨量越少、运笔越快、同一个字中越靠后的笔画,越容易出现飞白。 墨以字为单位({"c":…} 这一行)重新蘸取。纸上的墨有云一般的浓淡不均,飞白并不均匀,而是斑驳地出现。
在笔停住之处(停顿),墨会积聚变浓,轮廓圆润地洇开。停得越久,洇得越大。 墨越淡,洇得越快。
转角:转折
在 "k" 点处,曲线不平滑连接,而是形成转角。从横折向竖的地方,在转角前放慢速度, 在转角处按住并停顿,改变方向后稍微放松笔压再恢复,转角处就会留下“肩”。
书法的笔法
sho.js 中没有针对“钩”或“撇捺”等笔法的固定处理。与人类的运笔一样,露锋、藏锋、顿、钩、撇捺、垂露、悬针,都只通过各点的位置与笔压、角度、速度、停顿的组合来表现。例如撇,是一边顺时针旋转笔的角度一边向下行,在左下方先沉下,然后提高速度、放松笔压,向左流出。下面是系统提示词中示例的“永”字(永字八法)。
对语言模型的要求
仅仅排列坐标、描出字的形状,写不出好的书法。语言模型需要在每一笔都留意以下几点,并设计整幅作品。
- 笔的粗细:在整幅作品中选定一支合适的笔。太粗则留白被挤占,太细则书写显得瘦弱。
- 笔压:起笔、行笔、收笔要有轻重变化。只排列笔压恒定的线条会显得平板。
- 角度:是侧锋还是中锋。撇和竖画的收尾要转笔。转笔会改变线宽,要用笔压来补偿。
- 速度与停顿:顿处放慢并停顿,钩和撇的末端迅速带出。速度不同,飞白的出法也不同。
- 墨的浓淡与墨量:楷书以浓墨为本。淡墨能带来柔和与余韵,墨量略少则可借飞白写出有气势的书法。
- 笔尖的位置:点是笔尖,而不是线条的中心。侧锋时线条的粗处偏向点的右下,因此要按线条看起来的样子来考虑字形并落点。
- 笔顺与章法:按正确的笔顺书写,并在整张纸中决定字的位置、大小与留白。
随机数由笔的位置决定,所以同样的数据一定会写出同样的书法。作品之间的差异,全部来自语言模型所写数值的差异。
GitHub
筹备中
参考文献
- 新装版 書の技法用語100ハンドブック(可成屋书道编辑部 编)
- 脳トレ書道トレーニングブック 書道で長生き!(青山浩之)
- 現代書道全集〈一〉楷書(讲谈社,1967年)
- 現代書道全集〈二〉行書(讲谈社,1967年)
- 現代書道全集〈三〉草書(讲谈社,1967年)
- 現代書道全集〈四〉かな(讲谈社,1967年)