js开发一个类似ChatGPT的AI应用助手
作者:乘风远洋
一位创业朋友想做一个垂直领域的AI助手,经过一个月的开发迭代,我们成功上线了第一个版本,这篇文章分享了开发一个类似ChatGPT的应用的过程,包括技术选型、架构设计和实战经验,实现了流式响应、上下文记忆系统和优化提示词,应用得到了用户的高度评价
"你说我们能不能开发一个类似 ChatGPT 的应用?"上个月,一位创业朋友找到我,想做一个垂直领域的 AI 助手。作为一个经常和 AI API 打交道的全栈开发者,这个想法立刻勾起了我的兴趣。不过说实话,从零开始构建一个 AI 应用,还是让我有点小紧张。
经过一个月的开发迭代,我们成功上线了第一个版本,用户反馈出奇的好。今天就来分享这个过程中的技术选型、架构设计和实战经验。
技术选型
首先面临的是技术栈的选择。考虑到实时性、性能和开发效率,我们最终选定了这套技术栈:
// 项目技术栈 const techStack = { frontend: { framework: 'Next.js 14', // App Router + React Server Components ui: 'Tailwind CSS + Shadcn UI', state: 'Zustand', realtime: 'Server-Sent Events' }, backend: { runtime: 'Node.js', framework: 'Next.js API Routes', database: 'PostgreSQL + Prisma', cache: 'Redis' }, ai: { provider: 'OpenAI API', framework: 'Langchain', vectorStore: 'PineconeDB' } }
核心功能实现
1. 流式响应的实现
最关键的是实现打字机效果的流式响应:
// app/api/chat/route.ts import { OpenAIStream } from '@/lib/openai' import { StreamingTextResponse } from 'ai' export async function POST(req: Request) { const { messages } = await req.json() // 调用 OpenAI API 获取流式响应 const stream = await OpenAIStream({ model: 'gpt-4', messages, temperature: 0.7, stream: true }) // 返回流式响应 return new StreamingTextResponse(stream) } // components/Chat.tsx function Chat() { const [messages, setMessages] = useState<Message[]>([]) const [isLoading, setIsLoading] = useState(false) const handleSubmit = async (content: string) => { setIsLoading(true) try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: [...messages, { role: 'user', content }] }) }) if (!response.ok) throw new Error('请求失败') // 处理流式响应 const reader = response.body!.getReader() const decoder = new TextDecoder() let aiResponse = '' while (true) { const { done, value } = await reader.read() if (done) break // 解码并追加新内容 aiResponse += decoder.decode(value) // 更新UI setMessages(prev => [...prev.slice(0, -1), { role: 'assistant', content: aiResponse }]) } } catch (error) { console.error('聊天出错:', error) } finally { setIsLoading(false) } } return ( <div className='flex flex-col h-screen'> <div className='flex-1 overflow-auto p-4'> {messages.map((message, index) => ( <Message key={index} {...message} /> ))} {isLoading && <TypingIndicator />} </div> <ChatInput onSubmit={handleSubmit} disabled={isLoading} /> </div> ) }
2. 上下文记忆系统
为了让对话更连贯,我们实现了基于向量数据库的上下文记忆系统:
// lib/vectorStore.ts import { PineconeClient } from '@pinecone-database/pinecone' import { OpenAIEmbeddings } from 'langchain/embeddings/openai' export class VectorStore { private pinecone: PineconeClient private embeddings: OpenAIEmbeddings constructor() { this.pinecone = new PineconeClient() this.embeddings = new OpenAIEmbeddings() } async initialize() { await this.pinecone.init({ environment: process.env.PINECONE_ENV!, apiKey: process.env.PINECONE_API_KEY! }) } async storeConversation(messages: Message[]) { const index = this.pinecone.Index('conversations') // 将对话转换为向量 const vectors = await Promise.all( messages.map(async message => { const vector = await this.embeddings.embedQuery(message.content) return { id: message.id, values: vector, metadata: { role: message.role, timestamp: Date.now() } } }) ) // 存储向量 await index.upsert({ upsertRequest: { vectors } }) } async retrieveContext(query: string, limit = 5) { const index = this.pinecone.Index('conversations') const queryVector = await this.embeddings.embedQuery(query) // 查询相似向量 const results = await index.query({ queryRequest: { vector: queryVector, topK: limit, includeMetadata: true } }) return results.matches.map(match => ({ content: match.metadata.content, score: match.score })) } }
3. 提示词优化
好的提示词对 AI 输出质量至关重要:
// lib/prompts.ts export const createChatPrompt = (context: string, query: string) => ({ messages: [ { role: 'system', content: `你是一个专业的AI助手。请基于以下上下文信息, 用简洁专业的语言回答用户问题。如果问题超出上下文范围, 请诚实告知。 上下文信息: ${context} ` }, { role: 'user', content: query } ], temperature: 0.7, // 控制创造性 max_tokens: 1000, // 控制回答长度 presence_penalty: 0.6, // 鼓励话题扩展 frequency_penalty: 0.5 // 避免重复 })
性能优化
AI 应用的性能优化主要从这几个方面入手:
- 请求优化
// hooks/useChat.ts export function useChat() { const [messages, setMessages] = useState<Message[]>([]) // 使用防抖避免频繁请求 const debouncedChat = useMemo( () => debounce(async (content: string) => { // ... 发送请求 }, 500), [] ) // 使用缓存避免重复请求 const cache = useMemo(() => new Map<string, string>(), []) const sendMessage = async (content: string) => { // 检查缓存 if (cache.has(content)) { setMessages(prev => [...prev, { role: 'assistant', content: cache.get(content)! }]) return } // 发送请求 await debouncedChat(content) } return { messages, sendMessage } }
- 流式传输优化:
// lib/streaming.ts export class StreamProcessor { private buffer: string = '' private decoder = new TextDecoder() process(chunk: Uint8Array, callback: (text: string) => void) { this.buffer += this.decoder.decode(chunk, { stream: true }) // 按完整的句子进行处理 const sentences = this.buffer.split(/([.!?。!?]\s)/) if (sentences.length > 1) { // 输出完整的句子 const completeText = sentences.slice(0, -1).join('') callback(completeText) // 保留未完成的部分 this.buffer = sentences[sentences.length - 1] } } }
部署与监控
我们使用了 Vercel 进行部署,并建立了完整的监控体系:
// lib/monitoring.ts export class AIMonitoring { // 记录请求延迟 async trackLatency(startTime: number) { const duration = Date.now() - startTime await this.metrics.gauge('ai_request_latency', duration) } // 监控令牌使用 async trackTokenUsage(prompt: string, response: string) { const tokenCount = await this.countTokens(prompt + response) await this.metrics.increment('token_usage', tokenCount) } // 监控错误率 async trackError(error: Error) { await this.metrics.increment('ai_errors', 1, { type: error.name, message: error.message }) } }
实践心得
开发 AI 应用的过程中,我学到了很多:
- 流式响应是提升用户体验的关键
- 上下文管理要平衡准确性和性能
- 错误处理和降级策略很重要
- 持续优化提示词能带来明显提升
最让我惊喜的是用户的反馈。有用户说:"这是我用过的响应最快的 AI 应用!"这让我们备受鼓舞。
写在最后
AI 应用开发是一个充满挑战但也充满机遇的领域。关键是要专注用户体验,不断优化和迭代。正如那句话说的:"AI不是魔法,而是工程。"
到此这篇关于js开发一个类似ChatGPT的AI应用助手的文章就介绍到这了,更多相关js开发一个AI应用助手内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!