首页 > 其他分享 >AI 聊天应用开发实战:从构思到上线的全栈开发指南

AI 聊天应用开发实战:从构思到上线的全栈开发指南

时间:2024-12-10 11:55:50浏览次数:5  
标签:const AI await messages content 全栈 开发 async

"你说我们能不能开发一个类似 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 应用的性能优化主要从这几个方面入手:

  1. 请求优化
// 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 }
}
  1. 流式传输优化:
// 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 应用的过程中,我学到了很多:

  1. 流式响应是提升用户体验的关键
  2. 上下文管理要平衡准确性和性能
  3. 错误处理和降级策略很重要
  4. 持续优化提示词能带来明显提升

最让我惊喜的是用户的反馈。有用户说:"这是我用过的响应最快的 AI 应用!"这让我们备受鼓舞。

写在最后

AI 应用开发是一个充满挑战但也充满机遇的领域。关键是要专注用户体验,不断优化和迭代。正如那句话说的:"AI �� 是魔法,而是工程。"

有什么问题欢迎在评论区讨论,我们一起探索 AI 应用开发的更多可能!

如果觉得有帮助,别忘了点赞关注,我会继续分享更多 AI 开发实战经验~

标签:const,AI,await,messages,content,全栈,开发,async
From: https://www.cnblogs.com/yuanyanglu/p/18597005

相关文章

  • 性能测试磁盘wait分析
    在磁盘性能监控中,%util(磁盘利用率)是衡量磁盘繁忙程度的重要指标,通常用于表示磁盘是否处于过载状态。这个指标通常在系统监控工具(如iostat或vmstat)中看到,它反映了磁盘设备在特定时间段内的忙碌程度。%util的定义和公式:%util代表磁盘设备的使用率,具体公式如下:%util=磁盘忙......
  • 照片模糊修复怎么做?无需PS技术,AI一键智能处理,还原高清画质!
    在这个快节奏的数字时代,珍贵的老照片、经典的老电影,不仅是回忆的载体,更是时间的见证者。但岁月无情,它们往往因年代久远而失去原有的光彩,模糊、褪色,甚至破损。你是否曾渴望,能让这些记忆中的瑰宝重现昔日辉煌?现在,一切变得可能!千鹿AI,以尖端的人工智能技术,引领图像与视频修复的新......
  • WxPython跨平台开发框架之参数配置管理界面的设计和实现
    我曾经在2014年在随笔《Winform开发框架之参数配置管理功能实现-基于SettingsProvider.net的构建》介绍过基于.NET开发的参数配置管理界面,本篇随笔基于类似的效果,介绍在WxPython跨平台开发框架上使用LabelBook控件实现配置管理界面的效果。1、参数配置管理界面的特点和.NET实......
  • 国产免费 AI 工具汇总
    国产免费AI在近年来得到了迅速发展,各大科技公司纷纷推出了各自的大模型和工具,以满足不同用户的需求。使用AI可以大幅提高工作效率,使用国产AI操作简单,本文介绍一些国产好用的免费的AI。1、讯飞星火-科大讯飞https://xinghuo.xfyun.cn/讯飞星火是科大讯飞推出的一款认......
  • XAI4LLM:结合ML和LLM的医疗诊断框架,通过不同的交互方式(NC/NL-ST)实现信息的有效传递
    XAI4LLM:结合ML和LLM的医疗诊断框架,通过不同的交互方式(NC/NL-ST)实现信息的有效传递论文大纲理解1.排除推理:为什么选择LLM而不是传统ML方法?2.比较推理:NCvsNL-ST交互模式3.因果推理:领域知识如何影响模型性能作者解决思路全流程完全拆解数据分析解法拆解为什么作者选......
  • 敏捷开发框架大揭秘!5大优势让你从项目管理小白变大神!
    一、敏捷开发是什么敏捷开发是以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征。简单来说,就是把一个大项目分为多个相互联系但可独立运行的小......
  • AI与人类的四大互动区域:探索未来商业机会
    在1955年,心理学家JosephLuft和HarryIngham提出了“乔哈里窗”这一模型,用于描述人与人之间沟通的四个关键区域:公开区、隐秘区、盲点区和未知区。这一框架帮助我们更清晰地理解了人际沟通中常见的障碍与难题,并提供了解决这些障碍的思路。那么,当我们将这个模型应用到人类与AI,甚至AI......
  • 【StableDiffusion教程】AI绘画探索:通过Stable Diffusion实现角色稳定控制与线稿上色
    在角色控制方面,我们都了解到midjourney的局限性,其无法稳定地实现目标控制。然而,StableDiffusion提供了出色的可控性,使我们能够有效地弥补这一缺陷。今天就通过一个简单案例,给大分享如何使用StableDiffusion中的ControlNet插件实现角色稳定控制与线稿上色。(文末扫码......
  • Linux系统挂载exfat格式U盘教程,触觉智能RK3562开发板演示
    本文介绍Linux系统(Ubuntu/Debian通用)挂载exfat格式U盘的方法,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。修改对应的内核配置文件进入sdk目录cdrk3562_linux编辑......
  • 作为技术的Leader,带团队和提升开发能力的平衡点你是如何把握的?
    作为前端技术leader,在带领团队和提升自身开发能力之间找到平衡点至关重要。以下是我的一些经验和策略:一、时间管理与优先级排序:明确角色职责:Leader的主要职责是指导团队、制定技术方向、移除障碍,而不是亲自承担所有开发任务。要将更多时间投入到团队管理、代码审查、技术分......