鸿蒙 SDK 5 分钟跑通
@tansr/harmony 是会话服务的原生 ArkTS 薄客户端(HAR):发送输入、归约事件流、执行你显式注册的本地工具、应答权限与提问。智能体内核、权限引擎、上下文治理全部跑在你部署的 @tansr/serve;手机上没有任何平台凭据。视图归约与 Android / iOS 共用同一份金样。HAR 不包含 ArkUI 页面,录音 / 播放 / 列表虚拟化由宿主自己接。
兼容 Android 的旧鸿蒙设备继续用 Android SDK。当前声明最低 HarmonyOS 6.0 / API 20(Stage 模型;以 API 22 工具链构建);HarmonyOS 5.x 原生兼容后续补齐,本文不宣称可用。当前交付是独立发布的版本化 release 字节码 HAR(0.2.0,2026-10-10),随 harmony-sdk.zip 分发,尚未上架公共 OHPM,不会从公共渠道自动取最新版(2026-10-13 核对)。服务端按 @tansr/serve 0.15.1 核对:0.2.0 HAR 的全部请求只走服务端 0.13.0 起提供的统一调用面 /api(manifest revision 7;错误以统一码为主,响应头缺失时显式失败、不回退),SDK 2.0 的 RDB 档案接收器 / 执行日志 / 终端服务客户端也已随包提供;0.1.0 HAR 仍直连 /v2,而服务端 /v2 自 0.13.0 起只是内部适配入口、1.0.0 移除外部入口,请升级。2026-10-10 之后进入主线的加密记忆发布、加密增量 RDB 档位与只读副本等能力未随任何版本发布,本文不作描述。
手机端发送用户消息,服务端配置系统提示词
Section titled “手机端发送用户消息,服务端配置系统提示词”createSession 与 session.send(...) 都发送普通用户消息;鸿蒙 SDK 不经 /api 的会话请求传入 system。共享角色由平台应用配置管理,代码定制角色由 serve 的 platform.system 提供,宿主说明用 platform.systemAppend。
提示词与策略功能自 @tansr/serve 0.8.0 起提供,平台侧已于 2026-09-14 上线;默认 fallback 下 SDK 显式 system(包括空数组)替代平台段,prepend 下保留平台段在前。平台提示词与策略在后续新一轮前刷新,当前执行轮固定;前后台重连、SSE 恢复和 attach 可以保留原会话与历史,无需重开来取得更新。请由应用管理员消除业务段冲突,权限仍走独立机制。详见应用系统提示词。
- 一个可达的
@tansr/serve服务(见会话服务 5 分钟跑通),且已装配统一调用面/api(0.13.0 起)。本地可先起仓内examples/serve-demo:以DEMO_SERVE_ONLY=1、DEMO_PORT=8788常驻起服(源码缺省端口 8799),独立开发者登录服务pnpm login缺省127.0.0.1:8787。 - DevEco Studio 6.0+、HarmonyOS SDK API 20+(SDK 本身以 DevEco Studio 6.0.2 / API 22 工具链构建);宿主 HAP 声明
ohos.permission.INTERNET。录音等权限由实际使用该能力的宿主声明和申请。 - 你自己的登录体系:SDK 每次请求经
AuthProvider取短期认证头(通常是Authorization: Bearer <你的登录 token>),服务端的authenticate缝据此解出endUserId。不要在客户端持有平台 AppKey、上游模型密钥或服务端签名私钥。
解压独立 SDK 包 harmony-sdk.zip 得到固定目录 harmony-sdk/,从中取出 libs/tansr-harmony-0.2.0.har,先核对 libs/SHA256SUMS。HAR 含官方 ABC 与类型声明,不含 SDK 实现 ETS;字节码不构成绝对保密承诺。复制到业务模块后:
{ "dependencies": { "@tansr/harmony": "file:./libs/tansr-harmony-0.2.0.har" } }在应用 app.products[].buildOption.strictMode 设置 useNormalizedOHMUrl: true,再执行 ohpm install。升级时替换整套版本包并重新核对摘要,不要只替换 HAR 或改摘要跳过校验。SDK 没有外部运行依赖,不包含 Node.js、React Native、WebView 或 Android 兼容运行时。收到独立包即可接入,不必编译 SDK 源码,也不必把 Demo HAP 嵌进你的应用。
凭据:只有你自己的登录态
Section titled “凭据:只有你自己的登录态”SDK 不持久化任何凭据:每次请求经 AuthProvider.headers() 取一次头即用即弃。生产用 RefreshingAuthProvider 包装你的 CredentialIssuer,处理有效期、并发刷新与身份变化;刷新失败不要暗中重放密码登录,换票后身份变化须终止该实例。
import { NativeHttpTransport, StaticAuthProvider, TansrAgentClient } from '@tansr/harmony';
const headers = new Map<string, string>();headers.set('Authorization', 'Bearer ' + token);const client = new TansrAgentClient( 'https://agent.example.com', new NativeHttpTransport(), new StaticAuthProvider(headers),);StaticAuthProvider 只适合短时调试。默认要求 HTTPS;回环 HTTP 仅本地调试。真机连开发机私网地址时,经 NativeHttpOptions.allowPrivateNetworkHttp 显式开启内网 HTTP——不允许普通公网明文 HTTP,也不忽略 TLS 证书错误。
新建成功后先把确认的 sessionId 写入原登录作用域,再绑界面。保存失败或响应未确认要向用户报告,不能自动再建一条。verifiedEndUserId 必须来自已验证的登录回执。
import { AgentSession, JsonNode, NativeHttpTransport, SessionHistory, SessionView, StaticAuthProvider, TansrAgentClient } from '@tansr/harmony';
const headers = new Map<string, string>();headers.set('Authorization', 'Bearer ' + token);const client = new TansrAgentClient('https://agent.example.com', new NativeHttpTransport(), new StaticAuthProvider(headers));
const created = await client.createSession();// 已确认的会话 ID 先写入原登录作用域,再绑界面const session = new AgentSession(client, created.sessionId, verifiedEndUserId);const view = new SessionView('stream', 'off');view.onChange = (): void => render(view.state);session.onHistory = (history: SessionHistory): void => view.restoreHistory(history.messages);session.onFrame = (eventName: string, data: JsonNode): void => { if (!eventName.startsWith('server.')) view.consume(data);};session.start();await session.send('hi');session.stop() 只取消本地订阅与桥,不丢远端会话;session.start() 恢复订阅;close() 才请求关闭远端会话。前后台、退出登录和组件释放必须接这些入口。发送回执只表示接纳,实际输出通过事件流到达。
冷启动接着上次聊:先按原 sessionId 查归属,再交给 SDK attach / history / resume。恢复失败保留原 ID 并报告原因,不能把 forbidden、损坏和临时断网都处理为新建。
SessionView.state 已经是归约好的视图快照(消息列表、工具卡、待办、用量、lastError),多数 UI 订阅 onChange 即可。onFrame 收到的是原始 SSE 帧;server.* 控制帧交给 session.bridges,不要用普通 tool.permission.* 事件再弹一次审批。
连接态经 session.onState 观察:idle → connecting / recovering → live,闪断为 retrying,协议或鉴权失败为 failed,close() 后为 closed。断线不会浮到业务码:L1 携游标重连,L2 收到 gap 后拉 /history 重建,L3 在元信息 404 或 live = false 时 resume。lastSeq 恒按值续传,休眠判据恒 live = false。
本地工具与对话框
Section titled “本地工具与对话框”本地工具用 session.bridges.registerTool(declaration, handler) 注册,并在 createSession / resume 时传入同一份 clientTools 声明。parameters 是「参数名 → 参数规格」字典;无参数为 {},不能传整个 JSON Schema。未设置 onPermission 时默认拒绝;只响应 server.permission.request,用户确认后 answerPermission(id, 'allow' | 'deny')。提问走独立的 onQuestion / answerQuestion,补充文本不代表批准工具。
const declaration = JsonNode.object() .set('name', JsonNode.string('searchOrders')) .set('description', JsonNode.string('Search the user orders')) .set('parameters', JsonNode.object().set('keyword', JsonNode.object() .set('type', JsonNode.string('string')) .set('description', JsonNode.string('search keyword')))) .set('readOnly', JsonNode.boolean(true));session.bridges.registerTool(declaration, { async execute(args, cancel) { cancel.throwIfCancelled(); return JsonNode.object().set('status', JsonNode.string('ok')) .set('content', JsonNode.array([ JsonNode.object().set('t', JsonNode.string('text')).set('text', JsonNode.string(db.search(args.stringAt('keyword')))), ])); },});操作系统麦克风授权与智能体工具许可是两层:一层不能替代另一层。服务端 cwd 不映射为任意本地路径。
| 现象 | 处置 |
|---|---|
| 一连就 401 | AuthProvider 返回的头不被服务端 authenticate 认可。修好登录态后再 start() |
一连就 contract_unavailable |
baseUrl 没有指向 /api 门面(服务端早于 0.13.0,或代理 / 门户页改写了响应头)。SDK 不回退旧前缀;修好部署后再 start() |
| 模拟器 / 真机连不上 | 回环仅本地调试;连开发机私网须 allowPrivateNetworkHttp。生产恒上 TLS |
| 建会话 400 | invalid_request:clientTools.parameters 误写成了整份 JSON Schema;须为参数名字典 |
| 新会话 429 | capacity_exceeded(domainCode = session_limit_exceeded):每个终端用户缺省最多 8 个活跃会话;不用的会话请 close() |
- 鸿蒙接入指南:会话生命周期、三级恢复、工具桥、语音两条链、朗读双帽、媒体下载边界。
- Android 与 iOS 5 分钟跑通:对照三端同律差异。
- v2 协议与 webhook:服务端半场怎么把轮末通知交给你的推送后端。
- 移动应用的公网工具:让智能体读取网页、发起 HTTP 请求或联网搜索——在服务端执行,缺省关,鸿蒙端无需改代码。
本文是否有帮助?
感谢反馈,我们会持续改进这篇文章。