16 分钟阅读

用 Claude 做 Graph Engineering:它是什么,以及怎么真正用起来

Graph Engineering with Claude. What It Is and How to Actually Use It 原文发布于

文章封面

几周前,整个 AI 圈子都在谈循环(loop)。然后图(graph)出现在了每个人的时间线上,循环一夜之间成了旧闻。

转变发生得很快。但关于 Graph Engineering(图工程)的大多数帖子,要么空泛得没什么用,要么技术得根本跟不上。没有人先解释清楚图到底是什么,就开始教你去搭一个。

读完这篇文章,你会知道图到底是什么,以及如何辨认出藏在你当前工作流里的那一张。 还有让图变得强大的那一个模式、它们会在哪里悄悄失效,以及如何用 Claude 在几分钟内亲手搭出一个。


图到底是什么

大多数人听到“图”,想到的是带柱子或折线的图表。这里说的不是那个。在 AI 工作的语境里,图比听起来更简单:它是一张地图,标出哪些工作需要完成,以及每项工作依赖什么。

整件事由两样东西组成。

节点(node)是一个工作单元。一个 Agent,一项任务,一个输入,一个输出。不是“研究这个主题的一切,然后写总结,顺便再核对来源”,而只是其中的一件。工作越小、定义越清楚,节点就越有用。

边(edge)是一条依赖。当第二个节点真的需要第一个节点的产出时,边把它们连起来。不是“这两件事按先后发生”,而是只有当一个的输出确实喂给另一个的输入时才算。

图 1:节点与边。Research → Write → Verify,每个节点只做一件事,每条边都传递真实的东西

就是这样。节点干活,边传递它们之间流动的东西。Graph Engineering 里的其他一切,都只是把这两个概念用在不同的尺度上。


你当前的工作流已经是一张图

大多数人第一次听说 Graph Engineering 时都漏掉了这一点:你已经在做了。只是做得很差。

当你写下“研究这个主题,然后总结你的发现,然后根据总结写一份草稿”这样的 prompt 时,那就是一张图。一条没有分支的链,每一步都等前一步完成。一个头,一条线,一次一件事。

它能正确运行。但它跑得慢,也容易坏。如果总结那一步产出的东西没法用,写草稿那一步就失败了。如果研究那一步耗时太久,后面的一切都在等。链没有冗余,也没有弹性。它是最简单的图,而简单不等于高效。

Graph Engineering 的第一步不是学新东西,而是看看你已有的东西,然后问:每一步真的都需要等前一步吗?因为大多数时候,并不需要。

❌ 线性链:

研究 → 总结 → 写作 → 核对来源 → 排版 → 发布

六步排成一列。每一步都在等。总耗时:六步之和。

✅ 重画成图:

研究 + 核对来源(同时进行)→ 总结 → 写作 + 排版(同时进行)→ 发布

同样的工作。更少的等待。因为互相独立的工作不再排在彼此后面,所以完成得更快。


假边测试

一旦你能把工作流看成一张图,下一步就是找出那些本不该存在的边。

一步一步看你当前的工作流。在每个箭头处问一个问题:这一步真的需要上一步的结果吗?不是“它是不是排在后面”,而是它是否真的用到了上一步的产出?

如果是,这条边是真的。保持顺序。

如果不是,那就没有边。这两项工作彼此无关,它们之间的等待纯属浪费。

举个简单的例子:“审查文件 A 的 bug,然后审查文件 B 的 bug。”读起来像一个序列。但对文件 B 的审查从不看文件 A 返回了什么。它们一前一后地跑,只是因为你是按这个顺序敲的。让它们同时跑,整件事在较慢那一个的时间内就完成了,而不是两者相加。

不到五分钟就能对任何工作流跑一遍这个测试:

  1. 把每一步写成一个方框
  2. 在每对相邻步骤之间画一个箭头
  3. 对每个箭头问:步骤 A 的数据真的进入了步骤 B 吗?
  4. 是,保留箭头。这是真依赖
  5. 否,删掉箭头。这是一条假边
  6. 没有入边的都可以立即开始
  7. 没有出边的都是最终输出

几乎在你画出的任何工作流里,你都能找到两三条假边。每一条都是你白白送出去的时间。


菱形

一旦你开始删除假边,有一个模式会比其他任何模式都更频繁地出现。它叫菱形(diamond),正是它让图值得一用。

想法很简单。一个节点 fan out(扇出)成几个并行节点。这些并行节点全部汇入一个最终节点,由它把各自的输出收拢到一起。画出来,它就像一个菱形。

图 2:菱形。fan out → 并行 → 汇聚:RESEARCH 扇出到 SOURCE 1、2、3(并行层),再汇入 SYNTHESIZE

在实践中它长这样。假设你在为一篇文章做主题研究。线性版本是:搜索 → 读来源 1 → 读来源 2 → 读来源 3 → 综合。

菱形版本:搜索 → [并行读来源 1 + 来源 2 + 来源 3] → 综合。

最终的综合节点在两种方式下拿到的输入是一样的。但它等待的时间只是最慢那一次来源阅读的长度,而不是三者相加。

菱形之所以成立,是因为综合确实依赖全部三次阅读。这些是真边。但三次阅读之间彼此没有依赖。那些连接并不存在。所以你让它们同时跑,唯一的等待发生在最后,而那里的等待反正是免不了的。

这就是为什么一旦你开始留意,菱形就会无处不在。研究流水线。代码审查。市场分析。只要你的工作里有“从多个地方收集,然后合并”的形状,你就有一个菱形。收集是并行的。合并是汇聚点。

这个模式有两条规则。第一,并行节点必须真正独立,不能有伪装成真边的假边。第二,汇聚节点必须真的需要它们全部。如果它只需要其中一个,其他的就是白干。

把这两点都做对,菱形就是一个工作流所能采取的最快形状。


图会在哪里悄悄失效

菱形在理论上很干净。实践中它会在两个具体的地方出问题,而且两个都容易被忽略。

第一个是坏节点未被发现。三个来源并行运行,其中一个返回了垃圾:一个幻觉、一个空结果、一个读错的文件。这个坏输出会和另外两个好输出一起,直接流进你的综合节点。

综合节点并不知道它的某个输入是错的。它把所有东西合在一起,产出一个建立在坏材料上的、自信满满的答案。让事情变快的并行结构,同时也移除了那些你本来会注意到问题的天然检查点。

第二个是级联。在线性链里,一个坏步骤产出一个坏输出,你立刻就能看到。在有汇聚路径的图里,坏输出会和好输出混在一起,错误变得更难追踪。等到最终节点给出响应时,损害已经被稀释,看不见了。

两个问题的解法相同:一个检查节点(checker node)。

检查节点位于你的并行层和汇聚点之间。它唯一的工作是在每个输出往前传之前评估它。它不综合、不写作、不做任何主体工作。它只问:这个输出能用吗?能,就放行。不能,就标记、重试或丢弃,赶在它毒害下一步之前。

检查节点应该抓住的五件事:

  1. 空输出或 null 输出:一个没返回任何有用东西的节点
  2. 互相矛盾、不可能同时为真的输出
  3. 相对于原始任务跑题的输出
  4. 低到不可靠的置信度信号
  5. 会让综合节点解析失败的格式错误

没有检查节点的图,就是一张假设上游一切正常的图。这个假设失效的频率比你想的高。


静态图 vs. 动态图

到目前为止,一切都假设你在开始之前就知道图的形状。你定义节点,画出边,然后运行。对于结构不变的可重复工作流,这行得通。

但很多真实工作不符合这个形状。你开始一项研究任务,做到一半发现某个来源还需要另外三次查询。你开始一次代码审查,发现某个文件需要比其他文件更深入的分析。你需要的结构在开始时是不可知的,只有当工作展开后才变得清晰。

这就是动态图的用武之地。它不是预先定义好的固定结构,而是在运行过程中自己构建自己。一个节点完成工作,看看自己发现了什么,然后决定接下来应该有哪些节点。这张图不是规划出来的,而是长出来的。

这个区别在实践中很重要。静态图快而可预测。你确切知道什么会运行、按什么顺序、大概要多久。动态图灵活,能应对意外。但出了问题更难调试,因为实际运行的结构不是你最初画的那一张。

在开始前弄清楚你需要哪一种,能省下大量回头路:

  1. 用静态图,当任务可重复、结构每次都一样
  2. 用静态图,当速度和可预测性比灵活性更重要
  3. 用动态图,当工作范围取决于你一路上的发现
  4. 用动态图,当某些节点需要根据自己的输出决定下一步
  5. 永远先用静态图,只有当静态版本撞上它处理不了的墙时才切换到动态
  6. 绝不用动态图做任何你需要精确审计“到底运行了什么、为什么”的事情

大多数看起来需要动态图的工作流,其实只是需要一张设计得更好的静态图。动态版本更强大,也更难控制。把它放在第二位,而不是第一位。


差别实际上是什么样

理论在抽象层面容易理解。下面是同一个任务用两种方式跑的样子,你可以看到究竟什么变了。

任务:分析三个竞品并写一份对比。

不用图:

研究竞品 A → 研究竞品 B → 研究竞品 C → 三者对比 → 写草稿 → 核对事实 → 排版输出

七步,全部串行。总耗时是每一步之和。如果第二步比预期更久,后面的一切都在等。

用图:

[研究 A + 研究 B + 研究 C] → 检查节点 → 对比 → [写草稿 + 排版输出] → 最终检查

五个逻辑阶段。三个研究步骤同时跑。写作和排版同时跑。检查节点在坏的研究结果到达对比之前就把它拦下。总耗时大幅坍缩。

输出相同。结构不同。

下面是两种方式各自的胜负所在:

线性图
搭建时间低较高
总运行时间慢快
易于调试是较难
处理运行中的错误差好(检查节点)
适合一次性任务是杀鸡用牛刀
适合可重复工作流是更好
随任务增长而扩展否是

这张表看起来像是除了搭建和调试之外,图处处都赢。对于任何你要跑不止一次的事情,这大致是对的。对于永远不会重复的一次性任务,线性版本几乎总是更快搭好、更快跑完。

当任务大到时间节省会累积,或者中途的错误昂贵到检查节点能收回成本时,图才值得。


如何用 Claude 搭一个

上面这些在你给 Claude 一个它能执行的东西之前,都还只是一个心智模型。从这里开始,它变得可操作。

Claude Code 有一个 workflow 关键字,它会改变 Claude 处理你指令的方式。没有它,Claude 把你的 prompt 当作一个序列来读,一步接一步地执行。有了它,Claude 会解析结构,识别出哪些节点彼此没有依赖,并自动并行运行它们。你描述图,Claude 推算执行顺序。

一个基本的 workflow 长这样:

workflow: research-and-compare

nodes:
  research_a:
    task: "Research competitor A's pricing, features, and recent news"
    output: competitor_a.md

  research_b:
    task: "Research competitor B's pricing, features, and recent news"
    output: competitor_b.md

  research_c:
    task: "Research competitor C's pricing, features, and recent news"
    output: competitor_c.md

  checker:
    task: "Review each research file. Flag any that are incomplete or off-topic."
    depends_on: [research_a, research_b, research_c]
    output: checker_report.md

  compare:
    task: "Using the research files, write a structured comparison across price, features, and positioning."
    depends_on: [checker]
    output: comparison.md

图 3:WORKFLOW 的运行方式。research_a、research_b、research_c 组成并行层,checker 等待三者全部完成,再进入 compare

有三点值得注意。第一,research_a、research_b 和 research_c 没有 depends_on,workflow 一启动,Claude 就同时运行这三个。第二,checker 把这三个都列为依赖,所以它会等到三个全部完成才运行。第三,compare 只依赖 checker,而不直接依赖研究节点,检查节点就是把关者。

那一行 depends_on 是你设计任何图唯一需要理解的东西。没有依赖就意味着并行。有依赖就意味着等待。其他一切只是决定哪些节点需要什么。


可以直接粘贴的 prompt

上一节的 workflow 语法适用于任何可重复的任务。这里有四个你可以直接丢进 Claude Code 再自行调整的例子。

竞品研究:

workflow: competitive-research

nodes:
  research_a:
    task: "Research [Company A]. Cover: pricing, core features, recent product changes, public sentiment. Output a structured summary."
    output: company_a.md

  research_b:
    task: "Research [Company B]. Cover: pricing, core features, recent product changes, public sentiment. Output a structured summary."
    output: company_b.md

  research_c:
    task: "Research [Company C]. Cover: pricing, core features, recent product changes, public sentiment. Output a structured summary."
    output: company_c.md

  synthesize:
    task: "Using company_a.md, company_b.md, company_c.md — write a comparison table and a one-paragraph positioning summary for each."
    depends_on: [research_a, research_b, research_c]
    output: comparison.md

多文件代码审查:

workflow: code-review

nodes:
  review_auth:
    task: "Review auth.py for security issues, edge cases, and code quality. Be specific."
    output: review_auth.md

  review_api:
    task: "Review api.py for security issues, edge cases, and code quality. Be specific."
    output: review_api.md

  review_db:
    task: "Review db.py for security issues, edge cases, and code quality. Be specific."
    output: review_db.md

  checker:
    task: "Read all three review files. Flag any issues that appear in more than one file. Note cross-file dependencies that could cause problems."
    depends_on: [review_auth, review_api, review_db]
    output: checker.md

  summary:
    task: "Using all review files and checker.md, write a prioritized list of fixes — critical first, then medium, then low."
    depends_on: [checker]
    output: final_review.md

文章研究与草稿:

workflow: article-research

nodes:
  angle_a:
    task: "Research [topic] from the angle of [audience A]. What do they care about most? What are the common misconceptions?"
    output: angle_a.md

  angle_b:
    task: "Research [topic] from the angle of [audience B]. What do they care about most? What are the common misconceptions?"
    output: angle_b.md

  examples:
    task: "Find 3 specific real-world examples of [topic] that most people haven't heard of. No generic case studies."
    output: examples.md

  draft:
    task: "Using angle_a.md, angle_b.md, and examples.md — write a draft that speaks to both audiences and opens with one of the specific examples."
    depends_on: [angle_a, angle_b, examples]
    output: draft.md

把方括号里的内容替换掉。不管你在节点里放什么,结构都保持不变。


当你用图来思考时,什么会改变

前两节里的 workflow 立刻就能用。但更大的转变发生在你用了几周之后。

你不再把一个任务读成一份待办清单,而是读成一组依赖关系。第一个问题不再是“我先做什么?”,而是“到底什么需要等什么?”。大多数时候答案是:比你以为的少。

这种变化也体现在你写 prompt 的方式上。线性 prompt 告诉 Claude 按顺序做什么。图式 prompt 告诉 Claude 每一块需要什么,然后让它自己推算顺序。这样的 prompt 更小、更容易修改,而且当你换掉某个节点时也不会坏。

对于任何你跑过两次以上的 workflow,最后值得加上的一样东西是一条 CLAUDE.md 条目。它告诉 Claude 你希望在这个项目里如何处理图:你对输出格式、检查节点行为和错误处理的默认设定,这样你就不用每个会话都重建这些上下文:

# Workflow defaults

When running a workflow:
- All nodes without depends_on run in parallel by default
- Checker nodes should flag incomplete outputs, not silently pass them
- Output files go to /outputs with the node name as filename
- If a node fails, pause and report before continuing
- Never merge outputs from flagged nodes into the final synthesis

一个文件,设置一次。你在那个项目里运行的每个 workflow 都会继承它。

你现在画的图,六个月后看起来会显得理所当然。不是因为它们容易,而是因为一旦你清楚地看见了依赖关系,就再也无法视而不见。任何工作流的线性版本,都会开始露出它的本来面目:一张所有边都是假的图。


在文章开头我说过,关于 Graph Engineering 的大多数帖子要么太空泛,要么太技术。我是认真的,而我试着在两者之间走出一条路。

你现在知道了图是什么。你知道如何找出藏在你当前工作流里的那一张。你知道假边测试、菱形、检查节点,以及什么时候该用动态图而不是静态图。你有了在 Claude Code 里搭建它的语法,还有四个今天就能用的 prompt。

这就是全部。在这些东西变得有用之前,你不需要更深一层的图论。

如果有人让我别写某一项,我唯一会坚持保留的是:假边测试。这周对一个工作流跑一遍。只要一个。画出步骤,逐个检查箭头,问哪些真的在传递数据。你至少会找到一条不是的。

那就是整个模型豁然开朗的时刻。不是在你理解理论的时候,而是在你从自己搭的东西里找到第一条假边、并意识到你已经为它白等了几个月的时候。

其余的都从那里开始。