基于deepseek的Android智能问答助手
1、项目背景
在数字化时代的浪潮中,信息的快速获取与精准处理成为人们日常工作和生活的迫切需求。人工智能技术的蓬勃发展,尤其是大语言模型的出现,彻底改变了人类与信息交互的方式。大语言模型凭借其强大的自然语言理解和生成能力,能够快速、准确地理解用户的问题,并从海量知识储备中提取有效信息,生成高质量的回答,为用户提供高效、智能的问答服务。
与此同时,移动互联网的普及使得智能手机成为人们获取信息的主要终端。安卓系统以其开源性、广泛的设备兼容性和庞大的用户基数,占据了全球移动操作系统市场的重要份额。然而,目前安卓应用市场中,虽然存在着各式各样的问答类应用,但大多功能较为单一,缺乏基于前沿大模型技术的深度整合,难以满足用户日益多样化和复杂化的问答需求。
本项目旨在开发一款安卓平台上基于大模型 API 的问答助手,将大模型强大的智能问答能力与安卓系统的便捷性、灵活性相结合。通过该应用,用户能够在移动端随时随地获取快速、准确、个性化的问题解答,无论是学习、工作中的专业知识查询,还是日常生活中的各类疑问求解,都能得到高效响应。项目的开展不仅有助于提升用户在移动端的信息获取体验,也将推动大模型技术在移动应用领域的深度应用与创新发展,为安卓生态系统注入新的活力。
2、实现思路
在核心架构层面,采用经典的 MVC 模式,将数据模型、视图和控制器分离,通过 Activity 高效处理 UI 逻辑,确保界面交互流畅;运用 SQLite 数据库实现用户数据、会话记录和聊天消息的持久化存储,保障信息安全与可追溯性;设计抽象基类实现多 AI 模型支持,为接入更多先进 AI 模型奠定基础,满足用户多样化的交互需求。
功能模块上,构建了完善的用户认证系统,涵盖登录与注册功能,有效保障用户账号安全与隐私;支持 DeepSeek V3/R1 和 Qwen 3 等三种 AI 模型,用户可按需切换,获取不同风格与侧重的回答;会话管理功能支持创建新会话、查看历史会话,方便用户管理聊天记录,延续对话思路;消息持久化机制自动将聊天记录保存至本地数据库,避免信息丢失。
技术实现上,借助 AsyncTask 实现异步 API 调用,确保网络通信高效且不阻塞主线程,提升应用响应速度;通过专门设计的数据库管理类管理 SQLite 数据库,优化数据存储与读取操作;在 UI 交互方面,由特定 Activity 组件集中处理用户输入,并实时展示聊天内容,打造便捷直观的交互体验。
应用的数据流设计科学合理,从用户输入问题开始,经模型选择、API 调用获取答案,再到响应处理、数据存储,最后完成 UI 更新,形成闭环流程。同时,项目采用模块化设计,各功能组件高度解耦,新增 AI 模型只需继承抽象基类并实现对应方法,数据库表结构也充分考虑多用户多会话场景,极大提升了项目的扩展性与维护性,为后续功能迭代与优化提供有力支撑 。
3、技术工具
- Android SDK: 34 (Android 14)
- Gradle: 8.6
- Android Gradle Plugin: 8.2.2
- Java: 1.8
4、核心实现过程
4.1、聊天页面
页面代码过长,此处不予展示。
4.2、 聊天代码后端逻辑
public class ChatActivity extends AppCompatActivity { // 定义UI组件 private Spinner modelSpinner; // 模型选择下拉框 private ListView chatListView; // 聊天内容列表视图 private EditText messageEditText; // 输入消息的编辑框 private ImageButton sendButton; // 发送消息按钮 private TextView introTextView; // 欢迎信息文本视图 private Button newSessionButton; // 创建新会话按钮 private Button historyButton; // 查看历史会话按钮 // 定义数据结构 private List chatMessages; // 存储聊天消息的列表 private ArrayAdapter adapter; // 用于聊天列表视图的适配器 private BaseModel currentModel; // 当前选择的模型 private UserDatabaseHelper dbHelper; // 数据库辅助工具类 private String username; // 用户名 private int userId; // 用户ID private long currentSessionId; // 当前会话ID @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_chat); // 设置布局文件 // 初始化UI组件 modelSpinner = findViewById(R.id.modelSpinner); chatListView = findViewById(R.id.chatListView); messageEditText = findViewById(R.id.messageEditText); sendButton = findViewById(R.id.sendButton); introTextView = findViewById(R.id.introTextView); newSessionButton = findViewById(R.id.newSessionButton); historyButton = findViewById(R.id.historyButton); // 初始化聊天消息列表和适配器 chatMessages = new ArrayList(); adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, chatMessages); chatListView.setAdapter(adapter); // 初始化数据库辅助工具和获取用户信息 dbHelper = new UserDatabaseHelper(this); username = getIntent().getStringExtra("USERNAME"); userId = dbHelper.getUserId(username); // 设置UI组件 setupModelSpinner(); // 设置模型选择下拉框 setupSendButton(); // 设置发送消息按钮 setupNewSessionButton(); // 设置创建新会话按钮 setupHistoryButton(); // 设置查看历史会话按钮 startNewSession(); // 开始新会话 } private void setupModelSpinner() { String[] models = {"DeepSeek V3", "DeepSeek R1", "Qwen 3"}; // 模型列表 ArrayAdapter spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, models); modelSpinner.setAdapter(spinnerAdapter); // 设置适配器 // 监听模型选择变化 modelSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { switch (position) { case 0: currentModel = new DeepSeekV3Model(); // 选择DeepSeek V3模型 break; case 1: currentModel = new DeepSeekR1Model(); // 选择DeepSeek R1模型 break; case 2: currentModel = new Qwen3Model(); // 选择Qwen 3模型 break; } } @Override public void onNothingSelected(AdapterView parent) { // 当没有选择任何项时,不做任何操作 } }); currentModel = new DeepSeekV3Model(); // 默认选择DeepSeek V3模型 } private void setupSendButton() { sendButton.setOnClickListener(v -> { // 设置发送按钮点击事件 String userInput = messageEditText.getText().toString(); // 获取用户输入的消息 if (!userInput.isEmpty()) { // 如果用户输入不为空 chatMessages.add("You: " + userInput); // 将用户消息添加到聊天列表 adapter.notifyDataSetChanged(); // 更新UI显示 messageEditText.setText(""); // 清空输入框 // 添加思考中提示 int thinkingIndex = chatMessages.size(); chatMessages.add("AI: 思考中..."); adapter.notifyDataSetChanged(); // 在新线程中处理AI回复 new Thread(() -> { String response = currentModel.getResponse(userInput); // 获取AI回复 runOnUiThread(() -> { // 切换到主线程更新UI // 替换思考中提示为实际回复 chatMessages.set(thinkingIndex, "AI: " + response); adapter.notifyDataSetChanged(); // 如果是第一条消息,则创建会话 if (currentSessionId == -1) { String sessionName = userInput.length() > 10 ? userInput.substring(0, 10) : userInput; // 使用用户输入的前10个字符作为会话名 currentSessionId = dbHelper.addSession(userId, sessionName); // 创建会话并获取会话ID } // 将消息保存到数据库 dbHelper.addMessage(currentSessionId, userInput, true); // 保存用户消息 dbHelper.addMessage(currentSessionId, response, false); // 保存AI回复 }); }).start(); } }); } private void setupNewSessionButton() { newSessionButton.setOnClickListener(v -> { // 设置创建新会话按钮点击事件 startNewSession(); // 开始新会话 }); } private void setupHistoryButton() { historyButton.setOnClickListener(v -> { // 设置查看历史会话按钮点击事件 showHistoryDialog(); // 显示历史会话对话框 }); } private void startNewSession() { messageEditText.setText(""); // 清空消息输入框 chatMessages.clear(); // 清空聊天消息列表 adapter.notifyDataSetChanged(); // 更新UI显示 introTextView.setVisibility(View.VISIBLE); // 显示欢迎信息 currentSessionId = -1; // 初始化为-1表示未创建会话 } private void showHistoryDialog() { List sessions = dbHelper.getSessionsForUser(userId); // 获取用户的所有会话 final String[] sessionArray = sessions.toArray(new String[0]); // 将会话列表转换为数组 // 创建对话框构建器 android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this); builder.setTitle("历史会话:"); // 设置对话框标题 // 设置对话框选项 builder.setItems(sessionArray, (dialog, which) -> { String selectedSessionName = sessionArray[which]; // 获取选中的会话名 loadSession(selectedSessionName); // 加载选中的会话 }); // 设置取消按钮 builder.setNegativeButton("取消", (dialog, which) -> dialog.dismiss()); // 取消按钮点击事件 // 设置清空历史按钮 builder.setNeutralButton("清空历史", (dialog, which) -> { dbHelper.clearAllSessions(userId); // 清空所有会话 Toast.makeText(this, "已清空所有历史会话", Toast.LENGTH_SHORT).show(); // 显示提示信息 }); builder.show(); // 显示对话框 } private void loadSession(String sessionName) { List messages = dbHelper.getMessagesForSession(getSessionIdByName(sessionName)); // 获取会话中的所有消息 chatMessages.clear(); // 清空当前聊天消息列表 chatMessages.addAll(messages); // 将获取的消息添加到聊天消息列表 adapter.notifyDataSetChanged(); // 更新UI显示 introTextView.setVisibility(View.GONE); // 隐藏欢迎信息 } private long getSessionIdByName(String sessionName) { SQLiteDatabase db = dbHelper.getReadableDatabase(); // 获取可读数据库实例 String[] columns = {UserDatabaseHelper.COLUMN_SESSION_ID}; // 要查询的列 String selection = UserDatabaseHelper.COLUMN_SESSION_NAME + "=?"; // 查询条件 String[] selectionArgs = {sessionName}; // 查询条件参数 // 执行查询 Cursor cursor = db.query(UserDatabaseHelper.TABLE_SESSIONS, columns, selection, selectionArgs, null, null, null); long sessionId = -1; // 默认会话ID为-1 if (cursor.moveToFirst()) { // 如果查询结果不为空 sessionId = cursor.getLong(cursor.getColumnIndexOrThrow(UserDatabaseHelper.COLUMN_SESSION_ID)); // 获取会话ID } cursor.close(); // 关闭游标 db.close(); // 关闭数据库 return sessionId; // 返回会话ID } }
4.3、模型调用API示例代码
public class DeepSeekV3Model extends BaseModel { // API 密钥,用于身份验证,请替换为你的密钥 private static final String API_KEY = "your_key"; // API 的 URL 地址,请替换为你的url private static final String API_URL = "your_url"; // 连接超时时间(单位:毫秒) private static final int CONNECT_TIMEOUT = 150000; // 读取超时时间(单位:毫秒) private static final int READ_TIMEOUT = 150000; /** * 重写 BaseModel 类的 getResponse 方法,通过异步任务与 AI 模型进行交互。 * @param input 用户输入的内容 * @return AI 模型返回的响应内容 */ @SuppressLint("StaticFieldLeak") @Override public String getResponse(String input) { final String[] result = {null}; // 存储 AI 模型返回的结果 new AsyncTask() { /** * 在后台线程中执行 HTTP 请求。 * @param params 用户输入的内容 * @return AI 模型返回的响应内容 */ @Override protected String doInBackground(String... params) { try { URL url = new URL(API_URL); // 创建 URL 对象 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // 打开 HTTP 连接 connection.setRequestMethod("POST"); // 设置请求方法为 POST connection.setRequestProperty("Content-Type", "application/json"); // 设置请求内容类型为 JSON connection.setRequestProperty("Authorization", "Bearer " + API_KEY); // 设置请求头中的授权信息 connection.setConnectTimeout(CONNECT_TIMEOUT); // 设置连接超时时间 connection.setReadTimeout(READ_TIMEOUT); // 设置读取超时时间 connection.setDoOutput(true); // 允许输出 // 构建请求体 String requestBody = String.format("{\"model\":\"deepseek-ai/DeepSeek-V3\",\"messages\":[{\"role\":\"user\",\"content\":\"%s\"}]}", params[0]); OutputStream os = connection.getOutputStream(); // 获取输出流 os.write(requestBody.getBytes()); // 写入请求体 os.flush(); // 刷新输出流 os.close(); // 关闭输出流 int responseCode = connection.getResponseCode(); // 获取响应码 if (responseCode == HttpURLConnection.HTTP_OK) { // 如果响应码为 200 BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); // 读取响应内容 String inputLine; StringBuilder response = new StringBuilder(); // 构建响应字符串 while ((inputLine = in.readLine()) != null) { response.append(inputLine); // 逐行读取并拼接响应内容 } in.close(); // 关闭输入流 try { JSONObject jsonResponse = new JSONObject(response.toString()); // 将响应内容解析为 JSON 对象 JSONArray choices = jsonResponse.getJSONArray("choices"); // 获取 choices 数组 if (choices.length() > 0) { // 如果 choices 数组不为空 JSONObject firstChoice = choices.getJSONObject(0); // 获取第一个 choice 对象 JSONObject message = firstChoice.getJSONObject("message"); // 获取 message 对象 return message.getString("content"); // 返回 message 中的 content 字段 } return "No response content found"; // 如果 choices 数组为空,返回提示信息 } catch (Exception e) { e.printStackTrace(); // 打印异常信息 return "Error parsing response: " + e.getMessage(); // 返回错误信息 } } else { return "Error: " + responseCode; // 返回错误响应码 } } catch (Exception e) { e.printStackTrace(); // 打印异常信息 return "Error: " + e.getMessage(); // 返回错误信息 } } /** * 在主线程中执行,将后台线程的执行结果赋值给 result。 * @param response 后台线程返回的响应内容 */ @Override protected void onPostExecute(String response) { result[0] = response; // 将响应结果赋值给 result } }.execute(input); // 执行异步任务 // 等待后台线程完成并返回结果 while(result[0] == null) { try { Thread.sleep(100); // 每 100 毫秒检查一次结果是否已返回 } catch (InterruptedException e) { e.printStackTrace(); // 打印异常信息 } } return result[0]; // 返回最终结果 } }
5、整体功能展示
下图分别是登录/注册界面、聊天界面、历史会话界面。
![]() | ![]() | ![]() |