开发交接文档
项目:HarmonyOS NEXT AI 智能体助手
仓库:https://atomgit.com/2501_93461085/talk
分支:
main文档状态:2026-07-28,与当前功能工作区同步;提交后以
main最新提交为准
这份文档面向第一次接手项目的开发者。产品介绍和用户操作请先读 README,隐私边界请读 隐私与安全,真机验证请按 验收清单 执行,原生依赖及许可证见 第三方组件说明。
1. 项目目标
本项目是一款 HarmonyOS NEXT 原生 AI 智能体应用:
- 支持用户自定义 OpenAI 兼容模型供应商。
- 支持流式对话、工具调用、长期记忆和角色卡。
- 支持经过明确授权的有限无障碍自动化。
- 业务数据优先保存在本地,API Key 使用 HUKS 加密。
项目不是服务端应用,不随 HAP 打包模型权重,也不提供默认 API Key、云端账号系统或远程数据同步。应用提供人工核对的公开 GGUF 下载目录,只有用户主动选择后才下载到应用私有目录。
2. 当前技术基线
| 项目 | 当前值 |
|---|---|
| 语言与 UI | ArkTS 严格模式、ArkUI |
| 应用模型 | Stage 模型 |
| 系统目标 | HarmonyOS 6.1.1 / API 24 |
| Bundle name | com.example.talk |
| 应用版本 | 0.1.0 / versionCode 1000000 |
| 数据库 | RelationalStore,业务库版本 v5 |
| 向量检索 | 独立向量库,按真实 Embedding 维度初始化 |
| 模型协议 | OpenAI 兼容 Chat Completions / Embeddings + 本地 GGUF |
| 本地推理 | llama.cpp 固定提交、N-API、ARM64 CPU |
| 安全插件原型 | WAMR 2.4.5 固定提交、经典解释器、无 WASI/AOT/JIT |
| 页面 | Chat、Settings、ModelConfig、EmbeddingConfig、Character、Memory、Toolbox、ToolRuntime、Alarm、Automation |
| 工具 | 18 个内置工具 + 3 个自动化工具,共 21 个 |
| UI 基线 | AppTheme 语义令牌 + 根 Stack 应用内弹层 + 系统模糊 |
必须使用安装了 API 24 SDK 的 DevEco Studio。JDK、Node.js 和 Hvigor 优先使用 DevEco Studio 自带版本,避免版本错配。
首次从干净缓存构建原生模块时会下载 entry/src/main/cpp/CMakeLists.txt 固定提交的 llama.cpp 和 WAMR;构建目标目前仅为 arm64-v8a。离线构建必须预先保留对应 FetchContent 缓存,不能自动漂移到其他提交。
3. 当前完成情况
聊天与模型
- OpenAI 兼容 Base URL 规范化。
- HUKS AES-256-GCM 加密 API Key。
- 冷启动检查并复用 HUKS 主密钥,HUKS 操作有 5 秒超时;密钥失效时明确要求重新填写,不以明文兜底。
- DeepSeek、OpenAI、通义千问、Moonshot 快捷配置,以及自定义 OpenAI 兼容配置。
- 内置 GGUF 下载页:可信目录、流式落盘、下载进度/取消、大小与 SHA-256 校验、失败清理、自动创建配置和设为默认。
- GGUF 系统文件选择入口继续保留,支持文件头校验、应用私有目录复制、推理参数编辑和本地生成测试。
ModelAdapterFactory在 OpenAI 网络适配器与本地llama.cpp适配器之间切换。- 本地模型支持聊天模板、逐 token 流式输出、停止生成和文本工具协议,不要求 API Key。
- DevEco debug HAP 继续保留调试符号,但
llama、ggml、ggml-base和ggml-cpu推理核心必须在 CMake 中显式追加-O3;否则工具链注入的-O0会让轻量模型也长期没有首 token。 - 本地生成取消同步通知原生停止标记;页面退后台或锁屏时停止本地推理,避免恢复后遗留忙状态。
- 本地模型使用
LocalToolSelector按当前用户输入裁剪工具 schema;同一份清单必须继续传给执行授权检查,不能只缩短提示词却允许模型执行本轮未暴露的工具。 ToolCallFallback对显式<tool_call>块做受限兼容:允许回复末尾漏结束标签、已知时间字段数字前导零、对象后少量闭合符号、最多两个尾随},并展开唯一的arguments.parameters包装。Gemma 另只接受完整tool_code围栏中的单个工具名()或工具名(JSON 对象);不得扩展为解析标签外普通 JSON、普通代码块或任意表达式,且解析结果必须继续受本轮工具白名单约束。LocalThreadPolicy使用原生sched_getaffinity返回的应用可用处理单元数;未测速时自动留一个处理单元给系统,已测速结果仅在tunedForProcessors与当前数量一致时复用。手动模式仍接受 1–16。LocalThreadTuner使用同一模型、提示词和上下文,对三个候选线程正序/倒序各测一次并按平均elapsedMs选择;测速结束必须卸载临时上下文,确保聊天按正式配置重新加载。- 模型新增、编辑、删除、默认项和连通性测试;快捷配置只要求供应商、API Key 和模型。
- 聊天页模型选择。
- SSE 流式解析,支持 UTF-8 跨分块、CRLF、
data:变体。
麒麟真机 Qwen3.5 0.8B 当前基准:普通“你好”首 token 7574 ms、总耗时 12914 ms;“现在几点”完整工具回路包含两轮推理,分别耗时 8909 ms 和 12774 ms,工具卡片及最终回复均正常结束。真机数据会受对话历史、温度和系统负载影响,回归时重点检查不能重新出现全量工具注入或永久“正在生成”。
Mate X7 线程调优基准:应用 affinity 可用 9 个处理单元,220-token 固定输入正反各测一次后的平均值为 6 线程 3652 ms、8 线程 3810 ms、9 线程 3714 ms,因此当前 Qwen3.5 0.8B 保存为 6 线程“实测最优”。后续更换模型、系统调度策略或设备后应重新测速,不要仅按物理核心数直接覆盖。
- 取消、60 秒单轮超时、有限重试和网络资源释放。
- 已产生内容后不重试,避免重复回复或重复工具调用。
- 中断时持久化部分回复,并标记“已停止”或“生成中断”。
对话与界面
- 对话历史抽屉、搜索、新建、重命名、置顶和删除。
- 历史操作使用锚点菜单,避免列表内操作按钮点击后没有可见反馈。
- 从左侧向右滑打开,全屏向左滑关闭。
- 抽屉开合使用线性动画。
- Chat 与 Settings 共用窗口管理器;页面切换后重新同步全屏和上下安全区。
- 首页顶栏提供角色选择:默认助手、角色卡列表、创建/管理角色;切换角色时创建新对话。
- 页面统一使用
AppTheme的颜色、圆角、触控尺寸与安全区基线。 - 角色、模型、记忆、白名单、备份和危险确认采用应用内弹层,不再使用
bindSheet。 - 弹层使用系统模糊和半透明表面;返回键优先关闭弹层,危险确认除外。
- 生成期间阻止重复发送、模型切换、历史删除和进入破坏性设置流程。
工具系统
- 三级风险:READONLY / WRITE / DANGEROUS。
- 危险工具确认与可撤销白名单。
- 工具启停持久化,并在模型工具清单和运行时双重拦截。
- 云端严格模式只接受原生
tool_calls;本地 llama.cpp 没有原生函数调用通道,使用受限<tool_call>协议,并兼容 Gemma 的受限tool_code围栏调用。 - Qwen3.5 0.8B 真机可能漏结束标签、输出
minute:00或在 JSON 后追加闭合符号;兼容解析只在显式工具标签内部修复。重复闹钟还必须用用户原句校正星期、时间和标题,不能直接信任小模型参数。 - 工具参数在调度前统一做 JSON、长度、必填项和基础类型校验。
- 同批纯只读调用并行执行;含写入或危险操作时保持顺序。
- 连续重复工具批次会先拒绝,持续重复则终止循环。
create_reminder按系统错误码区分通知关闭(1700001)、数量超限(1700002)和权限拒绝(201)。数量超限时仅取消当前应用中过期、非重复的日历提醒并重试一次;禁止为腾出配额静默删除未来提醒或循环提醒。- 系统级提醒池也会返回
1700002。如果 Talk 查询到 0 条有效提醒,先调用当前应用作用域的cancelAllReminders重置残留状态并重试;仍失败时必须提示系统级配额问题,不能声称 Talk 已创建 30 条,也不能尝试清理其他应用提醒。 - 华为系统时钟使用独立的系统内部闹钟能力;真机已验证系统时钟可创建闹钟,而第三方
ReminderRequestCalendar和ReminderRequestAlarm同时返回1700002。不要把打开或操作系统时钟私有页面包装成跨设备通用能力,也不能在未获得公开 API 成功结果时向模型返回“提醒已创建”。 - Mate X7 + Qwen3.5 0.8B 已完成真实重复闹钟调用:用户原句“每周一早上 8 点”经
create_recurring_alarm落库为 Talk ID=1,list_alarms复核为“每周一 08:00”;系统1700002时记录保留为失败状态。 - 本地模型的闹钟确定性工具通过
ToolResult.finalAnswer权威直出。只有同一批所有结果都提供该字段时才能跳过第二轮推理;云端模型、普通工具和混合批次不得提前结束。 AlarmPage直接复用AlarmDao与AlarmScheduler展示和管理本地记录;删除必须先确认系统提醒已取消,系统取消失败时不得删除本地记录。AlarmPage会直接查询系统通知开关,并提供开启通知和“两分钟测试”入口,便于在没有模型配置时独立验证reminderAgentManager。- Mate X7 已执行备份后的彻底卸载重装:当前签名/Profile/权限一致,历史旧 App ID 已清除,通知已开启,但 Talk 有效提醒为 0、重置自身状态后两分钟测试仍返回
1700002。后续不要再把同一故障归因于旧签名残留或通知未开启。 - 文件工具限制在应用
filesDir,拒绝路径穿越。 file_read支持字符偏移分段读取,file_search支持受限递归文本搜索。- 网络工具只允许公开 HTTPS,阻止明显 SSRF、数字主机变体和自动重定向。
- 请求体、响应体、文件内容、请求头数量和超时均有限制。
- 工具审计保存统计但不保存真实正文、密钥、Cookie 或 URL 查询参数。
- 数据库 v4 升级会清理旧审计中的原始参数和结果;数据库 v5 新增不保存凭据的
alarm表。
工具运行环境
- 设置页已新增“工具运行环境”。当前不仅做系统能力探测,还在
libtalkllama.so内静态包含 WAMR 2.4.5 经典解释器,执行编译时固定的 WASMadd(20, 22)自检。 - WAMR 固定到提交
25bd7eb63e828e4bd242cc9b38d260b4b31c6605;仅启用经典解释器,AOT、JIT、WASI、libc、文件、网络、线程、共享内存和多模块均关闭。运行时使用 512 KiB 固定内存池,模块实例的栈和堆各限制为 16 KiB。 - WAMR 加载器会临时修改输入字节,因此内嵌只读模块必须先复制到可写缓冲区再调用
wasm_runtime_load()。直接const_cast传只读段会在 Mate X7 的wasm_const_str_list_insert触发SIGSEGV(SEGV_ACCERR);当前代码已修复并完成回归。 native_tool_runtime.cpp在 N-API 异步任务中依次运行固定 WASM 计算,并测试fork + pipe、ptrace、应用自带静态 ARM64 ELF、匿名内存 ELF、openpty与posix_spawn系统 Shell。固定模块、标记和命令均不可被页面或模型修改。- 探测通过不等于 Ubuntu 已安装;当前没有 PRoot、rootfs、包管理器或
shell_exec工具。 - Mate X7 真机连续执行两次均显示“WAMR 2.4.5 解释器已执行固定 add(20, 22) = 42”,Talk 进程保持存活,证明当前解释器最小闭环可重复初始化和销毁;这不等于任意 WASM 文件或插件系统已经实现。
- Mate X7 真机结果:N-API、普通
fork + pipe和PTRACE_TRACEME/PTRACE_CONT通过;filesDir 中的应用自带 ELF、openpty和系统 Shell 的posix_spawn均返回errno=13 (Permission denied)。 - 静态 ARM64 ELF 经
memfd_create写入成功,但fchmod返回errno=13,直接execveat(..., AT_EMPTY_PATH)返回errno=2。因此标准的落地执行与匿名内存执行通道当前都不可用。 - 不能直接照搬 Operit 的 Android 预编译可执行文件方案。主线已改为“WAMR 安全插件 → 资源限制、签名下载与权限声明 → Python-WASI → 可选远程 Ubuntu”;PRoot/进程内 ELF loader 只保留为独立研究路线,不阻塞主线。
- PRoot 上游默认仍会把内置 loader 写入临时文件并通过 tracee 的
execve启动,必须改成向停止的子进程注入 loader 与加载脚本;同时上游是 GPL-2.0-or-later,Talk 是 MIT,许可证方案确定前禁止直接链接或复制 PRoot/Operit 二进制。
数据、记忆和角色
- 会话、消息、角色、记忆、模型和工具审计 DAO。
- 删除单会话和清空聊天使用事务保持关联数据一致。
- 长期记忆主动写入、人工 CRUD、关键词降级和 Embedding 召回。
- 记忆召回 2 秒超时,不阻塞主聊天链路。
- 旧对话异步摘要与上下文裁剪。
- 角色卡 CRUD、JSON 导入导出、酒馆 PNG
chara/ccv3导入、头像落盘。 - 角色开场白先落库再展示。
- “设置 → 角色卡 → 创建第一个角色”和聊天首页“角色”入口已在 Pura 90 模拟器完成 UI 路径验证。
- 隐私安全备份导出、合并恢复、替换恢复和向量重建。
自动化
AutoOpAbility无障碍扩展。- 应用内事件桥、UI 树压缩、点击和滑动。
- 最多 20 步、重复动作保护、危险确认和急停。
- 自动化设置页提供服务状态与 UI 树自检。
4. 尚未完成或需要扩大验证
- 多个真实 OpenAI 兼容供应商的 Chat、工具调用、限流和异常响应回归。
- 多种 Embedding 供应商、不同向量维度、重建和旧记忆回填的真机回归。
- 更多酒馆 PNG 卡片样本、异常元数据和大图片导入回归。
- 无障碍跨应用场景、系统弹窗、后台/前台切换和服务重连回归。
- 弱网、断网、切网、超时、取消和应用退后台的真机回归。
- Phone / Tablet 不同尺寸、折叠屏、深色聊天模式、字体和上下安全区视觉回归。
- 处理 SDK 弃用 API 与 ArkTS “Function may throw” 警告。
- 正式图标、应用说明、隐私政策、签名和上架材料。
KeyPool多 Key 批量健康检查仍是后续功能。MemoryClassifier仍使用关键词启发式,尚未增加模型驱动的会话自动记忆提取。- 本地 GGUF 首版只有 ARM64 CPU 后端,尚未接入麒麟 NPU;需在麒麟真机扩大架构、量化、内存、温控和 token/s 回归。
- 本地 GGUF 暂不提供 Embedding,语义记忆仍需独立 Embedding 配置。
- 内置目录的下载地址、文件大小、SHA-256 和许可证提示需要随上游版本人工维护;新增条目前必须从模型官方或维护方仓库逐项核对,禁止指向不明网盘或未固定文件。
- WAMR 2.4.5 经典解释器固定计算已在 Mate X7 连续两次通过;任意 WASM 导入、插件清单/签名、资源计量、宿主能力授权、Python-WASI 和远程 Ubuntu 尚未实现。Operit 式标准外部 ELF 启动通道不可用,PRoot 注入原型及 GPL/MIT 分发方案仅作为独立研究项。
不要把“构建成功”描述成“真机验收完成”。每一项用户可见能力必须按验收清单记录实际结果。
5. 关键目录
entry/src/main/ets/
├── entryability/EntryAbility.ets
├── accessibility/AutoOpAbility.ets
├── pages/
│ ├── ChatPage.ets
│ ├── SettingsPage.ets
│ ├── ModelConfigPage.ets
│ ├── EmbeddingConfigPage.ets
│ ├── CharacterPage.ets
│ ├── MemoryPage.ets
│ ├── ToolboxPage.ets
│ ├── ToolRuntimePage.ets
│ ├── AlarmPage.ets
│ └── AutomationPage.ets
├── agent/
│ ├── AgentEngine.ets
│ ├── ContextManager.ets
│ └── PromptBuilder.ets
├── model/
│ ├── ModelAdapter.ets
│ ├── ModelAdapterFactory.ets
│ ├── ModelProviderPresets.ets
│ ├── local/
│ ├── openai/OpenAIAdapter.ets
│ └── sse/SseParser.ets
├── tools/
│ ├── Tool.ets
│ ├── ToolRegistry.ets
│ ├── SandboxPath.ets
│ ├── NetworkUrlPolicy.ets
│ ├── builtin/
│ ├── automation/
│ └── runtime/
├── automation/
├── alarm/
│ └── AlarmScheduler.ets
├── memory/
├── character/
├── data/
│ ├── DbHelper.ets
│ ├── BackupService.ets
│ └── dao/
│ └── AlarmDao.ets
└── common/
├── AppTheme.ets
├── Crypto.ets
├── Abort.ets
└── WindowLayoutManager.ets
entry/src/main/cpp/
├── CMakeLists.txt
├── native_llama.cpp
├── native_tool_runtime.cpp
├── native_tool_runtime.h
├── runtime_probe_helper.cpp
└── types/libtalkllama/
6. 不可破坏的约束
数据一致性
- 用户消息、助手消息和工具消息必须先写数据库,再通知 UI。
- 删除会话时先清工具审计,再删消息,最后删会话。
- 清空和恢复过程中必须使用事务;失败时不能留下半套数据。
- 生成过程中不得执行会破坏当前会话依赖的数据操作。
模型与流式处理
- SSE 必须使用流式 UTF-8 解码,不能逐块直接转字符串。
- 已经产生 token 或工具调用后不能自动重试整个请求。
- 所有网络请求结束、失败或取消时必须释放监听器和 HTTP 对象。
- 单轮响应 60 秒超时;工具循环最多 15 轮。
- 本地模型单轮含首次加载允许 300 秒;上下文请求必须按 GGUF 训练上限收敛。
- 模型目录下载必须先写
.download,只有大小、SHA-256 和 GGUF 头均通过才可重命名为正式文件;取消、网络失败和配置写入失败都必须清理对应文件。 - 直接冷启动的路由参数可能是
undefined;页面生命周期读取参数前必须同时排除null与undefined。 - 聊天模型属于首页主链路,应先于 Embedding 初始化;Embedding 失败只能降级关键词检索,不能阻塞模型显示与聊天。
页面与弹层
- 新增页面级面板时优先在页面根
Stack中渲染,避免重新引入已在 API 24 设备上出现无可见反馈的bindSheet。 - 弹层必须提供明确关闭入口,并在
onBackPress()中优先消费返回事件。 - 危险确认不能通过遮罩或返回键静默关闭,必须显式完成确认 Promise。
- 生成期间不得切换模型或角色;角色切换必须开启新对话,不能修改已有历史的人设语义。
- 顶栏新增入口时需在 1320 × 2760 模拟器和窄宽布局检查标题、角色、模型与设置是否挤压。
工具与安全
- 单个工具输出默认不超过 2000 字符。
- 文件路径必须经过
SandboxPath,不能直接拼接模型输入。 - 网络地址必须经过
NetworkUrlPolicy。 - 动态风险判断失败时必须按危险操作处理。
- 审计日志不得保存 API Key、Token、Cookie、请求正文、文件正文或剪贴板正文。
- 自动化点击和滑动必须保留危险确认与急停路径。
- 提醒数量超限时只允许自动清理当前应用的过期一次性提醒;若没有安全清理项,应明确失败并提示用户先删除旧提醒,不能取消仍在生效的提醒。
凭据与签名
- 不得提交 API Key、仓库访问令牌、Cookie、HUKS 明文或聊天备份。
- 不得提交个人签名证书、私钥、密码和本机绝对路径。
- 根目录
build-profile.json5可能包含开发者本地签名变更;提交前必须逐文件暂存,不能直接git add .。 - 仓库凭据应使用系统凭据管理器或交互式认证,不能放进远程 URL、命令历史或文档。
7. 构建方法
DevEco Studio
- 打开仓库根目录。
- 确认 SDK 为 HarmonyOS 6.1.1 / API 24。
- 配置个人调试签名。
- 运行
entry。
命令行
设置以下环境变量:
DEVECO_HOMEDEVECO_SDK_HOMEJAVA_HOME
然后执行:
macOS / zsh:
"$DEVECO_HOME/tools/node/bin/node" \
"$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" \
--mode project -p product=default assembleApp -p buildMode=debug --no-daemon
Windows / PowerShell:
& "$env:DEVECO_HOME\tools\node\node.exe" `
"$env:DEVECO_HOME\tools\hvigor\bin\hvigorw.js" `
--mode project -p product=default assembleApp -p buildMode=debug --no-daemon
产物:
entry/build/default/outputs/default/entry-default-signed.hap
构建日志中的已知弃用和异常处理警告目前不会阻止 HAP 生成,但新增修改不能引入 ArkTS 编译错误。
8. 提交流程
-
查看状态和差异:
git status --short git diff --check git diff -
只暂存本次相关文件,明确排除本地签名配置。
-
执行完整 HAP 构建。
-
再检查暂存差异与敏感信息。
-
创建小而明确的提交。
-
推送到
origin/main,然后用远程提交哈希核对。
禁止使用会丢失用户工作区内容的 Git 命令,例如未经明确授权的 git reset --hard 或 git checkout --。
9. 推荐后续顺序
- 定义 WASM 插件清单、入口 ABI、版本、SHA-256、发布者签名和宿主能力声明;先只支持仓库内固定的纯计算样例。
- 为 WAMR 增加模块大小、内存、调用时限、输出、并发和取消上限,并完成重复执行、切后台和熄屏回归。
- 把文件、网络、剪贴板、提醒和 UI 自动化做成默认拒绝的显式宿主能力,复用工具风险确认与脱敏审计。
- 纯 WASM 插件闭环稳定后再接 Python-WASI;完整 Ubuntu 只做可选远程 SSH,PRoot 继续作为不阻塞主线的研究项。
- 在至少一台真实 Phone 和折叠屏上复测首页角色、模型、历史、全部应用内弹层和 Chat → Settings → Chat 安全区。
- 对至少两个真实模型供应商执行快捷配置、普通聊天、工具调用、取消和弱网测试,并扩大 Embedding、角色 PNG 和无障碍样本。
- 收敛构建警告、补齐正式许可证随包材料,再进入发布准备。
10. 当前 Git 注意事项
- 主线为
main,远程为 AtomGitorigin。 - 当前文档以 AtomGit
main最新提交为功能基线,不在文档内固化容易过期的提交号。 - 本地开发环境可能保留未提交的签名配置差异,这是预期行为,不应随功能提交推送。
- 接手时先运行
git status --short和git log --oneline -10,不要根据旧聊天记录猜测仓库状态。