鸿蒙应用接入DeepSeek
本文详细介绍了在HarmonyOS应用中接入DeepSeek AI的完整流程。主要内容包括:1) 核心概念:解释AI API的工作原理和请求响应格式;2) 接入步骤:从获取API Key到理解请求/响应结构;3) 代码实现:包括数据模型定义、API服务封装、UI调用和数据持久化;4) 关键技术点:流式响应、上下文管理、Token计算和错误处理;5) 常见问题解答。通过清晰的架构设计和代码示例,开发
HarmonyOS 接入 AI 完整教程
目录
核心概念
什么是 AI API?
AI API 是一个 HTTP 接口,你发送文本请求,AI 返回生成的回复。就像调用天气 API 一样简单。
DeepSeek API 工作原理
你的应用 → HTTP POST 请求 → DeepSeek 服务器 → AI 处理 → 返回回复 → 你的应用显示
如果我要在应用中接入ai,如:deepseek
- 首先要获取deepseek的apikey,知道请求的端点是什么
- 然后,构建请求格式,封装请求头、请求体,响应体的接口对象
- 再进行实现时,要创建消息模型的枚举对象,并且封装消息实体,接着,需要去创建api服务,设置api,发送对话请求,解析响应
- 在发送对话请求时,首先需要构建请求体,然后使用http.createHttp().request()异步获取相应对象,设置请求方法、请求头、请求超时时间等参数
- 然后在解析响应时,根据状态码返回不同的业务,当状态码为200时,反序列化这个响应对象,并将其断言为string类型,将result返回给调用处
- 在单次对话结束后,释放资源。
- UI层点击发送消息时,构建对话历史对象,并且获取到对话历史的每一条消息,同时,通过deepseekService.chat方法可以获取到每一条历史记录的结果,如果要提取ai的回复,则可以从封装的消息对象中获取到消息的内容,和ai的思考的内容,通过构建消息对象,并为该对象添加思考过程,然后可以将这个对象添加到消息数组中。
- 若要对消息进行持久化存储,则封装了rdb关系型数据库,通过relationalStore.getRdbStore传入上下文和config构建数据库对象,通过executeSQL创建表结构,保存消息时,通过封装saveMessage进行消息的保存,主要就是进行了一个插入操作,查询消息时,通过query传入谓词对象可以获去一个结果集,当结果集存在时,可以通过goToNextRow获取到每行的信息,最后将查询到的消息push到初始的数组对象中。对于流式响应的实现,在获取到响应后,需要对数据进行解析,对数据进行过滤,在反序列化,最后通过实时回调更新ui
接入步骤
第 1 步:获取 API Key
-
注册账号并登录
-
进入 API Keys 页面
-
创建新的 API Key(类似:
sk-xxxxxxxxxxxxx) -
保存好这个 Key(只显示一次)
第 2 步:理解 API 请求格式
请求端点
POST https://api.deepseek.com/v1/chat/completions
请求头
{
"Content-Type": "application/json",
"Authorization": "Bearer sk-your-api-key"
}
请求体
{
"model": "deepseek-chat",
"messages": [
{"role": "user", "content": "你好"}
],
"stream": false
}
响应体
{
"id": "chatcmpl-xxx",
"choices": [
{
"message": {
"role": "assistant",
"content": "你好!有什么我可以帮助你的吗?",
"reasoning_content": "用户打招呼,我应该礼貌回应"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
}
}
代码实现详解
架构设计
UI 层 (AiChatPage.ets) ↓ 服务层 (DeepSeekService.ets) ↓ 网络层 (HTTP Request) ↓ 数据层 (AiDatabase.ets)
1. 创建数据模型
文件:model/AiMessage.ets
// 消息角色
export enum MessageRole {
USER = 'user', // 用户消息
ASSISTANT = 'assistant', // AI 回复
SYSTEM = 'system' // 系统提示(可选)
}
// 消息实体
export class AiMessage {
id: string = '';
role: MessageRole = MessageRole.USER;
content: string = ''; // 消息内容
thinkingProcess?: string = ''; // AI 思考过程
timestamp: number = Date.now();
conversationId: string = ''; // 所属会话
constructor(role: MessageRole, content: string, conversationId: string) {
this.id = `${Date.now()}_${Math.random()}`;
this.role = role;
this.content = content;
this.conversationId = conversationId;
}
}
为什么需要这些字段?
-
role: 区分是用户说的还是 AI 说的 -
content: 消息的实际内容 -
thinkingProcess: DeepSeek Reasoner 模型会返回思考过程 -
conversationId: 支持多个对话会话
2. 创建 API 服务
文件:services/DeepSeekService.ets
import { http } from '@kit.NetworkKit';
export class DeepSeekService {
private apiKey: string = '';
private baseUrl: string = 'https://api.deepseek.com/v1';
// 设置 API Key
setApiKey(apiKey: string) {
this.apiKey = apiKey;
}
// 发送对话请求
async chat(
messages: DeepSeekMessage[],
model: string = 'deepseek-chat'
): Promise<DeepSeekResponse> {
// 1. 构建请求体
const requestBody = {
model: model,
messages: messages,
stream: false // 非流式响应
};
// 2. 创建 HTTP 请求
const httpRequest = http.createHttp();
try {
// 3. 发送 POST 请求
const response = await httpRequest.request(
`${this.baseUrl}/chat/completions`,
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}` // 关键:API Key 认证
},
extraData: JSON.stringify(requestBody),
expectDataType: http.HttpDataType.STRING,
connectTimeout: 60000, // 60秒超时
readTimeout: 60000
}
);
// 4. 解析响应
if (response.responseCode === 200) {
const result: DeepSeekResponse = JSON.parse(response.result as string);
return result;
} else {
throw new Error(`API Error: ${response.responseCode}`);
}
} finally {
// 5. 释放资源
httpRequest.destroy();
}
}
}
关键点解析:
-
API Key 认证
'Authorization': `Bearer ${this.apiKey}`这是标准的 Bearer Token 认证方式
-
请求体格式
{ model: "deepseek-chat", // 模型名称 messages: [ // 对话历史 {role: "user", content: "你好"} ], stream: false // 是否流式返回 } -
超时设置
connectTimeout: 60000, // 连接超时 readTimeout: 60000 // 读取超时
AI 响应可能较慢,需要设置较长的超时时间
3. UI 层调用
文件:pages/AiChatPage.ets
async sendMessage() {
// 1. 构建对话历史
const historyMessages: DeepSeekMessage[] = [];
this.messages.forEach((m: AiMessage) => {
if (m.role !== MessageRole.SYSTEM) {
historyMessages.push({
role: m.role as 'user' | 'assistant',
content: m.content
});
}
});
// 2. 调用 API
try {
const result = await this.deepSeekService.chat(
historyMessages,
this.selectedModel.id
);
// 3. 提取 AI 回复
if (result.choices && result.choices.length > 0) {
const aiReply = result.choices[0].message.content;
const thinking = result.choices[0].message.reasoning_content;
// 4. 显示在 UI 上
const aiMessage = new AiMessage(MessageRole.ASSISTANT, aiReply, this.conversationId);
aiMessage.thinkingProcess = thinking;
this.messages.push(aiMessage);
}
} catch (error) {
console.error('API Error:', error);
}
}
为什么要传对话历史?
// 单轮对话(AI 没有记忆)
messages: [
{role: "user", content: "我叫小明"}
]
// 多轮对话(AI 有上下文)
messages: [
{role: "user", content: "我叫小明"},
{role: "assistant", content: "你好小明!"},
{role: "user", content: "我叫什么名字?"} // AI 能记住你叫小明
]
4. 数据持久化
文件:database/AiDatabase.ets
export class AiDatabase {
private store?: relationalStore.RdbStore;
// 初始化数据库
async init(): Promise<void> {
const config: relationalStore.StoreConfig = {
name: 'AiChat.db',
securityLevel: relationalStore.SecurityLevel.S1
};
this.store = await relationalStore.getRdbStore(this.context, config);
// 创建表
await this.store.executeSql(`
CREATE TABLE IF NOT EXISTS messages (
id TEXT PRIMARY KEY,
role TEXT,
content TEXT,
thinkingProcess TEXT,
timestamp INTEGER,
conversationId TEXT
)
`);
}
// 保存消息
async saveMessage(message: AiMessage): Promise<void> {
const valueBucket: relationalStore.ValuesBucket = {
id: message.id,
role: message.role,
content: message.content,
thinkingProcess: message.thinkingProcess || '',
timestamp: message.timestamp,
conversationId: message.conversationId
};
await this.store?.insert('messages', valueBucket);
}
// 查询消息
async getMessages(conversationId: string): Promise<AiMessage[]> {
const predicates = new relationalStore.RdbPredicates('messages');
predicates.equalTo('conversationId', conversationId);
predicates.orderByAsc('timestamp');
const resultSet = await this.store?.query(predicates);
const messages: AiMessage[] = [];
if (resultSet) {
while (resultSet.goToNextRow()) {
const msg = new AiMessage(MessageRole.USER, '', conversationId);
msg.id = resultSet.getString(resultSet.getColumnIndex('id'));
msg.role = resultSet.getString(resultSet.getColumnIndex('role')) as MessageRole;
msg.content = resultSet.getString(resultSet.getColumnIndex('content'));
msg.thinkingProcess = resultSet.getString(resultSet.getColumnIndex('thinkingProcess'));
msg.timestamp = resultSet.getLong(resultSet.getColumnIndex('timestamp'));
messages.push(msg);
}
resultSet.close();
}
return messages;
}
}
关键技术点
1. 流式响应 vs 非流式响应
非流式(一次性返回)
// 请求
{ "stream": false }
// 响应(等待完整回复后一次性返回)
{
"choices": [{
"message": {"content": "完整的回复内容"}
}]
}
流式(逐字返回,类似 ChatGPT)
// 请求
{ "stream": true }
// 响应(多次返回,每次一小段)
data: {"choices":[{"delta":{"content":"你"}}]}
data: {"choices":[{"delta":{"content":"好"}}]}
data: {"choices":[{"delta":{"content":"!"}}]}
data: [DONE]
流式响应实现:
async chatStream(
messages: DeepSeekMessage[],
onContent?: (content: string) => void
): Promise<void> {
const response = await httpRequest.request(url, {
extraData: JSON.stringify({ stream: true, messages })
});
// 解析流式数据
const lines = (response.result as string).split('\n');
let fullContent = '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.substring(6).trim();
if (data === '[DONE]') break;
const json = JSON.parse(data);
const delta = json.choices[0].delta;
if (delta.content) {
fullContent += delta.content;
onContent?.(fullContent); // 实时回调,更新 UI
}
}
}
}
2. 对话上下文管理
为什么需要上下文?
// ❌ 错误:每次只发送当前消息
await api.chat([
{role: "user", content: "今天天气怎么样?"}
]);
// ✅ 正确:发送完整对话历史
await api.chat([
{role: "user", content: "我在北京"},
{role: "assistant", content: "好的,北京今天..."},
{role: "user", content: "今天天气怎么样?"} // AI 知道你在北京
]);
上下文截断(避免超出 Token 限制)
// 只保留最近 10 轮对话 const recentMessages = allMessages.slice(-20); // 10轮 = 20条消息
3. Token 计算
什么是 Token?
-
1 个中文字 ≈ 2-3 个 Token
-
1 个英文单词 ≈ 1-2 个 Token
-
"你好" ≈ 4-6 个 Token
Token 限制:
// DeepSeek Chat: 最大 32K tokens
// 输入 + 输出 不能超过 32K
// 示例
{
"usage": {
"prompt_tokens": 100, // 输入消耗
"completion_tokens": 50, // 输出消耗
"total_tokens": 150 // 总消耗
}
}
4. 错误处理
try {
const result = await api.chat(messages);
} catch (error) {
// 常见错误码
if (error.code === 401) {
// API Key 无效
} else if (error.code === 429) {
// 请求频率过高
} else if (error.code === 500) {
// 服务器错误
}
}
5. 成本优化
减少 Token 消耗:
// 1. 精简系统提示 const systemPrompt = "你是助手"; // ✅ 简洁 // 而不是 const systemPrompt = "你是一个非常有帮助的AI助手..."; // ❌ 冗长 // 2. 限制对话历史长度 const recentMessages = messages.slice(-10); // 3. 使用更便宜的模型 // deepseek-chat: ¥1/百万 tokens // deepseek-reasoner: ¥14/百万 tokens
常见问题
Q1: 如何调试 API 调用?
添加日志:
console.info('Request:', JSON.stringify(requestBody));
console.info('Response:', JSON.stringify(response));
使用 Postman 测试:
POST https://api.deepseek.com/v1/chat/completions
Headers:
Content-Type: application/json
Authorization: Bearer sk-your-key
Body:
{
"model": "deepseek-chat",
"messages": [{"role": "user", "content": "你好"}]
}
Q2: 为什么 AI 没有记忆?
原因: 没有传递对话历史
解决:
// ❌ 错误
const messages = [{role: "user", content: currentInput}];
// ✅ 正确
const messages = this.allMessages.map(m => ({
role: m.role,
content: m.content
}));
Q3: 如何实现打字机效果?
使用流式响应:
let displayText = '';
await api.chatStream(messages, (chunk) => {
displayText += chunk;
this.aiReply = displayText; // 实时更新 UI
});
Q4: API Key 如何安全存储?
// 1. 使用 Preferences 加密存储
import { preferences } from '@kit.ArkData';
// 2. 不要硬编码在代码中
const apiKey = 'sk-xxx'; // ❌ 危险
// 3. 从用户输入获取
TextInput({ text: $$this.apiKey, type: InputType.Password })
Q5: 如何支持多模型切换?
const models = [
{ id: 'deepseek-chat', name: 'Chat', price: '¥1/M' },
{ id: 'deepseek-reasoner', name: 'Reasoner', price: '¥14/M' }
];
// 用户选择模型
await api.chat(messages, selectedModel.id);
完整流程图
用户输入 ↓ [UI 层] 收集消息 ↓ [服务层] 构建请求 ↓ [网络层] HTTP POST ↓ DeepSeek API ↓ [网络层] 接收响应 ↓ [服务层] 解析 JSON ↓ [UI 层] 显示回复 ↓ [数据层] 保存到数据库
总结
接入 AI 的核心步骤:
-
获取 API Key - 注册并获取认证凭证
-
理解 API 格式 - 请求/响应的 JSON 结构
-
发送 HTTP 请求 - 使用
@kit.NetworkKit -
解析响应 - 提取 AI 回复内容
-
管理上下文 - 传递对话历史
-
持久化存储 - 保存对话记录
关键代码只有 3 行:
const response = await http.request(url, {
header: { 'Authorization': `Bearer ${apiKey}` },
extraData: JSON.stringify({ model, messages })
});
const result = JSON.parse(response.result);
const aiReply = result.choices[0].message.content;
就这么简单!🎉
参考资源:
-
DeepSeek API 文档: https://platform.deepseek.com/api-docs/
-
HarmonyOS 网络请求: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/http-request-V5
-
本项目源码:
sample/entry/src/main/ets/
更多推荐

所有评论(0)