老胡茶室
老胡茶室

GitHub Copilot Agent Vibe Coding 实录:构建 AI 增强的个人博客

胡键

GitHub Copilot 最近也推出了 agent 模式,作为一名温和的技术激进派,尝鲜那是必须的。于是乎,就有了本文。

注:虽然本文是付费文章,但正文完全是免费的,付费的仅仅是文章对应的代码。因此,它并不影响你通过本文了解 copilot agent 的编程体验。

实现的练手项目源自我自己的需求:符合当前 ai 时代的静态博客生成站点,具体的特性如下:

  • 静态博客生成,当然必须支持标签,但不必有评论。
  • 支持页面内 ai 对话,对于代码块需要有语法着色和高亮。
  • 支持 llms.txt 生成

效果图

整体效果

image

Chat UI

image

RAG

image

语法高亮

image

llms.txt

image

  • llms-full.txt

image

闲话少说,直奔正题吧!

实战

准备

别误解,这里并非什么软件安装和服务配置之类的无聊话题,我也懒得说。这里主要是指学习!即:看看别人是如何使用 copilot agent 的,具体可以直奔这个链接去看视频:https://www.youtube.com/watch?v=dutyOc_cAEU

Action 1:工程初始化

在有如此多优秀静态博客生成器的今天,我们的项目完全没有必要从零开始。即使有了 ai agent 的加持,也没有必要就让它从头来干,即便不是我们来写代码。

这里,我们选择 Astro,利用它的 create 命令来初始化新项目即可,记得选择 blog 模板。

经验 1:Vibe Coding 不意味着放弃之前的经验,有框架支持那就优先用框架。

Action 2: 添加 Tailwind CSS

用样式,那必须是 Tailwind CSS

假若你看了上面的视频,应该就知道,在当前状况下 agent 将给你生成错误的代码,包括安装错误的依赖包和错误的配置代码。此时,按照视频里的做法,让 agent 先去 #fetch 文档就好了。

同样的,建议按照视频里的做法,配置对应的 copilot-instructions.md,它在 .github 目录下。相当于给 agent 定下一个项目内的行为准则。

此外,由于 llms.txt 趋势渐成,各个工具基本开始陆续有自己的 llms.txt 文件,因此强烈建议让 agent 去使用它。这里,为了简单,直接手动创建了一个 llms-txt 文件夹,然后将各个 llms.txtllms-full.txt 放到了里面。

此外,你还可以试试 langchain 的 mcpdoc

视频里还建议写一个 PRD 文档,也就是需求文档(其实就是 user stories),我个人觉得没有太多必要,因为咱们都知道在实际过程中需求经常变,初始需求大部分不太靠谱。再加上 agent 本来也是 llm,有上下文大小的限制,不如将这些放在对话交互时更实际。

但是,给出一些背景描述还是有意义,有助于 agent 了解项目的背景和目标。在实际中,这个往往并不会有大的变化。

这里总结一下视频中提到的关于准备工作的其他几点:

  • copilot-instructions.md 中列出技术栈和最佳实践,样板可自行搜索。
  • 最佳实践可以让 ai 帮忙生成。

经验 2:初始化工程之后,定义 agent 行为准则和提供必要的背景。

Action 3:添加标签

这一步非常顺利,简单几轮对话就完成了,其中包括了:风格调整、Content Schema 定义等等。

顺利的原因很简单:常规需求。

经验 3:常规需求,简单对话。

这里其实也给了咱们一个启示:凡所见之处, ai 一定会很快跟上 😄,不如将功夫花在它看不到的地方。

Action 4:Indexing blog

咱们的需求核心是一个针对个人博客的 RAG 系统,当然不能少了索引。这里 ai 尝试了若干次,但效果都不太理想,即便我已经明确告知它去读 llms.txt 了。

这个需求本质上有三个部分:

  1. 如何索引
  2. 对每个帖子进行索引
  3. 因为是静态站点,所以需要在构建时就索引

三个子任务仅最后一个算是正确,因为它知道该在哪里去配置并调用脚本,从而使之与 astro 的构建过程相结合。

其他两个则差强人意:

  1. 对于第一个任务,生成了不知所云的代码。即便明确告知了它技术选型,langchainpgvector,生成的代码依旧没法用。这倒也在意料之中,毕竟对于这些更新迭代较快的库,agent 也不一定能跟上。
  2. 对于第二个任务,对每个帖子进行索引,居然钻起了牛角尖,陷入固定思维模式,始终坚持尝试用 astro 的方式去解析 markdown 文件。没有在失败时去尝试其他的方式。

对此,只能采用人工干预。

对于第一个任务,简单。因为我们本来就在做一个 RAG 产品,这些 AI 相关的功能都是现成的,直接拿来稍作修改就完了。

对于第二个任务,叫停了它的尝试,提示它本来就是构建时的任务,不妨直接通过读文件的方式去解决,不要再去换着法的用 astro 了。

这次,终于往正确的方向上迈出了一步。大体逻辑没有问题,它也知道要去调用刚刚完成的 indexing 函数。但是,它依旧改不了过度设计的毛病,在帖子的元数据部分又遇到了麻烦,甚至建议了一个库来干这事。

于是,我又一次叫停,并告知去尝试正则表达式。这次终于成功了,并通过了我的人工验证:在构建过程中,帖子被正确的索引了并存入了数据库。

说起来简单,但整个过程反反复复花了不少时间。

到这一步,我们完成了:

  1. 针对每个帖子进行索引。
  2. 增量索引,这一点很重要。
    • 因为建索引是一个耗时的过程。
    • 缺省情况下,索引会在每次构建时都被重新创建,浪费。
  3. 索引的建立在构建时完成,与 astro 的构建过程完美融合。

经验 4:人工干预,该出手时就出手。

Action 5:添加 Flating Chat UI

这一步颇费了些周折。个中原因跟我既非前端专家也非 astro 专家有一定关系。但这并非主要原因,各位看细节吧。

首先,在 ui 的实现方案上有反复:经历了一次 react -> CopilotKit -> react

  1. 最开始时,直接让 ai 用 react 实现了一版。
    • 这里遇到了由于 astroui island特性和 react 组件渲染的问题。
    • ai 在此尝试了若干次,同时还反复的尝试过时 tailwind 集成方式的问题。
    • 其表现跟上面的钻牛角尖情况如出一辙,结果可想而知,都没成功。
    • 我自己也手工尝试了几次,结果也都失败了,毕竟我不是前端专家嘛!
    • 后来,我想起了 astroui island 特性并提示 ai 往此方面去想。
    • 这次终于成功了,ai 采用 inline css 之后,解决渲染问题。
  2. 然后考虑采用 CopilotKit,为未来的 chat ui 高级方案打下基础。
    • 尝试后发现 CopilotKit 对于 astro 的支持并不好,并且在阅读它的文档之后,发现与我的需求并不完全匹配,最终放弃。
    • 此处 ai 没有发挥作用。

这期间还优化了原有 astro blog 模版的 layout,并做了其他 ui 方面的小调整。

经验 5:在非专业领域指挥 ai 干活,费时费力。

Action 6:chating with AI

有了前面 ai 的工具函数,这次的任务就顺利多了,一句话就让 ai 完成了功能对接,它准确识别出了该调用的函数,虽然这不是最终的那个函数,但在 ui 上进行单轮对话基本没问题了。

同样的,通过一句话就让它给 llm 输出的 markdown 加上了语法高亮。

之后,我优化了一下函数,换上 langgraphReactAgent,并将提示词调整为 RAG 的标准模版。完成这些之后,将函数名替换掉之后,最简单的 RAG 版本就完成了。

此时,我们已经有了一个支持 hybrid search 的简版 RAG 增强的静态博客生成器。

经验 6:在专业领域指挥 ai 干活,事半功倍。

Action 7:streaming

作为 chatting 的常规功能,streaming 当然不能少。这里的实现也颇为有意思。

在我手动将 ai 工具函数调整到 streaming 模式之后(之前注销掉了,方便 ai 使用),它倒是在对接的 api endpoint 中实现了 streaming response 返回。

然而,在修改前端时则遇到了麻烦。经过提示,它了解到需要用到 ai sdk,同时也知道要用 ai sdk 的 react 组件。但实现上依旧不尽如人意,没有意识到可以直接用 useChat 来实现 ui 逻辑,以及利用 LangChainAdapter 来实现 langchainstreaming 以简化代码。

最搞笑的是,它居然自行实现了 ai sdk 的 streaming 协议,而且确实还能工作 😄。但它始终无法将其重构成我期望的样子。

最后,我手动替换了 LangChainAdapter 完成了后端 api,ai 则独立用 useChat 完成了前端的 streaming 逻辑。

经验 7: 如果不讲究,ai 也能生成烂但确实可以工作的代码。但要让它生成符合当下文档和有一定质量的代码,还需操心。

Action 8:tailwind CSS 优化和其他人工任务

到此,主体功能已经完成。于是,我打算让它优化一下整个工程的 css。

经过若干轮尝试,ai 始终无法生成符合我预期的代码。最终,我选择求助于团队的前端同事,完成了 css 的优化。

这里还将工程改成了支持 vercel 部署,这是人工完成的。因为简单到我自己干都比让 ai 干来的快。

Action 9:llms.txt

ai 在此处也没有发挥作用,因为我觉得 llms.txt 网上应该有现成答案。

果然,用关键字 “astro llms.txt” 便可得到现成的答案: https://scalabledeveloper.com/posts/llms-txt-with-astro/

有了先前的经验,读完原文,我发现经过小调整就可以直接用在项目里。于是,没让 ai 来干。

这里其实跟前面说的一样,有了 ai 并不意味着老经验就不吃香了,哈哈。

Action 10:优化 prompt 和 sainitization

调整 prompt 并没让 ai 去改,因为这里就只是一点增强:在答案中输出原文引用,就一句话的事情。

对于 sanitization,ai 完成得很好,我基本没过多干预,它很快给出了符合预期的代码。我估计原因和之前的一样,外面已经有充分多的可参考代码了。

其他

剩下的就是一些零散的杂活:代码整理、风格整理、文档整理。这里基本上都是人工完成,ai 没有介入。

总结

严格来算,整个项目算下来大约花了 3 天左右的时间,而且还不是连续的。这中间夹杂着其他工作会议和琐事。并没有想网上 ai 视频博主那么牛逼,xx 小时搞定一个应用并发布上线躺着收钱了。

如果说给这次体验打分的话,就 ai 部分来讲:6.8 分,整体表现尚可:

  • 常规需求表现稳定,对于流行工具支持到位。
  • 对于非常规需求表现一般,但也有亮点,有时会提示你一些新想法。
  • 假若用户缺乏经验,ai 表现过于软弱,无法充当在两者合作 pairing 时的专家角色。因为,专家有专家的权威嘛!而 ai 过于把用户的指令当回事。

从用时方面来讲,其实是低于我的预期的。我原本期望能在 2 天内完成。因为这样的需求,对于熟手来讲,我估计也就是 3 天的活。

不过考虑到非人类和非专家的合作,整体表现还算马马虎虎吧。

反思

关于整个过程的经验感受,我已经在上面提到过了,这里就不再赘述。

单就 vibe coding 本身来讲,个人已在之前的付费文章(见下)里提到过了,感兴趣的可以去看看。这里在补充几点:

  1. 不要纠结于 vibe coding 是否提高了编程效率。就现阶段来讲,对于 poc 和 mvp 搭建,vibe coding 可以完全胜任。
    • 从产品角度来讲,它可以用于快速验证产品想法,方便各方沟通。
    • 一旦不行,可以快速调整或放弃。
    • 此阶段,技术架构和所谓的代码质量并不是最重要的,ai 给出的方案已经足以应付此阶段的技术需求。
  2. ai 的能力还在快速演进,没有必要因为当前的表现就对其嗤之以鼻,并出于老司机的自负而拒绝。
    • 一旦技术成熟,你现在自豪的那些将不值一钱。想想,你会跟汽车去较劲谁跑得快吗?!
    • 尽早学习如何与 ai 合作,才是王道!

最后,套一句俗话:你今天看到跟 vibe coding 有关的论断可能都是错的,包括本文,哈哈。奉劝各位同行:不要坐而论道,“且吃茶去”(不知道典故的,自行搜索吧,出自《五灯会元》)!

Do you vibe coding today?

代码购买

看到这里,如果你还对代码有兴趣的话,请付费并在后台留言你的 github id,我会邀请你加入到该项目的私有仓库中,我们可以在仓库中继续关于这个示例代码的讨论。

另,在本文发布之前曾经购买过《聊聊 Vibe Coding》文章的朋友,请留下你的 github id,我会邀请你进入该仓库 😄。

付费内容

本文包含付费内容,需要会员权限才能查看完整内容。