第32期 | OpenAI API接入实战
2026/7/6 0:41:31 网站建设 项目流程

第32期 | OpenAI API接入实战

🎯 今天你将学会

  • 从零搭建 OpenAI API 调用环境(SDK 安装 + Key 管理)
  • 实现完整的后端代理接口(非流式 + 流式两种模式)
  • 射装可复用的 API 调用层——不是写一次就丢的临时代码
  • 处理所有常见错误:网络超时、token 超限、格式异常、rate limit

📖 核心知识

从零开始:环境搭建

Step 1:注册 OpenAI API

  1. 访问 https://platform.openai.com/signup 注册账号
  2. 进入 https://platform.openai.com/api-keys 创建 API Key
  3. 复制 Key,存到环境变量(绝不写进代码)

Step 2:环境变量管理

# .env.local(前端项目,Next.js 会自动加载)OPENAI_API_KEY=sk-xxxxxxxxxxxx# .env(后端项目,Node.js 用 dotenv 加载)OPENAI_API_KEY=sk-xxxxxxxxxxxx

⚠️.env文件绝不提交到 Git——在.gitignore中加上.env*

Step 3:安装 SDK

# 前端项目(Next.js)pnpmaddopenai# 纯后端项目(Express)npminstallopenai dotenv

为什么用官方 SDK 而不是直接 fetch?

方式优点缺点
直接 fetch最简单,几行代码要自己处理认证、超时、重试、类型
openai SDK类型完整、自动重试、流式支持多一个依赖

生产环境用 SDK——它帮你处理了 90% 的边界情况。

后端代理:完整实现

非流式接口(简单场景):

// app/api/ai/completion/route.ts (Next.js App Router)importOpenAIfrom'openai';import{NextRequest,NextResponse}from'next/server';constopenai=newOpenAI({apiKey:process.env.OPENAI_API_KEY,// 从环境变量读取});exportasyncfunctionPOST(req:NextRequest){try{const{prompt,systemPrompt}=awaitreq.json();// 参数校验if(!prompt||prompt.trim().length===0){returnNextResponse.json({error:'Prompt 不能为空'},{status:400});}if(prompt.length>4000){returnNextResponse.json({error:'Prompt 太长,请缩减到 4000 字以内'},{status:400});}constcompletion=awaitopenai.chat.completions.create({model:'gpt-4o-mini',// 用 mini 版降低成本messages:[{role:'system',content:systemPrompt||'你是一个技术助手。'},{role:'user',content:prompt},],temperature:0.7,// 0-2,越高越随机,技术回答建议 0.3-0.7max_tokens:2000,// 控制成本});returnNextResponse.json({content:completion.choices[0].message.content,usage:completion.usage,// token 使用量,方便监控成本});}catch(error){// 统一错误处理if(errorinstanceofOpenAI.APIError){returnNextResponse.json({error:`API Error:${error.message}`,code:error.code},{status:error.status||500});}returnNextResponse.json({error:'Internal server error'},{status:500});}}

流式接口(聊天场景):

// app/api/ai/chat/route.tsimportOpenAIfrom'openai';import{NextRequest}from'next/server';constopenai=newOpenAI({apiKey:process.env.OPENAI_API_KEY,});exportasyncfunctionPOST(req:NextRequest){const{messages,systemPrompt}=awaitreq.json();// 流式响应必须用 StreamTextResponse 或手动设置 SSE headersconststream=awaitopenai.chat.completions.create({model:'gpt-4o-mini',messages:[{role:'system',content:systemPrompt||'你是一个技术助手。'},...messages,// 多轮对话:传入完整消息历史],stream:true,// ← 开启流式temperature:0.7,});// 创建 SSE 流式响应constencoder=newTextEncoder();constreadableStream=newReadableStream({asyncstart(controller){try{forawait(constchunkofstream){constcontent=chunk.choices[0]?.delta?.content||'';if(content){// SSE 格式:data: {json}\n\ncontroller.enqueue(encoder.encode(`data:${JSON.stringify({content})}\n\n`));}}// 流结束标记controller.enqueue(encoder.encode('data: [DONE]\n\n'));controller.close();}catch(error){controller.error(error);}},});returnnewResponse(readableStream,{headers:{'Content-Type':'text/event-stream','Cache-Control':'no-cache','Connection':'keep-alive',},});}

前端调用层:封装可复用的 API 客户端

不要在每个组件里直接 fetch——封装一个统一的 API 客户端,处理认证、重试、错误。

// lib/ai-client.tsinterfaceCompletionRequest{prompt:string;systemPrompt?:string;}interfaceCompletionResponse{content:string;usage?:{prompt_tokens:number;completion_tokens:number;total_tokens:number};}interfaceChatRequest{messages:{role:'user'|'assistant'|'system';content:string}[];systemPrompt?:string;}classAIClient{privatebaseUrl:string;constructor(baseUrl='/api/ai'){this.baseUrl=baseUrl;}// 非流式调用asynccompletion(req:CompletionRequest):Promise<CompletionResponse>{constresponse=awaitthis.fetchWithRetry(`${this.baseUrl}/completion`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(req),});if(!response.ok){consterror=awaitresponse.json();thrownewAIError(error.error,response.status,error.code);}returnresponse.json();}// 流式调用asyncchatStream(req:ChatRequest):Promise<ReadableStream<string>>{constresponse=awaitthis.fetchWithRetry(`${this.baseUrl}/chat`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(req),});if(!response.ok){consterror=awaitresponse.json();thrownewAIError(error.error,response.status,error.code);}returnthis.parseSSEStream(response.body!);}// SSE 流解析privateparseSSEStream(rawStream:ReadableStream<Uint8Array>):ReadableStream<string>{constdecoder=newTextDecoder();letbuffer='';returnnewReadableStream({asyncstart(controller){constreader=rawStream.getReader();try{while(true){const{done,value}=awaitreader.read();if(done){controller.close();break;}buffer+=decoder.decode(value,{stream:true});constlines=buffer.split('\n');buffer=lines.pop()||'';for(constlineoflines){if(line.startsWith('data: ')){constdata=line.slice(6);if(data==='[DONE]'){controller.close();return;}try{constparsed=JSON.parse(data);if(parsed.content){controller.enqueue(parsed.content);}}catch{// 忽略无法解析的行}}}}}catch(error){controller.error(error);}},});}// 带重试的 fetchprivateasyncfetchWithRetry(url:string,options:RequestInit,maxRetries=3):Promise<Response>{for(letattempt=0;attempt<maxRetries;attempt++){try{constresponse=awaitfetch(url,options);// Rate limit — 等待后重试if(response.status===429){constretryAfter=parseInt(response.headers.get('retry-after')||'5');awaitnewPromise(resolve=>setTimeout(resolve,retryAfter*1000));continue;}returnresponse;}catch(error){if(attempt===maxRetries-1)throwerror;awaitnewPromise(resolve=>setTimeout(resolve,1000*(attempt+1)));}}thrownewAIError('Max retries exceeded',500);}}// 自定义错误类classAIErrorextendsError{status:number;code?:string;constructor(message:string,status:number,code?:string){super(message);this.status=status;this.code=code;}}exportconstaiClient=newAIClient();export{AIError};

成本控制:你必须知道的事

OpenAI API 按 token 计费。不了解成本模型,你的应用可能一个月烧掉几千块。

GPT 模型定价(2026年参考):

模型输入价格输出价格适用场景
gpt-4o-mini$0.15/1M tokens$0.60/1M tokens聊天、摘要、分类
gpt-4o$2.50/1M tokens$10/1M tokens复杂推理、代码生成
gpt-4-turbo$10/1M tokens$30/1M tokens最复杂任务

token 是什么?大约 1 个英文单词 = 1 token,1 个中文字 ≈ 2 tokens。一篇 500 字的中文文章约 1000 tokens。

成本控制策略:

策略做法节省效果
模型降级日常用 gpt-4o-mini,复杂任务才用 gpt-4o80% 成本节省
max_tokens 控制设 max_tokens=500 防止 AI 写太长50% 输出成本
缓存相似问题相同/相似问题缓存答案,不重复调用30-50% 节省
压缩 promptsystem prompt 精简,不要写长篇大论20% 输入成本
批量请求需要多个结果时用 batch API50% 成本节省

错误处理:完整的错误类型覆盖

// lib/ai-errors.tsexportfunctionhandleAIError(error:unknown):{message:string;action:string}{if(errorinstanceofAIError){switch(error.status){case401:return{message:'API Key 无效',action:'检查环境变量中的 OPENAI_API_KEY'};case429:return{message:'请求过多,请稍后再试',action:'等待后重试或升级 API 限额'};case500:return{message:'OpenAI 服务暂时不可用',action:'稍后重试'};case400:if(error.code==='context_length_exceeded'){return{message:'输入内容太长',action:'缩减 prompt 长度或切换到更大模型'};}return{message:'请求格式错误',action:'检查请求参数'};default:return{message:`未知错误:${error.message}`,action:'联系管理员'};}}if(errorinstanceofTypeError&&error.message.includes('fetch')){return{message:'网络连接失败',action:'检查网络连接'};}return{message:'未知错误',action:'请稍后重试'};}

常见误区

误区1:直接从前端调用 OpenAI API
API Key 暴露在前端 = 任何人都能盗用。必须后端代理。

误区2:不用 SDK,自己拼 HTTP 请求
SDK 帮你处理了类型、重试、流式解析。自己拼 HTTP 请求需要处理大量边界情况,容易出错。

误区3:不做成本控制
一个用户连续聊 30 分钟可能消耗 10 万 tokens = $0.06(gpt-4o-mini)。如果 1000 个用户每天聊 30 分钟 = $60/天 = $1800/月。必须设限。

🤖 AI协作实战

实战场景:封装完整的 AI 调用层

我给 AI 的 prompt:

@lib/ai-client.ts 帮我优化这个 AI 调用层,添加以下功能: 1. 请求超时处理(30秒非流式,流式不设超时) 2. Token 使用量追踪(每次调用记录 usage) 3. 请求取消(AbortController 支持) 4. 流式响应的中断处理(用户手动停止生成) 遵循项目 .cursorrules 规范。

AI 补充的关键代码:

// 超时处理privateasyncfetchWithTimeout(url:string,options:RequestInit,timeout=30000):Promise<Response>{constcontroller=newAbortController();consttimeoutId=setTimeout(()=>controller.abort(),timeout);try{constresponse=awaitfetch(url,{...options,signal:controller.signal,});clearTimeout(timeoutId);returnresponse;}catch(error){clearTimeout(timeoutId);if(errorinstanceofDOMException&&error.name==='AbortError'){thrownewAIError('Request timeout',408);}throwerror;}}// Token 使用量追踪interfaceTokenUsage{totalRequests:number;totalTokens:number;totalCost:number;lastRequestAt:string;}constusageTracker={data:{totalRequests:0,totalTokens:0,totalCost:0,lastRequestAt:''}asTokenUsage,track(usage:{prompt_tokens:number;completion_tokens:number;total_tokens:number}){this.data.totalRequests++;this.data.totalTokens+=usage.total_tokens;// gpt-4o-mini 成本估算this.data.totalCost+=(usage.prompt_tokens*0.00015+usage.completion_tokens*0.0006)/1000;this.data.lastRequestAt=newDate().toISOString();// 持久化到 localStoragelocalStorage.setItem('ai_usage',JSON.stringify(this.data));},getReport():TokenUsage{returnthis.data;},};

我的审查:

  1. ✅ 超时处理合理——非流式 30s,流式不限
  2. ✅ Token 追踪实用——方便监控成本
  3. ❌ 成本估算硬编码了 gpt-4o-mini 的价格——应该做成可配置的,因为可能切换模型
  4. ✅ AbortController 支持完整

学到了什么:AI 帮你补齐了你自己不容易想到的功能(超时、取消、追踪)。但模型价格硬编码需要你根据实际使用的模型来调整。

💻 动手练习

练习1(简单):搭建后端代理接口

用 Next.js API Routes 或 Express 实现一个最简单的/api/ai/completion接口:

  • 接收 prompt 参数
  • 调用 OpenAI API
  • 返回结果
  • API Key 存在环境变量中

练习2(中等):封装完整的 AI 客户端

根据本期的AIClient代码,实现一个完整的前端调用层,包含:

  • 非流式 + 流式两种模式
  • 重试机制(最多 3 次)
  • 错误处理(覆盖 4 种常见错误)
  • Token 使用量追踪

练习3(挑战):实现流式聊天接口 + 前端渲染

完整实现后端 SSE 流式 + 前端逐字渲染:

  • 后端:流式转发 OpenAI 响应
  • 前端:ReadableStream 读取 + 逐字追加到 UI
  • 支持中断(用户点击停止按钮,中止流式传输)
  • 显示 token 使用量统计

📌 本期要点

  1. API Key 安全:环境变量存储,后端代理转发,绝不暴露在前端代码
  2. 官方 SDK > 自己拼 HTTP:类型完整、自动重试、流式支持,省大量边界处理
  3. 流式响应实现:SSE 格式 + ReadableStream 解析 + 逐 token 推送到前端
  4. 成本控制:模型降级(gpt-4o-mini 日常用)+ max_tokens 限制 + 缓存 + token 追踪
  5. 错误处理全覆盖:401(Key无效) + 429(限流) + 500(服务不可用) + context_length_exceeded(太长) + 网络超时

🔗 下期预告

下一期我们进入聊天界面开发——消息列表、流式打字效果、Markdown 渲染。你将用 shadcn/ui + react-markdown 实现一个完整的 ChatGPT 风格聊天界面。
如果你没有苹果电脑,需要上传ios到APPStore可以访问以下网站
iPA上传工具 - IPA解析与AppStore提交

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询