"你说我们能不能开发一个类似 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 (
-
-
- {messages.map((message, index) => (
- <Message key={index} {...message} />
- ))}
- {isLoading && <TypingIndicator />}
-
- <ChatInput onSubmit={handleSubmit} disabled={isLoading} />
-
- )
- }
复制代码 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 �� 是魔法,而是工程。"
有什么问题欢迎在评论区讨论,我们一起探索 AI 应用开发的更多可能!
如果觉得有帮助,别忘了点赞关注,我会继续分享更多 AI 开发实战经验~
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |