以编程方式使用文档

当协调器代理生成专业子代理(研究员、分析员、作家)时,你需要将编排器的消息与每个子代理的流式输出分开渲染。v1 SDK 将协调器消息保留在 根流上,并将子代理作为发现快照公开。将快照传递给 选择器钩子或可组合组件,例如 来渲染 专家代理的作用域流。 useMessages(stream, subagent) 这就是 LangChain 前端 SDK 超越扁平聊天记录的地方: 子代理是一级流式实体,拥有自己的状态、消息、

工具调用元数据和结果。你的 UI 可以显示委托、进度、错误、 以及最终综合,而无需用户读取每个 交织的令牌。 为什么选择基于子代理流 worker.

根流保持专注于协调器对话:

仅包含协调器的消息

- stream.messages 包含具有身份、命名空间和状态的发现快照 - stream.subagents 每个子代理的消息、工具调用和值都通过选择器辅助函数读取 - UI 保持简洁:协调器的推理与 - 专家的工作分开 这种分离允许你在一个地方渲染编排器的消息,并

仅在用户需要查看专家工作时挂载子代理卡片。 对于大型任务,这也可以保持 UI 的可扩展性。用户可以浏览

协调器的高级计划,仅展开他们关心的专家工作, 同时仍然保留完整的子代理追踪用于调试、审计或回放。 设置

无需额外的流选项。将流指向你的深度代理, useStream

从 渲染协调器消息,并使用 stream.messages为活跃的专家挂载卡片。在聊天布局中,按 stream.subagents 生成它们的工具调用 ID 对子代理进行索引,以便每张卡片出现在协调器回合下 将流指向你的深度代理,从 渲染协调器消息,并使用 stream.messages为活跃的专家挂载卡片。在聊天布局中,按 stream.subagents 生成它们的工具调用 ID 对子代理进行索引,以便每张卡片出现在委托工作的协调器回合下。 提交消息

const AGENT_URL = "http://localhost:2024";

  const stream = useStream<typeof myAgent>({
    apiUrl: AGENT_URL,
    assistantId: "deep_agent_subagent_cards",
  });
  const subagents = [...stream.subagents.values()];
  const subagentsByCallId = new Map(subagents.map((s) => [s.id, s]));

  return (

      {stream.messages.map((msg) => {
        const turnSubagents = AIMessage.isInstance(msg)
          ? (msg.tool_calls ?? [])
              .map((tc) => subagentsByCallId.get(tc.id ?? ""))
              .filter((s): s is NonNullable<typeof s> => !!s)
          : [];

        return (

            {HumanMessage.isInstance(msg) && {msg.text}}
            {AIMessage.isInstance(msg) && msg.text.trim() && (
              {msg.text}
            )}
            {turnSubagents.map((subagent) => (

            ))}

        );
      })}

  );
}
<script setup lang="ts">




const AGENT_URL = "http://localhost:2024";

const stream = useStream<typeof myAgent>({
  apiUrl: AGENT_URL,
  assistantId: "deep_agent_subagent_cards",
});

const subagentsByCallId = computed(
  () => new Map([...stream.subagents.value.values()].map((s) => [s.id, s]))
);

function subagentsForMessage(msg: unknown) {
  if (!AIMessage.isInstance(msg)) return [];
  return (msg.tool_calls ?? [])
    .map((tc) => subagentsByCallId.value.get(tc.id ?? ""))
    .filter(Boolean);
}
</script>

<template>



        {{ msg.text }}


        {{ msg.text }}




</template>
<script lang="ts">


  const AGENT_URL = "http://localhost:2024";

  const stream = useStream<typeof myAgent>({
    apiUrl: AGENT_URL,
    assistantId: "deep_agent_subagent_cards",
  });
</script>


  {#each stream.messages as msg (msg.id)}

  {/each}
  {#each [...stream.subagents.values()] as subagent (subagent.id)}

  {/each}
const AGENT_URL = "http://localhost:2024";

@Component({
  selector: "app-deep-agent-chat",
  template: `
    @for (msg of stream.messages(); track msg.id) {
      <app-message [message]="msg" />
    }
    @for (subagent of subagents(); track subagent.id) {
      <app-subagent-card [stream]="stream" [subagent]="subagent" />
    }
  `,
})

  stream = injectStream<typeof myAgent>({
    apiUrl: AGENT_URL,
    assistantId: "deep_agent_subagent_cards",
  });

  subagents = computed(() => [...this.stream.subagents().values()]);
}

通过根流提交消息。深度代理工作流通常涉及

多层嵌套子图,因此如果你的代理可以深入委托,请设置适当的递归限制: 你的代理可以深度委托: 深度代理设置了默认递归限制为 10,000,这对于

stream.submit(
  { messages: [{ type: "human", content: text }] },
  { config: { recursion_limit: 100 } }
);

SubagentDiscoverySnapshot

每个 SubagentDiscoverySnapshot 是一个轻量级发现记录,用于 在 thread 内运行的 subagent。它告诉你的 UI 一个 subagent 存在, 它在 subagent 树中的位置,以及它所处的生命周期状态。

快照 **不** 包含 subagent 的流式消息或工具调用。 相反,将快照传递给选择器 hooks,例如 useMessages(stream, subagent) or useToolCalls(stream, subagent)。这些 hooks 使用快照命名空间仅订阅 subagent 的流式原语 当相应的 card 或 panel 挂载时。

构建 SubagentCard

每个 subagent card 显示 specialist 的名称、状态、流式内容和 工具调用。使用选择器 hooks 订阅 subagent 命名空间:

  useMessages,
  useToolCalls,
  type AnyStream,
  type SubagentDiscoverySnapshot,
} from "@langchain/react";

function SubagentCard({
  stream,
  subagent,
}: {
  stream: AnyStream;
  subagent: SubagentDiscoverySnapshot;
}) {
  const [expanded, setExpanded] = useState(true);
  const messages = useMessages(stream, subagent);
  const toolCalls = useToolCalls(stream, subagent);

  const lastAIMessage = messages
    .filter(AIMessage.isInstance)
    .at(-1);

  const displayContent =
    lastAIMessage?.text ?? subagent.output ?? "";

  return (

      <button
        onClick={() => setExpanded(!expanded)}
        className="flex w-full items-center justify-between p-4"
      >



            <h4 className="font-semibold capitalize">{subagent.name}</h4>
            <p className="text-xs text-gray-500">
              {toolCalls.length} tool call{toolCalls.length === 1 ? "" : "s"}
            </p>





      </button>

      {expanded && displayContent && (


            {displayContent}
            {subagent.status === "running" && (
              <span className="inline-block h-4 w-1 animate-pulse bg-blue-500" />
            )}


      )}

  );
}

进度跟踪

显示进度条和计数器,让用户知道有多少 subagent 已完成:

function SubagentProgress({
  subagents,
}: {
  subagents: SubagentDiscoverySnapshot[];
}) {
  const completed = subagents.filter((s) => s.status === "complete").length;
  const total = subagents.length;
  const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;

  return (


        <span>Subagent progress</span>
        <span>
          {completed}/{total} complete
        </span>





  );
}

使用 subagent cards 渲染消息

关键的布局模式是从根流渲染协调器消息, 并将 subagent cards 附加到生成它们的 AI 消息的工具调用上:

function DeepAgentLayout({ stream }: { stream: AnyStream }) {
  const subagents = [...stream.subagents.values()];
  const subagentsByCallId = new Map(subagents.map((s) => [s.id, s]));

  return (

      {stream.messages.map((message) => {
        const turnSubagents = AIMessage.isInstance(message)
          ? (message.tool_calls ?? [])
              .map((tc) => subagentsByCallId.get(tc.id ?? ""))
              .filter((s): s is SubagentDiscoverySnapshot => !!s)
          : [];

        return (


            {turnSubagents.length > 0 && (


                {turnSubagents.map((subagent) => (

                ))}

            )}

        );
      })}

  );
}

你可以将内联 cards 与全局 subagent 视图结合:按 协调器工具调用,为其生成记录卡,并使用 stream.subagents 用于持久侧边栏,总结所有活跃工作进程。 这让用户既能看到本地上下文,也能鸟瞰整个运行过程。

最佳实践

- **仅在需要的地方挂载选择器**。作用域消息和工具调用流 当卡片调用 useMessages(stream, subagent) or useToolCalls(stream, subagent). - **显示专家名称**. subagent.name 告诉用户哪个工作进程处于活跃状态。 - **使用可折叠卡片**。在包含5个以上子代理的工作流中,自动折叠 已完成的卡片,以便用户专注于活跃的工作。 - **仅在需要时覆盖递归**。深度代理设置了较高的默认值 递归限制;传递 config.recursion_limit 仅用于异常深度的自定义 workflows. - **按子代理处理错误**。一个子代理失败不应导致 整个UI。在该子代理的卡片中显示错误,同时让其他继续 running.