我是 Calix,目前是 USC Iovine & Young 学院的二年级学生。在 LangChain 的黑客驻留期间,我继续从事我的项目 Dream。
Dream 是一款 AI 无代码工具,可通过自然语言构建功能齐全的 Web 应用程序和组件。无论是 AI 应用程序、游戏还是内部工具,Dream 都是任何技术或非技术人员构建和部署功能性网站的一种方式。Dream 用户可以创建网站项目,在每个项目内创建页面,并在每个页面内生成部分,这些部分可以侧重于设计或功能。每个部分都充当一个组件,无论是导航栏还是博客文章生成器。数据库存储、身份验证或 API(OpenAI、Twilio 等)等集成被构建为模块化功能,专门为每个部分的生成/重新生成而选择。项目发布后,所有页面和部分都会编译在一起并部署到自定义域名。
开始使用
在我驻留之初,Dream 处于半完成阶段。我在夏天开始 Dream 项目,当时的想法是“如果 GPT-4 可以生成代码,那么它可以通过足够的迭代生成功能性 Web 应用程序吗?” 那时我正在开发 Dream 的第 3 个版本,每个版本都更加注重性能、可扩展性和生成质量。每个版本之间的大部分重大转变都涉及分解语言操作,使其更加模块化和有组织,以便随着用户迭代他们的项目,输出质量可以持续提高。
一开始,我只想对代码生成过程进行一些改进并改进用户体验,但它不断发展成为一个更长、更雄心勃勃的路线图。以下是我对 Dream 所做的所有改进,以及我是如何做到的。
用于提示增强的用户体验
Dream 的最终目标是成为一个包罗万象的平台,让任何人(尤其是非技术人员)都无需编码或面对陡峭的学习曲线即可构建功能性软件并与世界分享。因此,我解决的第一个主要问题是为非技术受众构建全面的用户体验。
有许多问题需要解答。如何构建一个平台,使用户能够将想法转化为文字,再将文字转化为代码?如何传达一种体验,帮助用户清楚地表达他们项目中想要什么,即使在大多数时候他们甚至不知道自己想要什么?如何在用户指导的上下文/指令与 AI 指导的生成决策之间取得平衡?最难的是,如何从非技术的角度帮助用户调试他们的项目并处理不可预见的边缘情况?
在这 10 周里,我一直在思考这些问题,并不断思考优化用户体验的方法。
我首先尝试构建一个对话式代理,以引导用户思考并阐明他们想要构建的内容。但是,很难正确检测用户阐述的结束,而不会过早打断他们,或者冗长地持续太长时间并且过于具体。
然后,我尝试采用调查方法,提出一系列模板化的开放式问题,迫使用户倾吐认知上下文。这效果好得多,但对于我的代码生成推理来说仍然不是一个很好的输入。
最后,我尝试了几个不同的迭代来构建当前正在使用的内容。首先,用户填写一份模板化的调查问卷,其中包含开放式问题和一些多项选择答案,这些答案指导调查的逻辑流程。然后,使用该上下文,创建正在生成的部分或修改的概述,并由此创建集成/数据源以及生成的技术范围,并显示给用户以供批准。在获得用户批准后,它会将概述和技术范围作为上下文传递,从而可以从用户调查中的几个简单答案生成详细的技术解释。
改进自定义集成
使 Dream 多功能且动态的最重要功能之一是自定义集成。Dream 具有用户常用服务和功能的预构建集成,例如 OpenAI 或文件提取。但是,Dream 用户还需要使用尚未预构建的集成和 API。这就是自定义集成发挥作用的地方。以前,Dream 通过要求用户指定他们想要的特定端点和 API 调用的所有详细信息来启用自定义集成。这仍然需要技术知识和对项目的清晰愿景,这两者都是相当大的障碍。
我想要的新体验类似于 Cursor — 用户可以放置他们想要添加的集成的文档链接,文档将被抓取并保存在内存中,并且只需在语义上提及它并描述所需的功能即可使用新的集成。
我构建此功能的第一个方法很简单:抓取所有持有相同顶级域名(例如“docs”子域名)的唯一链接,抓取每个页面上的所有内容,对其进行分块 + 嵌入,然后在生成时检索相关块。问题变得很明显:页面上有太多隐藏的乱码内容和元数据,导致检索变得越来越不准确。
我的第二种方法是抓取所有页面内容,然后在生成时使用 LangChain 的上下文压缩来分块和检索要使用的相关文档。这产生了更好的结果,但上下文窗口非常长,使得检索成本更高,并且仍然相对不准确。
最后,我确定的方法同时使用了嵌入和 Claude 2。我意识到我只需要抓取 API 参考文档和包含有关 REST API 信息(特别是,而不是 SDK!)的页面内容。为此,我使用了 Claude 2 的 10 万上下文窗口和一些基本的正则表达式匹配来对每个页面的内容进行分类,以确定它是否与要抓取的内容相关。过滤后,所有页面内容都将被分块和嵌入。在生成时,查询相关向量,然后使用 LangChain 上下文压缩进行压缩。
将生成输出从 HTML/JS 迁移到 React
以前,Dream 生成的是原始 HTML,其中包含 TailwindCSS 和 vanilla JS,用于函数调用和集成。我知道这个系统必须改变,并且在 LangChain(感谢 Jacob!)的支持下,我决定将所有项目迁移到生成 React。做出此决定有几个原因
React 更简洁、更通用且更易于使用
2. 由于原始 HTML/JS 不如 React 那样具有令牌效率,因此我的推理的上下文和完成长度变得太长
3. 它为使用预构建组件和 UI 库打开了机会,否则编写逻辑和样式会占用大量令牌
进行更改并不太难,因为它主要只是提示中的更改,但我花了很多时间设置上下文来指导 GPT-4 如何正确使用我提供给它的 UI 组件库(目前是 shadcn UI)。与集成一样,我设置了一个 LLM 选择管道来选择与正在进行的生成最相关的 UI 组件,以便尽可能缩短上下文长度,并使我的推理调用更具体和模块化。
调整提示风格和上下文管理
我对我所做的改进感到非常满意,但在 Hacker News 上偶然发现了 openv0。它是 v0 的开源版本,v0 是 Vercel 在我的黑客驻留的最初几周内一直在私下 beta 版中推广的流行平台。我非常了解 v0 以及他们想要采取的方向,并且不一定感到受到威胁。
由于 openv0 是开源的,我得到了机会了解其他人如何解决优化生成质量的问题。当我浏览代码库时,我看到了很多关于如何清理我的代码并更简洁有效地管理我的上下文模板和动态注入的机会。
更重要的是,我从以前的提示策略(主要基于示例)进行了重大转变。我在上下文中放入了 3 个自定义编写的部分示例,以指导推理遵循特定的输出格式,但最终通常会生成设计非常相似的设计,并清楚地显示出某些边缘情况生成的偏差。在 openv0 的启发下,我完全删除了我的上下文示例,并在保持良好质量并提高模型的设计灵活性的同时,大大缩短了我的上下文窗口。
结论
在为期 10 周的驻留期间,我对 Dream 进行了比我最初想象的更多的更改和改进。几个月来,我意识到像 Dream 这样的平台并不适合草率的方法,而是需要一种细致、周全的方法,并投入大量的工程时间。
非技术利益相关者尝试构建软件一直是一个长期存在的问题,而像 Bubble 这样的现有解决方案本身就具有陡峭的学习曲线。代码生成仍然是一个非常困难的技术过程,难以在生产环境中构建,并且围绕它设计直观的界面非常困难。非确定性平台仍然没有设计标准,这让我可以自由地设计全新的交互模式。
Dream 仍然是一项庞大的在建项目,过去 10 周一直充满挑战,但我很高兴继续改进该平台,并希望能够使非技术创始人、设计师和其他人构建他们以前从未能够构建的软件。
非常感谢 LangChain 和我的导师 Jacob Lee 在过去 10 周里给予的支持!1 在我解决的许多问题上获得技术指导非常有帮助,并且帮助我大大加快了工程时间。