Graph Engineering:把Agent的SOP画成图,让流程自己跑
2026/9/2 1:35:22 网站建设 项目流程

最近团队在做一个客服工单自动处理 Agent,最早的写法很直觉:把整套处理规范写成一段超长 prompt,让大模型按顺序执行。单条测试时效果不错,并发一上来问题就开始冒头——有的工单漏掉了必做核验,有的在同一个分支里反复重试,还有的直接忘记把上一步结论传给下一步。排查时只能翻对话日志,找半天都定位不到卡在哪一层。

后来我们把处理规范从一段文字描述改成了一张 graph:每个操作是一个节点,节点之间的流转条件是边,整个流程变成了一个可以执行、可以观测、可以单独测试的图结构。这个改变的收益比预期大得多。不是因为画图好看,而是因为把“给模型讲一遍流程”变成了“给 Agent 一条明确的运行轨道”。

这正是 Graph Engineering 想解决的问题:把 Agent 的 SOP 画成 graph,它就能自己跑。这句话真正的含义不是“画一张流程图”,而是把隐性的、靠提示词维持的流程,变成显性的、可执行、可维护的工程结构。

1. 先搞清楚 Graph Engineering 解决的是什么问题

1.1 文字 SOP 为什么会被 Agent 执行偏

SOP 本来是人类之间协作的产物:写清楚先做什么、后做什么、什么情况下做什么。把这段文字直接塞给大模型,看起来可行,实际上每一步都是在让模型重新“理解”流程。

问题出在三个地方。

第一,理解有损耗。不同模型、不同上下文长度、甚至同一模型在不同会话里,对“如果金额较大就转人工”这句话的把握都不一样。什么叫“较大”?边界不清晰,执行就不稳定。

第二,控制流藏在模型脑袋里。文字 SOP 里“先 A 再 B,遇到 C 跳 D”这种逻辑,模型读完以后是自己脑补执行的。你无法强制它走到 B 之后一定检查一个条件,只能靠提示词去“劝”。可“劝”不等于“保证”。

第三,出错以后没法定位。文字流程一旦跑偏,你看到的是最终输出不对,但不知道在哪一步偏了。翻对话日志成本极高,改起来更麻烦,可能为了修一个问题把整个 prompt 重写一遍。

所以文字 SOP 不是不能用,而是很难工程化。它适合给人看,不适合作为 Agent 的稳定执行规范。

1.2 图的本质:把“顺序”升级成“路径”

图结构带来的变化,表面上看是“把流程可视化”,实际是把执行控制权从模型手里拿回来一部分:控制流不再依赖模型临场发挥,而是由图的边和节点决定。模型在每个节点只做局部决策,整体路线由图引擎保障。

我习惯做这样一张对比:

维度文字 SOP图化 SOP
控制流位置模型内部,隐式图结构,显式
条件判断靠模型语义理解由边的条件和检查节点明确判断
执行稳定性依赖提示词质量依赖图结构和节点实现
失败定位翻全部对话看节点级日志
修改成本改 prompt,连带影响不确定改边或改节点,局部可控
可测试性很难单独测某个环节每个节点可独立验证

这张表是我判断一个流程该不该图化的核心依据。如果一段 SOP 的执行结果只能靠整体效果来评估,那说明它还停留在文字阶段;如果每个环节都能单独验证,那它已经具备图化的条件了。

2. 把 SOP 画成 graph 时,先确定这四类元素

2.1 节点不只是任务,还有决策、工具、检查点

很多人画图时会犯一个习惯性错误:每个节点都写成“让大模型做一件事”。比如“提取信息”“判断风险”“生成回复”,清一色是模型节点。

但真实 SOP 里不是每一步都需要大模型。常见节点至少可以分为几种:

  • 任务节点:调用大模型完成某个子任务,比如“从工单里提取客户诉求”。
  • 工具节点:调用 API、查询数据库、发送消息、写文件。这类节点不经过大模型,执行更快、更可控。
  • 决策节点:根据状态里的字段值选择走哪条边。判断逻辑可以用规则,不必每次都用模型。
  • 检查节点:校验上一步输出是否符合格式要求、是否有缺失字段,不合格就重试或转人工。
  • 人工节点:需要人确认或介入时挂起流程。

画图之前先做分类,比直接连线重要得多。因为不同节点类型的失败处理方式完全不同:工具节点重试策略是超时重连,模型节点重试策略是换 prompt 或降低温度,检查节点失败则不应该盲目重试,而是要暴露给上层。

2.2 边回答的不是“下一步”,而是“什么时候下一步”

边的最大价值在条件。没有条件的边只是顺序,有条件的边才是流程逻辑。

我一般会在边上写清楚这么几类条件:

  • 无条件流转:执行完 A 就立刻到 B。
  • 条件流转:状态里的某个字段满足某条件时选择某条路径。
  • 超时流转:节点执行超过限定时间,走降级分支。
  • 错误流转:节点抛异常时,进入补偿节点而不是直接终止。

条件一定要写成可验证的表达式,而不是再丢给模型判断。比如“金额大于 10000 转人工”,这就是一个明确规则,用代码判断即可。只有当规则本身无法用代码表达时,才考虑引入模型判断,而且要在判断节点里写清楚输出格式,让后续边能拿到结构化结果。

2.3 状态是图能跑起来的关键

图是骨架,状态是血液。节点之间怎么传数据、传什么数据,决定了这张图能不能真正跑起来。

我在实践里通常把状态设计成一个共享的 dict 或者结构体,每个节点从里面读自己需要的字段,写入自己产生的字段。关键原则有两条:

第一,明确输入输出。每个节点在被执行前,应该声明自己依赖哪些状态字段、产出哪些字段。这看起来像多写几行配置,但排查问题时会省很多时间。某一步没有值,一眼就能看出是上游哪个节点没写。

第二,控制状态体积。不要把整个历史对话都塞进状态,更不要在每个节点都把所有字段拼进 prompt。状态里只保留当前流程还需要的数据,以及下一节点真正要用的数据。否则图越跑越慢,上下文越长,效果越差。

2.4 把长文本拆进节点上下文,而不是一次性塞给大模型

这是图化 SOP 最容易被低估的收益。文字 SOP 通常是一大段话,包含背景、步骤、规则、例外情况。一次性塞给模型,模型要同时记住“流程”和“内容”,负担很大。

图化之后,每个节点可以有自己的 prompt:这个节点只需要知道“当前状态里的这几个字段,加上一条节点级指令”。比如风险判断节点只需要知道金额、客户类型、历史投诉次数,判断规则写在该节点的指令里。其他无关信息完全不用出现。

这个做法带来的效果是:指令更聚焦,模型犯错的概率更低,而且每个节点的 prompt 都是独立可调、独立测试的。改风险判断规则时,不会影响信息提取节点。

3. 从“画图”到“自己跑”:一次最小可运行的落地流程

3.1 先用配置或代码把图定义出来

画图软件只能帮你沟通,真正让它跑起来,需要把图翻译成配置或代码。

下面是一个简化的图定义结构,用来示意怎么描述节点、边、条件和状态字段。实际实现取决于你用的框架,但抽象是一致的。

{ "start": "extract_info", "nodes": { "extract_info": { "type": "task", "prompt": "从工单中提取客户诉求,输出 JSON,字段包括 amount, intent, urgency", "output_fields": ["amount", "intent", "urgency"], "retry": { "max_attempts": 2 } }, "risk_check": { "type": "decision", "condition": "amount > 10000 or urgency == 'high'", "true_next": "human_review", "false_next": "auto_reply" }, "auto_reply": { "type": "task", "prompt": "根据提取结果生成回复,语气保持专业", "output_fields": ["reply"] }, "human_review": { "type": "human", "assignee": "support_lead", "timeout_seconds": 3600 } }, "end": ["auto_reply", "human_review"] }

这里有个细节值得注意:节点的类型不只是“任务”,还有“决策”和“人工”。这样做的好处是,决策逻辑可以脱离模型独立运行,人工节点则把流程挂起等待介入。一张图里混用多种节点类型,才能真正对应现实中的 SOP。

3.2 执行引擎怎么循环

有了图定义,执行引擎的循环逻辑其实很固定:

  1. 找到起始节点,初始化状态。
  2. 执行当前节点,得到输出并写入状态。
  3. 根据节点类型和状态值,评估出边条件,确定下一个节点。
  4. 如果没有符合条件的边,且当前不是终止节点,按错误处理。
  5. 到达终止节点或触发全局终止条件,结束本次执行。

关键点在于:每一步都要留下记录。哪个节点、第几次尝试、读了哪些状态字段、写出了什么、走了哪条边、耗时多少。这些记录不是可选项,是图化流程能长期维护的基础。

3.3 分支、重试与终止条件

分支很容易理解,决策节点选边即可。真正要提前定好的是重试和终止策略。

我一般会设三类限制:

  • 节点级重试次数:模型节点或工具节点失败时最多重试几次,默认 2 到 3 次即可,不要太多。
  • 全局最大步数:防止图出现循环。不管逻辑上是不是死循环,超过步数就强制终止并告警。
  • 错误兜底分支:每个容易失败的节点后面,最好预设一条降级路径。比如模型解析失败两次后,不再重试,而是转人工。

终止条件也要写清楚。图结束不是“模型觉得结束了”,而是“执行到达了明确的终止节点”。如果一张图里存在多条终局路径,就要确保每条路径最后都有一个终止节点或人工节点收尾。

3.4 先跑通再批量:从一条样例到全量任务

我最推荐的落地顺序是:先用 5 到 10 条真实历史数据跑一遍,逐节点看结果,确认信息提取正确、边条件判断正确、终局路径合理。样本跑通之后,再加到几十条,观察稳定性和失败率。最后才考虑并发和批量。

注意:不要一上来就把批量数和并发数拉满。图结构能跑通,只说明流程没有断;批量场景下的限流、超时、状态写入冲突是另一类问题,需要单独验证。

如果样本阶段就发现某类输入频繁走错分支,不要急着改参数,先回看边条件和节点 prompt。图化流程里,多数“跑偏”问题不是模型能力问题,而是规则没写清楚或状态字段没接对。

4. Agent 执行图时真正的难点:不是图,而是节点之间的交接

4.1 上下文怎么传、怎么隔离

图跑起来的第一个难点是上下文传递。容易出现两种极端:一种是什么都不传,每个节点各看各的,结果下游节点拿不到上游信息;另一种是什么都传,每次执行把全量历史都带上,上下文越来越长。

比较好的做法是显式声明每个节点的“输入视野”。节点需要哪些字段,就在定义里列出来。执行引擎只透传这些字段,其他数据不进 prompt。这样做既控制成本,也避免模型被无关信息干扰。

同时要注意字段的覆盖问题。多个节点写同一个字段时,要明确以哪个为准,或者干脆设计成不同字段名。否则流程走到一半,某个值被意外覆盖,排查时很难发现。

4.2 子 Agent 与工具的边界:把 subagent 当成另一种 tool

多 Agent 设计里经常出现主从模式。一个常见的理解误区是:主 Agent 和子 Agent 之间需要对等协作,甚至互相聊天。实际上,更稳妥的做法是把 subagent 当作一种特殊的工具调用。

换句话说:当图中某个节点任务过于复杂,不适合继续展开成细粒度节点时,可以在这个节点内部启动一个子 Agent,给它一个明确的输入和输出契约,子 Agent 跑完把结果返回。对主图来说,这个节点就是一个工具节点:输入明确、输出明确、失败策略明确。

这样的好处是主图保持稳定,不会因为某个子任务复杂而无限膨胀。子 Agent 内部的流程也可以单独维护、单独优化,甚至可以先不图化,用普通对话式 Agent 实现,等它稳定了再决定要不要进一步拆图。

4.3 记忆、Skill 和 MCP 与图的关系

现在讨论 Agent 经常会提到记忆、Skill、MCP 这些概念,容易误以为它们是互相替代的关系。实际落地时它们的定位完全不同:

  • 负责编排,决定流程走向。
  • 记忆负责跨步骤、跨会话的数据积累。
  • Skill负责把某类能力打包成可复用的工具。
  • MCP负责统一工具访问接口,让节点能稳定地调用外部能力。

图形节点可以决定在什么时候读取记忆、什么时候调用 Skill、通过 MCP 访问哪个外部服务。也就是说,图是骨架,记忆和工具是血肉。一个训练有素的团队会把图定义、Skill 定义、MCP 接口配置放在不同目录里分别管理,而不是混在一起。

4.4 日志与可观测性:图化之后,排查终于有了抓手

图化流程和对话式流程最大的区别之一,就是可观测性。每跑一次,都能得到一条完整的执行轨迹:起始节点、每个节点的尝试次数、状态字段变化、边选择结果、耗时、终止状态。

我建议至少记录这些字段:run_id、node_id、attempt、event_type(start/end/error/edge)、input_fields、output_fields、duration_ms、error_message。用结构化日志或表存储。后期分析失败率、定位卡点、评估模型节点质量,都依赖这份数据。

没有这份日志,图化只完成了“能跑”,还没完成“能运维”。

5. 排查链路:图跑得不顺,先查哪几层

图化流程出问题时,最忌讳直接改 prompt 或调参数。我习惯按下面的顺序排查:

排查层看什么常见问题
现象层卡住、循环、无输出、走错分支、结果格式错误确定是哪个节点出的问题
输入与状态层节点输入字段是否齐全、值是否符合预期上游节点没写字段、字段被覆盖、状态类型不一致
边条件层条件表达式、阈值、比较逻辑条件写错、字段名不匹配、边界值处理遗漏
节点实现层模型节点 prompt、工具节点接口、超时配置prompt 指令不聚焦、工具报错、超时设置过短
引擎与参数层重试次数、全局步数限制、并发设置、依赖版本死循环、重试过于频繁、并发下状态写入冲突

这个顺序的核心逻辑是:先确定问题在哪一层,再决定修哪里。很多图流程问题看起来像是“模型理解错了”,实际是上游字段没传过来,或者边条件里字段名写错,模型根本拿不到判断依据。

有一个经验值得分享:所有节点输入输出字段用统一的命名规范,比如 snake_case 或 camelCase,边条件里不要频繁做类型转换,让状态里保存的值从写入到读取保持一致的类型。否则会出现“字符型的 10000”和“数字型的 10000”比较不相等这种低级但难查的问题。

注意:节点报错不等于模型不行。先看错误类型,再看是工具超时、格式解析失败还是模型输出非法 JSON。三种情况的处理方式完全不同。

6. 适用边界:不是所有 Agent 任务都适合画成图

6.1 适合图化的:流程稳定、可重复、有明确检查点

判断一个 SOP 是否适合图化,我用三个标准:

  • 流程是否稳定:同样的输入,处理步骤基本一致,不会每次需求都变。
  • 是否可重复:这个流程会被反复执行,值得投入成本做工程化。
  • 是否有明确检查点:每个环节的产出可以被验证,或者至少可以被明确判断是否继续。

符合这三条的,典型如客服工单处理、内容审核、订单异常处理、运维告警响应、常规报表生成。这类流程的收益逻辑是:每次执行都能复用同一套编排,并逐步积累优化数据。

6.2 不适合图化的:开放式探索、需求频繁漂移

图化本身有成本。画图、定义状态、写边条件、搭日志,都需要时间。如果一个任务属于开放式探索,比如“帮我想一个营销方案”,或者需求每天都在变,比如“今天这样明天那样”,强行图化反而会拖慢节奏。

这类任务更适合让 Agent 以较自由的循环方式执行:模型自己规划步骤、自己调用工具、根据结果调整策略。虽然可控性弱一些,但灵活性和探索能力更强。

还有一个容易被忽略的边界:团队规模。如果只有一个人维护,任务量也不大,用一套轻量的脚本加提示词可能就够。图化是工程手段,不是万能手段。它的价值需要一定的任务重复量来摊薄。

6.3 从图到工作流资产:版本化、测试与复用

图化 SOP 带来的长期价值,是流程本身变成了一种可版本化的资产。

过去的 SOP 是一份文档,改一次要重新同步所有人;现在的 SOP 是一份配置或代码,可以进版本库,可以打 tag,可以写单元测试。每次修改都有记录,每次优化都能对比前后的执行结果。之前那个客服工单流程,后来我们把风险判断条件调了三次,每次都是改一个边条件,跑回归样本验证,再灰度上线。

如果团队里有多条业务线,这套经验还能抽象成公共模板:信息提取节点做通用版本,人工审核节点做通用版本,不同业务线只替换边条件和节点 prompt。这才是 Graph Engineering 真正值得长期投入的地方:它把一个岗位的 SOP,变成了一台可以每天反复运行、不断改进的机器。

回到最开始那句话:把 Agent 的 SOP 画成 graph,它就能自己跑。这句话的准确理解是,把“靠模型临场理解流程”改成“靠图结构保证流程、靠模型完成节点任务”。图是人的业务逻辑,模型是节点的执行者,日志是迭代的依据。三者各司其职,这套流程才真正从“能跑”走向“能长期跑”。如果你手头正有一份靠长 prompt 维护的 SOP,我建议下个迭代先别急着调提示词,试着把它画成一张图,用三条真实数据跑一遍,体会一下区别在哪里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询