Transcript
00:00:00这是 Flu,一个由 Astro 团队打造的开源 AI 代理构建框架,
00:00:04它基本上将 Claude Code 作为一种工具框架,并使其实现了 100% 可编程。
00:00:09因此,诸如技能、工具、沙箱等功能都开箱即用,
00:00:13只需几行 TypeScript 代码,你就能创建一个功能完备的代理框架并部署到任何地方。
00:00:19但 Astro 团队当初为什么决定构建这样一个代理框架呢?
00:00:23还有沙箱中那个能让你更低成本运行代理的炫酷技巧是什么?
00:00:28订阅频道,我们一探究竟。
00:00:33Flu 是由 Astro 的联合创始人构建的,有趣的是,
00:00:36他们最初并没有打算开发一个代理框架。
00:00:39Fred 和他的团队开发 Flu 是为了在 Astro 自己的 GitHub 仓库中运行 AI 工作流。
00:00:44但当另一位来自 Amplitude 的工程师接触到它时,
00:00:47团队意识到这是一个任何代理都可以使用的工具,
00:00:51仔细想想其实很有道理。
00:00:53我的意思是,以 Claude Code 为例。
00:00:55终端或 UI 聊天界面之下其实是一个框架,
00:00:58它支持来自 MCP 服务器的自定义工具,它能读取 Claude MD 文件,
00:01:02它有沙箱支持以及对可重用技能的支持。
00:01:05这些功能以及更多其他特性使模型能够完成实际工作,
00:01:08而 Flu 只需几行代码就能为你提供这些能力。
00:01:11它之所以能做到这一点,是因为它建立在 Pi 之上,而 Pi 本身就是一个极简的代理框架,
00:01:16这也是 OpenClaw 所依赖的基础,
00:01:18它围绕 Pi 的代理核心构建了一个真正的框架。
00:01:21Flu 在沙箱方面确实做了一些巧妙的处理,帮你降低运行成本,
00:01:25这一点我稍后再谈。
00:01:26但如果回到 Claude Code 的例子,
00:01:28它假设背后有一个人类在操纵这个代理,
00:01:31通常情况确实如此。
00:01:33但 Flu 没有这个限制。
00:01:35使用 Flu,你可以构建像 Claude Code 那样需要人类输入的代理,
00:01:38但你也可以构建完全不需要人工参与的工作流,
00:01:42这对于那些非常具体且不需要频繁变动的代理流程非常有用。
00:01:44你可能在想,
00:01:46这听起来和 Mastra 或 Vercel AI SDK 差不多,
00:01:47我稍后会谈谈它们之间的区别。
00:01:52事实上,通过一个简单的演示,区别会更清晰。
00:01:54所以,让我们开始吧。
00:01:57所以,让我们开始吧。
00:01:58首先,你需要安装 Flu 运行时,
00:02:01这是你的代理导入并运行的环境,
00:02:04然后你需要安装 Flu CLI,
00:02:06它负责编译和启动你的代理。
00:02:08你还需要从 Pi 支持的众多提供商中设置一个 API 密钥。
00:02:13在这次演示中,我将使用 Anthropic,
00:02:15然后你需要运行 flu init 以及目标,
00:02:18这将创建一个 flu 配置文件,以便 CLI 知道如何打包你的项目。
00:02:22你可以在 Node 或 Cloudflare 之间选择,
00:02:24我稍后会谈谈它们的区别。
00:02:26但我已经完成了这些步骤,
00:02:27让我们来看看这些文件长什么样。
00:02:30这里是典型的空 bun 项目生成的文件,
00:02:33其中一些文件甚至没用到。
00:02:35如果我们看 index.ts,它不会被用于任何事情。
00:02:38readme 文件也不会,
00:02:39真正用到的是这个 flu config.ts 文件,
00:02:42它在后台使用 V,
00:02:45即使用 Node 而不是 Cloudflare 的 CI。
00:02:47区别在于 Node 在 HONO 之上使用 HTTP 服务器,
00:02:51而 Cloudflare 会将你的项目部署到 worker,
00:02:53并使用持久对象(durable object)进行持久化。
00:02:55在完成这些步骤后,
00:02:56你需要创建一个新目录,
00:02:57要么是 agents 目录,要么是 workflows 目录。
00:03:00我们稍后会讲工作流,
00:03:01但现在,我从一个简单的代理开始,
00:03:03它包含文档中的代码。
00:03:05这基本上是设置了一个模型
00:03:06并添加了一些指令,
00:03:08这些指令会追加到系统提示词中。
00:03:09就是这样。
00:03:10这就是创建一个基础 Flu 代理所需的全部内容。
00:03:13让我们看看它的实际效果。
00:03:14要运行它,我们可以使用 flu connect,
00:03:15它会构建并运行代理。
00:03:17我们匹配 TS 文件的名称,
00:03:20也就是 hello world,
00:03:21然后给它一个实例 ID,
00:03:22可以是任何 ID。
00:03:24甚至可以是本地的 1, 2, 3。
00:03:25如果你运行了大量代理,这很有用,
00:03:27每个代理都可以拥有自己唯一的 ID。
00:03:29这也适用于部署到 Cloudflare,
00:03:31因为这个 ID 映射到它自己的持久对象实例。
00:03:35所以现在按下回车键,
00:03:36我们可以看到它加载了配置,
00:03:38读取目标并运行它找到的代理。
00:03:40现在我们没有代理 MD 文件,
00:03:42但如果我们有的话,它会用到它。
00:03:43现在它已经将代理构建到这个 server.mjs 文件中,
00:03:46并赋予了我们输入提示词的能力。
00:03:48所以可以说一些类似“给我讲个随机笑话”之类的话。
00:03:50这里可以看到代理开始思考,
00:03:52它做出了响应,正在流式传输其生命周期。
00:03:54然后它给我讲了一个笑话,并问我还要不要再来一个。
00:03:57但随后在下面,它打印了最终的 JSON,
00:03:59其中包括文本,
00:04:00以及一些输入和输出 token,
00:04:02整个提示词的成本,
00:04:03以及所使用的模型。
00:04:05当然,我们可以继续与该代理交谈,
00:04:06但现在我打算关闭它。
00:04:08这就是使用 Flu 构建基础代理的一个例子。
00:04:11让我们做点更复杂的。
00:04:13让我们构建一个工作流,帮助为这个 YouTube 视频生成一些标题。
00:04:15为了做到这一点,我们再次创建一个代理,
00:04:16并带有一些更复杂的指令。
00:04:18这次我们实际上有了一个技能。
00:04:20所以这个技能是用 skill import 属性导入的。
00:04:23请注意,我们不再导出代理本身,
00:04:26而是这次导出了一个名为 run 的函数。
00:04:29它的作用是为工作流初始化代理,
00:04:31然后在框架中打开一个会话。
00:04:34接下来发生的事情非常有趣。
00:04:36我们正在从 payload 中获取路径,
00:04:38也就是在这里设置的这个 flux context 类型。
00:04:41所以如果我们把名字改成了 file,
00:04:43我们会得到类型错误。
00:04:44这里正在获取文件,
00:04:46我将其命名为 script,
00:04:47并将其作为提示词传入。
00:04:49如果我们看看那边的指令,
00:04:50这一切就说得通了,
00:04:52我们告诉它研究脚本,
00:04:53并使用 title score 技能为我生成 10 个 YouTube 点击标题并进行排名。
00:04:55让我们看看这是否可行。
00:04:57但在我们这样做之前,
00:04:59我想明确一点,工作流位于 workflow 目录中,
00:05:01技能位于项目根目录下的 skills 目录中。
00:05:02要运行此工作流,
00:05:03我们需要运行 flu run 加上我们的工作流名称。
00:05:04在我的例子中是 YT titles,
00:05:06后面跟着目标和 JSON payload,
00:05:08即该脚本的路径。
00:05:09如果我们按下回车键,
00:05:10你会看到我们得到了一个工作流 ID。
00:05:13这里它在做一些奇怪的事情。
00:05:14即使我之前已经指定了,它实际上仍在寻找技能,
00:05:16现在在推理中,
00:05:18它告诉我文件系统中没有任何文件。
00:05:19你会看到我们得到了一个工作流 ID。
00:05:21这里的情况有点奇怪。
00:05:23flu 仅使用 bash 在沙箱中运行代理。
00:05:25它唯一能访问的就是技能描述,
00:05:27这些描述是在这里注册的,
00:05:27但它无法访问与技能相关的任何文件。
00:05:30技能本身,如果我们看一下,
00:05:31它实际上是使用 bash 运行一个 Python 脚本,
00:05:32以便为 YouTube 标题得出准确的 vidIQ 风格的分数。
00:05:35所以为了解决这个问题,
00:05:37我要从 flu runtime node 导入 local,
00:05:39这告诉 flu 在我的本地系统上运行代理,
00:05:42以便它能访问我的所有文件并能运行 Python 脚本。
00:05:43如果你很注重安全,
00:05:44我稍后会在视频中解释如何绕过这个问题。
00:05:47但我们还要将当前工作目录更改为该项目 skills 目录内的技能目录。
00:05:50来为 YouTube 标题评分。
00:05:51现在当我运行这个工作流时,
00:05:52我们可以看到 flu 立即读取了技能的 MD 文件,
00:05:54并能够生成 10 个带有分数的点击标题。
00:05:57现在,如果你不想让你的代理或工作流访问你的本地系统,
00:05:59你可以改为从 Python 文件创建一个自定义工具。
00:06:01在这里,我正在加载技能中的 Python 文件,
00:06:02并创建一个名为 score title 的工具,
00:06:03它使用 value bots 来验证参数并运行 Python 脚本。
00:06:04然后我们可以在代理内部注册此工具,
00:06:05一切都应该按预期工作。
00:06:07现在让我们回到之前的项目,
00:06:10假设我们想通过 HTTP POST 调用来触发它。
00:06:11好吧,要启用它,我们只需要做一件事。
00:06:13那就是只需添加路由中间件。
00:06:15现在,我们要做的就是构建 flu 项目,
00:06:17指定我们的目标和一个可选的端口,
00:06:20然后运行我们的服务器文件。
00:06:21现在它就在我们指定的端口上监听了。
00:06:22请注意,server.js 文件
00:06:25内联了我们拥有的任何代理或工作流。
00:06:26所以,如果我们想把它部署到任何支持 Node.js 的地方,我们只需要这个文件。
00:06:28现在我可以使用 POST 方法运行 curl,
00:06:30指向指定的端口,
00:06:33选择一个工作流并给它一些数据,
00:06:35这会给我们一个工作流 ID。
00:06:37然后如果我们为工作流 curl,
00:06:40指定我们的特定工作流 ID
00:06:42并传递给 JQ 以使其更易于阅读,
00:06:44我们就可以看到有关工作流的信息
00:06:47和结果摘要。
00:06:50当然,如果你想流式传输工作流信息,Flu 支持 WebSocket 而不是 HTTP。
00:06:52像往常一样,Flu 还有很多我没有时间一一介绍的功能,
00:06:54比如用于可重用代理的代理配置文件,
00:06:56对 Daytona、Cloudflare 沙箱的支持,
00:06:58或仅通过 URL 使用任何其他沙箱,
00:07:00为身份验证或健康检查添加自定义路由,
00:07:01甚至对子代理的支持。
00:07:03但与其他开源 AI 代理框架(如 Mastra)相比如何呢?
00:07:05嗯,我上次使用 Mastra 是在我制作那个视频时,
00:07:07如果你想要复习它是什么,可以暂停本视频去看一看。
00:07:09但我使用它时,
00:07:11你仍然需要手动设置会话、
00:07:13内存、沙箱和工具加载。
00:07:14这是一个非常颗粒化的循序渐进过程,
00:07:16我不确定它是否已经变得更简单了,
00:07:18但我认为 Flu 采取的方法完全不同。
00:07:21它更多的是一种框架优先的方法,
00:07:23并假设你从一开始就会使用这些功能。
00:07:25说到沙箱,
00:07:27Flu 确实对它们做了些非常聪明的处理。
00:07:29因此,默认情况下每个代理都有自己的沙箱,
00:07:31正如我在演示中早些时候解释的那样,
00:07:33但这个沙箱是由 Vercel 的 just Bash 驱动的,
00:07:35它用 TypeScript 重新实现了 Bash。
00:07:37所以它是在内存中运行这个沙箱,
00:07:40而不是真正的容器,
00:07:42这意味着你可以使用 grep、glob 和读取工具,
00:07:44而不必每次都为容器付费,
00:07:45容器在你能做任何事情之前,
00:07:48还得启动整台 Linux 机器。
00:07:49这意味着 Flu 可以以极低的成本运行数千个代理,
00:07:50并且只有在你需要时,
00:07:52你才可以切换到真正的容器。
00:07:54但当我使用它时,
00:07:55你仍然需要手动设置会话、
00:07:58内存、沙箱和工具加载。
00:08:01那是一个更加颗粒化的分步过程,
00:08:03我不确定现在是否已经改变
00:08:05变得更简单了,
00:08:06但我认为 Flu 采取的方法
00:08:08是完全不同的。
00:08:10这更像是一种框架优先的方法,
00:08:11并且假设你一开始
00:08:13就会用到这些功能。
00:08:14说到沙箱,
00:08:16Flu 在这方面确实做得非常巧妙。
00:08:18因此,默认情况下每个代理都有自己的沙箱,
00:08:21这我在演示中早些时候已经解释过了,
00:08:22但这个沙箱是由 Vercel 的 just Bash 驱动的,
00:08:25它用 TypeScript 重新实现了 Bash。
00:08:27所以它是在内存中运行这个沙箱,
00:08:29而不是真正的容器,
00:08:31这意味着你可以获得对 grep、glob 和读取工具的访问权限,
00:08:34而无需每次都支付容器费用,
00:08:35容器必须在做任何事情之前,
00:08:38启动整台 Linux 机器。
00:08:40这意味着 Flu 可以以几乎零成本,
00:08:41运行成千上万个代理,
00:08:43并且只有在你需要时,
00:08:44你才可以切换到真正的容器。
Community Posts
No posts yet. Be the first to write about this video!
Write about this video