Skip to content

[BUG]: 并发场景 conversation_id 拼装格式与约定 {conv}-sub-{entity_id} 不一致,且 _remote_invocation 仅单层、无法支撑多跳并发前端呈现 #94

Description

背景

并发场景下(主 agent 并行扇出调用多个子 agent),当前 conversation_id 的拼装格式与此前约定的 {conv}-sub-{entity_id} 存在差异;同时 _remote_invocation 元数据仅支持 A→B 单层扁平投影,无法支撑真实的多层(多跳)并发场景在前端正确呈现。两者相互耦合,需一并解决。

延伸子项(单层投影"有条件发出"、单父单批次硬限制)另开 issue 单独跟踪,链接见文末。


问题一:conversation_id 拼装格式不一致

现状(并发远端调用路径)

serve 层并行远端调用的子会话 id 在 RemoteInvocationBatchCoordinator#remoteContextId 拼装:

private static String remoteContextId(RemoteInvocationBatch batch, Member member) {
    String parentContextId = batch.request.getConversationId();
    if (parentContextId == null || parentContextId.isBlank()) parentContextId = batch.parentTaskId;
    if (batch.members.size() <= 1) return parentContextId;                       // 单成员:不拼接
    return parentContextId + "_" + batch.batchId + "_" + member.toolCallId;      // 多成员:父_batchId_toolCallId
}

抓包观察到的实际值为 {parentUuid}_{batchUuid}_{toolCallId},如 8211b1a4-…_635e1021-…_call_01_…(分隔符为下划线,非约定的 -sub-)。

与约定 {conv}-sub-{entity_id} 的差异

  1. 没有 sub 关键字:全仓搜索 "-sub-" 零命中;唯一带 sub 的是本地子 agent 路径 TaskTool#buildSubSessionId,且用的是下划线 _sub_,仍与约定的连字符 -sub- 不符。
  2. 中间段是随机 batchId(每次批次都变的 UUID),不是稳定的 entity_id:前端无法从 id 字符串识别"这是哪个子 agent"。
  3. 子 agent 身份(target/agentName)不在 id 中:只存在于 _remote_invocation metadata(见问题二)。

根因:存在 3+ 套互不兼容的格式,无统一约定

路径 位置 格式 分隔符
serve 层并发远端调用 RemoteInvocationBatchCoordinator.java:629 {parent}_{batchId}_{toolCallId} _
本地子 DeepAgent TaskTool.java:67 {parent}_sub_{type}_{uuid8} _sub_
agent-as-tool 调用 AbilityManager.java:475 {parent}:{toolCallId} :
DeepAgent 请求级隔离 DeepAgent.java:597/641/671 {conv}_{seq} _

影响

前端拿到子会话 id 后,无法靠固定规则反向解析出"父会话 + 子实体身份",因为格式随调用路径变化、且不含实体名。约定的 {conv}-sub-{entity_id} 正是为前端可解析而设,当前任何路径都不满足。


问题二:_remote_invocation 仅 A→B 单层扁平投影

现状

唯一构造点 RemoteInvocationBatchCoordinator#forwardRemoteOutput(行 518-532),projection 永远只有 4 个字段:

projection.put("kind", "remote_agent_output");
projection.put("batchId", batch.batchId);
projection.put("toolCallId", member.toolCallId);
projection.put("target", …);

示例:

{"_remote_invocation":{"toolCallId":"call_00_…","kind":"remote_agent_output","batchId":"2445c385-…","target":"versatile-adapter"}}

多跳支持核查(全部为否)

  • ❌ 无 depth/chain/hop/lineage/rootBatchId 字段(全仓零命中)
  • ❌ 写入为覆盖式(每次 new LinkedHashMap,不合并父 projection);ChunkMapper#toParts(行 44)同样直接覆盖
  • ❌ 读取只判 key 存在性、不解析内部、不累积(A2aPartContent#hasRemoteInvocationMetadata
  • parentTaskId 是单层向上指针:B→C 时 B 的 coordinator 用自己的 task id 做 parent,不形成链
  • ❌ A→B 请求 metadata 经 outboundMetadata 过滤掉保留键,A 的 projection 根本不传给 B

影响

多跳并发(A→B→C)时,客户端无法还原调用链路(谁调了谁、第几跳、根会话是谁),无法在前端正确呈现多跳并发拓扑。


两个问题的耦合

前端要正确呈现多跳并发,需要同时具备:

  • 稳定、可解析、按统一约定的每跳 conversation_id 命名(问题一)
  • 携带链路信息的嵌套 metadata(问题二)

当前两者都不满足,且互不协同:id 是每跳向上拼接但不带链路语义;metadata 是扁平单跳投影。


建议修复方向

  1. 统一 conversation_id 命名约定:明确采用 {conv}-sub-{entity_id}(或定死分隔符),用稳定的子 agent 身份target/agentName)作为 entity_id不要用每次随机的 batchId。集中到单一工厂方法,消除 3+ 套格式分叉。
  2. _remote_invocation 增加链路字段:如 depth/parentBatchId/rootConvId/chain[]forwardRemoteOutput 改为合并而非覆盖父 projection;放宽 outboundMetadata 过滤,允许链路信息跨跳传递。

关联

  • 延伸子项(单层投影"有条件发出"、单父单批次硬限制)见姊妹 issue(链接将在评论中补充)。
  • 详细代码追踪背景见 documents/zh/deepagent-a2a-delegate-dual-channel-leak-defect.cn.md

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions