十分钟构建一个 AI 驱动的旅行计划工具

大家好,这里公众号 Geek技术前线

想象一下,我们正在计划一次终极度假——为期两周的欧洲之旅,充满了博物馆参观、美食享受和风景徒步。

从决定参观哪些地标到找出最佳的用餐地点,选择的数量之多可能会让我们感到不知所措。

解决方案来了:一个 AI 驱动的旅行计划工具,也就是我们的CopilotKit😉。

要点总结

  • 使用 Next.jsTypeScriptTailwind CSS 构建 AI 驱动的旅行计划工具应用。
  • 使用 CopilotKit 将 AI 功能集成到旅行计划工具应用中。
  • 使用 LangchainTavily 从网络收集信息,以高效地计划旅行的各个方面。

前置条件

为了完全理解本教程,我们需要对 React 或 Next.js 有基本的了解。

以下是构建 AI 驱动的旅行计划工具所需的工具。

  • Langchain - 提供了一个框架,使 AI 代理能够搜索网络、进行研究并抓取任何主题或链接。
  • OpenAI API - 提供一个 API 密钥,使我们能够使用 ChatGPT 模型执行各种任务。
  • Tavily AI - 一个搜索引擎,使 AI 代理能够在应用程序内进行研究或抓取数据并访问实时知识。
  • CopilotKit - 一个用于构建自定义 AI 聊天机器人、应用内 AI 代理和文本区域的开源Copilot框架。

什么是 AI Copilot?

AI Copilot是一种应用内的 AI 助手,可帮助用户在应用内回答问题并采取行动。它将 LLM 直接引入我们的应用程序中。

一些常见的形式因素:

  • 聊天机器人:具有上下文感知的应用内聊天机器人,可以在应用内采取行动💬
  • AI 自动完成:具有上下文感知自动完成和插入功能的 AI 驱动的文本字段📝
  • CoAgents:可以与我们的应用程序和用户动态交互的应用内 AI Agent🤖

CopilotKit 是领先的、最强大且最易于使用的开源框架,用于构建应用内 AI Copilot。我们可以在几分钟内让一个完全自定义的 AI Copilot在我们的应用程序中运行。

项目设置和包安装

首先,在我们的终端中运行以下代码片段来创建一个 Next.js 应用程序:

npx create-next-app@latest ai-trip-planner

我们可以选择自己喜欢的配置设置。对于本教程,我们将使用 TypeScript 和 Next.js App Router。

接下来,我们将安装 Langchain 包及其依赖项。

npm install @langchain/langgraph@^0.0.7

最后,安装 CopilotKit 包。这些包使我们能够从 React 状态中检索数据,并将 AI Copilot添加到应用程序中。

npm install @copilotkit/react-ui @copilotkit/react-core @copilotkit/runtime

现在我们已经安装了这些包,让我们开始构建这个 AI 驱动的旅行计划助手吧。

构建 AI 驱动的旅行计划助手前端

首先,我将带大家了解使用静态内容创建 AI 驱动的旅行计划助手前端的过程,以定义旅行计划助手的用户界面。

要开始操作,在我们的代码编辑器中前往 /[root]/src/app,并创建一个名为 components 的文件夹。在 components 文件夹内,创建一个名为 TripPlan.tsx 的文件。

TripPlan.tsx 文件中,添加以下代码,定义一个名为 TripPlan 的 React 函数式组件。

"use client"; // Indicates that this file is a client-side file in a Next.js app

import Link from "next/link"; // Importing Link component from Next.js for navigation
import React, { useState } from "react"; // Importing React and useState hook

// Define the structure of a Todo item with an interface
interface Todo {
  time: string;
  activity: string;
  details: string;
}

// Define the TripPlan component
function TripPlan() {
  // Declare a state variable 'tripPlan' to store an array of Todo items, initialized as an empty array
  const [tripPlan, setTripPlan] = useState<Todo[]>([]);

  return (
    <div className="flex flex-col w-full min-h-screen bg-gray-100 dark:bg-gray-800">
      {/* Header section */}
      <header className="flex items-center h-16 px-4 border-b shrink-0 md:px-6 bg-white dark:bg-gray-900">
        {/* Link component for navigation */}
        <Link
          href="#"
          className="flex items-center gap-2 text-lg font-semibold md:text-base"
          prefetch={false}>
          <span className="sr-only text-gray-500">Trip Plan Dashboard</span>
          <h1>AI Trip Plan Generator</h1>
        </Link>
      </header>

      {/* Main content section */}
      <main className="flex-1 p-4 md:p-8 lg:p-10">
        <div className="container mx-auto p-4">
          <h1 className="text-2xl font-bold mb-4">Trip Plan Schedule</h1>
          <div className="overflow-x-auto">
            {/* Table for displaying the trip plan schedule */}
            <table className="min-w-full bg-white border border-gray-300">
              <thead>
                <tr>
                  <th className="px-4 py-2 border-b">Time</th>
                  <th className="px-4 py-2 border-b">Activity</th>
                  <th className="px-4 py-2 border-b">Details</th>
                </tr>
              </thead>
              <tbody>
                {/* Map over the tripPlan state to display each item in the table */}
                {tripPlan.map((item, index) => (
                  <tr
                    key={index}
                    className={index % 2 === 0 ? "bg-gray-100" : "bg-white"}>
                    <td className="px-4 py-2 border-b">{item.time}</td>
                    <td className="px-4 py-2 border-b">{item.activity}</td>
                    <td className="px-4 py-2 border-b">{item.details}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </main>
    </div>
  );
}

export default TripPlan;

接下来,前往 /[root]/src/page.tsx 文件,并添加以下代码,该代码导入 TripPlan 组件并定义一个名为 Home 的函数式组件。

import TripPlan from "./components/TripPlan";

export default function Home() {
  return <TripPlan />;
}

最后,在命令行中运行命令 npm run dev,然后访问 http://localhost:3000/

现在,我们应该在浏览器上看到如下面所示的由 AI 驱动的旅行计划助手前端。

我们现在已经准备好为这个由 AI 驱动的旅行计划助手添加 AI 功能了。

将 AI 功能集成到使用 CopilotKit 的旅行计划助手中

在这一部分,我们将学习如何向这个由 AI 驱动的旅行计划助手添加一个 AI Copilot,以使用 CopilotKit 创建旅行计划。

CopilotKit 提供了前端和后端的包。它们使我们能够接入 React 状态,并使用 AI 代理在后端处理应用程序数据。

首先,让我们将 CopilotKit 的 React 组件添加到旅行计划助手的前端。

将 CopilotKit 添加到旅行计划助手前端

在这里,我将带我们逐步完成将这个由 AI 驱动的旅行计划助手与 CopilotKit 前端集成的过程,以方便创建旅行计划。

首先,使用下面的代码片段在 /src/app/components/TripPlan.tsx 文件的顶部导入 useCopilotReadableuseCopilotAction 这两个自定义钩子。

import { useCopilotAction, useCopilotReadable } from "@copilotkit/react-core";

TripPlan 函数内部,在状态变量下方,添加以下使用 useCopilotReadable 钩子的代码,以将将要创建的旅行计划作为应用内聊天机器人的上下文添加。这个钩子使旅行计划对Copilot是可读的。

useCopilotReadable({
  description: "The user's trip plan.",
  value: tripPlan,
});

在上述代码下方,添加以下使用 useCopilotAction hook的代码,以设置一个名为 createTripPlan 的操作

该操作接受一个名为 TripDaySchedule 的参数,该参数具有旅行计划的时间、活动和细节作为属性。它包含一个处理函数,该函数根据给定的提示创建一个旅行计划。
在处理函数内部,我们使用新创建的行程计划日程来更新 tripPlan 状态,如下所示。

// Use the useCopilotAction hook to define a new action
useCopilotAction(
  {
    name: "createTripPlan", // Name of the action

    description: "Create a trip plan following a day schedule format.", // Description of the action

    parameters: [
      {
        name: "TripDaySchedule", // Name of the parameter
        type: "object[]", // Type of the parameter (array of objects)
        description: "The schedule for the day trip.", // Description of the parameter

        attributes: [
          {
            name: "time", // Name of the attribute
            type: "string", // Type of the attribute
            description: "The time of the trip day activity.", // Description of the attribute
          },
          {
            name: "activity", // Name of the attribute
            type: "string", // Type of the attribute
            description:
              "The activity to be done in a specific time of the trip day.", // Description of the attribute
          },
          {
            name: "details", // Name of the attribute
            type: "string", // Type of the attribute
            description: "The details for each activity.", // Description of the attribute
          },
        ],
        required: true, // Indicates that this parameter is required
      },
    ],

    // Handler function that sets the trip plan using the TripDaySchedule parameter
    handler: async ({ TripDaySchedule }) => {
      setTripPlan(TripDaySchedule);
    },

    render: "Creating Your Trip...", // Message to display while the action is being processed
  },
  [] // Dependency array (empty in this case)
);

之后,前往 /[根目录]/src/app/page.tsx 文件,并使用以下代码在顶部导入 CopilotKit 前端包和样式。

import { CopilotKit } from "@copilotkit/react-core";
import { CopilotSidebar } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";

然后,使用 CopilotKit 来包裹 CopilotSidebarTripPlan 组件,如下所示。CopilotKit 组件指定了 CopilotKit 后端端点(/api/copilotkit/)的 URL,而 CopilotSidebar 则渲染了应用内的聊天机器人,我们可以向其提供提示来创建行程计划。

import TripPlan from "./components/TripPlan";
import { CopilotKit } from "@copilotkit/react-core";
import { CopilotSidebar } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";

// Export the Home component as the default export
export default function Home() {
  return (
    // CopilotKit component with a runtimeUrl prop pointing to the API endpoint
    <CopilotKit runtimeUrl="/api/copilotkit">
      {/* CopilotSidebar component to provide instructions and UI for creating a trip plan */}
      <CopilotSidebar
        instructions={
          "Help the user create a trip plan. Don't add the trip plan to the response."
        } // Instructions for the copilot
        labels={{
          initial:
            "Welcome to the Trip Plan app! Describe the trip you want below.",
        }} // Labels for the copilot UI
        defaultOpen={true} // Sidebar is open by default
        clickOutsideToClose={false} // Clicking outside the sidebar does not close it
      >
        {/* Render the TripPlan component inside the CopilotSidebar */}
        <TripPlan />
      </CopilotSidebar>
    </CopilotKit>
  );
}

现在我们需要运行开发服务器并访问 http://localhost:3000/。

我们应该看到应用内的聊天机器人已集成到人工智能驱动的旅行计划助手中。

将CopilotKit后端添加到人工智能驱动的旅行计划助手中

在这里,我逐步完成将旅行计划助手与CopilotKit后端集成的过程,该后端处理来自前端的请求,并提供函数调用以及各种LLM后端,如GPT。

首先,在根目录中创建一个名为.env.local的文件。然后在该文件中添加以下环境变量,其中包含您的ChatGPTTavily搜索API密钥。

OPENAI_API_KEY="您的ChatGPT API密钥"
TAVILY_API_KEY="您的Tavily搜索API密钥"
OPENAI_MODEL=gpt-4-1106-preview

要获取ChatGPT API密钥,请导航到https://platform.openai.com/api-keys

为了获取 Tavily 搜索 API 密钥,我们需前往 https://app.tavily.com/home

接下来,我们去到 /[root]/src/app 并创建一个名为 api 的文件夹。在 api 文件夹中,我们再创建一个名为 copilotkit 的文件夹。

copilotkit 文件夹中,我们创建一个名为 research.ts 的文件。然后,我们导航至 这个 research.ts 的代码片段文件,复制代码,并将其添加到 research.ts 文件中。

现在,我们在 /[root]/src/app/api/copilotkit 文件夹中创建一个名为 route.ts 的文件。该文件将包含设置后端功能以处理 POST 请求的代码。它有条件地包含一个“研究”操作,该操作会对给定的主题进行研究。

// Import the researchWithLangGraph function from the research module
import { researchWithLangGraph } from "./research";
// Import the Action type from the @copilotkit/shared package
import { Action } from "@copilotkit/shared";
// Import the NextRequest type from the next/server module
import { NextRequest } from "next/server";
// Import required modules and classes from the @copilotkit/runtime package
import {
  CopilotRuntime,
  copilotRuntimeNextJSAppRouterEndpoint,
  OpenAIAdapter,
} from "@copilotkit/runtime";

// Define the researchAction object with type Action<any>
const researchAction: Action<any> = {
  name: "research", // Name of the action
  description:
    "Call this function to research on a certain topic. Respect other notes about when to call this function", // Description of the action
  parameters: [
    {
      name: "topic", // Name of the parameter
      type: "string", // Type of the parameter, which is a string
      description: "The topic to research. 5 characters or longer.", // Description of the parameter
    },
  ],
  // Define the handler function for the action, which is asynchronous
  handler: async ({ topic }) => {
    console.log("Researching topic: ", topic); // Log the topic being researched
    return await researchWithLangGraph(topic); // Call the researchWithLangGraph function with the topic and return the result
  },
};

// Define the POST function to handle POST requests
export const POST = async (req: NextRequest) => {
  const actions: Action<any>[] = []; // Initialize an empty array to hold actions

  // Check if the TAVILY_API_KEY environment variable is set and not equal to "NONE"
  if (
    process.env["TAVILY_API_KEY"] &&
    process.env["TAVILY_API_KEY"] !== "NONE"
  ) {
    actions.push(researchAction); // Add the researchAction to the actions array
  }

  const openaiModel = process.env["OPENAI_MODEL"]; // Get the OpenAI model from the environment variable

  // Destructure the handleRequest function from the copilotRuntimeNextJSAppRouterEndpoint function
  const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
    runtime: new CopilotRuntime({ actions }), // Create a new CopilotRuntime instance with the actions
    serviceAdapter: new OpenAIAdapter({ model: openaiModel }), // Create a new OpenAIAdapter instance with the model
    endpoint: req.nextUrl.pathname, // Set the endpoint to the current request URL path
  });

  return handleRequest(req); // Call the handleRequest function with the request and return the result
};

如何创建旅行计划

现在前往我们之前集成的应用内聊天机器人,并给它一个提示,例如,“Create a trip to London”。

一旦它生成完成,我们应该会看到创建的旅行计划,如下所示。

可以看到结果,我们已经完成了本教程的项目。

总结

CopilotKit 是一个非常棒的工具,它能让我们在几分钟内为产品添加 AI Copilot。无论我们是对 AI 聊天机器人和助手感兴趣,还是想要自动化复杂任务,CopilotKit 都能让这一切变得更加简单。

参考 https://dev.to/copilotkit/the-ai-powered-trip-planner-you-cant-live-without-2pk6

更多好文,欢迎关注公众号Geek技术前线

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Geek技术前线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值