当前位置: 首页 > news >正文

基于Next.js 14与AI SDK构建智能菜谱生成器全栈实践

1. 项目概述:一个由AI驱动的智能菜谱生成器

最近在捣鼓一些AI应用落地的项目,发现了一个挺有意思的开源项目——Chef Genie。简单来说,这就是一个“AI大厨”,你告诉它你冰箱里有什么、想吃什么口味、有什么忌口,它就能给你生成一份像模像样的菜谱。项目本身基于Next.js 14构建,集成了OpenAI、Supabase、Clerk等一堆现代Web开发的热门技术栈,非常适合想学习如何将这些技术组合起来,打造一个完整AI应用的开发者。

我自己也尝试部署和魔改了一下,发现它不仅仅是一个玩具。从技术选型到实现细节,都体现了当前全栈开发的一些最佳实践。比如用Next.js 14的Server Actions处理AI请求,用Clerk做无痛身份验证,用Supabase管理用户数据和生成的菜谱。整个流程跑下来,对理解如何构建一个数据驱动、用户友好的AI交互应用很有帮助。无论你是想学习Next.js全栈开发,还是想了解如何将ChatGPT API集成到自己的产品中,这个项目都是一个不错的起点。

2. 技术栈深度解析与选型考量

2.1 核心框架:为什么是Next.js 14 App Router?

项目选择了Next.js 14,并且明确使用了App Router模式,这几乎是2024年新建React项目的默认选择了。App Router带来的最大改变是基于文件系统的路由和**服务端组件(Server Components)**的默认支持。

对于Chef Genie这样的AI应用来说,使用Server Components和Server Actions有天然优势。生成菜谱是一个需要调用OpenAI API的“慢操作”,如果放在客户端,不仅会暴露API密钥(虽然可以通过代理,但增加了复杂性),还会因为网络延迟导致用户体验不佳。通过Server Action,我们可以在服务端安全地调用AI接口,并将生成的流式结果逐步推送到客户端。这意味着用户提交请求后,能看到菜谱标题、食材、步骤一条条“流式”地出现,而不是对着一个空白页面干等,体验提升非常明显。

另一个关键点是SEO和性能。菜谱生成页面如果被分享,其内容(生成的菜谱)是希望被搜索引擎收录的。使用Server Components可以在构建时或请求时生成完整的HTML,对搜索引擎友好。同时,Next.js内置的图片优化、字体优化、脚本加载策略,都为这个可能包含大量文本和图片(未来扩展)的应用提供了性能保障。

注意:从Pages Router迁移到App Router需要一定的学习成本,尤其是数据获取、缓存和渲染策略的理解。但长远来看,拥抱App Router是更优解,其开发模式更统一,功能也更强大。

2.2 AI集成:Vercel AI SDK的价值所在

项目没有直接裸调OpenAI的Node.js SDK,而是引入了Vercel AI SDK。这是一个明智的选择,它不是一个“套壳”,而是一个强大的抽象层

首先,它提供了统一的流式响应(Streaming)处理。OpenAI的Chat Completion API支持以流的形式返回token,Vercel AI SDK的streamText函数让处理这种流式响应变得异常简单,几行代码就能在Next.js的Server Action中实现,并配合useChat等React Hook在前端实时渲染。如果你自己手动处理分块解码、状态管理,会麻烦很多。

其次,它带来了多模型支持的可能性。虽然当前项目只用了GPT-3.5 Turbo,但AI SDK的接口设计是模型无关的。这意味着如果你未来想换成Anthropic的Claude、Google的Gemini,甚至本地部署的Ollama模型,只需要更换配置和调用函数,业务逻辑代码改动可以降到最低。这种可移植性对于长期维护的项目至关重要。

最后,它内置了一些实用工具,比如计算Token数量(对于控制成本很有用)、处理AI消息的历史记录等。这些工具函数能避免重复造轮子,让开发者更专注于提示工程和业务逻辑。

2.3 数据层与身份验证:Supabase + Clerk的组合拳

为什么选择Supabase而不是独立的PostgreSQL数据库加自研API?对于这样一个起步项目,开发速度一体化体验是关键。Supabase提供了开箱即用的实时数据库、身份认证、存储和边缘函数,其与PostgreSQL的深度绑定意味着你可以用标准的SQL操作数据,同时享受BaaS(后端即服务)的便利。

在Chef Genie中,Supabase很可能用于存储用户生成的菜谱历史、收藏夹,或者用户自定义的食材偏好。通过Row Level Security(RLS),可以方便地实现数据隔离,确保用户只能访问自己的数据。其JavaScript/TypeScript客户端库非常易用,与Next.js的Server Components和Server Actions能很好地配合。

身份验证则交给了Clerk。这是一个专门做开发者体验的Auth服务。它的优势在于提供了预构建的、可定制的UI组件(如<SignInButton />,<UserButton />),以及完整的用户管理后台。集成Clerk通常只需要几行代码,就能获得邮箱/密码、社交登录(Google, GitHub等)、多因素认证等全套功能。对于个人开发者或小团队,使用Clerk或类似服务(如Auth.js)远比从头实现一套安全、稳定的认证系统要高效、安全得多。

这个组合(Supabase + Clerk)实际上形成了一种“后端即服务”的架构,让前端开发者能够快速构建出功能完整的全栈应用,而无需深入后端基础设施的运维。

2.4 UI与样式:从Tailwind CSS到shadcn/ui的演进

技术栈中UI部分的选择非常具有代表性:Tailwind CSS + Radix UI + shadcn/ui。

Tailwind CSS是实用优先的CSS框架,它通过提供大量原子类来加速UI开发。在Chef Genie这样的项目中,它能确保样式的高度定制化和一致性,同时避免了传统CSS可能出现的类名冲突和样式臃肿问题。

Radix UI是一个“无头”(Headless)UI组件库。它不提供任何样式,只提供完全无障碍、功能完备的交互逻辑和组件状态管理。例如,一个下拉菜单(Dropdown)的打开/关闭状态、焦点管理、键盘导航等复杂交互,Radix UI都帮你处理好了。开发者需要自己用Tailwind CSS来给它“穿衣服”(添加样式)。这带来了极大的样式自由度和可控性。

shadcn/ui正是基于上述两者理念的产物。它不是一个通过npm install安装的组件库,而是一套你可以复制粘贴到自己项目中的高质量组件代码。这些组件使用Radix UI作为功能基座,用Tailwind CSS编写样式。你可以完全控制这些组件的源代码,并根据项目需求进行任意修改。这对于需要品牌定制化,但又不想从零开始造轮子的项目来说,是完美的选择。Chef Genie采用它,既能获得美观、一致的UI,又能保持技术的纯粹性和可维护性。

3. 项目本地运行与核心配置详解

3.1 环境准备与依赖安装

要运行这个项目,你需要一个相对现代的Node.js环境(建议18.17或更高版本)。项目使用pnpm作为包管理器,这比传统的npmyarn在安装速度和磁盘空间利用上更有优势。如果你没有安装pnpm,可以通过npm install -g pnpm快速安装。

第一步是克隆代码并安装依赖,这看起来简单,但有几个细节需要注意:

git clone https://github.com/giacomogaglione/chef-genie.git cd chef-genie pnpm install

执行pnpm install时,它会读取package.jsonpnpm-lock.yaml,确保安装的依赖版本与作者锁定的版本完全一致。这能最大程度避免“在我机器上是好的”这类问题。如果安装过程中出现网络问题,可以尝试配置淘宝镜像源或使用科学的上网方式(此处指代合规的网络加速服务,需用户自行合法解决)。

3.2 环境变量配置:项目的命脉

这是最关键的一步,所有第三方服务的接入都依赖于此。项目提供了一个.env.example文件作为模板。

cp .env.example .env

接下来,你需要用文本编辑器打开新创建的.env文件,并逐一填写以下关键变量:

  1. OpenAI API Key (OPENAI_API_KEY)

    • 作用:调用GPT模型生成菜谱的核心凭证。
    • 获取:前往 OpenAI平台 注册登录,创建新的API Key。注意,新账号通常有免费额度,但生成菜谱这类文本任务消耗token,需关注用量和成本。
    • 安全警告:此密钥绝不能提交到Git仓库。.env文件已被项目.gitignore排除,请务必确认。
  2. Clerk密钥 (NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,CLERK_SECRET_KEY)

    • 作用:用于前端展示登录组件和后端验证用户身份。
    • 获取:在 Clerk仪表板 创建新应用后,在“API Keys”页面即可找到这两组密钥。NEXT_PUBLIC_前缀的变量意味着它可以在客户端代码中被访问,而CLERK_SECRET_KEY仅用于服务端。
  3. Supabase连接信息 (NEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEY,SUPABASE_SERVICE_ROLE_KEY)

    • 作用:连接你的Supabase项目数据库。
    • 获取:在 Supabase控制台 创建新项目后,进入项目设置(Settings) -> API页面。Project URL就是NEXT_PUBLIC_SUPABASE_URLanonpublic密钥就是NEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYservice_role密钥,拥有绕过RLS的权限,必须妥善保管,仅用于服务端
    • 配置延伸:你还需要在Supabase中根据项目SQL文件(如果提供)创建数据表,或者根据项目代码中的类型定义来设计表结构。通常,你需要一个recipes表来存储生成的菜谱,字段可能包括id,user_id(关联Clerk用户ID),title,ingredients,instructions,created_at等。
  4. Vercel Analytics (VERCEL_ANALYTICS_ID)

    • 作用:如果你将项目部署到Vercel并启用了Analytics功能,可以在此配置ID以收集页面访问数据。本地开发时可留空或使用假值。

实操心得:建议在填写前,先在对应的服务平台(OpenAI, Clerk, Supabase)完成账号注册和项目创建,形成一个清晰的配置清单。一个常见的错误是复制密钥时多出空格或换行符,导致连接失败。如果运行时出现认证错误,第一件事就是检查.env文件中的值是否完全正确。

3.3 启动开发服务器与初步验证

配置完成后,运行开发命令:

pnpm run dev

如果一切顺利,终端会输出类似“Ready on http://localhost:3000”的信息。此时在浏览器打开http://localhost:3000,你应该能看到应用界面。

首先测试的是身份验证流程。点击登录/注册按钮,应该能跳转到Clerk提供的托管认证页面。成功注册或登录后,会被重定向回应用,并且UI上会显示你的用户头像或邮箱。这一步验证了Clerk集成是成功的。

接下来测试核心的AI功能。在输入框中尝试输入一些食材,比如“西红柿,鸡蛋,盐”,选择“中式”口味,点击生成。此时,观察两个方面:

  1. 网络请求:打开浏览器开发者工具的“网络”(Network)选项卡,你应该能看到一个向/api或类似本地端点发出的请求,并且响应类型可能是“text/event-stream”,这表明流式响应在工作。
  2. 界面反馈:菜谱应该以逐字或逐段的形式显示出来,而不是整个页面卡住后一次性弹出。

如果这两步都成功了,恭喜你,项目的核心链路已经跑通。如果失败,请根据终端和浏览器控制台的错误信息进行排查,最常见的问题依然是环境变量配置错误或第三方服务(如OpenAI)的额度用尽。

4. 核心功能实现与代码剖析

4.1 AI菜谱生成:提示工程与流式响应

项目的核心灵魂在于如何与GPT对话,让它扮演一个厨师。这不仅仅是一个简单的API调用,而是涉及提示工程(Prompt Engineering)

在代码中,你可能会找到一个类似这样的提示词模板:

const prompt = ` 你是一位专业且富有创造力的厨师。请根据用户提供的食材、菜系偏好和饮食限制,生成一份详细的菜谱。 请严格按照以下JSON格式回应,不要包含任何其他解释: { "title": "菜谱名称", "description": "一段吸引人的简短描述", "ingredients": ["食材1及用量", "食材2及用量", ...], "instructions": ["步骤1", "步骤2", ...], "tips": "一些烹饪小贴士" } 用户输入: 食材:${ingredients} 菜系偏好:${cuisine} 饮食限制:${restrictions} `;

这个提示词做了几件关键事:

  1. 设定角色:让AI进入“专业厨师”的语境。
  2. 明确指令:要求生成“详细的菜谱”。
  3. 结构化输出:强制要求以特定JSON格式回应,这极大简化了后端处理逻辑。前端可以直接将流式响应的最终结果解析为JavaScript对象,方便渲染。
  4. 注入变量:将用户输入的食材、口味等动态插入提示词中。

在Server Action中,调用Vercel AI SDK的流程大致如下:

import { streamText } from 'ai'; import { openai } from '@ai-sdk/openai'; export async function generateRecipe(ingredients: string, cuisine: string) { 'use server'; // Next.js Server Action标记 const result = streamText({ model: openai('gpt-3.5-turbo'), // 指定模型 prompt: prompt, // 上面构建的提示词 temperature: 0.7, // 控制创造性,0.7是一个平衡值 }); // 将AI SDK的流式响应转换为Next.js可用的流 return result.toDataStreamResponse(); }

前端则使用useChatHook来连接这个Server Action,并实时更新UI:

import { useChat } from 'ai/react'; export function RecipeForm() { const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({ api: '/api/recipe', // 指向你的Server Action路由 }); // messages数组会随着流式响应的推进自动更新 // 你可以遍历messages,将最后一条AI回复的内容解析为JSON并渲染 }

这种模式清晰地将AI逻辑隔离在服务端,前端只负责展示和交互,是构建AI应用的推荐架构。

4.2 用户数据持久化:与Supabase的交互

生成菜谱后,用户很可能希望保存它。这就涉及到将数据存入Supabase。通常在生成菜谱的Server Action中或生成完成后,前端发起一个保存请求。

首先,你需要确保Supabase客户端在服务端和客户端都能正确初始化。项目通常会有一个lib/supabase.ts文件:

import { createClient } from '@supabase/supabase-js'; const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!; const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!; export const supabase = createClient(supabaseUrl, supabaseAnonKey);

在Server Action中保存菜谱时,你需要使用服务端Supabase客户端,并传入SUPABASE_SERVICE_ROLE_KEY以获得足够权限,或者利用从Clerk获取的当前用户ID,结合Supabase的RLS策略进行安全插入。

假设有一个recipes表,其RLS策略允许认证用户插入自己的数据:

CREATE POLICY "Users can insert their own recipes" ON recipes FOR INSERT TO authenticated WITH CHECK (auth.uid() = user_id);

那么在Server Action中,保存逻辑可能如下:

import { supabaseServer } from '@/lib/supabase-server'; // 使用服务端密钥初始化的客户端 import { auth } from '@clerk/nextjs/server'; export async function saveRecipe(recipeData: any) { 'use server'; const { userId } = auth(); // 从Clerk获取当前用户ID if (!userId) throw new Error('未认证'); const { error } = await supabaseServer .from('recipes') .insert({ user_id: userId, title: recipeData.title, ingredients: recipeData.ingredients, instructions: recipeData.instructions, // ... 其他字段 }); if (error) throw error; return { success: true }; }

前端则可以调用这个Server Action,并处理成功或错误状态。这样,一个完整的“生成-保存”闭环就实现了。

4.3 前端状态管理与UI交互

对于这样一个交互相对集中的应用,状态管理并不复杂。React的useStateuseEffect配合Server Actions和useChatHook基本够用。

一个典型的页面状态可能包括:

  • inputIngredients: 用户输入的食材字符串。
  • selectedCuisine: 选择的菜系。
  • isGenerating: 是否正在生成菜谱(来自useChatisLoading)。
  • generatedRecipe: 解析后的菜谱对象。
  • savedRecipes: 从Supabase获取的用户已保存菜谱列表。

UI交互的重点在于良好的反馈。当用户点击“生成”时,按钮应变为禁用状态并显示加载指示器(如旋转图标)。使用useChatHook提供的流式响应,菜谱内容应逐行或逐段出现,可以加入一个打字机效果(Typewriter Effect)的组件来提升体验。

对于保存功能,成功或失败应有即时的Toast通知。可以使用react-hot-toastsonner(与shadcn/ui风格很搭)这样的轻量库来实现。

5. 部署指南与生产环境考量

5.1 部署到Vercel

由于项目本身就是为Vercel优化的,部署过程非常顺畅。

  1. 推送代码到Git仓库:将你的代码(注意不要包含.env文件)推送到GitHub、GitLab或Bitbucket。
  2. 在Vercel导入项目:登录 Vercel ,点击“Add New” -> “Project”,选择你刚推送的仓库。
  3. 配置环境变量:在项目设置的“Environment Variables”页面,将你在本地.env文件中配置的所有变量,一一添加进去。这是最关键的一步,确保生产环境能正确连接所有服务。
  4. 部署:Vercel会自动检测到这是Next.js项目,并配置好构建命令和输出目录。点击“Deploy”即可。

部署后,Vercel会为你生成一个生产环境的URL(如chef-genie.vercel.app)。你可以访问这个链接,测试生产环境下的认证、AI生成和数据库功能是否全部正常。

5.2 生产环境优化与安全加固

将开发项目变为可用的生产应用,还需要一些额外步骤:

  1. 自定义域名与SSL:在Vercel项目设置中,可以绑定你自己的域名,并自动配置免费的SSL证书。
  2. Clerk生产实例:在Clerk仪表板中,将你的应用环境从“开发”切换到“生产”。你需要为生产环境配置允许的回调URL(即你的Vercel生产域名)。生产环境下的密钥与开发环境不同,记得在Vercel环境变量中更新。
  3. Supabase生产数据库:Supabase的免费计划足够支撑小规模使用。确保生产环境连接的是Supabase生产项目的URL和密钥。考虑为生产数据库建立单独的连接,并与开发数据隔离。
  4. OpenAI API成本与限额:在OpenAI平台,为生产环境的API Key设置使用限额(Spending Limits),防止意外超支。同时,考虑对用户进行限流(Rate Limiting),例如每个用户每小时只能生成有限次数的菜谱,这可以在Next.js的Server Action中通过检查数据库记录来实现。
  5. 错误监控与日志:集成像Sentry或Logtail这样的服务,监控运行时错误和性能。Vercel自身也提供函数日志和Analytics。
  6. 内容安全策略(CSP):由于涉及AI生成内容,建议配置严格的CSP头,防止XSS攻击。Next.js可以通过next.config.js中的headers函数进行配置。

5.3 性能与扩展性思考

当前架构对于中小流量已经足够。如果用户量增长,可以考虑以下方向:

  • AI响应缓存:相同的食材和偏好组合,可能会生成相同或相似的菜谱。可以在Server Action中引入缓存层(如使用Vercel KV、Upstash Redis或直接在Supabase中缓存结果),对请求参数进行哈希,短时间内相同的请求直接返回缓存结果,大幅降低OpenAI API调用成本和响应时间。
  • 数据库索引优化:如果recipes表数据量变大,频繁按user_idcreated_at查询,务必在相应字段上创建数据库索引。
  • 静态资源优化:未来如果添加菜谱图片,应使用Next.js的<Image />组件进行自动优化,并考虑将图片存储到Supabase Storage或Vercel Blob中。

6. 常见问题排查与调试技巧

在实际运行和魔改过程中,你肯定会遇到各种问题。这里记录一些典型问题的排查思路。

6.1 环境变量相关错误

  • 症状:应用启动失败,或功能(登录、AI生成)不可用,控制台报错“Missing API Key”或“Invalid Supabase URL”。
  • 排查
    1. 本地:确认.env文件在项目根目录,且变量名与代码中process.env.XXX引用的完全一致(注意大小写)。重启开发服务器(pnpm dev)。
    2. Vercel生产环境:登录Vercel控制台,进入项目设置 -> Environment Variables,逐一核对所有变量是否已添加且值正确。特别注意密钥中是否有意外空格。修改后需要触发重新部署。

6.2 AI生成失败或响应慢

  • 症状:点击生成后无反应,或等待很久后报错。
  • 排查
    1. OpenAI额度:首先检查OpenAI平台账户的额度是否用尽或过期。
    2. 网络问题:Server Action调用OpenAI API受服务器网络影响。如果部署在Vercel,其服务器全球分布,通常网络良好。本地开发时,不稳定的网络可能导致超时。
    3. 提示词与参数:检查传递给AI的提示词是否过长或格式错误。过高的temperature参数可能导致生成时间变长。尝试将temperature调低至0.5,或设置max_tokens限制生成长度。
    4. 流式响应中断:检查前端useChat配置和后端Server Action的流式返回逻辑。确保没有在流结束前过早关闭连接。

6.3 身份验证问题

  • 症状:无法登录/注册,或登录后用户状态不持久。
  • 排查
    1. Clerk密钥:确认NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYCLERK_SECRET_KEY配对正确,且来自同一Clerk应用实例。
    2. 回调URL:在Clerk仪表板的“Redirects”设置中,确保添加了你的应用地址(本地开发是http://localhost:3000,生产环境是你的Vercel域名)到“Allowed redirect URLs”和“Allowed callback URLs”。
    3. 中间件配置:Next.js项目通常有一个middleware.ts文件来处理Clerk认证。检查其matcher配置,确保需要保护的页面路由被正确覆盖。

6.4 数据库操作失败

  • 症状:保存菜谱失败,前端报“RLS policy violation”或“insert error”。
  • 排查
    1. RLS策略:登录Supabase控制台,进入“Authentication” -> “Policies”,检查recipes表的INSERT策略是否已正确创建并启用。确保策略中的auth.uid()能与Clerk的用户ID对应上。有时需要创建一个自定义函数来将Clerk的userId映射到Supabase的auth.users表。
    2. 用户ID映射:这是一个常见痛点。Clerk的用户ID与Supabase内置的auth.users表的ID不同。常见的做法是:在用户首次登录时,在一个自定义的profiles表或直接在你的recipes表中,将Clerk的userId存储为一个字段(如clerk_user_id)。然后,你的RLS策略需要基于这个自定义字段进行校验,而不是auth.uid()。或者,使用Clerk的Webhooks在用户注册时,在Supabase的auth.users表中创建一条对应记录,但这更复杂。
    3. 表结构:确认你插入的数据字段名、类型与数据库表定义完全一致。

6.5 样式或组件显示异常

  • 症状:页面布局错乱,或shadcn/ui组件无法交互。
  • 排查
    1. Tailwind CSS类名冲突:检查是否在全局CSS或组件中引入了其他可能冲突的样式库。
    2. Radix UI Provider缺失:许多Radix UI组件需要被对应的Provider包裹(如ToastProvider,DialogProvider)。检查应用的根布局(app/layout.tsx)是否包含了必要的Provider。
    3. CSS变量未定义:shadcn/ui的样式依赖于一套CSS变量(如--background,--foreground)。检查app/globals.css中是否引入了主题CSS文件,并正确定义了这些变量。

调试时,养成习惯:首先查看浏览器开发者控制台的“Console”和“Network”选项卡,这里通常有最直接的错误信息。对于服务端错误,查看Vercel部署日志或本地终端输出。对于数据库问题,Supabase控制台的“SQL Editor”和“Table Editor”是验证数据和SQL语句的好帮手。

http://www.jsqmd.com/news/806269/

相关文章:

  • 基于LLM与插件化架构构建个人办公自动化智能体:从原理到实践
  • 2026乡村桥梁护栏哪家好:市政道路防撞护栏/景观道路护栏/桥梁河道景观护栏/河道景观桥梁护栏/河道桥梁景观护栏/选择指南 - 优质品牌商家
  • 保姆级教程:用Keil5和GD32F103 SDK从零搭建开发环境(附J-Link/ST-Link烧录避坑)
  • 智能体通信协议agentic-signal:构建高效多智能体系统的核心
  • AI智能体开发工具链全解析:从运行时到部署的实战选型指南
  • 5分钟搞定Word参考文献格式:APA第7版免费终极安装指南
  • 星间光传输FPGA实时收发算法【附代码】
  • 2026年5月更新成都小型别墅电梯实力公司哪家强 - 2026年企业推荐榜
  • 嵌入式系统开发变革:MBSE与PLM工具链的协同实践
  • AlphaPy:量化金融与AI的自动化管道实践
  • AGHub:统一管理AI编码助手配置与技能,打造高效开发工作流
  • 3步搞定B站视频下载:BBDown让你的收藏从未如此简单 [特殊字符]
  • 如何免费激活Windows和Office:KMS智能激活完整指南
  • Unity任务系统框架设计:数据驱动与事件架构实践
  • 淘金币自动化脚本:每天6分钟搞定淘宝全任务,彻底解放你的双手
  • Testcontainers Keycloak:Java微服务身份认证测试的容器化解决方案
  • 多智能体协作AI漫剧生成平台:从架构到部署的完整实践
  • 2026宜宾装饰公司推荐:性价比比较高的装饰公司、本地装修公司、本地装饰公司、装修公司排行榜、附近装修公司、附近装饰公司推荐选择指南 - 优质品牌商家
  • Vivid MCP:基于MCP协议与AI Agent的企业银行开户自动化实践
  • 基于T4技术栈的现代全栈应用开发实践与最佳实践解析
  • OpenClaw用户如何快速接入Taotoken以扩展Agent能力
  • Shell 脚本中 grep 匹配不到内容返回码 1 怎么忽略?
  • Capacitor-Mobile-Claw:简化混合应用原生功能集成的开发利器
  • FlowGlad:轻量级数据流编排框架的设计理念与实践指南
  • 基于Next.js与Tailwind CSS构建高性能数学学院官网实战指南
  • 芯片工艺节点迁移的技术挑战与成本分析
  • 2026高端定制护栏厂家标杆名录:旋转楼梯/无框架(极简)护栏/楼梯生产出口/楼梯踏板/泳池护栏/焊接护栏/现代简约楼梯/选择指南 - 优质品牌商家
  • Arm架构DC IGVAC指令与MTE缓存维护详解
  • Vector RAG失效了?GraphRAG和Vectorless RAG这两种新方案,如何让你的AI系统更准确?
  • 基于Vue 3与UnoCSS构建轻量级个人导航页:从零部署到高级定制