TraceStudio-dev/docs/issues/workflow_results_structure_issue.md
Boshuang Zhao 5790ec164f add web v2
2026-01-10 19:08:49 +08:00

197 lines
7.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Workflow Execution Results Structure - Redundancy & Complexity"
created: 2026-01-10
author: copilot
labels: [bug, api, design, discussion]
---
# 问题报告:工作流执行结果的数据结构冗余与复杂性
摘要:
- 后端在生成并返回工作流执行报告时保留了多套数据(`node_infos`、`node_results`、并在 API 层做额外合并与序列化),导致返回体中字段重复、语义混淆、序列化逻辑分散,增加前端解析复杂度与潜在性能问题。
## 1) 核心矛盾
- 后端为了兼容历史实现同时保留新的执行上下文,当前返回给前端的执行报告既包含 `node_infos` 又包含 `node_results`(并在 API 层再次合并/序列化),导致字段冗余、语义重复、序列化逻辑被多处重复实现。
## 2) 关键代码片段
- 执行器在 `_get_execution_report` 中返回:
```py
"node_infos": { node_id: info.to_dict() for node_id, info in self.context.node_infos.items() },
"node_results": self.context.node_results
```
- API 层(`endpoints_graph.execute`)对 report 做两种兼容解析并合并后序列化:
```py
if 'node_infos' in report or 'node_results' in report:
node_infos = report.get('node_infos', {}) or {}
node_results = report.get('node_results', {}) or {}
elif isinstance(report, dict):
node_infos = report
node_results = {}
for nid in all_node_ids:
info = node_infos.get(nid)
outputs = node_results.get(nid)
ser_outputs = serialize(outputs) # polars.DataFrame -> preview
results_out[nid] = {
'status': _get_status(info),
'outputs': ser_outputs,
'error': _get_error(info)
}
```
## 3) 技术限制与风险
- 冗余存储:`NodeExecutionInfo.result`、`context.node_results[node_id]`、以及 API 层 `results_out` 三处可含相同数据。
- 性能与带宽DataFrame/大对象可能被多次序列化,产生额外 CPU 与内存消耗。
- 语义不一致:前端需同时解析多套字段,提升错误率。
## 4) 可决策方案
### 方案 A推荐—— 单一标准响应canonical schema
- 描述:强制执行一个统一的响应结构:顶层 `nodes` 映射,每个 node 包含 `status,duration,cache_hit,error,outputs,meta`
- 优点:清晰、便于文档化与版本化、降低重复序列化。
- 缺点:需要一次性后端变更与前端适配窗口。
### 方案 B渐进兼容—— 分层输出summary/results
- 描述API 层导出 `summary`(轻量)与 `results`(可选详细),通过参数控制是否返回详细 outputs`?full=true`)。
- 优点:低破坏、可渐进迁移。
- 缺点:仍需前端适配 `full` 策略。
### 方案 C重构—— 大数据 artifact 存储与引用
- 描述将完整的大对象DataFrame写入临时 artifact 存储,响应仅包含 `preview``artifact_id`
- 优点:解决大 payload 问题,支持按需拉取。
- 缺点实现复杂存储、TTL、权限
## 5) 立刻可执行的短期修复
- 把 DataFrame 序列化抽成单一函数并确保只执行一次。
- 在响应中避免重复包含相同数据(检测并合并重复字段)。
- 添加 `api_schema_version` 字段并在返回 header 中标注,便于兼容管理。
## 6) 建议与决策请求给 Gemini
1. 是否接受 breaking-change方案 A并安排前端迁移窗口
2. 是否采用渐进方案(方案 B为过渡并设定过渡期例如 2 个版本)?
3. 是否在短期内实现 artifact 存储(方案 C 的关键部分)?
## 7) 建议的 canonical schema示例
```json
{
"status": "success",
"execution_id": "uuid",
"execution_time": 0.123,
"nodes": {
"node1": {
"status": "success",
"duration": 0.032,
"cache_hit": false,
"error": null,
"outputs": {
"out": {
"__type": "DataFrame",
"columns": ["a","b"],
"preview": [{"a":1,"b":2}],
"rows": 1234
}
},
"meta": { "class_name": "SomeNode", "node_type": "normal" }
}
}
}
```
## 8) 后续动作(会议后)
- 如果选 A制定迁移计划API version、前端适配、回退策略
- 如果选 B实现 `summary/results``?full` 控制,并优化序列化集中点。
- 如果选 C实现 artifact 存储与权限管理。
---
---
title: "Refactor: Unified Execution Protocol & Compatibility Cleanup"
created: 2026-01-10
author: gemini
labels: [architecture, breaking-change, cleanup, protocol]
---
# 🧠 《Copilot 开发指导手册》:执行引擎标准化重构
## 1. 功能摘要
废除 `node_infos``node_results` 的冗余双轨数据流。强制推行以节点为中心的 **Canonical Schema** 作为唯一真相来源,彻底清理开发期遗留的兼容性逻辑(如旧版 Input/Output 节点分支),确保执行引擎职责单一化。
## 2. 核心矛盾
后端为了兼容历史实现当前返回的报告中字段重复且语义混淆。API 层(`endpoints_graph.execute`)被迫进行繁琐的合并与二次序列化,这增加了前端解析难度并导致大型对象(如 DataFrame的性能损耗。
## 3. 逻辑契约 (Canonical Schema)
`WorkflowExecutor._get_execution_report` 必须输出如下扁平化结构:
{
"success": "boolean",
"execution_id": "string (uuid)",
"total_duration": "float",
"nodes": {
"{node_id}": {
"status": "success | error | pending",
"metrics": {
"duration": "float",
"cache_hit": "boolean"
},
"outputs": {
"{port_name}": {
"__type": "DataFrame | any",
"preview": "array",
"shape": "tuple"
}
},
"error": "string | null",
"meta": {
"class_name": "string",
"node_type": "string"
}
}
}
}
## 4. 实现提示 (Implementation Hints)
* **彻底移除兼容性方法**:删除已在 `workflow_executor.py` 头部声明弃用的 `_execute_input_node``_execute_output_node` 内部方法。
* **清理 API 层冗余**:重构 `endpoints_graph.py`,直接透传执行器结果,禁止使用 `if 'node_infos' in report` 等逻辑做降级解析。
* **数据精炼原则**:在执行器内部实现 `_smart_serialize`,针对 Polars DataFrame 等对象强制执行采样预览(如 `.head(5)`),贯彻“采样预览,全量生产”的核心原则。
## 5. 核心函数重构示例 (WorkflowExecutor)
def _get_execution_report(self) -> Dict:
"""
[utrace 架构决策]:废除双轨制,执行数据精炼采样。
"""
if not self.context:
return {"success": False, "error": "Context not initialized"}
nodes_map = {}
for nid, info in self.context.node_infos.items():
# 合并执行上下文与结果
raw_res = self.context.node_results.get(nid, {})
raw_outputs = raw_res.get("outputs", {})
nodes_map[nid] = {
"status": info.status.value,
"metrics": {
"duration": round(info.duration, 4),
"cache_hit": info.cache_hit
},
"outputs": self._smart_serialize(raw_outputs),
"error": info.error,
"meta": {
"class_name": self.graph.nodes[nid].get("class_name"),
"node_type": info.node_type
}
}
return {
"success": all(n["status"] == "success" for n in nodes_map.values()),
"execution_id": self.context.execution_id,
"nodes": nodes_map
}
---
**utrace 架构审计批注**
TraceStudio 坚持“逻辑即文档”。本次重构是消除系统熵增的关键一步。所有不符合此 Schema 的前端调用均视为待修复 Bug而非后端需要兼容的对象。