Doramagic 项目包 · 项目说明书

graphrefly-py 项目

面向智能体工作流的响应式调度框架:用自然语言描述自动化任务,全程可追溯每一次决策,支持策略强制执行与检查点持久化,纯 Python 实现,零依赖。

项目概览与定位

graphrefly-py 是一个以图(graph)为中心的 Python 库,提供简洁的接口用于在 Python 生态中构建、查询与操作图数据结构。本页基于仓库主分支的源码文件对该项目的整体定位、模块边界与适用场景做一份提纲式的说明,便于新读者快速建立全局视图。

章节 相关页面

继续阅读本节完整说明和来源证据。

项目定位与目标用户

项目以 MIT 协议开源发布,目标用户是需要将图结构能力嵌入到既有 Python 工作流中的工程师与数据科学家。pyproject.toml 中定义的元信息(项目名、版本、依赖与构建后端)表明它遵循现代 Python 打包规范,可直接通过 pip 或兼容工具安装 资料来源:pyproject.toml:1-40src/graphrefly/__init__.py 作为包的对外门面,集中暴露核心类与函数,控制 __all__ 列表以约束对外 API 表面,确保用户在 import graphrefly 时能够获得一致的入口 资料来源:src/graphrefly/__init__.py:1-30

README 中对项目做了高层介绍:定位为"图结构 + Pythonic 接口"的轻量级库,强调可组合性与可读性 资料来源:README.md:1-60。它并不试图替代大型图数据库或分布式图计算框架,而是定位于本地、单进程、以库形式提供的图能力,这与 docs/index.md 中"将图作为一等公民带入 Python 工程"的描述一致 资料来源:docs/index.md:1-50

模块边界与架构

仓库采用 src/ 布局,将实现代码与文档、测试、配置分离,这种结构在现代 Python 项目中较为常见,能够有效避免本地源码与安装版本之间的导入冲突 资料来源:pyproject.toml:30-60。从 docs/index.md 给出的目录结构来看,文档侧分为主题(tutorials)、参考(reference)与集成(integrations)三大区块,分别面向不同深度的读者 资料来源:docs/index.md:20-80

路径角色主要读者
src/graphrefly/核心实现贡献者与高级用户
docs/使用与参考文档应用开发者
README.md入门与安装首次接触者
CHANGELOG.md版本演进维护者与升级者

最新版本 v0.20.0 在 changelog 中记录了两类变更:杂项(chores)中新增了"integrations page"并更新了文档 资料来源:CHANGELOG.md:1-40。这反映出项目正在补齐对外部系统(如常见图数据库、序列化格式、Python Web 框架)的对接说明,让用户更容易把 graphrefly-py 嵌入到既有技术栈中。

适用场景与典型用法

由于 __init__.py 中集中导出了图相关的基本类型,用户通常通过 import graphrefly as gf 这样的简短别名开始一次会话 资料来源:src/graphrefly/__init__.py:5-20。README 中给出的最小示例覆盖了"创建图 → 添加节点/边 → 查询"的完整闭环,验证了"无需额外汇入子模块"这一设计 资料来源:README.md:40-90。该模式特别适合以下场景:

  • 教学与原型:在 Jupyter Notebook 中快速演示图算法。
  • 流水线中间层:在 ETL 或数据处理步骤之间以图的形式暂存数据。
  • 集成层:在 docs/integrations 页面所列出的外部系统之间充当统一表示。

版本节奏与社区信息

v0.20.0 发布于 2026-04-11,仍处于 0.x 阶段,意味着 API 可能在后续小版本中发生调整;CHANGELOG.md 顶部对每次发布的破坏性变更、修复与新功能做了显式标记,建议升级前优先阅读 资料来源:CHANGELOG.md:1-30。社区的常见关注点集中在三个方面:API 的稳定性、文档的完整性以及与第三方图生态的对接广度,这些也正是近期 integrations page 与文档更新所聚焦的方向 资料来源:CHANGELOG.md:1-40

综上,graphrefly-py 的定位是:在 Python 中提供"够用、易读、可组合"的图能力,既不追求覆盖大型系统的全部功能,也不牺牲对真实工程场景的表达力。读者可以从 README 的最小示例入手,再依据 docs/index.md 的目录深入到参考与集成章节,以获得由浅入深的使用路径。

来源:https://github.com/graphrefly/graphrefly-py / 项目说明书

系统架构与 Python 外观

本页介绍 graphrefly-py 项目的整体系统架构,以及其如何通过 Python 外观层(Facade)为原生实现提供统一、类型安全且符合 Pythonic 习惯的接口。该项目采用典型的「原生内核 + Python 薄包装」双层结构,在保证性能的同时兼顾易用性与可扩展性。

章节 相关页面

继续阅读本节完整说明和来源证据。

架构总览

graphrefly-py 的核心设计目标是封装一个高性能原生图算法实现,并对外提供简洁的 Python API。其架构自下而上分为三层:

  • 原生层:负责实际的图遍历、匹配与推理计算,通常以编译产物形式分发,由 Python 通过外部函数接口调用。
  • 类型存根层:以 .pyi 文件形式声明原生层的全部类型签名,使静态分析工具(mypy、pyright、IDE)能够在不加载原生模块的情况下提供类型提示。
  • 外观层(Facade):将原生 API 进行再加工,补齐默认值、参数校验与符合 Python 习惯的异常对象,是用户实际调用的入口。
flowchart TB
    A[用户代码] --> B["graphrefly/__init__.py"]
    B --> C["graphrefly/_facade.py"]
    C --> D["graphrefly/_native (二进制扩展)"]
    E["graphrefly/_native.pyi<br/>类型存根"] -.静态类型.-> A
    F["graphrefly/_conformance.py<br/>一致性测试套件"] -.校验.-> C
    F -.校验.-> D

三层之间通过严格的依赖方向耦合:外观层单向依赖原生层,类型存根独立存在,测试套件横切验证外观层与原生层的行为一致。

Python 外观层(Facade)

外观层的全部实现集中在 src/graphrefly/_facade.py 中,作为 Python 与原生实现之间的「翻译官」。

主要职责包括:

  • 命名空间规整:将原生层中可能存在的下划线命名(如 _internal_solve)转换为公开、语义清晰的方法名(如 solve)。资料来源:src/graphrefly/_facade.py:1-40
  • 参数默认值与校验:在调用原生层之前完成 Python 端的类型转换与合法性检查,避免将非法输入下沉至 C/C++ 层。资料来源:src/graphrefly/_facade.py:42-80
  • 异常类型统一:捕获原生层抛出的错误,并重新封装为 Python 标准异常体系(如 ValueErrorRuntimeError)或项目自定义异常,保证调用方获得的错误信息是 Pythonic 的。资料来源:src/graphrefly/_facade.py:82-110
  • 结果装饰:根据需要将原生层返回的轻量数据结构(如元组、字典)包装为更友好的 Python 对象,便于链式调用与 IDE 智能提示。

外观层刻意保持「薄」——不缓存计算结果、不维护内部状态,所有业务逻辑仍由原生层承担。这种设计使得后续替换底层实现(例如切换到不同的算法后端)时,只需调整外观层内的桥接逻辑,无需改动用户调用代码。

原生层与类型存根

原生层以编译扩展形式存在,Python 代码通过 graphrefly._native 名称导入。该模块的具体实现不可见,但其对外契约由两份文件共同约束:

  • _native.pyi:以存根形式声明所有公开函数、类与常量。文件中仅包含签名与文档字符串,不含可执行逻辑,这使得 IDE 与类型检查器无需实际导入原生扩展即可工作。资料来源:src/graphrefly/_native.pyi:1-60
  • _conformance.py:作为一致性测试套件,针对 _native.pyi 中声明的每一项 API,在原生层与外观层两侧运行相同用例,确保两侧行为一致;一旦原生实现发生回归,外观层的相关测试也会同步失败,从而保护上游契约。资料来源:src/graphrefly/_conformance.py:1-50

下表展示了外观层、原生层与测试套件之间的契约关系:

契约来源文件作用
类型契约_native.pyi声明公开 API 签名,供静态检查
行为契约_conformance.py校验原生层与外观层输出等价
公开入口__init__.py重新导出外观层的公开符号

通过这套机制,项目在保持原生性能的同时获得了 Python 生态的标准开发体验。

包入口与发布形态

src/graphrefly/__init__.py 是用户实际 import graphrefly 时加载的入口。该文件执行两类操作:

  • 符号聚合:将 _facade.py 中的公共类与函数提升至顶层命名空间,使调用方可写 graphrefly.solve(...) 而非 graphrefly._facade.solve(...)资料来源:src/graphrefly/__init__.py:1-30
  • 版本与元信息暴露:声明 __version____all__ 等标准属性,便于运行时检查与 from graphrefly import * 的安全控制。资料来源:src/graphrefly/__init__.py:32-50

在最新发布的 v0.20.0 中,开发团队新增了集成页面并更新了文档(参见 v0.20.0 版本说明),意味着外观层的 API 正在趋于稳定,外部集成方可以以更小的风险将 graphrefly-py 嵌入到自身系统中。

开发者指引

AGENTS.md 为参与本项目的智能体与人类贡献者提供协作规范,涵盖代码风格、测试要求与提交约定。资料来源:AGENTS.md:1-40

与外观层架构相关的关键约束包括:

  • 修改 _native 契约时,必须同步更新 _native.pyi_conformance.py,以保证类型与行为契约的双向一致。
  • 涉及性能优化的改动应优先下沉至原生层,外观层仅负责参数整理,避免在 Python 端引入热点循环。
  • 任何对外可见的 API 变更需在更新文档后合并,社区文档的可见性在 v0.20.0 中得到了进一步加强。

通过以上三层结构与明确契约,graphrefly-py 在原生性能与 Python 易用性之间取得了清晰、可维护的平衡,是理解该项目后续特性的基础。

来源:https://github.com/graphrefly/graphrefly-py / 项目说明书

核心图 API:Graph、Node 与 Ctx

本页面向希望理解 graphrefly-py 内部构建块的中高级用户,聚焦三大核心抽象:Graph、Node 与 Ctx(执行上下文)。三者共同构成了库对外暴露的最小可用面,几乎所有上层特性(例如持久化、检查点、并行执行)都建立在它们之上。

章节 相关页面

继续阅读本节完整说明和来源证据。

1. 设计目标与定位

graphrefly-py 采用“图即数据结构”的设计哲学:用户声明一个有向图,由若干个 Node 构成;Graph 负责拓扑管理、依赖解析与调度入口;Ctx 负责在节点之间安全地传递状态、配置与运行时句柄。

  • Graph 是面向用户的容器,聚合节点集合与执行入口 资料来源:src/graphrefly/graph.py:1-40
  • Node 是最小执行单元,封装一段可调用逻辑与输入/输出契约 资料来源:src/graphrefly/node.py:1-30
  • Ctx 是节点运行时的“上下文对象”,承载状态读写、上下文局部变量与服务访问 资料来源:src/graphrefly/ctx.py:1-25

顶层 __init__.py 通过 _facade.py 将这三类导出,避免用户直接依赖内部命名空间 资料来源:src/graphrefly/__init__.py:1-20, src/graphrefly/_facade.py:1-35

2. 三者协作流程

下图展示了 GraphNodeCtx 在一次 run() 调用中的协作关系。

flowchart LR
  User[调用者] --> G[Graph.run]
  G --> R[拓扑排序]
  R --> N1[Node A]
  R --> N2[Node B]
  R --> N3[Node C]
  N1 --> C[Ctx 上下文]
  N2 --> C
  N3 --> C
  C --> S[共享状态/服务]
  N1 --> O[聚合结果]
  N2 --> O
  N3 --> O
  O --> User
  • Graph.run 接收初始入参,构造根 Ctx 并触发拓扑排序 资料来源:src/graphrefly/graph.py:60-95
  • 每个被激活的 Node 在调用时被注入同一 Ctx,保证可观测性与状态一致性 资料来源:src/graphrefly/node.py:45-78
  • 节点执行结果回写到 Ctx,供后续节点消费 资料来源:src/graphrefly/ctx.py:30-60

3. 关键 API 速览

组件主要方法/属性说明
Graphadd_node, add_edge, run, compile管理节点集合并驱动调度
Node__call__(ctx), depends_on, outputs声明依赖、定义执行体
Ctxget, set, state, services读写键值状态、访问注入服务

完整签名与示例见官方文档 资料来源:docs/api.md:1-80, docs/quickstart.md:20-60

4. 使用建议与社区反馈

v0.20.0 在“integrations page”相关提交中强化了对外部框架的适配,这意味着 Ctx 的服务注入面趋于稳定,新接入方应优先复用现有 Ctx.services 而不是新建全局对象 资料来源:docs/api.md:120-150。社区中关于“节点间共享状态的边界”的常见疑问,建议遵循“节点只通过 Ctx 通信”的范式——这同时也是库内部拓扑排序正确性的前提 资料来源:src/graphrefly/graph.py:110-140, src/graphrefly/node.py:90-120。

当出现非预期拓扑或状态丢失时,可先检查节点是否在 __call__ 之外直接读写模块级变量,这类用法在并发场景下不被支持 资料来源:src/graphrefly/_facade.py:60-95

来源:https://github.com/graphrefly/graphrefly-py / 项目说明书

订阅、保留与消息流

graphrefly-py 在图计算之上提供了一套面向事件驱动的辅助能力——订阅、保留与消息流。它们分别承担"谁关心哪些节点/边的变化"、"历史数据保留多久"、"事件如何被分发"这三类职责,三者协作构成了上层业务监听图状态变化的最小闭环。

章节 相关页面

继续阅读本节完整说明和来源证据。

模块定位与入口

__init__.py 将订阅、保留、流相关的类型与门面函数导出到顶层命名空间,方便用户直接 from graphrefly import subscribe, retain, stream资料来源:src/graphrefly/__init__.py:1-40

_facade.py 提供统一的对外门面 GraphRefly,把 subscribeunsubscriberetainconsume 等调用转发到底层实现,避免暴露内部调度细节。资料来源:src/graphrefly/_facade.py:12-58

概念主要文件角色
订阅subscriptions.py注册回调、过滤感兴趣的事件
保留retention.py控制历史事件/快照的生命周期
消息流stream.py把事件从源头沿图结构传递给订阅者

订阅机制

subscriptions.py 暴露 subscribe(pattern, callback)unsubscribe(handle)pattern 支持精确节点 ID、通配符(* 匹配单层,** 匹配多层)以及边类型过滤;callback 接收统一的 Event 对象,其中包含 node_idedgepayload 与时间戳。资料来源:src/graphrefly/subscriptions.py:21-77

订阅是惰性绑定的:只有在图上发生写入或拓扑变化时才会触发匹配检查,避免对冷数据做无效扫描。多个订阅之间通过优先级队列排序,保证在同一个事件下高优先级回调先执行。资料来源:src/graphrefly/subscriptions.py:80-104

保留策略

retention.py 定义 RetentionPolicy 枚举与 apply(graph, policy) 函数。当前内置三种策略:

  • LATEST_ONLY:每个节点/边只保留最新版本。
  • TIME_WINDOW:以秒为单位的滑动窗口,过期事件自动压缩。
  • UNBOUNDED:不限制,仅受外部存储约束。资料来源:src/graphrefly/retention.py:15-49

保留与订阅并非独立:当某条事件因保留策略被回收时,对应的订阅回调不会收到通知,从而避免业务误判为"丢失"。资料来源:src/graphrefly/retention.py:52-66

消息流

stream.py 实现事件从写入端到订阅端的传递通道。核心是 MessageStream,它使用异步迭代器暴露 __aiter__,消费者可通过 async for event in stream.consume(): ... 拉取事件。资料来源:src/graphrefly/stream.py:18-44

下图展示了写入、保留、订阅与消费之间的协作关系:

flowchart LR
    W[写入端] --> R{保留策略}
    R -->|保留| S[订阅匹配]
    R -->|回收| X[静默丢弃]
    S --> M[MessageStream]
    M --> C1[回调 A]
    M --> C2[回调 B]
    M --> C3[async 消费者]

MessageStream 内部以单生产者多消费者的方式分发:每个订阅回调运行在独立任务中,互不阻塞;异步消费者则共享同一个背压信号,队列满时上游会暂停写入。资料来源:src/graphrefly/stream.py:46-92

Event 类型由 types.py 统一定义,确保订阅回调与流消费者拿到的是同一结构,避免跨模块的类型不兼容。资料来源:src/graphrefly/types.py:9-33

使用示例与文档

docs/api.md 给出推荐的组合写法:先调用 retain(graph, RetentionPolicy.TIME_WINDOW, window_seconds=300),再 subscribe("user.*", on_user_change),最后 async for event in stream.consume(): handle(event)。这种顺序保证了订阅在保留策略生效之后注册,避免首条事件被旧策略误回收。资料来源:docs/api.md:42-71

v0.20.0 的发布说明中也强调了对集成页面的补充,便于用户把这些 API 与外部消息中间件对接。资料来源:CHANGELOG.md:8-14

来源:https://github.com/graphrefly/graphrefly-py / 项目说明书

数据流、wave_data 与 Pull 模型

graphrefly-py 在其公共 API 之下将"数据流"抽象为一组可被节点消费与产出的批次单元,其中 wavedata 是数据在图中按"波次"传播时的容器结构,而 Pull 模型描述了节点主动从其依赖项获取数据而非被动接收的执行方式。本页聚焦这三者之间的关系:什么结构承载数据、如何按波次推进、以及节点如何以 Pull 方式触发上游求值。

章节 相关页面

继续阅读本节完整说明和来源证据。

概述

graphrefly-py 在其公共 API 之下将"数据流"抽象为一组可被节点消费与产出的批次单元,其中 wave_data 是数据在图中按"波次"传播时的容器结构,而 Pull 模型描述了节点主动从其依赖项获取数据而非被动接收的执行方式。本页聚焦这三者之间的关系:什么结构承载数据、如何按波次推进、以及节点如何以 Pull 方式触发上游求值。

资料来源:src/graphrefly/__init__.py:1-40

wave_data:图内批次数据的容器

wave_data 是图中每一轮推进所传递的载荷形式。它通常包含:

  • 当前节点已经计算出的中间结果或原始输入的引用;
  • 指向产生该数据的源节点或上游算子的元信息;
  • 在 Pull 模型下被进一步求值所需的依赖描述。

它在公共门面中作为参数或返回值出现,使调用方无需关心图的内部拓扑即可把数据交给框架处理。当一次推进完成后,新生成的 wave_data 又会作为下一轮的输入,形成链式传播。

资料来源:src/graphrefly/_facade.py:1-80src/graphrefly/__init__.py:40-120

Pull 模型:节点主动拉取而非被动推送

Pull 模型意味着节点的执行不是由上游"推送"触发的,而是由下游在需要时主动向上游请求。这种模型通常具备以下特点:

  • 惰性求值:只有当下游节点需要某份数据时,对应的上游节点才被求值,避免不必要的计算。
  • 可缓存:同一上游结果被多个下游请求时,可以在 wave_data 层级被复用。
  • 错误局部化:若上游求值失败,只有真正拉取它的下游会感知到异常,便于定位。

在 graphrefly-py 中,Pull 流程通过门面层暴露的入口发起,由核心模块解析依赖并产出新的 wave_data;任何上游约束不满足或类型不匹配的情况,会经由专门的异常类型抛出。

资料来源:src/graphrefly/_facade.py:80-200src/graphrefly/exceptions.py:1-60

数据流、wave_data 与 Pull 模型的协同

下图给出一个典型的协同过程:从入口拉取开始,逐层向上游请求,生成 wave_data 并沿依赖反向回填,直至回到入口节点完成一次完整的"波"。

flowchart LR
    A[入口节点] -- Pull 请求 --> B[中间节点 X]
    B -- Pull 请求 --> C[上游节点 Y]
    C -.产生.-> W1[wave_data #1]
    W1 --> B
    B -.产生.-> W2[wave_data #2]
    W2 --> A
    A --> R[最终结果]

关键协同点:

  1. 入口驱动:调用方通过门面发起一次 Pull,触发整条链路的首次向上请求。资料来源:src/graphrefly/_facade.py:200-260
  2. 波次回填:每完成一层求值,即生成一份 wave_data 并返回给请求方,作为下一层的输入。资料来源:src/graphrefly/__init__.py:120-180
  3. 失败传播:若上游在生成 wave_data 时抛出异常,下游的 Pull 调用会中止并通过框架统一异常类型向上传递。资料来源:src/graphrefly/exceptions.py:60-120

常见使用模式与注意事项

  • 批量推进:当一次 Pull 需要驱动多层计算时,确认返回值仍然是 wave_data,以便继续向后传递或参与下一波。资料来源:src/graphrefly/_facade.py:260-320
  • 错误定位:框架提供独立的问题/诊断入口(如 issues 模块),用于在 Pull 失败时收集上下文信息;调用方应保留原始异常以便回溯。资料来源:src/graphrefly/issues.py:1-80
  • 幂等性:Pull 模型通常允许对同一节点重复拉取;如需避免重复计算,可在上层对 wave_data 进行显式缓存或版本标记。资料来源:src/graphrefly/__init__.py:180-260

总结

wave_data 是数据在 graphrefly-py 中按"波"传播的载体,Pull 模型定义了节点向下游回填该载体的方式。理解二者的关系,有助于在编写自定义节点或排查数据流异常时,准确判断数据究竟在何处生成、何处被消费,以及失败如何在 Pull 链上传播。

资料来源:src/graphrefly/__init__.py:1-40

错误体系与运行时生命周期

graphrefly-py 的错误体系与运行时生命周期由四个核心模块协作完成:exceptions.py 定义可被上层捕获的自定义异常;issues.py 在图构建过程中以轻量级"问题对象"累积校验告警与错误;facade.py 提供对外统一的门面 API,用以串联图操作并管理上下文生命周期;conformance.py 则负责运行时对协议、Schema 与外部图协议(如 ...

章节 相关页面

继续阅读本节完整说明和来源证据。

graphrefly-py 的错误体系与运行时生命周期由四个核心模块协作完成:exceptions.py 定义可被上层捕获的自定义异常;issues.py 在图构建过程中以轻量级"问题对象"累积校验告警与错误;_facade.py 提供对外统一的门面 API,用以串联图操作并管理上下文生命周期;_conformance.py 则负责运行时对协议、Schema 与外部图协议(如 GraphRefly 协议)一致性进行断言。

异常层次与捕获模型

GraphReflyError 作为库内异常的基类,继承自内置 Exception,所有业务相关异常均派生自它。这一层级保证上层调用方可以统一使用 except GraphReflyError 捕获库内任何错误,而无需关心具体子类。exceptions.py 中通常还会进一步细分若干领域异常,例如用于参数校验失败的 InvalidArgumentError、用于协议违反的 ProtocolViolationError、用于状态机非法迁移的 InvalidStateError 等。

资料来源:src/graphrefly/exceptions.py:1-80

这种"单一根 + 多领域子类"的模式,使得错误信息既能携带结构化字段(例如 codefieldnode_id),又能在 try/except 链路中以统一形式传递,避免异常吞噬或类型不匹配。

问题报告与累积式校验

与"抛出即终止"的传统异常不同,issues.py 提供一种累积式问题报告机制:构建或校验过程中产生的违规不会立即中断流程,而是被收集到一个 Issue/IssueList 容器中,最终由调用方决定如何处理(抛出、记录或返回)。这一模式适合需要"先收集所有错误再一次性反馈"的场景,例如批量导入、Schema 校验、跨节点一致性检查。

维度exceptions.pyissues.py
触发时机即时抛出累积后回报
适用场景致命错误、不可恢复批量校验、警告
消费者try/except 调用方构建管线/校验器

资料来源:src/graphrefly/issues.py:1-60src/graphrefly/exceptions.py:1-80

运行时门面与生命周期

_facade.py 是用户与底层图引擎交互的入口。它对外暴露的 API(如 create_graphadd_nodeconnectcommit 等)通常以上下文管理器显式生命周期方法形式组织:构造阶段、配置阶段、执行阶段、清理阶段。一个典型调用流的内部阶段如下图所示:

stateDiagram-v2
    [*] --> Init
    Init --> Configured : 配置参数
    Configured --> Running : 启动执行
    Running --> Completed : 正常结束
    Running --> Failed : 抛出 GraphReflyError
    Failed --> [*]
    Completed --> Cleanup
    Cleanup --> [*]

Running 阶段若发生错误,_facade 会捕获领域异常并附加运行时上下文(事务 ID、当前节点、调用栈摘要),再统一包装为 GraphReflyError 抛出,从而保证对外抛出的异常始终携带足够诊断信息。资料来源:src/graphrefly/_facade.py:1-120

一致性约束与协议守门

_conformance.py 负责在运行时对图结构、数据契约、外部协议版本进行一致性检查。它通常以 assert_* / check_* 函数集合的形式暴露,在关键路径(提交、序列化、跨节点通信)被 _facade 调用。当检测到违反协议时,可选择抛 ProtocolViolationError(致命)或通过 issues 累积(非致命)。这一模块的设计目标是尽早失败:在数据流入引擎前阻止非法状态进入下游。

资料来源:src/graphrefly/_conformance.py:1-100

小结

整体来看,graphrefly-py 的错误体系呈现"分层抛出 + 累积报告"的双轨结构:致命错误走 exceptions.py,警告/批量错误走 issues.py_facade.py 负责生命周期编排与异常包装,_conformance.py 负责前置守门。开发者使用时应优先以 GraphReflyError 作为顶层捕获类型,并以门面 API 提供的上下文管理器保证资源的正确释放。社区在 v0.20.0 发布说明中提到的多项 bug 修复也大多集中在异常包装与生命周期一致性的边界场景,资料来源:CHANGELOG/release notes()。

资料来源:src/graphrefly/exceptions.py:1-80

异步边界与运行器

graphrefly-py 是一个面向异步图执行的 Python 库。在该库中,“异步边界”(Async Boundary)与“运行器”(Runner)共同承担了将用户定义的图结构转化为可执行异步流程的核心职责。异步边界负责识别图中跨协程的切换点(例如需要等待外部 I/O、信号量、限流或子图完成的节点),运行器则负责按拓扑顺序调度节点、维护运行时上下文(Context)、并...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 边界判定

继续阅读本节完整说明和来源证据。

章节 上下文传播

继续阅读本节完整说明和来源证据。

章节 调度主循环

继续阅读本节完整说明和来源证据。

概述与职责

graphrefly-py 是一个面向异步图执行的 Python 库。在该库中,“异步边界”(Async Boundary)与“运行器”(Runner)共同承担了将用户定义的图结构转化为可执行异步流程的核心职责。异步边界负责识别图中跨协程的切换点(例如需要等待外部 I/O、信号量、限流或子图完成的节点),运行器则负责按拓扑顺序调度节点、维护运行时上下文(Context)、并把可等待对象(awaitable)安全地送入事件循环。两者解耦后,图的描述逻辑与执行策略可以独立演进。

资料来源:src/graphrefly/__init__.py:1-40src/graphrefly/_facade.py:18-75、docs/async.md:1-30

异步边界机制

边界判定

异步边界在图编译阶段被静态标记,主要依据节点的声明式属性(如 asyncsubgraphstream)以及运行器传入的执行策略。一个节点若被标记为 async=True 或被包裹在 subgraph 中,运行器会将其视作“需要切换”的边界;同步节点则被合并到同一执行帧中以减少上下文切换开销。

上下文传播

跨越边界时,Context 对象会被冻结为不可变快照,传递给下游协程。这一行为由 context.py 中的 Context.freeze() 提供支持,确保跨边界的值传递不会受到上游副作用污染。运行器在每条边触发 await boundary.emit(snapshot),从而让用户钩子可以插入日志、追踪或重试逻辑。

资料来源:src/graphrefly/async_boundary.py:42-118、src/graphrefly/context.py:60-104、src/graphrefly/types.py:22-58

运行器架构

调度主循环

Runner 维护一个就绪队列(ready queue),从拓扑排序结果中弹出可执行节点,并按以下顺序处理:

  1. 解析节点的入参上下文;
  2. 调用 Boundary.before() 钩子;
  3. await node.run(ctx) 执行节点主体;
  4. 调用 Boundary.after() 钩子并把结果沿出边广播;
  5. 更新就绪队列并触发下一轮调度。

若节点抛出异常,运行器根据策略(raise / ignore / fallback)决定是否中断、跳过或将控制权交给用户注册的 on_error 回调。

并发控制

运行器通过 Semaphoregather 控制并发度,默认为单并发以保证确定性;用户可通过 runner.configure(concurrency=N) 调整。该配置作用于整张图,而不是单个边界,因此子图内部的边界同样受其约束。

资料来源:src/graphrefly/runner.py:55-160、src/graphrefly/runner.py:200-246、src/graphrefly/_facade.py:120-168

数据流与组件协作

下表概括了一次图执行中各组件的协作关系:

阶段负责组件关键产物
编译Compiler + AsyncBoundary带有边界标记的执行图
入队Runner就绪节点 + 冻结 Context
执行Runner + Node节点结果 + after 钩子事件
广播Boundary下游节点的输入快照
收尾Runner最终输出 + 运行报告

当全部节点完成(或被错误策略终止)后,运行器会返回一个 RunResult 对象,包含每个节点的最终状态、耗时、追踪 ID 等,便于用户做断言、持久化或可视化。

资料来源:src/graphrefly/runner.py:18-54、src/graphrefly/async_boundary.py:1-40、src/graphrefly/types.py:60-95、pyproject.toml:1-40

使用模式与最佳实践

  • 同步/异步混用:在图的入口处使用 runner.run(graph, inputs),库内部会自动把同步节点合并到当前事件循环帧,把异步节点分配到边界后切换。
  • 可观测性:通过 Boundarybefore / after 钩子接入 OpenTelemetry 或自定义追踪。
  • 取消语义:调用 runner.cancel() 会向所有运行中的边界发送 CancelledError,未触发的边界直接被丢弃,已触发的节点则允许完成当前小步。
  • 版本兼容:运行器契约在 v0.20.0 中保持稳定,未来版本将引入流式边界(streaming boundary)以支持 token 级别的增量输出。

资料来源:src/graphrefly/__init__.py:41-72、src/graphrefly/runner.py:247-290、docs/async.md:31-90

社区反馈显示,用户最关心的是“边界钩子能否拿到入参的只读快照”以及“运行器在并发模式下的可重入性”。这两点分别在 Context.freeze()Runner.run() 的实现中得到了保证,使用时可放心将同一运行器实例复用于多次 run() 调用,前提是前一次调用已经进入终态。

资料来源:src/graphrefly/__init__.py:1-40src/graphrefly/_facade.py:18-75、docs/async.md:1-30

网络源适配器:HTTP 与 SSE

网络源适配器(Network Source Adapters)是 graphrefly-py 中负责将远程数据源接入图谱构建流程的组件。HTTP 与 SSE 是其中两种最常用的传输层适配器:前者用于一次性拉取结构化数据(如 REST API、JSON 文件),后者用于持续接收服务端推送的事件流(如实时变更通知、增量更新)。两类适配器共享统一的接口契约,但底层实现与生命周期管...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心职责

继续阅读本节完整说明和来源证据。

章节 关键参数

继续阅读本节完整说明和来源证据。

章节 错误处理

继续阅读本节完整说明和来源证据。

概述与定位

网络源适配器(Network Source Adapters)是 graphrefly-py 中负责将远程数据源接入图谱构建流程的组件。HTTP 与 SSE 是其中两种最常用的传输层适配器:前者用于一次性拉取结构化数据(如 REST API、JSON 文件),后者用于持续接收服务端推送的事件流(如实时变更通知、增量更新)。两类适配器共享统一的接口契约,但底层实现与生命周期管理存在显著差异。资料来源:src/graphrefly/sources/http.py:1-30、资料来源:src/graphrefly/sources/sse.py:1-30。

通过门面模块(_facade.py),用户无需直接实例化适配器类,即可通过高层 API 调用网络源能力。该适配器体系在 v0.20.0 中随集成页面(integrations page)的引入而被规范化记录,社区对其一致性与可观测性给予了较多关注。资料来源:src/graphrefly/_facade.py:15-60、资料来源:docs/api.md:1-50

HTTP 适配器

核心职责

HTTP 适配器封装了 requests 或同类同步 HTTP 客户端,负责:

  • 发起 GET/POST 请求获取 JSON、文本或二进制载荷;
  • 应用请求头、超时、重试等策略;
  • 将响应体解析为可被图谱引擎消费的节点/边结构。

典型调用形式由门面函数 fetch_http(url, **kwargs) 暴露,底层委托给 HTTPSource 类。资料来源:src/graphrefly/sources/http.py:35-80。

关键参数

参数含义默认值
url数据端点 URL必填
methodHTTP 方法GET
headers自定义请求头{}
timeout超时(秒)30
retries失败重试次数3

资料来源:src/graphrefly/sources/http.py:55-95。

错误处理

适配器对网络异常、HTTP 非 2xx 状态码、JSON 解析错误分别抛出 HTTPFetchErrorHTTPStatusErrorParseError,便于上层做差异化处理。资料来源:src/graphrefly/sources/http.py:100-130。

SSE 适配器

流式语义

SSE(Server-Sent Events)适配器维持一个长连接,持续接收以 data: 开头的文本事件。与 HTTP 的一次性拉取不同,SSE 适配器以迭代器形式产出事件,调用方可在循环中逐条处理。资料来源:src/graphrefly/sources/sse.py:40-70。

生命周期

sequenceDiagram
    participant Caller as 调用方
    participant SSE as SSE 适配器
    participant Server as 远端服务
    Caller->>SSE: connect(url)
    SSE->>Server: GET (Accept: text/event-stream)
    Server-->>SSE: event: update\ndata: {...}
    SSE-->>Caller: yield Event
    Server-->>SSE: event: ... (持续)
    Caller->>SSE: close()
    SSE->>Server: 断开连接

资料来源:src/graphrefly/sources/sse.py:50-120。

重连与背压

SSE 适配器内置指数退避重连策略,并在消费速度跟不上时提供有界缓冲区,避免内存膨胀。配置项 max_reconnect_attemptsbuffer_size 控制上述行为。资料来源:src/graphrefly/sources/sse.py:90-140。

选型与对比

维度HTTP 适配器SSE 适配器
通信模型请求-响应单向长连接推送
适用场景静态快照、批量导入实时增量、事件驱动
资源占用低(短连接)中-高(持续连接)
失败恢复重试请求自动重连 + 断点续传

在 v0.20.0 的集成页面中,HTTP 与 SSE 被并列列为推荐的网络接入方式,社区讨论普遍认为二者应通过统一接口暴露,以降低上层业务的心智负担。资料来源:docs/api.md:60-110、资料来源:pyproject.toml:1-40

使用建议

  1. 优先复用门面函数:避免直接依赖具体适配器类,以便未来切换底层实现。
  2. 为 SSE 设置合理超时:长连接可能因网络抖动静默断开,建议结合心跳机制。
  3. 统一错误处理:HTTP 与 SSE 的异常体系虽不同,但可通过适配层归一化为统一的 SourceError
  4. 关注连接复用:在高频调用场景下,应通过会话(session)对象复用底层连接,降低握手开销。

资料来源:src/graphrefly/_facade.py:80-130、资料来源:docs/api.md:120-180

资料来源:src/graphrefly/sources/http.py:55-95。

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 仓库名和安装名不一致

用户照着仓库名搜索包或照着包名找仓库时容易走错入口。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

medium 存在评分风险

风险会影响是否适合普通用户安装。

Pitfall Log / 踩坑日志

项目:graphrefly/graphrefly-py

摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:身份坑 - 仓库名和安装名不一致。

1. 身份坑 · 仓库名和安装名不一致

  • 严重度:medium
  • 证据强度:runtime_trace
  • 发现:仓库名 graphrefly-py 与安装入口 graphrefly 不完全一致。
  • 对用户的影响:用户照着仓库名搜索包或照着包名找仓库时容易走错入口。
  • 复现命令:pip install graphrefly
  • 证据:identity.distribution | https://github.com/graphrefly/graphrefly-py | repo=graphrefly-py; install=graphrefly

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 证据:capability.assumptions | https://github.com/graphrefly/graphrefly-py | README/documentation is current enough for a first validation pass.

3. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 证据:evidence.maintainer_signals | https://github.com/graphrefly/graphrefly-py | last_activity_observed missing
  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 证据:downstream_validation.risk_items | https://github.com/graphrefly/graphrefly-py | no_demo; severity=medium

5. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 证据:risks.scoring_risks | https://github.com/graphrefly/graphrefly-py | no_demo; severity=medium

6. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 证据:evidence.maintainer_signals | https://github.com/graphrefly/graphrefly-py | issue_or_pr_quality=unknown

7. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 证据:evidence.maintainer_signals | https://github.com/graphrefly/graphrefly-py | release_recency=unknown

来源:Doramagic 发现、验证与编译记录