AI 代理聊天机器人

构建一个简单的 AI 代理聊天机器人,能读取和编辑 Tiptap 文档。

查看GitHub 上的源码

技术栈

安装

创建一个 Next.js 项目:

npx create-next-app@latest ai-agent-chatbot

安装核心的 Tiptap 包以及用于 OpenAI 的 Vercel AI SDK

npm install @tiptap/react @tiptap/starter-kit ai @ai-sdk/react @ai-sdk/openai

安装 Tiptap AI 工具包以及 Vercel AI SDK 的工具定义。

专业包

AI 工具包是一个专业版包。在安装之前,请按照私有注册表指南设置对私有 NPM 注册表的访问权限。

npm install @tiptap-pro/ai-toolkit @tiptap-pro/ai-toolkit-ai-sdk

API 端点

创建一个使用 Vercel AI SDK 调用 OpenAI 模型的 API 端点。包含用于 Tiptap AI 工具包的工具定义。如果你的后端不是 TypeScript,请参见非 TypeScript 后端

// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai'
import { toolDefinitions } from '@tiptap-pro/ai-toolkit-ai-sdk'
import { createAgentUIStreamResponse, ToolLoopAgent, UIMessage } from 'ai'

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json()

  const agent = new ToolLoopAgent({
    model: openai('gpt-5.4-mini'),
    instructions: 'You are an assistant that can edit rich text documents.',
    tools: toolDefinitions(),
  })

  return createAgentUIStreamResponse({
    agent,
    uiMessages: messages,
  })
}

要访问 OpenAI API,请在 OpenAI 控制台 创建一个 API 密钥,并将其作为环境变量添加。Vercel AI SDK 会自动检测该环境变量。

# .env
OPENAI_API_KEY=your-api-key

客户端设置

创建一个客户端的 React 组件,渲染 Tiptap 编辑器和一个简单的聊天 UI。该组件使用 Vercel AI SDK 的 useChat 钩子 来调用 API 端点和管理聊天对话。当 AI 模型输出工具调用时,利用 Tiptap AI 工具包执行该工具。

// app/page.tsx
'use client'

import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls } from 'ai'
import { useChat } from '@ai-sdk/react'
import { EditorContent, useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { useState, useRef } from 'react'
import { AiToolkit, getAiToolkit } from '@tiptap-pro/ai-toolkit'

export default function Page() {
  const editor = useEditor({
    immediatelyRender: false,
    extensions: [StarterKit, AiToolkit],
    content: `<h1>AI 代理演示</h1><p>请让 AI 改进这段内容。</p>`,
  })

  // 解决问题:https://github.com/vercel/ai/issues/8148
  const editorRef = useRef(editor)
  editorRef.current = editor

  const { messages, sendMessage, addToolOutput } = useChat({
    transport: new DefaultChatTransport({ api: '/api/chat' }),
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
    async onToolCall({ toolCall }) {
      if (!editor) return

      const { toolName, input, toolCallId } = toolCall

      // 使用 AI 工具包执行工具
      const toolkit = getAiToolkit(editor)
      const result = toolkit.executeTool({
        toolName,
        input,
      })

      addToolOutput({ tool: toolName, toolCallId, output: result.output })
    },
  })

  const [input, setInput] = useState('用一个关于 Tiptap 的短篇故事替换最后一段')

  if (!editor) return null

  return (
    <div>
      <EditorContent editor={editor} />
      {messages?.map((message) => (
        <div key={message.id} style={{ whiteSpace: 'pre-wrap' }}>
          <strong>{message.role}</strong>
          <br />
          {message.parts
            .filter((p) => p.type === 'text')
            .map((p) => p.text)
            .join('\n')}
        </div>
      ))}
      <form
        onSubmit={(e) => {
          e.preventDefault()
          sendMessage({ text: input })
          setInput('')
        }}
      >
        <input value={input} onChange={(e) => setInput(e.target.value)} />
      </form>
    </div>
  )
}

最终效果

配合额外的 CSS 样式,效果是一个简单但精致的 AI 聊天机器人应用:

查看GitHub 上的源码

下一步

  • 让你的用户通过审查更改指南审查 AI 生成的更改
  • 使用流式指南添加实时工具流功能,以便实时看到更改
  • 你的文档包含自定义节点和标记吗?学习如何让你的 AI 代理理解它们,详见模式感知指南