Skip to main content
MemoryLake 实现了 Google 的 A2A(Agent 对 Agent)协议。如果您已熟悉 A2A,可以使用任何兼容 A2A 的客户端与 MemoryLake Agent 交互。 有关标准请求和响应 schema,请参阅 A2A 规范。官方 SDK 可在 github.com/a2aproject 获取。
所需权限: workspace_agent:a2a

Base URL

直接追加标准 A2A 路径即可 —— 例如 POST {baseUrl}/message:send 或 GET {baseUrl}/tasks/{taskId}。

协议版本

MemoryLake 并行暴露两套 A2A 路由,分别对应一个协议版本;每个版本都可以通过两种传输方式调用:REST 与 JSON-RPC 2.0。
/v1/ 路径前缀指的是较旧的 A2A v0.3 传输格式,而非协议 1.0 版本。不带前缀的路由实现的才是当前的 A2A v1.0 格式。请确保请求体结构与所调用的路由匹配 —— v0.3 风格的 REST 请求体(message.content)会被 v1.0 REST 路由拒绝,反之亦然。
走 JSON-RPC 时,两个协议版本都 POST 到不带后缀的 {baseUrl},由 method 指定具体操作:v1.0 使用 SendMessage、SendStreamingMessage、GetTask、CancelTask、SubscribeToTask;v0.3 使用 message/send、message/stream、tasks/get、tasks/cancel、tasks/resubscribe。协议版本由方法名协商得出;v1.0 客户端还应额外发送 A2A-Version: 1.0。 四组路由都接受同一个 configuration 对象,以及下文描述的同一套 MemoryLake 扩展。两个协议版本对「是否等待任务完成」的开关叫法不同:
不支持推送通知。 Agent Card 声明 pushNotifications: false,传 pushNotificationConfig(v0.3)或 taskPushNotificationConfig(v1.0)都不会收到回调。要跟踪任务进度,请使用流式响应,或订阅这个任务。
同一会话一次只处理一条消息。 使用相同 contextId 的消息属于同一个会话,同一会话同一时间只能处理一条消息。上一条消息仍在处理时(包括非阻塞发送后任务尚未结束),用同一 contextId 发送的新消息会被直接拒绝(400 INVALID_ARGUMENT),不会排队。请等上一条消息的响应或任务结束后再发送下一条;需要并行处理的请求,请为每个请求使用不同的 contextId。一个会话只对应一个 Agent。 contextId 归属于第一次使用它的 Agent,用同一个 contextId 向其他 Agent 发送的消息会被拒绝。要与另一个 Agent 对话,请使用新的 contextId 开启新会话。

MemoryLake 扩展

MemoryLake 通过 metadata.memorylake 命名空间扩展了标准 A2A 协议。在 message:send 或 message:stream 请求的 metadata 里传入此对象:REST 请求体放在顶层 metadata,JSON-RPC 放在 params.metadata。Agent 不会从 message.metadata 里读取这些字段。 这是与普通 A2A 服务器的核心区别 —— 这些字段将 Agent 连接到 MemoryLake 中的工作空间、项目和 Actor。对象里的字段分两类:
  • 记忆与身份:actorId、readWriteProjectId、readOnlyProjectIds、skipMemory,决定 Agent 使用谁的记忆、读写哪些项目。
  • 运行配置:overrides、runtimeOptions,调整 Agent 处理这条消息的方式。
请使用本页列出的驼峰字段名。未知字段会被忽略而不是报错,所以某个设置看起来没生效时,请先检查拼写。metadata 下除 memorylake 以外的键,Agent 都不会读取。
metadata.memorylake 必须传。 不传时请求返回 400 INVALID_ARGUMENT。传空对象 {} 即使用默认设置:Agent 使用您自己的 Actor,记忆处于开启状态。

记忆与身份

string
发出这条消息的终端用户,填 MemoryLake 的 Actor ID(actor- 加 32 位十六进制字符)。Agent 会检索这个 Actor 的记忆,会话中用户一方的发言也记在这个 Actor 名下,从而实现按用户记忆。
  • 默认值: 当前认证用户在该工作空间里的 Actor。该用户在这里没有 Actor 时,请求返回 400 STATE_NOT_READY。
  • 必须是已绑定到该工作空间的 Actor。其他 ID 返回 400,已删除的 Actor 返回 400 ACTOR_INACTIVE。
  • 权限: 需要对该 Actor 有 workspace_actor:fact_add 和 workspace_actor:fact_search。会话开始时校验一次;之后某条消息带来会话里还没有过的 Actor 时,会再校验。
string
Agent 工作所在的项目(proj- 加 32 位十六进制字符)。Agent 会检索这个项目的文档和记忆,会话也记在这个项目下,从会话中提取的记忆就保存在这里。会话历史本身存储在工作空间层级。
  • 一个会话只绑定一个项目。 会话(contextId)的第一条消息绑定项目,之后的消息可以不传,沿用该项目。传入不同的项目,或者给一个开始时没有项目的会话补上项目,都会返回 400。
  • 只能是同一工作空间的项目。 其他工作空间的项目返回 404。
  • 权限: 需要对该项目有 project:mem_add、project:doc_add、project:mem_search 和 project:doc_search,在会话开始时校验。
  • 带文件时必填。 消息里的文件(drive:// 引用或 inline 字节)会作为文档导入这个项目。带文件的消息必须自己写明项目,不能靠从会话继承,否则请求返回 400。
string[]
Agent 可以检索(文档和记忆)但不会写入的其他项目。用于让 Agent 访问共享知识库。
  • 只对这一条消息生效。 它不会存到会话里,所以每条需要看到这些项目的消息都要带上。
  • 权限: 需要对每个项目有 project:mem_search 和 project:doc_search,缺任何一项都返回 403。
  • 找不到对应项目的 ID 会被跳过,不报错。
boolean
default:"false"
为 true 时,这条消息不使用记忆:Agent 不检索记忆和项目文档,这条消息的内容也不会写入记忆。会话照常创建,对 Actor 和项目的权限照常校验。

运行配置

object
只对这一条消息修改 Agent 的配置。没有传的项沿用 Agent 自身的配置。
object
这条消息的运行选项。

按消息开启能力

overrides.capabilitiesOverride 用来给单条消息额外开启能力。它是一个对象:键是能力名,值是该能力的配置。能力名及其字段一律用蛇形命名(snake_case),与周围的驼峰字段不同(也接受 webSearch、openDatasets 这样的驼峰写法)。
使用时请注意:
  • 只对这一条消息生效。 同一会话的下一条消息不带这个覆盖,就不会开启。
  • Agent 默认没有这些能力。 不传覆盖时,只有 Agent 自身配置了联网搜索或读取网页,它才会使用(见创建 Agent 的 capabilities)。pii、vega 和 dataset 只能在这里开启。
  • 传入的配置会替换 Agent 自身的配置。 请给出该能力完整的配置,不要指望从 Agent 那里继承字段。例如 Agent 的 web_search 配置了 open_datasets,而这次只传 "web_search": {},这条消息就不会检索任何 Open Data 数据集。
  • 只能开启,不能关闭。 不传某个能力,即沿用 Agent 自身的配置;传 null 也关不掉 Agent 已有的能力。{"enabled": false} 更要避免:并没有 enabled 这个字段,它会被当成 {},反而以默认配置开启该能力,即使 Agent 原本没有。需要不带某个能力运行时,请使用没有配置该能力的 Agent。
写错不会报错。 拼错的能力名会被忽略。某个能力的配置不合法时(例如 open_datasets 传成字符串、web_search 传成 true),整个能力会被丢弃,请求照常返回 200,只是这次没有该能力。不认识的 Open Data 标识符会被跳过,全部无效时只做普通联网搜索。只有 capabilitiesOverride 本身不是对象(例如传成数组)时才会返回 400。如果 Agent 表现得像是没开某个能力,请先核对您请求里的能力名和配置。

示例

发送一条消息涉及三个彼此独立的选择 —— 协议版本(v1.0 / v0.3)×方法(send / stream)×传输方式(REST / JSON-RPC),因此共有 8 种有效组合。以下把 8 种全部列出。 下表的路径均相对于上文的 base URL;JSON-RPC 一律 POST 到不带后缀的 base URL,由 method 指定操作。 上表 header 列中,SSE 表示 Accept: text/event-stream,v1.0 表示 A2A-Version: 1.0。8 种组合都使用相同的 configuration 字段(v1.0 默认等待并使用 returnImmediately,v0.3 使用 blocking)和同一套 metadata.memorylake 扩展。其中 4 个 streaming 变体以 text/event-stream 返回;4 个 send 变体返回单个 JSON 响应体。
请注意版本与传输方式之间的三处结构差异:v1.0 使用 parts,role 为 "ROLE_USER";v0.3 REST 使用 content,role 为 "ROLE_USER";v0.3 JSON-RPC 使用 parts 且每个 part 都带 kind 判别符,role 为小写的 "user"。

REST 传输

JSON-RPC 传输

两个协议版本共用同一个路径 —— 不带任何后缀的 POST {baseUrl}。协议版本由方法名决定;v1.0 客户端还应额外发送 A2A-Version: 1.0。

响应

所有组合返回的都是同一套任务模型,只有外层结构和少数拼写随协议版本和传输方式变化,见 v0.3 的差异。本节示例使用 v1.0 REST。

非流式发送

message:send 总是返回一个任务,不会只返回一条消息。默认会等任务执行完再返回:
string
任务 ID。
string
任务所属的会话。下一条消息把它作为 message.contextId 传入即可继续这个会话。请求里没有传时,会生成一个新的。
object
array
回答:最多一个 artifact,名为 result。任务失败或没有产出时不出现。见回答内容。
array
您发出的消息,之后按顺序是 Agent 的消息:执行过程中写的文字、思考内容,以及工具调用。连续的文字会合并成一条消息。configuration.historyLength 只保留最后 N 条,传 0 时不返回 history。
传 returnImmediately: true(v1.0)或 blocking: false(v0.3)时,任务一创建就返回:状态为 TASK_STATE_SUBMITTED(也可能已经是 TASK_STATE_WORKING),history 里只有您发出的消息,没有 artifact。任务会在后台继续执行;要拿到回答,请订阅这个任务。

流式发送

message:stream 以 text/event-stream 返回,每行 data: 是一个 JSON 事件,顺序如下:
  1. task:刚创建的任务,history 里是您发出的消息。
  2. statusUpdate,状态 TASK_STATE_WORKING:Agent 开始执行。
  3. statusUpdate,状态 TASK_STATE_WORKING:每一步进展一个,status.message 里只有一个 part,可能是:
    • 一段回答文字。文字是增量下发的,需要依次拼接;每段都有自己的 messageId;
    • 一段思考内容,带 metadata.adk_thought: true;
    • 一次工具调用或工具结果;
    • Agent 生成的文件,形如 {"url": "...", "mediaType": "...", "filename": "..."}。
  4. artifactUpdate:回答,见回答内容。
  5. statusUpdate:最终状态,TASK_STATE_COMPLETED、TASK_STATE_FAILED(status.message 里是错误说明)或 TASK_STATE_CANCELED。之后流结束。
文字片段只用于实时展示,最终回答请以 artifact 为准:片段里还包含 Agent 在调用工具前写的过渡文字,artifact 里的文字才是完整的最终回答。以 : 开头的行是保活注释,忽略即可。
为便于阅读,ID 用 … 做了缩写,重复字段也已省略。

回答内容

名为 result 的 artifact 以一组 part 承载回答: artifact 和流里还可能出现其他 data part。遇到不认识的 kind,或者没有 kind 的 data part,跳过即可。data part 里的数字会以浮点数返回,例如 2 会变成 2.0。

工具调用

Agent 的工具调用以 data part 的形式出现,用 metadata.adk_type 标记,这是 Google Agent Development Kit 的约定。流和 history 里都会出现。 工具调用上可能还带有 metadata.adk_thought_signature,这是一个不透明的值,忽略即可。

跟踪任务

GET {baseUrl}/tasks/{taskId}(v0.3:{baseUrl}/v1/tasks/{taskId})只返回任务的 id、contextId 和 status(含 state 与 timestamp):不包含回答和历史,失败的任务也不带错误说明。 要拿到一个没有等待的任务的回答,请订阅它:GET {baseUrl}/tasks/{taskId}:subscribe(v0.3:{baseUrl}/v1/tasks/{taskId}:subscribe),并带上 Accept: text/event-stream。它会从头重放该任务的事件,格式与 message:stream 相同,只是开头没有 task 事件;之后实时跟随,直到任务结束。已经失败或被取消的任务无法订阅。

错误

任务失败。 请求仍然返回 HTTP 200,任务以 TASK_STATE_FAILED 结束,status.message.parts[0].text 是错误说明。例如 overrides.model 填了不存在的模型时,任务失败,错误为 LLM model config not found: <model>。 请求被拒绝。 REST 路由返回 HTTP 错误状态码和标准的错误响应体(success、message、error_code),例如: JSON-RPC 下,MemoryLake 在 Agent 运行之前发现的错误(例如配额或权限错误)同样使用上面的 HTTP 状态码和错误响应体;Agent 报告的错误则以 JSON-RPC error 对象返回,HTTP 状态码为 200,其中 v0.3 方法一律使用错误码 -32603。

v0.3 的差异

  • JSON-RPC。 result 直接就是任务,带 "kind": "task"。流事件带 "kind": "status-update" 或 "artifact-update",最后一个状态更新带 "final": true。状态用小写,例如 completed、failed、canceled、submitted、working;角色为 user 和 agent。每个 part 都带 kind:{"kind": "text", "text": ...}、{"kind": "data", "data": {...}} 或 {"kind": "file", "file": {...}}。
  • REST。 状态拼写与 v1.0 相同,只有已取消拼作 TASK_STATE_CANCELLED。消息的 part 放在 content 下而不是 parts,data part 的形式是 {"data": {"data": {...}}}。GET 返回的任务不带 timestamp。
  • REST 的默认值。 不传 blocking 时,message:send 会立即返回而不是等待;不传 historyLength 时不返回 history。请显式设置这两个字段。