1. 为什么要在 SQLiteDatabase 项目里接一层统一 Key
如果你正在用 Android 的 SQLiteDatabase 做本地结构化存储,大概率已经写过openOrCreateDatabase、rawQuery、execSQL这一套。数据落在/data/data/<package_name>/databases/下,一个文件就是一个库,跨平台可复制,轻量、无服务器进程,这些特性让 SQLite 在移动端和桌面工具链里一直很稳。
但现在的开发场景变了:你不再只是「存了查、查了显示」。越来越多的本地工具链希望把 AI 能力嵌进来,比如让模型帮你把自然语言转成 SQL、对查询结果做摘要、或者根据表结构生成建表语句。问题就出在这里——每个模型供应商一套 Key、一套 Base URL、一套鉴权头,散落在settings.json、local.properties、环境变量里,改一次配置要翻五个文件。
我试过把 Key 直接硬编码进MySQLiteDatabaseHelper那种封装类里,结果换环境时全乱套。后来改成统一走一个 API 通道,所有模型请求都从同一个入口出,settings.json里只留一个 Key 字段,配置骨架就干净多了。这篇就围绕这个思路,给你一份可直接复制的settings.json骨架,再走一遍最小连通性验证,确认配置真的生效。
适合谁看:用 SQLiteDatabase 做本地存储、又想接入 AI 能力的 Android/Java/Kotlin 开发者;以及维护本地工具链、需要统一管理模型 Key 的同学。核心检索词就三个:SQLiteDatabase、settings.json 骨架、连通性验证。
2. TaoToken 前置:统一 Key 与 API 通道怎么理解
TaoToken 在这里扮演的角色,是一个统一的模型调用入口。你不需要为每个模型单独记 Base URL 和鉴权方式,只要拿到一个 Key,填进配置文件的固定位置,请求统一发到https://taotoken.net/api这个地址就行。对 SQLiteDatabase 项目来说,好处是配置项收敛:数据库路径、库名、AI 通道 Key 各管各的,互不干扰。
先做两件前置准备。第一,去官网了解通道能力,地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,页面上能看到支持的模型范围和接入说明。第二,进控制台创建 API Key,入口在 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,Key 只在创建时完整显示一次,复制后先存到安全的地方。
注意:Key 属于敏感凭证,不要提交到 Git 仓库,也不要写进会被打包进 APK 的明文资源里。本地开发可以放
settings.json并加入.gitignore,生产环境建议走服务端转发或密钥管理服务。
如果你后续要做长期编码、Agent 类任务,可以了解 Coding Plan,入口是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ;只是想先验证模型能不能通,用模型对话页面就够了,地址 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。接入细节和参数说明统一看文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
3. settings.json 可复制骨架与字段填写位置
下面这份骨架是我在本地工具链里实际用的结构,分三块:数据库配置、AI 通道配置、请求默认参数。你可以直接复制,把apiKey换成自己的,dbPath按项目实际路径改。
{ "database": { "dbName": "android_manual.db", "dbPath": "/data/data/com.example.app/databases", "version": 1, "enableTransaction": true }, "aiChannel": { "provider": "taotoken", "baseUrl": "https://taotoken.net/api", "apiKey": "sk-你的Key粘贴在这里", "defaultModel": "claude-sonnet-4-5", "timeoutMs": 30000 }, "requestDefaults": { "maxTokens": 1024, "temperature": 0.3, "stream": false } }字段说明用表格对照更清楚:
| 字段 | 作用 | 填写要点 |
|---|---|---|
database.dbName | 数据库文件名 | 与openOrCreateDatabase传入的名字保持一致 |
database.dbPath | 数据库所在目录 | 默认路径是/data/data/<package_name>/databases |
aiChannel.baseUrl | 统一 API 入口 | 固定为https://taotoken.net/api,不要加多余斜杠 |
aiChannel.apiKey | 鉴权凭证 | 从控制台创建后粘贴,注意不要带空格 |
aiChannel.defaultModel | 默认模型 | 按文档里支持的模型名填写 |
requestDefaults.temperature | 采样温度 | 做 SQL 生成建议 0.2–0.4,偏确定性 |
读取这份配置的 Java 代码可以这样写,放在你的MySQLiteDatabaseHelper同级:
public class AppConfig { private static JSONObject root; public static void load(InputStream in) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); root = new JSONObject(sb.toString()); } public static String getApiKey() throws Exception { return root.getJSONObject("aiChannel").getString("apiKey"); } public static String getBaseUrl() throws Exception { return root.getJSONObject("aiChannel").getString("baseUrl"); } public static String getDbName() throws Exception { return root.getJSONObject("database").getString("dbName"); } }这样数据库连接和 AI 通道的配置就彻底解耦了。getConnection()只管拿SQLiteDatabase对象,AI 请求只管从AppConfig取 Key 和 Base URL,谁也不用知道对方的细节。
4. 最小连通性验证:一次请求确认配置生效
配置写完不算完,得发一次真实请求确认通道是通的。验证分两步:先确认 SQLiteDatabase 本身能正常打开和查询,再确认 AI 通道能返回结果。
第一步,数据库连通性。用openOrCreateDatabase打开库,建一张最小表,插一条数据再查出来:
String path = context.getFilesDir().getParent() + "/databases/" + AppConfig.getDbName(); SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(path, null); db.execSQL("create table if not exists tb_ping (_id integer primary key autoincrement, note text)"); db.execSQL("insert into tb_ping (note) values (?)", new Object[]{"connectivity-check"}); Cursor cursor = db.rawQuery("select note from tb_ping order by _id desc limit 1", null); if (cursor.moveToFirst()) { Log.d("PING", "db ok: " + cursor.getString(0)); } cursor.close(); db.close();日志里出现db ok: connectivity-check,说明 SQLiteDatabase 这条链路没问题。
第二步,AI 通道连通性。发一个最小请求,只让它回一句话,验证 Key 和 Base URL 都对:
curl -X POST "https://taotoken.net/api/v1/messages" \ -H "Content-Type: application/json" \ -H "x-api-key: sk-你的Key" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-5", "max_tokens": 64, "messages": [ {"role": "user", "content": "只回复两个字:通了"} ] }'成功时你会拿到一个 JSON 响应,content数组里有模型返回的文本。如果返回里能看到「通了」两个字,说明 Key 有效、Base URL 正确、请求格式没问题。这一步跑通之后,再把它接进你的 SQLiteDatabase 工具链,比如让模型根据表结构生成查询语句,就只是把messages内容换掉的事。
提示:验证阶段把
max_tokens设小一点,比如 64,既省额度又能快速看到结果。确认通了之后再按实际需求调大。
5. 本篇常见错排查
配置和验证过程中,最容易卡在几个固定位置。下面按报错现象倒推原因。
报 401 或鉴权失败:九成是 Key 的问题。检查settings.json里apiKey有没有多余空格、换行,或者复制时漏了前缀。另外确认请求头字段名和文档一致,不同接口的鉴权头写法可能不同,以文档为准。
报 404 或路径不存在:Base URL 拼错了。https://taotoken.net/api后面接的路径要严格按文档来,不要自己加/v1或去掉某一段。建议先用 curl 在终端验证,排除代码里字符串拼接的干扰。
数据库打不开,报 unable to open database file:dbPath目录不存在,或者应用没有该路径的读写权限。Android 上默认数据库目录是/data/data/<package_name>/databases,如果自定义到外部存储,要确认已申请存储权限,并且目录已创建。
Cursor 返回空但表里明明有数据:检查rawQuery的 SQL 有没有拼错表名,以及moveToFirst()是否返回了 false。另外注意 SQLite 是弱类型的,但INTEGER PRIMARY KEY这一列有特殊约束,建表时别把主键类型写错。
请求超时:timeoutMs设得太短,或者网络本身不稳定。先把超时调到 30000 以上再试。如果持续超时,用 curl 单独测一次,区分是网络问题还是代码问题。
模型名不识别:defaultModel填了文档里没有的模型名。回到文档确认可用模型列表,换成受支持的名称。
排查顺序建议固定下来:先 curl 验证通道,再查配置文件字段,最后看代码里的字符串拼接。这样能最快定位问题在哪一层。
6. 把配置固化下来,后续接入就顺了
走到这里,你手上应该有一份能用的settings.json骨架、一段读取配置的 Java 代码、以及一次成功的连通性验证记录。这套结构的好处是,以后不管换模型还是加新能力,改动都集中在aiChannel这一块,SQLiteDatabase 的封装类完全不用动。
如果你在接入过程中遇到鉴权或路径类的报错,优先去 API Keys 页面重新确认 Key 状态,入口是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,配合接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 对照参数。想先直观感受模型返回效果,用模型对话页面最快:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。长期做编码和 Agent 任务的话,Coding Plan 会更合适:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
最后留一个实操建议:把settings.json加进.gitignore,同时提交一份settings.example.json作为模板,团队里每个人复制一份填自己的 Key。这样既不会泄露凭证,新人拉下代码也知道该填哪些字段。配置这件事,一次理清楚,后面省的是反复排查的时间。