前言 随着人工智能技术的快速发展,大语言模型(LLM)已经成为前端开发中不可或缺的一部分。DeepSeek作为国内领先的大语言模型,提供了强大的对话能力和API接口,使得前端开发者可以轻松地将AI对话功能集成到自己的应用中。
本文将从前端开发者的角度,详细介绍如何接入DeepSeek大语言模型,实现一个完整的对话系统,包括API调用、流式响应处理、错误处理、用户体验优化等关键技术点。
1. DeepSeek API 概述 DeepSeek提供了RESTful API接口,支持多种编程语言调用。对于前端开发者来说,最常用的是对话补全(Chat Completion)接口。
1.1 API 基础信息
基础URL : https://api.deepseek.com
认证方式 : Bearer Token
主要端点 : /v1/chat/completions
支持模型 : deepseek-chat, deepseek-coder等
1.2 请求格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const requestBody = { model: "deepseek-chat" , messages: [{ role: "system" , content: "你是一个有帮助的AI助手" }, { role: "user" , content: "你好,请介绍一下你自己" } ], stream: true , temperature: 0.7 , max_tokens: 1000 };
2. 前端实现方案 2.1 环境准备 首先,我们需要获取API密钥并设置项目环境:
1 2 3 npm install axios event-source-parser
2.2 基础API调用 非流式响应(一次性返回) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 async function callDeepSeekAPI (messages, apiKey ) { try { const response = await fetch('https://api.deepseek.com/v1/chat/completions' , { method: 'POST' , headers: { 'Content-Type' : 'application/json' , 'Authorization' : `Bearer ${apiKey} ` }, body: JSON .stringify({ model: 'deepseek-chat' , messages: messages, stream: false , temperature: 0.7 }) }); if (!response.ok) { throw new Error (`API请求失败: ${response.status} ` ); } const data = await response.json(); return data.choices[0 ].message.content; } catch (error) { console .error('调用DeepSeek API失败:' , error); throw error; } }
流式响应(实时显示) 流式响应可以提供更好的用户体验,让用户看到AI思考的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 async function streamDeepSeekResponse (messages, apiKey, onChunk, onComplete ) { const response = await fetch('https://api.deepseek.com/v1/chat/completions' , { method: 'POST' , headers: { 'Content-Type' : 'application/json' , 'Authorization' : `Bearer ${apiKey} ` }, body: JSON .stringify({ model: 'deepseek-chat' , messages: messages, stream: true , temperature: 0.7 , max_tokens: 2000 }) }); if (!response.ok) { throw new Error (`API请求失败: ${response.status} ` ); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = '' ; try { while (true ) { const { done, value } = await reader.read(); if (done) break ; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n' ); buffer = lines.pop(); for (const line of lines) { if (line.trim() === '' ) continue ; if (line.startsWith('data: ' )) { const data = line.slice(6 ); if (data === '[DONE]' ) { onComplete(); return ; } try { const parsed = JSON .parse(data); const content = parsed.choices[0 ]?.delta?.content || '' ; if (content) { onChunk(content); } } catch (e) { console .warn('解析流数据失败:' , e); } } } } } finally { reader.releaseLock(); } }
2.3 使用EventSource处理SSE 对于更简单的SSE处理,可以使用EventSource API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 function createDeepSeekEventSource (messages, apiKey, onMessage, onError ) { const eventSource = new EventSourcePolyfill( 'https://api.deepseek.com/v1/chat/completions' , { method: 'POST' , headers: { 'Content-Type' : 'application/json' , 'Authorization' : `Bearer ${apiKey} ` }, body: JSON .stringify({ model: 'deepseek-chat' , messages: messages, stream: true }), pollingInterval: 0 } ); eventSource.onmessage = (event ) => { if (event.data === '[DONE]' ) { eventSource.close(); return ; } try { const data = JSON .parse(event.data); const content = data.choices[0 ]?.delta?.content || '' ; if (content && onMessage) { onMessage(content); } } catch (error) { console .error('解析消息失败:' , error); } }; eventSource.onerror = (error ) => { console .error('EventSource错误:' , error); if (onError) onError(error); eventSource.close(); }; return eventSource; }
3. 对话状态管理 3.1 消息历史管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class ChatManager { constructor ( ) { this .messages = []; this .systemPrompt = "你是一个有帮助的AI助手,请用中文回答用户的问题。" ; this .maxHistoryLength = 20 ; } addMessage (role, content ) { this .messages.push({ role, content, timestamp: Date .now() }); if (this .messages.length > this .maxHistoryLength) { const systemMessage = this .messages.find(m => m.role === 'system' ); const recentMessages = this .messages.slice(-this .maxHistoryLength + 1 ); this .messages = systemMessage ? [systemMessage, ...recentMessages] : recentMessages; } } getConversationHistory ( ) { return [{ role: 'system' , content: this .systemPrompt }, ...this.messages.filter(m => m.role !== 'system' ) ]; } clearHistory ( ) { this .messages = this .messages.filter(m => m.role === 'system' ); } }
3.2 Token计数与限制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class TokenManager { static estimateTokens (text ) { const chineseChars = text.match(/[\u4e00-\u9fa5]/g ) || []; const englishWords = text.match(/[a-zA-Z]+/g ) || []; return chineseChars.length + englishWords.length * 0.75 ; } static truncateMessages (messages, maxTokens = 4000 ) { let totalTokens = 0 ; const truncated = []; for (let i = messages.length - 1 ; i >= 0 ; i--) { const message = messages[i]; const messageTokens = this .estimateTokens(message.content) + 10 ; if (totalTokens + messageTokens > maxTokens) { break ; } truncated.unshift(message); totalTokens += messageTokens; } return truncated; } }
4. 用户体验优化 4.1 打字机效果实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class TypewriterEffect { constructor (element, options = {} ) { this .element = element; this .speed = options.speed || 50 ; this .cursorChar = options.cursorChar || '▌' ; this .isTyping = false ; this .currentText = '' ; } async type (text ) { if (this .isTyping) { await this .stop(); } this .isTyping = true ; this .currentText = '' ; for (let i = 0 ; i < text.length; i++) { if (!this .isTyping) break ; this .currentText += text[i]; this .element.textContent = this .currentText + this .cursorChar; await this .delay(this .speed); } if (this .isTyping) { this .element.textContent = this .currentText; this .isTyping = false ; } } async stop ( ) { this .isTyping = false ; this .element.textContent = this .currentText; } delay (ms ) { return new Promise (resolve => setTimeout (resolve, ms)); } }
4.2 错误处理与重试机制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class APIRetryManager { constructor (maxRetries = 3 , baseDelay = 1000 ) { this .maxRetries = maxRetries; this .baseDelay = baseDelay; } async withRetry (apiCall, shouldRetry = (error) => true ) { let lastError; for (let attempt = 0 ; attempt < this .maxRetries; attempt++) { try { return await apiCall(); } catch (error) { lastError = error; if (!shouldRetry(error) || attempt === this .maxRetries - 1 ) { break ; } const delay = this .baseDelay * Math .pow(2 , attempt); console .log(`请求失败,${delay} ms后重试...` , error); await this .delay(delay + Math .random() * 1000 ); } } throw lastError; } delay (ms ) { return new Promise (resolve => setTimeout (resolve, ms)); } } const retryManager = new APIRetryManager();try { const response = await retryManager.withRetry( () => callDeepSeekAPI(messages, apiKey), (error) => { return error.message.includes('Network' ) || (error.status && error.status >= 500 ); } ); } catch (error) { console .error('所有重试尝试都失败了:' , error); }
5. 安全考虑 5.1 API密钥安全 重要:永远不要在前端代码中硬编码API密钥!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' ;async function callDeepSeekThroughProxy (messages ) { const response = await fetch('/api/deepseek-proxy' , { method: 'POST' , headers: { 'Content-Type' : 'application/json' }, body: JSON .stringify({ messages }) }); return response.json(); } const API_KEY = process.env.REACT_APP_DEEPSEEK_API_KEY;async function getApiToken ( ) { const user = await auth.getCurrentUser(); return user.getIdToken(); }
5.2 输入验证与过滤 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function sanitizeUserInput (input ) { let sanitized = input .trim() .replace(/[<>]/g , '' ) .substring(0 , 5000 ); const sensitivePatterns = [ /password\s*[:=]/i, /credit\s*card/i, /\d{16 }/, ]; for (const pattern of sensitivePatterns) { if (pattern.test(sanitized)) { throw new Error ('输入包含敏感信息,请修改后重试' ); } } return sanitized; }
6. 性能优化 6.1 请求防抖与节流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Debouncer { constructor (delay = 300 ) { this .delay = delay; this .timeoutId = null ; } debounce (fn ) { return (...args ) => { clearTimeout (this .timeoutId); this .timeoutId = setTimeout (() => fn(...args), this .delay); }; } } const searchDebouncer = new Debouncer(500 );const debouncedSearch = searchDebouncer.debounce(async (query) => { if (query.length < 2 ) return ; const suggestions = await getSearchSuggestions(query); updateSuggestions(suggestions); });
6.2 响应缓存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class ResponseCache { constructor (maxAge = 5 * 60 * 1000 ) { this .cache = new Map (); this .maxAge = maxAge; } getKey (messages ) { return JSON .stringify(messages); } get (messages ) { const key = this .getKey(messages); const cached = this .cache.get(key); if (cached && Date .now() - cached.timestamp < this .maxAge) { return cached.data; } return null ; } set (messages, data ) { const key = this .getKey(messages); this .cache.set(key, { data, timestamp: Date .now() }); this .cleanup(); } cleanup ( ) { const now = Date .now(); for (const [key, value] of this .cache.entries()) { if (now - value.timestamp > this .maxAge) { this .cache.delete(key); } } } }
7. 完整示例:React组件实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 import React, { useState, useRef, useEffect } from 'react' ; import './ChatInterface.css' ; const ChatInterface = ({ apiKey } ) => { const [messages, setMessages] = useState([]); const [input, setInput] = useState('' ); const [isLoading, setIsLoading] = useState(false ); const messagesEndRef = useRef(null ); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior : 'smooth' }); }; useEffect(() => { scrollToBottom(); }, [messages]); const handleSubmit = async (e) => { e.preventDefault(); if (!input.trim() || isLoading) return ; const userMessage = input.trim(); setInput('' ); setMessages(prev => [...prev, { role: 'user' , content: userMessage, timestamp: new Date ().toISOString() }]); setIsLoading(true ); try { const response = await fetch('https://api.deepseek.com/v1/chat/completions' , { method: 'POST' , headers: { 'Content-Type' : 'application/json' , 'Authorization' : `Bearer ${apiKey} ` }, body: JSON .stringify({ model: 'deepseek-chat' , messages: [ { role : 'system' , content : '你是一个有帮助的AI助手' }, ...messages.map(m => ({ role : m.role, content : m.content })), { role : 'user' , content : userMessage } ], stream: false , temperature: 0.7 }) }); if (!response.ok) { throw new Error ( `API请求失败: ${response.status} ` ); } const data = await response.json(); const aiResponse = data.choices[0 ].message.content; setMessages(prev => [...prev, { role: 'assistant' , content: aiResponse, timestamp: new Date ().toISOString() }]); } catch (error) { console .error('对话失败:' , error); setMessages(prev => [...prev, { role: 'system' , content: `抱歉,出现错误: ${error.message} ` , timestamp: new Date ().toISOString(), isError: true }]); } finally { setIsLoading(false ); } }; return ( <div className="chat-container" > <div className="messages-container" > {messages.map((msg, index ) => ( <div key={index} className={ `message ${msg.role} ${msg.isError ? 'error' : '' } ` } > <div className="message-header" > <span className="role" >{msg.role === 'user' ? '你' : 'AI助手' }</span> <span className="timestamp" > {new Date (msg.timestamp).toLocaleTimeString()} </span> </div> <div className="message-content" > {msg.content} </div> </div> ))} <div ref={messagesEndRef} /> </div> <form onSubmit={handleSubmit} className="input-form" > <div className="input-container" > <textarea value={input} onChange={(e ) => setInput(e.target.value)} placeholder="输入你的问题..." disabled={isLoading} rows={3 } className="message-input" /> <button type="submit" disabled={isLoading || !input.trim()} className="send-button" > {isLoading ? '思考中...' : '发送' } </button> </div> <div className="input-hint" > 按 Enter 发送,Shift + Enter 换行 </div> </form> </div> ); }; export default ChatInterface;
8. 进阶功能实现 8.1 多轮对话上下文管理 在实际应用中,我们需要维护对话的上下文,确保AI能够理解整个对话流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class ConversationContext { constructor (maxContextLength = 10 ) { this .context = []; this .maxContextLength = maxContextLength; } addExchange (userMessage, aiResponse ) { this .context.push({ user: userMessage, ai: aiResponse, timestamp: Date .now() }); if (this .context.length > this .maxContextLength) { this .context = this .context.slice(-this .maxContextLength); } } getContextSummary ( ) { if (this .context.length === 0 ) return '' ; return this .context .map((exchange, index ) => `第${index + 1 } 轮对话: 用户:${exchange.user} AI:${exchange.ai} ` ) .join('\n\n' ); } clear ( ) { this .context = []; } }
8.2 实时语音输入集成 结合Web Speech API,可以实现语音输入功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class VoiceInputManager { constructor ( ) { this .recognition = null ; this .isListening = false ; this .onResult = null ; this .onError = null ; if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window ) { const SpeechRecognition = window .SpeechRecognition || window .webkitSpeechRecognition; this .recognition = new SpeechRecognition(); this .recognition.continuous = false ; this .recognition.interimResults = true ; this .recognition.lang = 'zh-CN' ; this .recognition.onresult = (event ) => { const transcript = Array .from(event.results) .map(result => result[0 ].transcript) .join('' ); if (this .onResult) { this .onResult(transcript); } }; this .recognition.onerror = (event ) => { if (this .onError) { this .onError(event.error); } }; } } startListening ( ) { if (!this .recognition) { throw new Error ('浏览器不支持语音识别' ); } if (!this .isListening) { this .recognition.start(); this .isListening = true ; } } stopListening ( ) { if (this .recognition && this .isListening) { this .recognition.stop(); this .isListening = false ; } } toggleListening ( ) { if (this .isListening) { this .stopListening(); } else { this .startListening(); } } }
8.3 文件上传与处理 DeepSeek支持文件上传功能,可以处理图像、PDF、Word等文档:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 async function uploadAndProcessFile (file, apiKey ) { const validTypes = ['image/jpeg' , 'image/png' , 'application/pdf' , 'text/plain' ]; const maxSize = 10 * 1024 * 1024 ; if (!validTypes.includes(file.type)) { throw new Error ('不支持的文件类型' ); } if (file.size > maxSize) { throw new Error ('文件大小超过10MB限制' ); } const formData = new FormData(); formData.append('file' , file); formData.append('purpose' , 'vision' ); const uploadResponse = await fetch('https://api.deepseek.com/v1/files' , { method: 'POST' , headers: { 'Authorization' : `Bearer ${apiKey} ` }, body: formData }); if (!uploadResponse.ok) { throw new Error (`文件上传失败: ${uploadResponse.status} ` ); } const uploadData = await uploadResponse.json(); const fileId = uploadData.id; const chatResponse = await fetch('https://api.deepseek.com/v1/chat/completions' , { method: 'POST' , headers: { 'Content-Type' : 'application/json' , 'Authorization' : `Bearer ${apiKey} ` }, body: JSON .stringify({ model: 'deepseek-chat' , messages: [{ role: 'user' , content: [{ type: 'text' , text: '请分析这个文件的内容' }, { type: 'file' , file_id: fileId } ] }] }) }); return chatResponse.json(); }
9. 测试与调试 9.1 单元测试示例 使用Jest进行单元测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 import { ChatManager } from './chatManager' ; describe('ChatManager' , () => { let chatManager; beforeEach(() => { chatManager = new ChatManager(); }); test('应该正确添加消息' , () => { chatManager.addMessage('user' , '你好' ); expect(chatManager.messages).toHaveLength(1 ); expect(chatManager.messages[0 ].role).toBe('user' ); expect(chatManager.messages[0 ].content).toBe('你好' ); }); test('应该限制历史记录长度' , () => { for (let i = 0 ; i < 25 ; i++) { chatManager.addMessage('user' , `消息${i} ` ); } expect(chatManager.messages.length).toBeLessThanOrEqual(20 ); }); test('应该包含系统提示' , () => { const history = chatManager.getConversationHistory(); expect(history[0 ].role).toBe('system' ); expect(history[0 ].content).toContain('AI助手' ); }); }); import { callDeepSeekAPI } from './apiClient' ; describe('API客户端' , () => { beforeEach(() => { global .fetch = jest.fn(); }); test('应该正确处理API响应' , async () => { const mockResponse = { ok: true , json: async () => ({ choices: [{ message: { content: '你好,我是DeepSeek助手' } }] }) }; global .fetch.mockResolvedValue(mockResponse); const result = await callDeepSeekAPI( [{ role: 'user' , content: '你好' }], 'test-key' ); expect(result).toBe('你好,我是DeepSeek助手' ); expect(global .fetch).toHaveBeenCalledWith( 'https://api.deepseek.com/v1/chat/completions' , expect.any(Object ) ); }); test('应该处理API错误' , async () => { global .fetch.mockResolvedValue({ ok: false , status: 429 }); await expect(callDeepSeekAPI([], 'test-key' )) .rejects .toThrow('API请求失败: 429' ); }); });
9.2 调试技巧
网络请求调试 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const originalFetch = window .fetch;window .fetch = async function (...args ) { console .log('请求开始:' , args[0 ], args[1 ]); const startTime = Date .now(); try { const response = await originalFetch.apply(this , args); console .log('请求完成:' , { url: args[0 ], status: response.status, time: Date .now() - startTime }); return response; } catch (error) { console .error('请求失败:' , error); throw error; } };
性能监控 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class PerformanceMonitor { constructor ( ) { this .metrics = []; } startMeasurement (name ) { return { name, startTime: performance.now(), end: () => { const duration = performance.now() - this .startTime; this .metrics.push({ name, duration }); console .log(`${name} : ${duration.toFixed(2 )} ms` ); return duration; } }; } getReport ( ) { return this .metrics.reduce((acc, metric ) => { if (!acc[metric.name]) { acc[metric.name] = { count: 0 , total: 0 , avg: 0 }; } acc[metric.name].count++; acc[metric.name].total += metric.duration; acc[metric.name].avg = acc[metric.name].total / acc[metric.name].count; return acc; }, {}); } }
10. 部署与优化 10.1 生产环境配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const config = { development: { apiBaseUrl: 'https://api.deepseek.com' , logLevel: 'debug' , enableMock: true }, production: { apiBaseUrl: 'https://api.deepseek.com' , logLevel: 'error' , enableMock: false , features: { streaming: true , fileUpload: true , voiceInput: false } } }; export default config[process.env.NODE_ENV || 'development' ];
10.2 CDN与缓存策略 1 2 3 4 5 6 7 8 9 10 11 12 13 <script src ="https://cdn.jsdelivr.net/npm/event-source-polyfill@1.0.0/dist/eventsource.min.js" > </script > <script > if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js' ).then(registration => { console .log('ServiceWorker注册成功:' , registration.scope); }).catch(error => { console .log('ServiceWorker注册失败:' , error); }); } </script >
10.3 监控与告警 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 window .addEventListener('error' , (event ) => { fetch('/api/monitor/error' , { method: 'POST' , headers: { 'Content-Type' : 'application/json' }, body: JSON .stringify({ message: event.message, filename: event.filename, lineno: event.lineno, colno: event.colno, error: event.error?.stack, timestamp: new Date ().toISOString() }) }); }); const observer = new PerformanceObserver((list ) => { for (const entry of list.getEntries()) { if (entry.duration > 1000 ) { console .warn('慢API调用:' , entry.name, entry.duration); } } }); observer.observe({ entryTypes: ['resource' ] });
总结 通过本文的介绍,我们全面探讨了前端接入DeepSeek大语言模型的技术实现。从基础的API调用到高级功能如流式响应、对话状态管理、用户体验优化、安全考虑、性能优化等,我们覆盖了构建一个完整AI对话系统所需的关键技术点。
示例代码基于DeepSeek API v1版本,实际使用时请参考最新官方文档