AI 代理聊天机器人
构建一个简单的 AI 代理聊天机器人,能读取和编辑 Tiptap 文档。
查看GitHub 上的源码。
技术栈
- React + Next.js
- Vercel 的 AI SDK + OpenAI 模型
- Tiptap AI 工具包
安装
创建一个 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-sdkAPI 端点
创建一个使用 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 上的源码。