【HarmonyOS 7新能力|026】Agent Framework Kit工程封装:把接入逻辑放进可维护的分层结构

Agent Framework Kit工程封装

Agent 原型通常很快:接收一句话、调用几个工具、输出结果。真正进入工程阶段后,问题会集中出现——页面直接拼提示词、工具返回值未经校验、A2A 对端超时拖住主流程、重试导致重复副作用、日志记录了敏感上下文。

本文将 Agent 与 A2A 接入拆成交互、编排、能力、适配、治理和基础设施六层,重点是可维护边界,不虚构具体平台 API。示例类型和调用方式均为应用侧教学封装,不代表 HarmonyOS 7 Agent Framework Kit 的官方签名;能力范围、A2A 接入条件和设备支持应以当前 SDK 与华为官方文档为准。

一、先把 Agent 定义为受控任务系统

Agent 不是可以无限行动的聊天框,而是一个接收目标、生成计划、调用允许能力、验证结果并反馈的任务系统。每个动作都必须能回答:谁请求、允许做什么、预算多少、结果怎样验证、失败后是否重试。

第一版只允许只读查询和本地计算。发送消息、删除文件、支付和外部提交等副作用不自动开放。验收目标是:未知能力拒绝;每个任务有终态;取消能传递;超时不会无限重试;A2A 只发送最小数据;最终结果可追溯到步骤证据。

二、用契约注册能力

能力注册表不只保存函数引用,还要描述输入、输出、权限、风险和超时。编排器只能调用注册且通过策略检查的能力。

type RiskLevel = 'read' | 'write' | 'external'

interface CapabilityContract<I, O> {
  name: string
  version: number
  risk: RiskLevel
  timeoutMs: number
  validateInput(input: unknown): input is I
  execute(input: I, context: ExecutionContext): Promise<O>
  validateOutput(output: unknown): output is O
}

泛型帮助应用侧保持类型清晰,运行时校验仍不可省略,因为输入可能来自模型或远端 Agent。

三、任务状态机替代散落的布尔值

使用 isLoadingisDonehasError 很容易形成矛盾组合。任务状态机明确描述计划、运行、等待协作、取消和终态。

type TaskState =
  | 'created'
  | 'planning'
  | 'running'
  | 'waiting-peer'
  | 'completed'
  | 'failed'
  | 'cancelled'

interface AgentTask {
  id: string
  state: TaskState
  revision: number
  deadlineAt: number
  stepIndex: number
}

每次迁移增加 revision,异步回调落地前检查版本。用户取消或任务重规划后,旧回调即使成功也不能覆盖新状态。

四、编排器只负责决策与调度

Agent任务与A2A协作链路

编排层把目标拆成步骤、匹配能力、安排依赖和汇总结果,不直接读数据库、发网络请求或调用平台对象。所有副作用通过能力适配器完成。

interface PlanStep {
  id: string
  capability: string
  dependsOn: ReadonlyArray<string>
  input: Record<string, unknown>
  status: 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped'
}

interface TaskPlan {
  taskId: string
  steps: ReadonlyArray<PlanStep>
  maxParallel: number
}

计划生成后先做静态检查:能力是否存在、依赖是否成环、参数是否符合契约、风险是否超过授权范围。

五、把平台能力放进适配层

平台 Kit、本地数据库、文件系统和网络服务都通过适配器暴露窄接口。编排层不持有 Context,不解析平台原始错误,也不决定权限弹窗何时出现。

interface SearchInput { keyword: string; limit: number }
interface SearchItem { id: string; title: string; summary: string }

interface SearchPort {
  search(input: SearchInput, signal: AbortSignal): Promise<ReadonlyArray<SearchItem>>
}

适配器负责把平台结果映射成稳定模型,并将权限拒绝、不可用和超时转换成有限错误码。

六、A2A 是受控能力而非万能转发

Agent与A2A工程分层架构

只有本地无法完成且策略允许时才进入 A2A。发送前确认对端身份、能力版本、数据最小化和用户授权;接收结果后仍按不可信输入校验。

interface A2ARequest {
  requestId: string
  capability: string
  contractVersion: number
  deadlineAt: number
  payload: Record<string, string | number | boolean>
}

interface A2AResponse {
  requestId: string
  status: 'ok' | 'rejected' | 'failed'
  payload?: Record<string, string | number | boolean>
  errorCode?: string
}

不要把整段会话、用户文件或内部提示词默认转发给对端。请求仅包含完成该步骤必需的字段。

七、来源、授权与能力三重校验

A2A 请求通过传输层到达并不意味着可以执行。服务侧依次验证可信来源、授权范围和目标能力;调用方在业务参数中自报的身份不能作为依据。

interface PeerPolicy {
  peerId: string
  allowedCapabilities: ReadonlySet<string>
  maxPayloadBytes: number
  expiresAt: number
}

function canInvoke(policy: PeerPolicy, capability: string, now: number): boolean {
  return now < policy.expiresAt && policy.allowedCapabilities.has(capability)
}

身份信息必须来自平台或可信传输层。授权过期、能力不匹配或载荷超限时,在任何业务副作用发生前拒绝。

八、预算约束防止任务失控

任务应同时限制步骤数、总时长、工具调用次数、并行度和外部请求量。预算不是模型提示语,而是编排器强制执行的状态。

interface ExecutionBudget {
  maxSteps: number
  maxToolCalls: number
  maxElapsedMs: number
  maxPeerCalls: number
}

function exhausted(budget: ExecutionBudget, task: AgentTask, toolCalls: number, peerCalls: number): boolean {
  return task.stepIndex >= budget.maxSteps || toolCalls >= budget.maxToolCalls ||
    peerCalls >= budget.maxPeerCalls || Date.now() >= task.deadlineAt
}

达到预算后进入可解释的失败或部分完成状态,不能悄悄继续消耗资源。

九、重试必须与幂等绑定

查询类步骤可对瞬时失败有限重试;写入和外部动作只有在目标能力支持幂等键时才允许自动重试。退避、次数和可重试错误集合都由策略定义。

interface RetryPolicy {
  maxAttempts: number
  retryableCodes: ReadonlySet<string>
  baseDelayMs: number
}

function idempotencyKey(taskId: string, stepId: string, revision: number): string {
  return `${taskId}:${stepId}:${revision}`
}

用户拒绝授权、参数无效和能力不存在不是瞬时错误,重复请求只会制造干扰。

十、验证结果而不是相信结果

工具调用成功只说明获得了响应,不说明业务目标完成。输出先通过结构校验,再执行领域规则检查;重要结果还需要第二来源或确定性计算验证。

interface EvidenceRef {
  stepId: string
  source: string
  observedAt: number
  digest: string
}

interface VerifiedResult<T> {
  value: T
  evidence: ReadonlyArray<EvidenceRef>
  confidence: 'verified' | 'partial' | 'unverified'
}

无法验证时明确返回“不确定”,不能用语言润色掩盖证据缺失。

十一、可观测性必须保护隐私

日志记录任务号、步骤号、能力名、契约版本、耗时、结果码和预算消耗。会话正文、凭据、个人信息和完整工具结果默认不入日志。

interface StepMetric {
  taskId: string
  stepId: string
  capability: string
  elapsedMs: number
  outcome: 'ok' | 'failed' | 'cancelled' | 'timeout'
}

跨端链路使用关联 ID 追踪,但关联 ID 本身不包含用户身份。错误日志也先脱敏再持久化。

十二、以失败注入完成验收

测试至少覆盖:计划依赖成环、能力未注册、输入校验失败、权限拒绝、预算耗尽、用户中途取消、本地工具超时、A2A 对端离线、返回结构错误、重复响应、重试中的幂等、旧 revision 迟到,以及日志敏感字段扫描。

还要验证应用重启后的任务恢复策略:只恢复安全且有持久检查点的步骤;可能产生外部副作用的未知状态先进入人工确认,而不是自动重放。

工程化 Agent 的关键不是堆更多工具,而是让每个决策和副作用都经过清晰边界。通过状态机、能力契约、适配器、A2A 最小数据、预算、幂等和结果验证,Agent Framework Kit 接入才能随着业务增长保持可维护、可测试和可审计。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐