Vibe Coding 实战!花了两天时间,让 AI 写了一个富文本渲染引擎!

一、先上效果图

最近动手实践了下 Vibe Coding,想尝试​一行代码不写,纯通过 Prompt 让 AI 写了一个富文本渲染引擎​。

整体花了两天时间不到,效果如上图,支持的特性有:

  • 类似前端的 Block、InlineBlock、Inline 布局
  • 文本样式:加粗、斜体、下划线、删除线,前景色,背景色,同一行不同字体大小混排等
  • Attachment:图文混排或插入自定义 View 等
  • 异步排版和算高:基于 CoreText API,支持子线程布局算高,主线程渲染
  • 单测覆盖

项目用的 Claude AI,差不多耗费了 50$(是真的贵!但也是真的强!),本文将记录整个过程和一些经验总结。

二、过程记录

2.1 Claude 安装和项目初始化

Claude 安装和使用在网上有很多教程,细节这里不再赘述,推荐直接使用 VSCode 的 Claude AI 插件;后文「经验总结」部分也会总结 Claude AI 的常用命令,感兴趣可以直接跳转。

首先,我们需要新建一个空的 iOS 项目和富文本渲染引擎的 pod(这里我们叫 RichView),创建完成之后在 VSCode 中打开,点击右上角 Claude AI 的图标开启会话,输入/init 命令初始化工程。

/init命令的作用是让 Claude 理解整个项目,这是在项目中使用 Claude 的第一步,只需要执行一次就好。

/init会在根目录下自动创建一个CLAUDE.md文件,这个文件可以理解成​全局上下文​,即每次新开 Claude 会话都会自动加载其中的内容,我们可以在这里记录一些如修改历史、全局说明等内容。

2.2 技术选型、架构

让 AI 写代码,和我们自己写代码基本类似,不过是将我们的思路转换成 Prompt 告诉 AI。

编码之前需要先确定几件事情:这些确定好之后,我们后续的任务拆分才会更顺利。

1)需要支持哪些 Feature

  • 支持文本样式:加粗、斜体、下划线、删除线,前景色,背景色,同一行不同字体大小混排等
  • 支持 Attachment:图文混排或插入自定义 View 等
  • 支持子线程排版算高
  • 支持单元测试

2)技术选型

自定义富文本渲染引擎,最难的点在于如何实现精确的文本分词排版(原理可以参考从 0 到 1 自定义文字排版引擎:原理篇),iOS 有内置的 CoreText API(见链接)用于文本分词排版,当然也可以基于开源的跨端排版引擎 HarfBuzz(见链接)进行处理。

我们这里不需要跨端,因此选择 CoreText 作为方案选型。

官方封装的 NSAttributedString 当然也能做这件事情,但是从工程实践看,NSAttributedString 在扩展性(比如支持列表、表格等自定义布局)、使用方便性,以及长文本的性能方面不尽如人意。

3)技术架构

文本分词之后,还需要进行布局排版,为方便后续拓展布局,我们这里参考前端的布局模型,引入 Block、InlineBlock、Inline 的概念。

同时参考浏览器的布局渲染过程,引入三棵树的概念:

  • ElementTree:用户输入,整个富文本可以通过一颗 ElementTree 来表示
  • LayoutTree:负责布局排版,会在这一层处理好文本的分词、图文混排时各自的位置等
  • RenderTree:负责渲染,这一层接收布局完成的结果,进行最终的上屏绘制

敲定技术选型、技术架构之后,我们就可以按思路拆分子任务了。

2.3 子任务:ElementTree

由于我们参考了前端的布局模型,因此我们需要告诉 AI 在 CSS 中 Block、InlineBlock、Inline 的布局规范,这个在MDN中可以直接摘录,当然也可以直接让 AI 帮我们生成(如上图)。

接着,我们需要告诉 AI 怎么构建 ElementTree,也就是上图所示 Prompt。

最后,我们就可以让 AI 参照 Prompt,生成 ElementTree 了。

ElementTree 生成完成后,我们发现遗漏了单测环节,继续完善 ElementTree 的 Prompt,然后​明确告诉 AI xx 文件新增了 xx 任务​,让 AI 继续完成任务,如下图:

ElementTree 的创建还算比较顺利,AI 理解也比较到位,生成的代码基本符合预期。

2.4 子任务:LayoutTree

同样,我们定义好 Prompt,让 AI 生成 LayoutTree。

LayoutTree 的生成不太顺利,而且从最后的测试效果看也有很多 Bug,主要如下:

  • AI 将绘制相关逻辑也加到了 LayoutTree 中,但预期绘制是单独的 RenderTree
  • 布局问题:InlineBlock 无法整体换行,多个 Inline 在同一行时被换行展示,margin、padding 不生效等
  • 对齐问题:同一行包含不同字号的文本时,对齐方式不对
  • attachment 无法显示
  • ...

2.5 子任务:RenderTree

由于 LayoutTree 这个底层基础没扎实,RenderTree 的搭建也不顺利,RenderTree 的 Prompt 如上。

2.6 BugFix

至此,AI 生成了初版的富文本渲染引擎,接下来就是让 AI 写个 Demo 试用一下,在使用过程中,发现了很多上面罗列的 Bug,针对这些 Bug,也可以让 AI 来修复:

在让 AI 修 Bug 过程中,也踩了一些坑,参见下文经验总结。

三、一些经验总结

3.1 Claude AI 常用命令

  • /init:项目初始化,第一次使用 Claude AI 时执行,每个项目只需要执行一次即可 ;会生成一个CLAUDE.md文件,这是项目的全局上下文 ,每次新建 Claude 会话时,会自动读取其中的内容;可以在CLAUDE.md文件中补充修改历史、全局说明等

  • @:可以输入@来添加文件到会话窗口,将文件作为上下文给 AI

  • /exit:关闭当前会话

  • /clear:清除当前会话上下文,和退出会话然后新开一个会话效果一样

  • /compact:压缩和总结当前会话上下文,和/clear的区别是,/compact会将当前会话上下文总结后作为当前会话的新上下文,/clear会直接清除所有上下文

  • /resume:显示和恢复历史上下文

  • 自定义 command:可以将通用的 Prompt 做成自定义 command,文件位置在.claude/commands/;还可以通过 $ARGUMENUTS 来接收自定义参数

  • /agents:有的任务比较复杂,或上下文较多,那可以拆分成多个 agents 进行组合,比如写业务逻辑 -> 构建单元测试 -> CI/CD 等,可以拆分多个 agents 组合使用

  • 会话模式:在最新版本的 Claude AI 插件中,除了之前命令行风格的 GUI 以外,还提供了会话框风格的 GUI,切换会话模式,查看历史会话等会更方便;如下,会话模式可以在输入框左下角切换

    • Edit automatically:AI 根据输入 Prompt 进行理解并直接编辑文件,一般使用该模式即可
    • Plan mode:AI 根据输入 Prompt 列出修改计划,你可以进一步校验和修改 Plan
    • Ask before edits:AI 修改文件前询问
  • MCP:常用的 MCP 是context7context7是用于帮助 AI 查找最新文档的,避免使用过时 API

3.2 经验总结

不得不感叹,AI 编程实在太强大了,相信在不久的将来,一个只会写 Prompt 的非专业程序员,也能完整交付一个 App 了。

让 AI 编程,并不是说给一句话就能让 AI 完成代码,各种细节还是需要人来提前想清楚,毕竟最终维护代码和解决问题的还是我们自己,AI 只是帮我们提效和扩展思路的工具;有句话总结的蛮好:你可以将 AI 视为一个非常聪明,甚至资深,但是没有业务经验的程序员。

下面我想总结下最近实战的一些经验,希望对各位有帮助:

1)架构设计需要提前规划好,尽量想清楚细节

谋定而后动,不管是我们自己写代码,还是让 AI 写代码,我觉得提前想好要做什么,怎么做是非常重要的。

架构设计好了,细节想清楚了,那怎么拆分子任务,其实也就明确了。

2)任务拆分越小越好,上下文越明确越好

AI 最适合做有明确输入输出的事情,给的上下文越明确,AI 产生幻觉的概率越低,输出结果也会越准确。

当然,如果是输入输出明确的任务,也可以让 AI 先输出测试用例,测试用例人工检测完备之后,再让 AI 编码也是可以的(测试驱动开发/TDD)。

3)每一项目任务做好之后再进行下一项任务

基础不牢,地动山摇!

推荐打磨好每一项子任务再继续下一项任务,否则千里之堤毁于蚁穴,每个任务都留一点坑,最终可能带来灾难性的结果!

另外,​单测是个好东西​,对每项任务补齐单测,可以有效防止后续 AI 改出问题。

4)善用 Git,防止代码污染

Claude 在 Edit automatically 模式下会直接修改文件,为了防止污染其他代码,每次让 AI 修改前尽量保证工作区干净,这样也能方便我们 Review 代码。

5)写 Prompt 尽量用明确的词汇,不要表意不清

比如在构建 ElementTree 时,我会明确告诉 AI 要支持哪些 Style,可以有效避免 AI 臆测

与之相反的反例是,在构建 LayoutTree 时,限定不足,导致 AI 自由发挥,最终实现出很多 Bug。

6)善用提示词:think < think hard < think harder < ultrathink

可以在 Prompt 中追加 think hard / think harder 等词汇,来让 AI 进入​深度思考 ​,这并不是什么黑魔法,而是 Claude AI 官方认证的,参见:https://www.anthropic.com/engineering/claude-code-best-practices

实践下来,确实还是有效果的,如下是让 AI 修复文本对齐问题,加了 think hard AI 会更深入理解代码,找到问题原因;当然,这种方式也有弊端,就是会耗费更多的 token(money)👺

7)善用/compact ​​​ ​/clear命令,减少模型幻觉

如果不主动清除,Claude AI 会话中的上下文是会一直保存的,当一个会话中问答轮次过多,可能会导致 AI 理解不准确(幻觉)。

可以通过/compact/clear命令,来压缩/清除上下文。

一般我在修复有关联性的 Bug 时,会使用/compact命令,这样 AI 就不需要重新理解工程,理解 Bug 了,可以提高效率。

8)BugFix 尽量构造最小可复现 Demo

BugFix 其实也是一个子任务,最小可复现 Demo 减少 AI 的理解负担。

9)及时人工介入,避免在一个问题上死磕

有时候让 AI 修复 Bug 时,可能反复修改都解决不了,这时候大概率是 AI 没有真正理解问题,或者就是输入的 Prompt 有问题,这种情况下就没必要让 AI 死磕问题了,我们可以及时人工介入,避免浪费时间。

10)善用 Plan 模式

在任务拆分时,我们自己可能也没想明白应该怎么做,那可以切换到 Plan 模式,让 AI 和我们一起拆任务。

3.3 Vibe Coding 的一些弊端

1)付费,而且还挺贵!

这是一个挺现实的问题,一些好的模型都挺贵,而且还是消耗的刀乐,国内厂商的模型质量又不尽如人意。

2)编码风格问题 & 扩展性、易用性、鲁棒性不足

AI 写的代码还是挺容易看出来的,感觉很难带有程序员的个人风格,一个明显的表现是会用一些比较少见的 API,虽然,这可能也是 AI 的厉害之处。

另外,AI 在一些函数复用性、扩展性、使用方便性上有时候差强人意,比如 AI 生成代码如下:如果要配置 Element 的 Style,需要不断的调用text.style.xxx,但其实写成链式调用使用起来会更舒服,如下注释部分

复制代码
let text = TextElement(text: "一、晨光初照")
text.style.color = .red
text.style.font = UIFont.systemFont(ofSize: 17)

// 更好的写法
// text.style.setColor(xxx).setFont(xxx)

鲁棒性方面,AI 不会主动考虑调用场景,比如我虽然告诉了 AI 我要支持子线程布局,但是 AI 生成的代码并不是线程安全的。

当然,上述这些,可以通过完善 Prompt 来部分弥补。

3)问题定位幻觉

有时候让 AI 排查一些 Bug,它无法找到真正的原因,反复修改后还是有问题。

这种情况下,就需要人工介入了,我们可以自己定位问题,再告诉 AI 怎么修改,而不要让 AI 死磕问题,避免浪费时间。

四、贴下源码 & Prompt

https://github.com/HusterYP/RichView/tree/main

内容首发在公众号「非专业程序员Ping」,觉得有用的话,三连再走吧~ (⁎˃ᴗ˂⁎)

富文本相关,你可能感兴趣:

相关推荐
m0_495562783 小时前
Swift的逃逸闭包
服务器·php·swift
00后程序员张4 小时前
HTTP抓包工具推荐,Fiddler配置方法、代理设置与使用教程详解(开发者必学网络调试技巧)
网络·http·ios·小程序·fiddler·uni-app·webview
m0_495562784 小时前
Swift-static和class
java·服务器·swift
2501_940094024 小时前
iphone Delta模拟器如何从夸克网盘导入游戏ROM 附游戏资源下载
游戏·ios·iphone
紫小米4 小时前
提示词(Prompt)工程与推理优化
人工智能·ai·prompt·ai agent
狠活科技5 小时前
Claude Code 重大更新:支持一键原生安装,彻底别了 Node.js
人工智能·aigc·ai编程·claude·claude code
陈果然DeepVersion6 小时前
Java大厂面试真题:从Spring Boot到AI微服务的三轮技术拷问(二)
spring boot·redis·spring cloud·微服务·ai·java面试·rag
hello kitty w8 小时前
[6]. SpringAI Alibaba 向量化和向量数据库
ai
伟大的大威10 小时前
LLM + TFLite 搭建离线中文语音指令 NLU并部署到 Android 设备端
python·ai·nlu