不只是数据:图数据库驱动的确定性智能体
不只是数据:图数据库驱动的确定性智能体
注: 本文灵感来源于nebula graph的Graph 与 Ontology 驱动的 Agentic AIOps:
既然Function Calling可以写进llm的输出供Agent使用,为什么不能和workflow一起写进database或者Graph Database里呢?
引言:当 Agent 迷失在无尽的 Prompt 与黑盒路由中
试想这样一个场景:你的团队开发了一个处理复杂客服工单的 LLM Agent。最初,它只有 5 个工具(查订单、查物流、退款、转人工、发邮件),依靠 Prompt 中的 If-Else 逻辑和模型自带的 Function Calling 能力,它运行得很好。
但随着业务发展,工具飞速膨胀,并且需要对接外部数据源,流程分支多达上百条:
- 如果用户是 VIP,必须走 A 链路;如果是普通用户,走 B 链路;
- 在调用"退款"工具前,必须强制调用"风控校验"工具,且 LLM 绝对不能跳过这一步;
- 由于某个外部 API 经常超时,你需要频繁热更新这段路由逻辑;
- 数据散落在不同系统(MySQL 存权限、SAP 存财务、ES 存日志),Agent 无法自主完成跨源关联查询。
此时,传统的 Agent 架构开始崩溃:Prompt 变得冗长且难以维护,LLM 频繁出现幻觉调用了错误的工具,硬编码的路由逻辑每次修改都需要重新发布代码。
我们如何为 LLM 装上"合规的刹车"与"寻址的导航"?
答案或许不在更复杂的代码框架里,而在数据结构里——将 Agent 的工作流逻辑(Workflow)、工具调用(Function Calling)以及外部数据源的物理映射,全部定义在图结构(Graph)中。
1. 核心范式:从"图作为工具"到"图作为大脑"
1.1 当前局限:图只是另一个工具
目前业界普遍的做法是将图数据库(如 Neo4j、Memgraph)封装成一组工具供 LLM 调用(例如 execute_cypher、get_neighbors)。这只是让 Agent “看见"了图,本质上仍然是"LLM 主导,图被动响应”。
在这种模式下:
- LLM 仍然决定"是否要查图"以及"查图的哪部分";
- 流程控制仍靠 Prompt 中的文字描述,脆弱且不可审计;
- 外部数据源的字段映射硬编码在工具参数中,Schema 变更即代码失效。
1.2 范式转移:图作为大脑
真正的 Graph Agent 构想是:让图结构本身成为 Agent 的逻辑大脑和工作流引擎。
LLM 要不要调用工具、调用哪些工具、先去哪个外部数据源取数、取完数后下一步往哪走——不再由系统 Prompt 决定,而是取决于图数据库中的点(Node)和边(Edge)关系。
在这种架构下:
- 图存储的是"元数据"(Metadata):流程的蓝图、工具的 Schema、数据源的物理坐标。——不只是数据,更是逻辑与规则。
- LLM 是"执行引擎"(Execution Engine):负责执行当前节点指派的具体任务(推理、生成、语义判断)。
- 编排器(Orchestrator)是"调度器"(Scheduler):负责读图、解析边的条件、维护会话状态、决定下一跳。
三者各司其职,确定性归图,发散性归 LLM。
2. 图结构定义:点(Node)与边(Edge)
在这种架构下,图不存储业务数据(如"张三的订单金额"),而是存储执行逻辑的元数据和外部数据源的物理映射。
2.1 节点类型(Node Labels)
| 节点标签 | 语义 | 关键属性 |
|---|---|---|
:Start |
工作流入口 | entry_point: true |
:End |
工作流终止 | output_template |
:LLMNode |
调用 LLM 推理/生成 | model, system_prompt(支持模板变量) |
:ToolNode |
调用外部工具/API | tool_name, params_schema, timeout |
:ConditionNode |
纯逻辑条件分支 | expression(如 {{ratio}} > 0.1),由编排器硬解析 |
:ExternalSource |
核心特色:外部数据源锚点 | source_type, connection_ref, table, columns, filter_hint |
:CompositeNode |
核心特色:进入一个子图(复合节点) | subgraph_id, input_mapping, output_mapping |
:ParallelNode |
并行执行 | branches, merge_strategy |
:HumanNode |
人工介入等待 | prompt, timeout |
2.2 边类型(Edge Types)
| 边标签 | 语义 | 关键属性 |
|---|---|---|
:NEXT |
无条件顺序流转 | 无 |
:ON_TRUE / :ON_FALSE |
条件分支 | condition(表达式字符串) |
:ON_FAILED |
核心特色:节点执行异常时流转 | error_type(可选),retry_count(可选) |
:JOIN_ON |
核心特色:定义两个外部数据源的关联键 | left_key, right_key, join_type |
:PARALLEL / :MERGE |
并行与汇聚 | branch_id |
也正因图只承载确定性骨架,运行时才能保持轻量、可热更新。
2.3 一个关键设计原则:存储分离
图数据库只存储"静态资产"——流程拓扑、业务规则、数据源映射。不存储会话状态。
| 存储层 | 存储内容 | 技术选型 | 变更频率 |
|---|---|---|---|
| 图数据库 | 流程拓扑、业务规则、数据源字段映射 | Neo4j / GrafeoDB / YAML | 低频(按周/月变更,热更新) |
| 外部 KV/内存 | 会话状态:current_node、call_stack、取数结果、工具返回 |
本地缓存 / Agent 内置 Context | 高频(每轮读写) |
这一原则确保了:
- 图数据库保持纯净,不被瞬时数据污染;
- 高频状态读写不影响图数据库性能;
- 流程图变更与运行时状态完全解耦。
2.4 会话状态(State)的数据结构
State 存储在本地缓存中,支持子图嵌套:
{
"workflow_id": "finance_compliance_v3",
"current_node_id": "start_sub_approval",
"call_stack": [
{ "parent_workflow": "finance_compliance_v3", "parent_node": "composite_approval" }
],
"data": {
"input": { "user": "张三", "dept": "华东区" },
"external_data": { "budget": { "actual": 12000, "budget": 10000 } },
"tool_results": { "oa_task_id": "TASK-8842" },
"llm_output": { "summary": "超支20%,需VP审批" },
"history": ["start", "fetch_sap", "check_budget"]
}
}
3. 软硬结合的路由机制
图结构不仅定义了路径,还定义了怎么走。
| 路由类型 | 执行者 | 适用场景 | 示例 |
|---|---|---|---|
| 硬路由 | 编排器(纯逻辑) | 数值比较、空值判断、权限校验、超时处理 | expression: "{{ratio}} > 0.1" → :ON_TRUE 走 VP 审批,LLM 无法绕过 |
| 软路由 | LLM(语义理解) | 意图分类、情感判断、模糊匹配 | 多条 :NEXT 边带 hint 属性,LLM 根据用户语义选择 |
定界原则:
- 凡能用纯逻辑表达式描述的 → 硬路由(确定、可审计、零 Token 消耗)。
- 只有需要语义理解的 → 软路由(交给 LLM)。
- 当软路由选错可能引发合规风险时 → LLM 输出后增加
:ConditionNode做二次硬校验。
4. 为什么必须是图数据库?(适用边界分析)
4.1 什么时候不需要图?
明确澄清:如果满足以下条件,用 YAML/JSON 甚至硬编码足矣,引入图数据库是过度设计:
- 流程节点较少,且流程拓扑固定不变;
- 只涉及单数据源;
- 任务可拆解为无状态的单轮工具调用(翻译、查天气);
- 不存在必须强制执行的前后顺序依赖。
4.2 什么时候必须引入图?
| 核心痛点 | Graph Agent 解决方案 |
|---|---|
| 动态热更新需求 | 流程逻辑与代码完全解耦。运营人员只需在图数据库中修改节点属性或增加一条边,Agent 的业务逻辑即刻生效,无需重启服务。 |
| 多源异构数据联邦 | 真实业务中,权限在 MySQL,财务在 SAP,日志在 ES。图数据库可以通过 :JOIN_ON 边维护这些不同库之间的关联键,充当超级索引。 |
| 严格的合规与风控 | 存在必须执行的链路(A → B → C)。硬编码在边上的条件构成**“合规刹车”**,彻底杜绝 LLM 幻觉导致的跳步或违规操作。 |
| 长周期任务断点续传 | 任务执行几天后中断(如等待人工审批)。只需将当前节点 ID 存在本地缓存,重启后从图的该节点精准恢复。 |
| 子图复用 | 多个流程共享同一套子流程(如"用户身份认证"),通过 :CompositeNode 引用同一子图,一处修改,处处生效。 |
4.3 与 Dify / LangGraph 工作流的对比
| 维度 | Dify / LangGraph | Graph Agent |
|---|---|---|
| 流程存储 | 配置文件 / 代码仓库(设计时固定) | 图数据库持久化(运行时实时读取) |
| 流程更新 | 需重新编辑并发布/重启 | 修改图属性后下一请求即生效,无需重启 |
| 多租户隔离 | 多份配置文件 | 不同 workflow_id 天然隔离 |
| 外部数据源映射 | 硬编码在工具节点中 | :ExternalSource + :JOIN_ON 统一管理,改图不改代码 |
| 子图复用 | 需复制粘贴或代码组合 | :CompositeNode 原生支持,入栈/出栈自动管理 |
| 异常兜底 | 需代码中 try-catch | :ON_FAILED 边在图层面定义降级路径 |
| 可审计性 | 依赖平台日志 | 图遍历路径 + State 历史完整可追溯 |
| 适用场景 | 固定流程、单数据源、快速原型 | 流程多变、多源异构、合规严控的企业级场景 |
4.4 与 LLM 原生 Skill/Plugin 的对比
| 维度 | Skill / Plugin | Graph Agent |
|---|---|---|
| 能力边界 | 原子能力(单次函数调用) | 原子能力的编排层(组合多个 Skill 成流程) |
| 状态管理 | 无状态 | 有状态(State 跨节点传递,存于本地缓存) |
| 流程确定性 | 完全依赖 LLM 自主决策 | 硬路由由编排器强制执行,铁律不可跳步 |
| 动态路由 | 改 Prompt 或代码,需发版 | 改图边即生效 |
| 数据源感知 | 工具参数固定 | :ExternalSource 实时读图获取字段映射 |
| 异常处理 | 工具内部自行处理 | :ON_FAILED 边在图层面统一编排降级 |
5. 工作流生命周期:一次完整的执行循环
在这种架构下,Agent 的一次执行循环变成了与图数据库的持续交互:
1. 状态加载
Agent 启动,编排器根据 session_id 从本地缓存加载 State
(包含 workflow_id、current_node_id、call_stack)
2. 图查询(只读)
编排器拿着 workflow_id + current_node_id 查询图数据库,
获取当前节点的完整定义(Label、属性、出边)
3. 跳转决策(核心)
根据当前节点的出边类型计算下一跳:
a. ConditionNode → 硬路由(ON_TRUE / ON_FALSE)
b. 节点执行异常 → ON_FAILED(降级/重试)
c. CompositeNode → 入栈 call_stack,进入子图
d. 多条 NEXT 边 → 软路由(LLM 选边)
e. 只有一条出边 → 顺序流转
4. 节点执行(编排器分发)
- :ExternalSource → 根据 columns/connection_ref 拉取外部数据,写入 State
- :ToolNode → 渲染 params_template,调用工具,写入 State
- :LLMNode → 渲染 system_prompt,调用 LLM,写入 State
- :ConditionNode → 解析 expression,硬路由计算下一跳
- :CompositeNode → 切换 workflow_id 为子图,current_node 设为子图 :Start
- :HumanNode → 挂起等待人工输入,保存 State
5. 状态更新(落本地缓存,不落图)
将新 current_node_id、call_stack、取数结果、工具返回全部写入本地缓存中的 State
(子图结束时:call_stack.pop(),恢复父图 workflow_id 和 current_node)
6. 返回响应
编排器将下一步动作("调用 Tool X" 或 "回复用户")返回给 Agent
关键原则:整个循环中,图数据库仅被读取,从未被写入。所有可变状态(当前节点指针、中间结果、调用栈、临时变量)均存放于外部暂存区。
6. 产品落地形态
为了将这一构想落地,不建议开发一个过度厚重的独立系统,可以采用轻量级 Hook 扩展方式,以最低的侵入成本集成到现有 Agent 中。
核心方案:Hook 扩展(集成 Claude Code / piAgent 等)
利用 Claude Code 的 Hooks 机制或 piAgent 的 Extensions 系统,在 PreToolUse(工具调用前)生命周期钩子中进行拦截。
6.1 完整执行流程
1. 拦截工具调用请求
Agent 即将执行某个工具时,PreToolUse 钩子触发,拦截请求。
2. 加载状态 + 查询图
编排器根据 session_id 从本地缓存加载 State(含 current_node_id),
再根据 workflow_id + current_node_id 查询图数据库,获取当前节点完整定义。
3. 跳转决策(编排器执行)
a. 当前节点是 ConditionNode → 硬路由解析 expression,走 ON_TRUE/ON_FALSE
b. 当前节点执行异常 → 查找 ON_FAILED 边(若存在),走降级节点
c. 当前节点是 CompositeNode → call_stack 入栈父节点信息,切换至子图
d. 当前节点有多条 NEXT 边 → 软路由,将 (target_node, hint) 列表交给 LLM 选择
e. 只有一条出边 → 顺序流转
4. 节点执行(编排器分发)
- :ExternalSource → 编排器直接执行取数(查 MySQL/SAP/ES),结果写入 State,返回 skipTool: true
- :ConditionNode → 编排器硬解析表达式,更新 current_node_id,返回 skipTool: true
- :ToolNode → 编排器渲染 params_template,注入/修改参数,放行让 Agent 执行
- :LLMNode → 编排器向 State 注入 system_prompt,引导 Agent 生成方向
- :CompositeNode → 编排器切换 workflow_id 为子图,current_node 设为子图 Start
- :HumanNode → 编排器挂起流程,等待人工输入
5. 状态回写(PostToolUse)
工具执行完毕后,PostToolUse 钩子捕获结果,写入本地缓存中的 State
(更新 current_node_id、call_stack、业务数据)
若子图到达 :End,call_stack.pop(),恢复父图执行
6. 工作流回写(用户驱动,沉淀经验)
用户执行特定命令(如 /summarize-workflow 或 /save-as-workflow),
编排器自动完成以下动作:
a. 分析当前会话的 State.history,提取工具调用序列、外部数据源访问记录
b. 识别序列中的依赖关系(A 必须在 B 之前执行),概括为通用步骤
c. 将步骤抽象为节点(:ToolNode / :ExternalSource / :LLMNode),将依赖关系抽象为边(:NEXT / :ON_FAILED)
d. 生成新工作流的 YAML/Cypher 定义,写入图数据库,生成新的 workflow_id
e. 该流程可在后续会话中被任何 Agent 引用或作为 :CompositeNode 的子图复用
至此,图既是流程的“数据源”,也是流程的“知识库”——Agent 在执行中积累的经验,可以通过用户指令直接沉淀为新的流程资产,实现“用图越多,图越聪明”的飞轮效应。
7. 返回响应
编排器将下一步动作返回给 Agent,本轮结束
6.2 优势
- 零代码侵入:不修改 Claude Code / piAgent 的主逻辑,仅通过 Hook 脚本扩展。
- 动态路由:流程变更只需改图,Hook 脚本无需重启。
- 强制性合规:即使 Agent 想跳过步骤,Hook 层也会强制拦截并纠正。
- 子图透明:
CompositeNode的入栈/出栈对 Agent 完全透明,Agent 只感知"当前要执行什么"。
辅助方案:MCP 轻量查询
编排器也可以封装成一个 execute_workflow 工具,可以将图数据库的只读查询能力暴露为 MCP Resources,供 Agent 在自主探索时参考。
例如,Agent 可以查询:
graph://workflow/{id}/current_node:了解当前在流程中的位置。graph://datasource/{id}/schema:获取外部数据源的最新字段映射(用于自己写查询语句时的参考)。
这种模式下,执行权仍在 Hook 层,MCP 只负责提供"地图浏览"功能。
7. 结语
Graph Agent 并不颠覆 LLM,而是通过经典的图论与数据库技术,为大模型的发散性思维加上了工程化的轨道。
它的本质是:
- 将确定性(流程拓扑、数据映射)从代码中剥离,以图的形态持久化存储;
- 将发散性(语义理解、内容生成)留给 LLM,让其专注擅长的事;
- 将路由控制权交给编排器,由其根据图的拓扑和硬条件做决策。
当业务满足流程多变、多源异构、合规严格、需长周期状态持久化时,Graph Agent 所体现的热更新能力、确定性路由、跨源数据联邦、子图复用、流程可审计、经验可沉淀等优势,是纯 LLM + Function Calling 或 Dify/LangGraph 等固定流程方案所无法替代的。
它不仅是 Agent 架构的一次升级,更是 Graph Engineering 在 AI 时代的全新注脚。
附注:华为云 GES Graph Skill
本文所述 Graph Agent 架构的落地,需要图数据库的稳定访问。若选用华为云图引擎服务(GES),其官方 GES Graph Access Guidance Skill 可被编码类 Agent(如 Claude Code)感知,借助 VibeCoding 快速为其他工程配置 GES 的访问能力,包括 Cypher/GQL 查询、节点/边 CRUD、Schema 管理等操作。
# 安装方式
npx clawhub install @huaweiclouddev/huawei-cloud-ges-graph
npx skills add huaweicloud/huaweicloud-skills --skill huawei-cloud-ges-graph
详情:https://skills.huaweicloud.com/detail/huawei-cloud-ges-graph
- 点赞
- 收藏
- 关注作者
评论(0)