Canvas 引擎与 DSL
Canvas 引擎与 DSL
相关源文件
本章引用的主要源码文件:
agent/canvas.pyagent/component/agent_with_tools.pyagent/component/base.pyagent/component/categorize.pyagent/component/llm.pyagent/tools/base.pycommon/mcp_tool_call_conn.pyrag/app/picture.pyrag/flow/chunker/__init__.pyrag/flow/chunker/schema.pyrag/flow/parser/parser.pyrag/flow/parser/pdf_chunk_metadata.pyrag/flow/parser/utils.pyrag/flow/tests/dsl_examples/general_pdf_all.jsonrag/flow/tokenizer/schema.pyrag/flow/tokenizer/tokenizer.pyrag/prompts/generator.pyweb/src/pages/agent/canvas/edge/index.tsxweb/src/pages/agent/canvas/node/handle.tsxweb/src/pages/agent/constant/pipeline.tsxweb/src/pages/agent/form/parser-form/common-form-fields.tsxweb/src/pages/agent/form/parser-form/index.tsxweb/src/pages/agent/form/parser-form/pdf-form-fields.tsxweb/src/pages/agent/form/parser-form/spreadsheet-form-fields.tsxweb/src/pages/agent/form/parser-form/text-html-form-fields.tsxweb/src/pages/agent/form/parser-form/word-form-fields.tsxweb/src/pages/agent/store.tsweb/src/pages/agent/utils.ts
Canvas 引擎是 RAGFlow 的工作流执行系统,它通过基于图的领域特定语言(DSL)来编排 AI 智能体的交互。本文档涵盖了 Graph 和 Canvas 类的实现、DSL 结构、变量解析以及工作流持久化机制。
DSL 结构
Canvas DSL 是一种基于 JSON 的模式,它定义了工作流的完整状态和连接关系。每个 canvas 都表示为一个可序列化和存储的 DSL 对象。
核心 DSL 模式
DSL 遵循在 agent/canvas.py:43-82 中定义的以下结构:
{
"components": {
"begin": {
"obj": {
"component_name": "Begin",
"params": {}
},
"downstream": ["retrieval_0"],
"upstream": []
},
"retrieval_0": {
"obj": {
"component_name": "Retrieval",
"params": {}
},
"downstream": ["generate_0"],
"upstream": ["begin"]
}
},
"history": [],
"path": ["begin"],
"retrieval": {"chunks": [], "doc_aggs": []},
"globals": {
"sys.query": "",
"sys.user_id": "tenant_id",
"sys.conversation_turns": 0,
"sys.files": []
}
}
DSL 字段:
| 字段 | 类型 | 用途 |
|---|---|---|
components | 对象 | 组件 ID 到其定义和图连接关系的映射 agent/canvas.py:97 |
history | 数组 | 以角色/内容对形式存储的对话历史 agent/canvas.py:72 |
path | 数组 | 当前执行路径,跟踪组件 ID agent/canvas.py:111 |
retrieval | 对象 | 存储检索到的片段和文档聚合结果 agent/canvas.py:74 |
globals | 对象 | 所有组件均可访问的系统级变量 agent/canvas.py:75-80 |
组件定义: components 对象中的每个条目包含:
obj:组件实例数据,包含component_name和paramsagent/canvas.py:48-51。downstream:后续组件的 ID 列表agent/canvas.py:52。upstream:前置组件的 ID 列表agent/canvas.py:53。
来源: agent/canvas.py:43-111
Canvas 和 Graph 类层次结构
类图:自然语言空间到代码实体空间
此图将概念上的工作流实体映射到实现它们的特定 Python 类和方法。
来源: agent/canvas.py:43-838, agent/component/base.py:40-188
Graph 类实现
Graph 类 agent/canvas.py:43-281 提供了基础的图基础设施:
关键职责:
- DSL 加载:
load()方法agent/canvas.py:96-111实例化组件对象。它使用component_class(name + "Param")创建参数对象,并使用component_class(name)创建组件本身agent/canvas.py:101-109。 - 变量解析:使用正则表达式模式解析诸如
{sys.query}或{component_id@output}之类的表达式agent/canvas.py:168-193。 - 任务管理:跟踪执行状态,并通过
task_id处理取消操作agent/canvas.py:91。它通过has_canceled(self.task_id)监控取消状态agent/canvas.py:35。
Canvas 类实现
Canvas 类 agent/canvas.py:283-838 扩展了 Graph,用于处理特定于对话的逻辑:
对话上下文:
- 历史管理:
get_history(window_size)检索最近 $N$ 轮的对话agent/canvas.py:330-341。 - 全局变量:管理
sys.*变量,包括sys.query、sys.user_id和sys.filesagent/canvas.py:286-293。 - 引用跟踪:
add_reference()存储检索到的片段,用于生成引用agent/canvas.py:756-764。它使用rag.prompts.generator中的chunks_format来规范化片段数据agent/canvas.py:40。
来源: agent/canvas.py:43-111, 168-193, 283-341, 756-764, rag/prompts/generator.py:40-63
执行模型
Canvas 引擎使用基于路径的执行模型,工作流通过组件的有向图进行推进。
组件实例化与校验
在 load() 期间,引擎会对组件参数进行严格校验:
- 它使用
component_class工厂获取参数类agent/canvas.py:101。 - 它使用 DSL 中的值更新参数对象
agent/canvas.py:103。 - 它调用
param.check()agent/canvas.py:105。例如,LLMParam的检查会确保提供了模型 ID 和提示词agent/component/llm.py:53-60。
动态路由与控制流
执行并非严格线性的。某些组件可以动态改变路径:
| 组件 | 逻辑实体 | 行为 |
|---|---|---|
Categorize | Categorize agent/component/categorize.py:99 | 分析输入,并根据大语言模型(LLM)分类将 _next 输出设置为特定的下游分支 agent/component/categorize.py:157-158。 |
Agent | Agent agent/component/agent_with_tools.py:74 | 实现 ReAct 循环,通过 LLMToolPluginCallSession 和 MCPToolCallSession 调用工具,直到得出最终答案 agent/component/agent_with_tools.py:110-113。 |
LLM | LLM agent/component/llm.py:83 | 标准聊天组件,根据系统提示词和用户提示词生成响应 agent/component/llm.py:118-127。 |
来源: agent/canvas.py:96-111, agent/component/llm.py:53-60, agent/component/agent_with_tools.py:110-113, agent/component/categorize.py:157-158
变量与数据流
RAGFlow 使用基于字符串的插值系统在组件之间传递数据。
变量解析逻辑
get_variable_value 方法 agent/canvas.py:195-237 解析三种类型的变量:
- 系统变量:以
sys.为前缀(例如sys.query)。 - 环境变量:以
env.为前缀。 - 组件输出:使用
@语法(例如retrieval_0@content)。
# 组件输出的内部解析 [agent/canvas.py:199-202]
cpn_id, var_nm = exp.split("@")
cpn = self.get_component(cpn_id)
# ...
root_val = cpn["obj"].output(root_key)
数据流图:变量插值
此图展示了数据如何从系统流入组件,以及如何通过 Canvas 引擎在组件之间流动。
来源: agent/canvas.py:168-237, agent/component/base.py:284-301
持久化与序列化
工作流以 DSL 字符串的形式存储在数据库中,并在运行时重新构建。
序列化与版本控制
Graph.__str__ 方法 agent/canvas.py:113-132 处理将图序列化回 DSL JSON 字符串的过程。它会遍历所有已加载的组件,并调用它们各自的 __str__ 方法,这些方法会使用 ComponentParamBase 中的 as_dict() 方法 agent/component/base.py:99-125。
为确保数据完整性,RAGFlow 实现了一个规范化步骤:
- 规范化:在加载 DSL 之前,通过
normalize_chunker_dsl对其进行规范化,以处理遗留模式的转换agent/canvas.py:89。
前端 DSL 构建
前端使用 web/src/pages/agent/utils.ts 中的工具函数,将可视化图形转换为后端期望的 DSL。
| 工具函数 | 用途 |
|---|---|
buildComponentDownstreamOrUpstream | 计算节点的 upstream 和 downstream 列表 web/src/pages/agent/utils.ts:56-86。 |
buildAgentTools | 递归收集 Agent 组件的工具配置 web/src/pages/agent/utils.ts:104-134。 |
buildCategorize | 格式化 category_description 映射以及分类分支关联的下游 ID web/src/pages/agent/utils.ts:140-163。 |
来源: agent/canvas.py:113-132, agent/component/base.py:99-125, web/src/pages/agent/utils.ts:56-163