分析时间: 2026-02-12
目的: 验证当前数据库设计是否支持规则引擎DSL需求
@_call_verify_func_int(expected_output_id)
def calculate_score(标准分_ids: list[id]) -> str:
return sum(标准分_ids)
@_call_verify_func_notnone()
def build_one_five_section(one_two_ch: id, one_tree_ch: id, calculate_score_callback: ref, prompt: str) -> str:
one_two_ch_str = _call_export_resource_str(one_two_ch)
one_tree_ch_str = _call_export_resource_str(one_tree_ch)
return _call_ai_assistant(system=prompt, user='%s\n%s\n标准分:%s' % (one_two_ch_str, one_tree_ch_str, calculate_score_callback()))
@_call_verify_func_notnone()
def build_one_full_chapter(one_two_ch: id, one_tree_ch: id, one_four_ch: id, one_five_ch_callback: ref):
one_two_ch_str = _call_export_resource_str(one_two_ch)
one_tree_ch_str = _call_export_resource_str(one_tree_ch)
one_four_ch_str = _call_export_resource_str(one_four_ch)
return '%s\n%s\n%s\n%s' % (one_two_ch_str, one_tree_ch_str, one_four_ch_str, one_five_ch_callback())
# 参数配置
one_two_ch_id=12578
one_tree_ch_id=12389
one_four_ch_id=13456
score_expected_output_id=120234989
standard_item1_score_id=234808
standard_item2_score_id=234874
standard_item3_score_id=2234
standard_item4_score_id=12398
section_prompt='从原文生成100以内字数的摘要,并说明标准分'
# 执行链
score_ref = &calculate_score([standard_item1_score_id, standard_item2_score_id, standard_item3_score_id, standard_item4_score_id], expected_output_id=score_expected_output_id)
section_ref = &build_one_five_section(one_two_ch_id, one_tree_ch_id, score_ref, prompt=section_prompt)
one_full_chapter = build_one_full_chapter(one_two_ch_id, one_tree_ch_id, one_four_ch_id, section_ref)
return one_full_chapter
| 特性 | 说明 | 示例 |
|---|---|---|
| 函数定义 | 支持自定义函数,带装饰器 | @_call_verify_func_int |
| 参数类型 | id, list[id], ref, str | 标准分_ids: list[id] |
| 内置函数 | 导出资源、AI调用 | _call_export_resource_str() |
| 函数引用 | 创建和调用函数引用 | &calculate_score(...) |
| 依赖链 | 函数间依赖关系 | score_ref → section_ref → result |
| 输出验证 | 验证输出类型和非空 | expected_output_id |
-- 规则节点属性
node_properties:
- rule_type: VARCHAR # 规则类型(direct_entity/extraction/llm/aggregate)
- action_type: VARCHAR # 动作类型(use_entity_value/regex_extract/llm_generate)
- description: TEXT # 规则描述
- action_config: JSONB # 动作配置(JSON格式)
- dsl_content: TEXT # DSL内容(预留字段)
- last_output_text: TEXT # 最后输出文本
- last_output_json: JSONB # 最后输出JSON
- last_run_status: VARCHAR # 最后运行状态
- last_run_time: TIMESTAMP # 最后运行时间
- last_run_error: TEXT # 最后运行错误
-- 规则关系
PROJECT --HAS_RULE--> RULE # 项目包含规则
RULE --FOR_ELEMENT--> ELEMENT # 规则对应要素
RULE --INPUT_FROM--> ENTITY # 规则输入来源(实体)
RULE --INPUT_FROM--> ATTACHMENT # 规则输入来源(附件)
RULE --INPUT_FROM--> VALUE # 规则输入来源(其他值)
-- 输入边属性
edge_properties:
- input_key: VARCHAR # 输入参数名(如 'entity')
- input_type: VARCHAR # 输入类型(entity_ref/attachment_ref/value_ref)
- input_name: VARCHAR # 输入名称(显示用)
- fixed_value: TEXT # 固定值(可选)
| DSL特性 | 当前设计 | 说明 |
|---|---|---|
| 节点ID引用 | ✅ 支持 | INPUT_FROM 边 + input_type='entity_ref' |
| 输入参数 | ✅ 支持 | edge_properties.input_key |
| 输出存储 | ✅ 支持 | last_output_text, last_output_json |
| 规则描述 | ✅ 支持 | description 字段 |
| 执行状态 | ✅ 支持 | last_run_status, last_run_time |
| DSL特性 | 当前设计 | 问题 |
|---|---|---|
| 函数定义 | ❌ 不支持 | 没有存储函数定义的结构 |
| 函数引用 | ❌ 不支持 | 没有 RULE --DEPENDS_ON--> RULE 关系 |
| 参数类型 | ❌ 不完整 | 只有 input_type,没有详细类型定义 |
| 装饰器/验证 | ❌ 不支持 | 没有存储验证规则的字段 |
| DSL代码 | ⚠️ 部分支持 | 有 dsl_content 字段,但未定义结构 |
| 执行顺序 | ❌ 不支持 | 没有依赖关系的拓扑排序机制 |
| 输出验证 | ❌ 不支持 | 没有 expected_output_id 机制 |
核心思路: 在当前图数据库基础上扩展,支持DSL特性
-- 不需要新增节点类型,RULE节点足够
INSERT INTO edge_types (type_code, type_name, from_node_type, to_node_type, description) VALUES
('DEPENDS_ON', '依赖规则', 'RULE', 'RULE', '规则依赖关系(用于函数引用)'),
('VALIDATES_TO', '验证输出', 'RULE', 'VALUE', '规则验证输出到指定要素值');
-- 新增属性
ALTER TABLE node_properties ADD COLUMN IF NOT EXISTS prop_int BIGINT;
-- 规则节点新增属性
node_properties:
- rule_type: VARCHAR # 规则类型
- 'function_def' # 函数定义
- 'direct_entity' # 直接引用实体
- 'extraction' # 正则提取
- 'llm' # LLM生成
- 'aggregate' # 聚合计算
- function_name: VARCHAR # 函数名(如 'calculate_score')
- function_params: JSONB # 函数参数定义
{
"标准分_ids": {"type": "list[id]", "required": true},
"expected_output_id": {"type": "id", "required": false}
}
- function_body: TEXT # 函数体(DSL代码)
- return_type: VARCHAR # 返回类型(str/int/float/json)
- validators: JSONB # 验证器配置
[
{"type": "verify_int", "target_id": 120234989},
{"type": "verify_notnone"}
]
- execution_order: INT # 执行顺序(拓扑排序后的序号)
-- 输入边属性扩展
edge_properties:
- input_key: VARCHAR # 参数名(如 'one_two_ch')
- input_type: VARCHAR # 输入类型
- 'id' # 单个节点ID
- 'list[id]' # 节点ID列表
- 'ref' # 函数引用
- 'str' # 字符串
- 'int' # 整数
- input_value_type: VARCHAR # 值类型(node_ref/rule_ref/literal)
- input_value: TEXT # 字面值(如 prompt字符串)
- input_value_json: JSONB # 复杂值(如ID列表)
- sort_order: INT # 参数顺序
-- 示例:calculate_score 函数
INSERT INTO nodes (id, node_type, node_key, name, status) VALUES
(700, 'RULE', 'func:calculate_score', 'calculate_score函数', 'active');
INSERT INTO node_properties (node_id, prop_key, prop_value, prop_json) VALUES
(700, 'rule_type', 'function_def', NULL),
(700, 'function_name', 'calculate_score', NULL),
(700, 'function_params', NULL, '{
"标准分_ids": {"type": "list[id]", "required": true}
}'),
(700, 'function_body', 'return sum(标准分_ids)', NULL),
(700, 'return_type', 'int', NULL),
(700, 'validators', NULL, '[{"type": "verify_int", "target_id": 120234989}]');
-- 输入:标准分ID列表
INSERT INTO edges (id, edge_type, from_node_id, to_node_id, sort_order) VALUES
(2000, 'INPUT_FROM', 700, 234808, 1),
(2001, 'INPUT_FROM', 700, 234874, 2),
(2002, 'INPUT_FROM', 700, 2234, 3),
(2003, 'INPUT_FROM', 700, 12398, 4);
INSERT INTO edge_properties (edge_id, prop_key, prop_value) VALUES
(2000, 'input_key', '标准分_ids'),
(2000, 'input_type', 'list[id]'),
(2000, 'input_value_type', 'node_ref'),
(2001, 'input_key', '标准分_ids'),
(2001, 'input_type', 'list[id]'),
(2001, 'input_value_type', 'node_ref'),
(2002, 'input_key', '标准分_ids'),
(2002, 'input_type', 'list[id]'),
(2002, 'input_value_type', 'node_ref'),
(2003, 'input_key', '标准分_ids'),
(2003, 'input_type', 'list[id]'),
(2003, 'input_value_type', 'node_ref');
-- 示例:build_one_five_section 函数
INSERT INTO nodes (id, node_type, node_key, name, status) VALUES
(701, 'RULE', 'func:build_one_five_section', 'build_one_five_section函数', 'active');
INSERT INTO node_properties (node_id, prop_key, prop_value, prop_json) VALUES
(701, 'rule_type', 'function_def', NULL),
(701, 'function_name', 'build_one_five_section', NULL),
(701, 'function_params', NULL, '{
"one_two_ch": {"type": "id", "required": true},
"one_tree_ch": {"type": "id", "required": true},
"calculate_score_callback": {"type": "ref", "required": true},
"prompt": {"type": "str", "required": true}
}'),
(701, 'function_body', 'one_two_ch_str = _call_export_resource_str(one_two_ch)\none_tree_ch_str = _call_export_resource_str(one_tree_ch)\nreturn _call_ai_assistant(system=prompt, user=''%s\\n%s\\n标准分:%s'' % (one_two_ch_str, one_tree_ch_str, calculate_score_callback()))', NULL),
(701, 'return_type', 'str', NULL),
(701, 'validators', NULL, '[{"type": "verify_notnone"}]');
-- 输入1: one_two_ch (节点ID)
INSERT INTO edges (id, edge_type, from_node_id, to_node_id, sort_order) VALUES
(2010, 'INPUT_FROM', 701, 12578, 1);
INSERT INTO edge_properties (edge_id, prop_key, prop_value) VALUES
(2010, 'input_key', 'one_two_ch'),
(2010, 'input_type', 'id'),
(2010, 'input_value_type', 'node_ref');
-- 输入2: one_tree_ch (节点ID)
INSERT INTO edges (id, edge_type, from_node_id, to_node_id, sort_order) VALUES
(2011, 'INPUT_FROM', 701, 12389, 2);
INSERT INTO edge_properties (edge_id, prop_key, prop_value) VALUES
(2011, 'input_key', 'one_tree_ch'),
(2011, 'input_type', 'id'),
(2011, 'input_value_type', 'node_ref');
-- 输入3: calculate_score_callback (函数引用)
INSERT INTO edges (id, edge_type, from_node_id, to_node_id, sort_order) VALUES
(2012, 'DEPENDS_ON', 701, 700, 3);
INSERT INTO edge_properties (edge_id, prop_key, prop_value) VALUES
(2012, 'input_key', 'calculate_score_callback'),
(2012, 'input_type', 'ref'),
(2012, 'input_value_type', 'rule_ref');
-- 输入4: prompt (字符串字面值)
INSERT INTO edge_properties (edge_id, prop_key, prop_value) VALUES
(2013, 'input_key', 'prompt'),
(2013, 'input_type', 'str'),
(2013, 'input_value_type', 'literal'),
(2013, 'input_value', '从原文生成100以内字数的摘要,并说明标准分');
核心思路: 将DSL代码作为整体存储,运行时解析
-- 只需使用 dsl_content 字段
INSERT INTO node_properties (node_id, prop_key, prop_value) VALUES
(700, 'dsl_content', '完整的DSL代码...');
-- 1. 新增关系类型
INSERT INTO edge_types (type_code, type_name, from_node_type, to_node_type, description) VALUES
('DEPENDS_ON', '依赖规则', 'RULE', 'RULE', '规则依赖关系'),
('VALIDATES_TO', '验证输出', 'RULE', 'VALUE', '规则验证输出');
-- 2. 新增属性定义
INSERT INTO property_definitions (owner_type, target_type, prop_key, prop_name, data_type, required) VALUES
('node', 'RULE', 'function_name', '函数名', 'string', false),
('node', 'RULE', 'function_params', '函数参数', 'json', false),
('node', 'RULE', 'function_body', '函数体', 'string', false),
('node', 'RULE', 'return_type', '返回类型', 'string', false),
('node', 'RULE', 'validators', '验证器', 'json', false),
('node', 'RULE', 'execution_order', '执行顺序', 'number', false),
('edge', 'INPUT_FROM', 'input_value_type', '值类型', 'string', false),
('edge', 'INPUT_FROM', 'input_value', '字面值', 'string', false),
('edge', 'INPUT_FROM', 'input_value_json', '复杂值', 'json', false);
/**
* DSL规则解析器
*/
@Service
public class RuleDSLParser {
/**
* 解析DSL代码,创建规则节点和关系
*/
public Long parseDSL(String dslCode, Long projectId) {
// 1. 解析函数定义
List<FunctionDef> functions = parseFunctions(dslCode);
// 2. 为每个函数创建RULE节点
Map<String, Long> functionNodeMap = new HashMap<>();
for (FunctionDef func : functions) {
Long ruleId = createRuleNode(func, projectId);
functionNodeMap.put(func.getName(), ruleId);
}
// 3. 创建依赖关系(DEPENDS_ON边)
for (FunctionDef func : functions) {
createDependencies(func, functionNodeMap);
}
// 4. 拓扑排序,计算执行顺序
calculateExecutionOrder(functionNodeMap.values());
return functionNodeMap.get("main"); // 返回主函数ID
}
}
/**
* DSL规则执行器
*/
@Service
public class RuleDSLExecutor {
/**
* 执行规则(按依赖顺序)
*/
public Object executeRule(Long ruleId) {
// 1. 获取规则节点
Rule rule = ruleService.getById(ruleId);
// 2. 获取依赖规则(DEPENDS_ON边)
List<Rule> dependencies = getDependencies(ruleId);
// 3. 按execution_order排序
dependencies.sort(Comparator.comparing(Rule::getExecutionOrder));
// 4. 递归执行依赖规则
Map<String, Object> context = new HashMap<>();
for (Rule dep : dependencies) {
Object result = executeRule(dep.getId());
context.put(dep.getFunctionName(), result);
}
// 5. 执行当前规则
Object result = executeFunctionBody(rule, context);
// 6. 验证输出
validateOutput(rule, result);
// 7. 保存输出
saveOutput(ruleId, result);
return result;
}
/**
* 执行函数体
*/
private Object executeFunctionBody(Rule rule, Map<String, Object> context) {
// 根据 rule_type 选择执行器
switch (rule.getRuleType()) {
case "function_def":
return executePythonFunction(rule, context);
case "direct_entity":
return executeDirectEntity(rule);
case "llm":
return executeLLM(rule, context);
default:
throw new UnsupportedOperationException("Unknown rule type: " + rule.getRuleType());
}
}
}
<template>
<div class="rule-dsl-editor">
<!-- DSL代码编辑器 -->
<CodeEditor
v-model="dslCode"
language="python"
@save="saveDSL"
/>
<!-- 规则依赖图 -->
<RuleDependencyGraph
:rules="parsedRules"
@node-click="selectRule"
/>
<!-- 规则详情 -->
<RuleDetail
v-if="selectedRule"
:rule="selectedRule"
@execute="executeRule"
/>
</div>
</template>
// 1. DSL解析接口
POST /api/v1/projects/{projectId}/rules/parse-dsl
{
"dslCode": "完整的DSL代码..."
}
Response:
{
"code": 200,
"data": {
"mainRuleId": 700,
"functions": [
{"id": 700, "name": "calculate_score", "order": 1},
{"id": 701, "name": "build_one_five_section", "order": 2},
{"id": 702, "name": "build_one_full_chapter", "order": 3}
]
}
}
// 2. 规则依赖查询接口
GET /api/v1/rules/{ruleId}/dependencies
Response:
{
"code": 200,
"data": {
"ruleId": 701,
"dependencies": [
{"id": 700, "name": "calculate_score", "type": "ref"}
],
"dependents": [
{"id": 702, "name": "build_one_full_chapter", "type": "ref"}
]
}
}
// 3. 规则执行接口(支持依赖链)
POST /api/v1/rules/{ruleId}/execute
{
"context": {
"one_two_ch_id": 12578,
"one_tree_ch_id": 12389,
"section_prompt": "从原文生成100以内字数的摘要"
}
}
Response:
{
"code": 200,
"data": {
"ruleId": 702,
"output": "完整章节内容...",
"executionTrace": [
{"ruleId": 700, "name": "calculate_score", "output": 93.33, "duration": 10},
{"ruleId": 701, "name": "build_one_five_section", "output": "摘要内容...", "duration": 2500},
{"ruleId": 702, "name": "build_one_full_chapter", "output": "完整内容...", "duration": 100}
]
}
}
| 维度 | 评分 | 说明 |
|---|---|---|
| 基础支持 | ⭐⭐⭐⭐ | 节点、关系、属性基础完善 |
| DSL支持 | ⭐⭐ | 缺少函数引用、依赖关系 |
| 扩展性 | ⭐⭐⭐⭐⭐ | 图数据库架构易于扩展 |
| 实现难度 | ⭐⭐⭐ | 需要扩展但不复杂 |
✅ 推荐采用方案A(扩展当前设计)
需要新增:
DEPENDS_ON(规则依赖)function_name, function_params, function_body, return_type, validators, execution_orderinput_value_type, input_value, input_value_json实现优先级:
✅ 完全兼容当前设计
direct_entity、extraction 等规则类型继续有效init_mock_new.sql,添加新的关系类型和属性定义RuleDSLParser 解析器RuleDSLExecutor 执行器