BLOG

DAG (重要)

2026/05/14 11 min read BLOG DAG (重要)

这玩意就是层级结构,也就是说显式写出自己的依赖,比如喝水之前必须要打开瓶盖

“喝水之前必须打开瓶盖”

就是一个最标准的 DAG 例子。


因为:

喝水

依赖:

瓶盖已经打开

所以:

系统知道:

OpenBottleCap -> DrinkWater

这就是:

显式依赖。


以前:

你可能只是:

openCap()drink()

但:

系统其实不知道:

drink 为什么必须在 openCap 后面

只是:

你手写了顺序。


DAG 化后:

你是在:

明确声明:

DrinkWater dependsOn OpenBottleCap

这样:

系统自己就理解:

“喝水依赖瓶盖打开”。


再举个更复杂的。


做泡面

你以前:

烧水()拆调料()开盖()泡面()

但:

其实:

烧水

和:

拆调料

没依赖。


只是:

你代码写成串行。


DAG 化后:

系统知道:

BoilWater: []OpenSeasoning: []CookNoodle: dependsOn:   - BoilWater   - OpenSeasoning

于是:

自动并行。


所以:

DAG 的核心其实是:

“把隐含关系显式写出来”。


不是:

单纯层级结构

而是:

“依赖关系结构”。


这个思想:

其实到处都是。


Linux package manager

例如:

安装 A依赖:libsslpython

Docker

容器启动依赖:networkvolume

React

组件渲染依赖:stateprops

编译器

编译 B依赖:A.o

你现在 ContentBase

也是:

PromptBuilder依赖:CreativeContextContinuityState

所以:

你现在其实是在:

让系统自己知道:

“什么东西依赖什么东西”

这一步特别重要。

因为:

以前:

只有你脑子知道系统结构。


以后:

Runtime 自己知道系统结构。


这就是:

拓扑化。

Capability Node DAG

你刚刚其实是在做:

「把隐式系统结构显式化」。

而且这是一个非常高级的动作。


因为你原来:

GenerationPipeline.ts

虽然能跑,

但:

真正的 runtime topology 是隐藏的。


也就是说:

以前系统是:

“代码顺序”

决定系统结构。

例如:

await resolveContext()
await buildPrompt()
await invokeLLM()
await qualityGate()

但这时候:

系统真正的:

  • dependency

  • capability

  • retry

  • orchestration

  • boundary

其实:

全埋在代码顺序里。


所以:

你刚刚让 AI 做的事情,

本质上是:

「把 Runtime Capability 拆出来」。


例如:

原来:

generation-pipeline.ts

是一整坨。


现在开始识别:

CreativeContextResolver
ChapterContinuityResolver
GenerationLexicalPlanner
ChapterPromptBuilder
DraftQualityGate
DraftRevisionLoop

这一步意味着:

你开始承认:

系统真正的单位:

不是:

函数

而是:

Capability Node。


这是整个思想变化的关键。


因为:

以前:

pipeline = giant function

现在:

你开始变成:

runtime
 = capability graph

这一步为什么重要?

因为:

你现在的系统已经:

不是:

“调一下 LLM”

了。

而是:

上下文解析
连续性
记忆搜索
Prompt
质量检查
修复循环
投影
写回

组成的:

AI Runtime System。


所以:

你刚刚做的事情,

其实是:

“Runtime Kernelization”。


什么意思?

就是:

你开始把:

GenerationPipeline

从:

“巨型业务文件”

变成:

“Runtime Kernel”。


以后:

真正执行的不是:

一个大函数

而是:

Capability Node DAG

然后:

Temporal / Workflow / Retry / Repair

才能真正工作。


否则:

你现在虽然用了:

Temporal

但其实:

只是:

拿 Temporal 包着一个巨型 pipeline

这不是真正的 workflow system。


真正成熟之后会变成:

Workflow
 -> Runtime DAG
     -> Context Resolver
     -> Canon Guard
     -> Prompt Builder
     -> LLM Invoke
     -> Quality Gate
     -> Repair Loop
     -> Publish Manifest

所以:

你刚刚让 AI “整理 DAG”,

实际上是在:

给整个 ContentBase 建 runtime topology。

DAG 是:

Directed Acyclic Graph

中文:

有向无环图


拆开解释:


1. Graph(图)

就是:

节点
+
连接关系

例如:

A -> B -> C

2. Directed(有向)

意思是:

有方向

例如:

生成上下文
 -> 拼 Prompt
 -> 调模型
 -> 质量检查

方向不能反。


3. Acyclic(无环)

意思是:

不允许循环

不能:

A -> B -> C -> A

因为:

会无限循环。


所以 DAG 本质上是:

“一张有执行顺序、不会死循环的依赖图”。


你现在的 GenerationPipeline

其实已经是:

隐式 DAG。

例如:

你现在实际在做:

读取章节
 -> 读取角色
 -> continuity check
 -> resolve context
 -> build prompt
 -> invoke llm
 -> quality gate
 -> repair
 -> persist

但你现在是:

一个 pipeline.ts
里面顺序调用

而 DAG 化之后:

会变成:

ResolveCreativeContext:
  outputs:
    - contextBundle
 
ResolveContinuityState:
  dependsOn:
    - contextBundle
 
BuildPrompt:
  dependsOn:
    - contextBundle
    - continuityState
 
InvokeLLM:
  dependsOn:
    - prompt
 
QualityGate:
  dependsOn:
    - llmOutput
 
RepairLoop:
  dependsOn:
    - qualityReport

这样:

workflow 不再是代码顺序。

而是:

能力节点之间的依赖图。


为什么这很重要?

因为:

现在你的:

GenerationPipeline

越来越像:

“上帝函数”。


以后会:

  • 5000 行

  • 10000 行

  • 不敢改

  • Temporal 难接

  • repair loop 很乱

  • retry 很痛苦

  • parallel 很难做


而 DAG 化以后:

你可以:


1. 并行执行

例如:

角色记忆
世界观检查
相关章节读取

可以同时跑。


2. 可重试

例如:

只重跑 QualityGate

不用整个 pipeline 重来。


3. 可缓存

例如:

creative context

已经解析过。

直接复用。


4. 可观察

你会得到:

Runtime Graph Visualization

像:

  • Airflow

  • Temporal

  • LangGraph

  • Prefect

那种执行图。


5. 可插拔

以后:

新的 continuity checker

直接插一个 node。

不用改 pipeline 巨石。


6. AI-native

最关键。

未来 AI runtime:

本质都是 DAG。


包括:

  • LangGraph

  • Temporal

  • Prefect

  • Airflow

  • Dify workflow

  • ComfyUI

  • n8n

  • AutoGen graph

本质都是:

capability DAG。

对。

而且不只是:

“拆小函数”。

更准确说是:

「把巨型任务拆成有边界的能力原子(Capability Atom)」。


普通“拆函数”:

可能只是:

function buildPrompt(){}
function invokeModel(){}

但:

本质还是一个大泥球。

因为:

  • 生命周期还混着

  • retry 还混着

  • 状态还混着

  • dependency 还混着

  • orchestration 还混着


你现在开始做的是:

Runtime Atomization。


也就是:

原来:

Generate Chapter

是:

一个不可分黑箱。


现在:

你开始承认:

它其实由:

Context
Memory
Continuity
Lexical Plan
Prompt
LLM
Quality
Repair
Projection

组成。


然后:

每一个:

都是独立 capability。


这一步之后:

系统会从:

“代码驱动”

变成:

“拓扑驱动”。


以前:

await a()
await b()
await c()

就是系统结构。


以后:

系统结构会变成:

BuildPrompt:
  dependsOn:
    - ResolveContext
 
InvokeLLM:
  dependsOn:
    - BuildPrompt
 
QualityGate:
  dependsOn:
    - InvokeLLM

这意味着:

系统真正理解了自己的结构。


然后:

你才能真正拥有:


1. 局部重试

例如:

只重跑 QualityGate

2. 并行

例如:

角色记忆
世界观检查

同时跑。


3. 缓存

例如:

creative context

不用重复解析。


4. 热插拔

以后:

新的 continuity checker

直接插 node。


5. Runtime Visualization

真正看到:

Generation Graph

6. Workflow 化

例如:

draft
repair
review
publish

所以:

你刚刚说的:

原子化

其实非常准确。

但:

不是:

“代码原子化”

而是:

“Runtime Capability 原子化”。


这是:

AI-native system

和:

普通 Node.js 项目

真正的分水岭。


你现在其实已经走到:

“应该 DAG 化” 的阶段了。

因为:

你的系统已经不是:

单 prompt 调用

了。

而是:

上下文解析
语义约束
连续性
质量
修复
写回
投影

组成的:

Runtime Capability System。

可以这么理解。

但:

DAG 不只是“画出来的流程图”。

更准确说:

DAG 是:

“可执行的依赖拓扑”

普通流程图:

只是:

给人看

而 DAG:

是:

给系统执行的。


比如:

普通流程图:

开始
 -> 读取上下文
 -> 调模型
 -> 输出

只是示意图。


但 DAG 会真的描述:

BuildPrompt:
  dependsOn:
    - ResolveContext
 
InvokeLLM:
  dependsOn:
    - BuildPrompt
 
QualityGate:
  dependsOn:
    - InvokeLLM

系统可以根据这个:

真的去:

  • 调度

  • 重试

  • 并行

  • 缓存

  • 追踪

  • 回滚


所以:

DAG = “带依赖关系的可执行流程图”。


你现在的:

GenerationPipeline

其实是:

“写死在代码里的 DAG”。

例如:

await resolveContext()
await buildPrompt()
await invokeLLM()
await qualityGate()

但:

真正 DAG 化之后:

这些步骤会变成:

节点(Node)

然后:

系统自己决定:

  • 谁先执行

  • 谁可以并行

  • 谁失败重试

  • 谁缓存复用


举个最简单的例子:

现在你可能这样:

读取角色
读取世界观
读取章节

一个一个跑。


但 DAG 会发现:

它们互不依赖

于是:

可以同时跑。


再比如:

QualityGate 失败

现在:

你可能:

整个 pipeline 重来

DAG 会:

只重跑:

RepairLoop
 -> QualityGate

所以:

DAG 的核心不是“图”。

而是:

“依赖驱动执行”。

意思是:

你现在已经确认:

GenerationPipeline

不是一个“函数”。

而是:

一个隐藏的工作流系统。


你原来可能以为:

pipeline.ts

只是:

生成小说

的代码。


但现在真正分析后发现:

它实际上已经在同时负责:

上下文解析
连续性
记忆搜索
Prompt 构建
模型调用
质量检查
修复循环
润色
进度汇报

这意味着:

它其实已经是:

“Runtime Workflow Engine”

了。

只是:

还没显式化。


比如:

你现在里面有:

CreativeContextResolver

本质是:

Context Node


有:

DraftQualityGate

本质是:

Quality Node


有:

DraftRevisionLoop

本质是:

Repair Node


有:

ModelInvocationPort

本质是:

LLM Execution Node


也就是说:

你现在:

不是“生成一篇小说”。

而是在:

执行一张 Runtime DAG。


只是:

你目前把所有 DAG 节点:

塞进了一个 2100 行文件。


所以他说:

这就是隐式 DAG

意思就是:


DAG 已经存在了。

但:

还没有被“拆出来”。


现在:

pipeline.ts

像这样:

await resolveContext()
await prepareContinuity()
await searchMemory()
await buildPrompt()
await invokeLLM()
await qualityGate()
await revisionLoop()

这其实已经是:

DAG 节点顺序执行。


但:

还不是:

显式 Runtime Graph。


所以:

他说的:

“第一阶段拆分建议”

意思是:


不要大重构。

不要:

重写系统

不要:

推翻 API

不要:

重构数据库

而是:

先把 pipeline 内部:

拆成:

独立 capability node。


例如:

现在:

generation-pipeline.ts

里面:

function resolveContext(){...}
function buildPrompt(){...}
function qualityGate(){...}

全混一起。


第一步应该:

拆文件。

变成:

runtime/nodes/

下面:

CreativeContextResolver.ts
ChapterContinuityResolver.ts
GenerationLexicalPlanner.ts
ChapterPromptBuilder.ts
DraftQualityGate.ts
DraftRevisionLoop.ts

然后:

原来的:

GenerationPipeline

变成:

orchestration layer。


例如:

await creativeContextResolver.run()
await continuityResolver.run()
await lexicalPlanner.run()
await promptBuilder.run()
await llmPort.run()
await qualityGate.run()

这样:

逻辑不变。

输出不变。

API 不变。

但:

Runtime Topology 开始清晰。


这就是:

他说的:

第一阶段不改变 API、不改变输出

因为:

这是:

最安全的切法。


否则:

如果现在直接:

上 Temporal
上 Workflow DSL
上 Runtime Graph Engine

你会:

一次性炸整个系统。


所以:

现在真正的意思是:

先把“隐式 DAG”

变成:

“显式 Capability Node”。


这是:

你系统从“巨型 pipeline”

进入:

“AI Runtime Architecture”

的第一步。