惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
P
Privacy & Cybersecurity Law Blog
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cisco Blogs
博客园 - 司徒正美
L
LINUX DO - 热门话题
D
Docker
M
MIT News - Artificial intelligence
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
Jina AI
Jina AI
Last Week in AI
Last Week in AI
Security Latest
Security Latest
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
A
Arctic Wolf
小众软件
小众软件
T
Threat Research - Cisco Blogs
Know Your Adversary
Know Your Adversary
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
腾讯CDC
Google DeepMind News
Google DeepMind News
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
I
Intezer
NISL@THU
NISL@THU
A
About on SuperTechFans
爱范儿
爱范儿
C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
G
Google Developers Blog
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Cyberwarzone
Cyberwarzone
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
Latest news
Latest news

博客园 - Zhentiw

[GenAI] Migration Plan: Flat API → Layered Architecture [Skill] Frontend Design Skill Claude Code Hooks: Complete Guide [GenAI] Pre-retieval overview [GenAI] About Indexing [GenAI] Indexing overview [Vibe Coding] 降低大模型幻觉 - 重试机制 [Vibe coding] 降低大模型幻觉 - JSON 安全输出提示词 [Node.js] WebSocket基础知识 [LangGraph] 应用结构 [LangGrpah] Unit testing [LangGraph] Functional API [LangGraph] 中断注意事项 [LangGraph] 中断相关细节 [LangGrpah] 静态断点 [LangGrpah] 非阻塞式中断 [LangGraph] 阻塞式中断 [LangGraph] 语义搜索 [LangGraph] 长期记忆 [LangGraph] 管理短期记忆 [LangGraph] 自定义checkpointer [LangGraph] 短期记忆 [LangGraph] 时间旅行 [LangGraph] checkpoint常用API [LangGraph] 元数据标记 [LangGraph] 流 [Vitest] mockClear, mockReset, mockRestore
[LangGraph] 将子图添加为节点
Zhentiw · 2026-02-24 · via 博客园 - Zhentiw

核心概念

子图直接“嵌入”到父图内,成为父图的一部分,与父图共享 state 的 key。

示意图:

父图节点  ===>  { 子图内部的很多节点 } ===> 父图下一个节点

看起来像父图的一个 node,但内部却是一个完整的 graph。

也正因为如此:

  • 子图与父图使用同一个 state(共享部分或全部 key)

  • 子图内部的 node 可以读写父图 state

子图不再是一个“黑盒”,而是父图的一部分

适用场景:

  • 多团队协作,把一段流程拆成一个子图
  • 想复用一段常用流程(比如全局日志链路、消息管道)
  • 子图需要访问父图的多个 state 字段,不止输入/输出

快速上手

场景

客户注册需要执行复杂的 KYC(身份核验)流程:

子图负责:

  • OCR 身份证识别
  • 人脸对比
  • 风险评分
  • 写入结果到父图的 shared state

父图负责:

  • 收集用户信息
  • 调用 KYC 子图验证
  • 根据验证结果决定是否注册成功

示意图

flowchart TD %% ---------- 父图 ---------- subgraph ParentGraph[父图:用户注册流程] P_START([START]) P1[父节点:kycFlow<br/>(子图作为复合节点)] P2[父节点:finish<br/>根据 kycPassed 生成注册结果] P_END([END]) P_START --> P1 --> P2 --> P_END end %% ---------- 子图 ---------- subgraph Subgraph[子图:KYC 验证流程(共享父图 State)] S_START([START]) S1[子节点:OCR 校验<br/>ocrPassed] S2[子节点:人脸比对<br/>faceMatch] S3[子节点:KYC 汇总<br/>kycPassed] S_END([END]) S_START --> S1 --> S2 --> S3 --> S_END end %% ---------- 连接关系 ---------- %% 说明:父图的 kycFlow 节点 == 整个子图执行 P1 -. 调用并共享 state .-> S_START S_END -. 返回更新后的 state .-> P2

index.ts

import { mainGraph } from "./mainGraph.ts";

async function main() {
  // 模拟数据
  const input = {
    userName: "张三",
    idCardImage: "path/idcard.jpg",
    selfImage: "path/selfie.jpg",
  };

  const result = await mainGraph.invoke(input);

  console.log("\n=== 最终结果 ===");
  console.log(result);
}
main();

mainGraph.ts

// 父图
import { StateGraph, START, END } from "@langchain/langgraph";
import { z } from "zod/v4";
import { kycSubgraph } from "./kycSubgraph.ts";

// 父图的状态
const MainState = z.object({
  // 用户注册的基本信息
  userName: z.string().describe("用户名"),
  idCardImage: z.string().describe("用户身份证图片"),
  selfImage: z.string().describe("用户相关的图片"),

  // 各种验证
  ocrPassed: z.boolean().optional().describe("ocr验证是否通过"),
  faceMatch: z.boolean().optional().describe("人脸匹配是否通过"),
  kycPassed: z.boolean().optional().describe("kyc验证是否通过"),

  // 最终注册的结果
  registerResult: z.string().optional().describe("最终注册的结果"),
});

type TMainState = z.infer<typeof MainState>;

function finish(state: TMainState) {
  if (state.kycPassed) {
    return {
      registerResult: "注册成功",
    };
  }
  return {
    registerResult: "注册失败,KYC验证没有通过",
  };
}

export const mainGraph = new StateGraph(MainState)
  .addNode("kycFlow", kycSubgraph)
  .addNode("finish", finish)
  // 边
  .addEdge(START, "kycFlow")
  .addEdge("kycFlow", "finish")
  .addEdge("finish", END)
  .compile();

kycSubgraph.ts

// 做身份验证的子图
import { StateGraph, START, END } from "@langchain/langgraph";
import { z } from "zod/v4";

const KycState = z.object({
  // 用户注册的基本信息
  userName: z.string().describe("用户名"),
  idCardImage: z.string().describe("用户身份证图片"),
  selfImage: z.string().describe("用户相关的图片"),

  // 各种验证
  ocrPassed: z.boolean().optional().describe("ocr验证是否通过"),
  faceMatch: z.boolean().optional().describe("人脸匹配是否通过"),
  kycPassed: z.boolean().optional().describe("kyc验证是否通过"),
});

type TKycState = z.infer<typeof KycState>;

// 检查的节点:1. OCR验证   2. 人脸比对
async function ocrCheck() {
  const randomPass = Math.random() > 0.5; // 90% 通过

  console.log("🔍 [子图] OCR 检查:", randomPass);

  return { ocrPassed: randomPass };
}

async function faceMatchCheck() {
  const randomPass = Math.random() > 0.5; // 80% 通过

  console.log("🔍 [子图] 人脸比对:", randomPass);

  return { faceMatch: randomPass };
}

// 汇总节点
async function summary(state: TKycState) {
  // 这两项验证都通过了,那就是通过了
  const passed = state.ocrPassed && state.faceMatch;

  return {
    kycPassed: passed,
  };
}

export const kycSubgraph = new StateGraph(KycState)
  .addNode("ocrCheck", ocrCheck)
  .addNode("faceMatchCheck", faceMatchCheck)
  .addNode("summary", summary)
  // 边
  .addEdge(START, "ocrCheck")
  .addEdge("ocrCheck", "faceMatchCheck")
  .addEdge("faceMatchCheck", "summary")
  .addEdge("summary", END)
  .compile();