【共创稿事节】HarmonyOS 7 Agent A2A 实战:让日程智能体和打车智能体自己谈成一单

本文基于 HarmonyOS 7(API 26)官方《通过 AgentAbilityExtension 实现智能体间 A2A 协议通信》开发指导与 Agent Framework Kit 相关接口参考整理。文中代码示例为说明问题自写,接口名均出自官方文档并标注出处,方法签名与配置细节以官方 SDK 为准;未核实到底层调用细节的部分以示意性伪代码呈现并标注;文中不含实测数据,场景为按官方能力描述做的推演,运行表现以真机实测为准;7.0 相关能力需升级至 HarmonyOS 7 并以实际支持机型为准。


引子:一句"赶飞机",两个 App 自己谈成了

兄弟们好,我是V哥。

先描述一个按官方能力推演的场景:用户对小艺说"明早七点半赶飞机,帮我安排"。系统拆解意图,找到行程应用登记的日程智能体,日程智能体算出"七点十分出门",然后把"需要一辆车"这个子意图交回系统;系统撮合到打车应用登记的打车智能体,两边按 A2A 协议把时间、地点、车型谈拢,用户确认后订单落地,行程卡片自动更新(运行表现以真机实测为准)。

全程用户没打开任何一个 App。上一期V哥写过 Skill 化------应用把功能递进系统的意图分发池;这一期往上走一层:智能体和智能体之间,自己谈 。这就是 HarmonyOS 7(API 26)新增的 Agent A2A 能力(官方发布说明)。

官方在发布说明里举的例子是健身 Agent:训练前中后的记录、指导、回顾、问答,全链路健身管理。V哥把"日程 + 打车"这个组合拆成三件事讲清楚:A2A 到底协作了什么、智能体怎么把自己挂进系统、一单是怎么按状态机谈成的。


一、A2A 不是接口互调,是意图协商

先纠正一个最常见的误解。很多同学一听"智能体之间通信",脑子里浮现的是 A 应用 import B 应用的 SDK,然后调 B 的方法。那叫接口互调,不叫 A2A。

接口互调的前提是调用方认识对方:知道对方是谁、方法签名是什么、出错返回什么。而 A2A 的前提恰恰相反------双方互不相识 。官方对这套机制的表述是(通过 AgentAbilityExtension 实现智能体间 A2A 协议通信):

A2A(Agent to Agent)协议用于智能体之间的通信。A2A 服务端负责接收客户端请求、触发智能体执行任务、更新任务状态和返回执行结果。

V哥从官方的基本概念里读出的关键,是几个名词撑起的协商结构:

概念 官方定义 在"一单生意"里的角色
Agent Card JSON 元数据文档,描述智能体的身份、能力、端点地址、技能和认证要求 生意场上的名片:先递名片,再谈事
Task 有唯一标识和明确定义生命周期的有状态工作单元 这单生意本身,全程可跟踪
Message 客户端与智能体之间一次通信的单元,带 user / agent 角色 谈判桌上说的每一句话
Artifact 任务过程中生成的有形交付物,有唯一的产物 ID 和名称 成单后的交付:订单、票据、结果
TaskState 已提交、工作中、需要用户输入、已完成、已取消、已失败、已拒绝、需要认证 谈判进度条

注意"认证要求"这三个字。接口互调的世界里,权限是编译期定死的;A2A 的世界里,智能体在名片上写清楚"找它办事需要什么资质",客户端解析 Agent Card 才知道如何安全有效地交互。发现、认证、协商、交付,四个环节都长在协议里,而不是长在某一次硬编码里------这是V哥判断"A2A 不是接口互调"的依据。

还有一条官方边界划在前头:实现 A2A 协议通信从 API 26.0.0 开始支持,AgentExtensionAbility 首批接口从 API 24 起就有,仅支持 Stage 模型,且不支持在 har 包中使用(接口参考)。7.0 相关能力需升级至 HarmonyOS 7 并以实际支持机型为准。


二、把智能体"挂"进系统:Agent Card 与 A2A 服务端

上一期 Skill 化的活儿是"写契约",这一期的活儿是"写名片 + 写服务端"。官方给的开发路径很清晰:服务端继承 AgentExtensionAbility 获得跨 App 进程通信能力,再通过 Agent Framework Kit 创建支持 A2A 协议的 Server 实例。V哥的打车智能体骨架这么写(接口名出自官方开发指导,方法签名以官方 SDK 为准):

typescript 复制代码
// RideAgentExtAbility.ets ------ 打车智能体的 A2A 服务端骨架
import { hilog } from '@kit.PerformanceAnalysisKit';
import { common, Want, AgentExtensionAbility } from '@kit.AbilityKit';
import { RequestContext, createA2AServer, Server, TaskState, Role } from '@kit.AgentFrameworkKit';

const TAG = '=====RideA2AServer===='

export default class RideAgentExtAbility extends AgentExtensionAbility {
  // 服务端实例:负责处理智能体通信和任务生命周期管理
  private server: Server | null = null;

  // 核心业务逻辑:A2A Server 收到客户端请求后触发
  private agentOnData = (method: string, context: RequestContext) => {
    // V哥先做防御:从结构化上下文里取 AgentID,取不到直接拒绝
    const agentId: string = context.getAgentId() ?? '';
    if (!agentId) {
      hilog.error(0x0000, TAG, 'Agent ID not found in request context');
      return;
    }
    const taskId: string = context.getTaskId() ?? '';

    switch (method) {
      case 'Execute':
        // ① 先报"开工":把任务推进到工作中
        this.server?.updateStatus(taskId, {
          state: TaskState.WORKING,
          message: { messageId: 'msg1', role: Role.AGENT,
            parts: [{ mediaType: 'text/plain', text: '正在为你锁定车辆...' }] }
        });
        // ② 业务跑完,把交付物(订单结果)作为产物挂到任务上
        this.server?.addArtifact(taskId, {
          artifactId: 'ride-order',
          parts: [{ mediaType: 'application/json', text: '{"orderNo":"...","eta":"6min"}' }]
        });
        // ③ 最后通知任务完成,整单闭环
        this.server?.updateStatus(taskId, {
          state: TaskState.COMPLETED,
          message: { messageId: 'msg3', role: Role.AGENT,
            parts: [{ mediaType: 'text/plain', text: '车辆已预订成功!' }] }
        });
        break;
      case 'Cancel':
        // 用户取消:收尾逻辑写在这里,别让任务悬着
        hilog.info(0x0000, TAG, 'Cancel called');
        break;
      default:
        break;
    }
  }

  // 实例创建完成:首次收到请求时创建 A2A Server
  async onCreate(want: Want) {
    try {
      const card = this.context.agentCard;   // 智能体名片来自组件上下文
      this.server = createA2AServer(card, this.agentOnData);
    } catch (error) {
      hilog.error(0x0000, TAG, `Failed to create server: ${error}`);
    }
  }

  // 客户端建连:开门营业,启动服务端
  onConnect(want: Want, proxy: common.AgentHostProxy) {
    this.server?.start();
  }

  // 收到请求体:转交 server.onMessage,回包走 proxy.sendData
  async onData(proxy: common.AgentHostProxy, data: string) {
    this.server?.onMessage(data, (response: string) => {
      proxy.sendData(response);
    });
  }

  // 断连与销毁:打烊,回收资源
  onDisconnect(want: Want, proxy: common.AgentHostProxy) {
    this.server?.stop();
  }
  onDestroy() {
    this.server?.stop();
  }
}

V哥把官方要求的生命周期方法全部列出来了,因为这套骨架的时序本身就是协议:create(建名片)→ start(开门营业)→ onMessage(接单)→ stop(打烊)onCreate 里那句 this.context.agentCard 值得多看一眼------智能体的名片不是在代码里现场拼的,它来自组件上下文,是随应用声明与配置登记好的(Agent Card 的具体配置方式以官方 SDK 文档为准)。

对照上一期会发现一个同构关系:SKILL.md 是 Skill 在意图分发池里的简历,Agent Card 就是智能体在协作网络里的简历。区别在于,智能体的简历多了两项硬信息------端点地址和认证要求。功能被调可以匿名,智能体协作必须验明正身。


三、一单是怎么谈成的:状态机走完才算数

把引子里那个场景的协作链路画出来:

链路里V哥最想展开的是"意图协商"这一段,因为它和接口互调的差别全在这里。日程智能体发起打车需求后,双方不是一次调用定生死,而是在 Task 的状态机里推进:

plaintext 复制代码
(示意性伪代码,描述协商语义;TaskState 各枚举字段以官方 SDK 为准)

Task 已提交
  └─> 打车 Agent:工作中(WORKING,正在匹配车辆)
        └─> 打车 Agent:需要用户输入(跨 App 动作用户拍板:确认车型与价格)
              └─> 用户确认
                    └─> 打车 Agent:工作中(锁定车辆)
                          └─> 已完成(COMPLETED)+ Artifact(订单交付)

两个值得停下来想的点。

第一,"需要用户输入"是写进协议的状态,不是你自定义的弹窗。 官方列出的任务状态里有这么一项,说明鸿蒙的 A2A 在协议层面就承认:智能体协作走到有副作用的动作时,必须停下来让人拍板。V哥的判断是------查天气、算出发时间这类只读动作可以自动流转,而下单、扣款这种动作,就该老老实实停在"需要用户输入",把确认权还给用户。协议给了你踩刹车的位置,别把油门焊死。

第二,Artifact 和 Message 是两种东西。 谈判过程中说的话是 Message------指令、上下文、状态更新;最终交付的是 Artifact------有唯一 ID 和名称的交付物。把订单结果当聊天消息发出去,下游就没法可靠地引用它,这在多轮、多智能体的协作里是致命的。

还有一类特殊请求单独提一下:官方定义了 PerceptionSuggest 类型的请求,用于小艺感知用户当前所在 App、向智能体请求推荐内容(AgentChips 场景),交互流程有单独文档。也就是说,你的智能体不只是"被别的智能体调",还能在小艺的推荐位上主动露脸。


四、V哥的三条判断

① 撮合靠系统,被撮合的资格靠自己。 日程智能体不需要认识打车智能体------它把子意图交给系统,系统按 Agent Card 撮合。官方把这一范式概括为"意图即服务",小艺作为系统级智能体承担意图理解与服务分发(官方发布说明)。撮合质量取决于系统,而轮不轮得到你进场,取决于名片上的能力描述写得清不清------写得含糊,协商还没开场你就出局了。

② 端 A2A 与云 A2A 是双轨,不是二选一。 官方口径里,端侧保障低时延本地响应、隐私数据不出端,云侧支撑复杂任务的深度推理。日程、行程这类敏感数据走端侧,跨城比价、长程规划这类重推理走云侧,按任务属性分轨,别一刀切。

③ 开发者的活儿从"写页面"变成了"写能力"。 这期和上一期合起来看,脉络很清楚:Skill 化让功能被系统调用,A2A 让智能体彼此协商,界面退居"最后一步",能力登记成了第一等公民。V哥的原话:以前你的应用是一座楼,用户找门牌号;现在你的应用是一个谈判代表,系统按名片找它谈事。 代表的水平体现在名片和谈判记录(Agent Card 与任务状态机)上,不体现在装修上。


五、收尾:协作网络的价值,随节点超线性增长

A2A 的红利有个特点:单看你自己的智能体,价值有限;网络里接入的智能体越多,每一次协商的可能组合就越多。日程智能体今天跟打车谈,明天可能跟机票、酒店、会议助手谈------而你的接入成本,就是一张名片加一个服务端骨架。

7.0 刚发布,协作网络里的节点还不多。上一期V哥说 Skill 化是新门票,这一期补一句:A2A 是你在智能体协作网络里的席位,席位放出来的时候,坐上去的人最少。


参考与出处

本文的协议概念、接口名与能力描述来自以下官方文档与发布说明:


最后一句:图标时代比的是谁的门面亮,A2A 时代比的是谁的名片硬------把 Agent Card 当名片写,把任务状态机当谈判记录记,下一个被系统拉去谈事的,就是你的智能体。

相关推荐
桃西西呀1 小时前
机器眼里没有脸,怎么识别人脸?手写 CNN 拆开卷积层与 BatchNorm
人工智能·深度学习·llm
范小兵1 小时前
# DevEco CLI实战:鸿蒙App「至客」从0开发到正式上架
前端·harmonyos
Rocky Ding*1 小时前
一文读懂Hallo数字人核心基础知识
论文阅读·人工智能·深度学习·机器学习·aigc·数字人·ai-native
熊猫钓鱼>_>2 小时前
声临其境:HarmonyOS 空间音频全链路开发实战
音频·harmonyos·arkts·鸿蒙·arkui·空间·hap
倔强的石头1063 小时前
【深度学习】词嵌入技术_从Word2Vec到现代Embedding
人工智能·深度学习·机器学习
Geek_Vison3 小时前
小程序容器如何抹平系统差异,让一个小程序运行在 iOS、安卓、鸿蒙和电脑端
小程序·uni-app·harmonyos·mpaas
大雷神3 小时前
【共创稿事节】HarmonyOS ArkGraphics 3D 实操:用 GLB 与 PBR 完成智能音箱外观预览器
harmonyos
Latte Moments开发4 小时前
Harmony鸿蒙实战开发-记账app「可对时间进行分类管理,支出分析和收入分析-升级版」【源码在文末】
华为·harmonyos
●VON4 小时前
Flutter 鸿蒙插件适配实战:用 flutter_native_timezone_2025 1.0.1 读取当前时区与系统目录
flutter·华为·harmonyos·鸿蒙