chore(dispatcher): 升级 eino v0.9.5 → v0.9.9 + 全面采纳迁移方案
- dispatcher 升级 cloudwego/eino 到 v0.9.9(go work sync 同步各模块 transitive 依赖,如 golang.org/x/term v0.44.0);编译 + eino 链路测试通过 - 新增 EINO_ADOPTION.md:从"只借类型"演进为 Eino-native 编排核心的分阶段 方案(A 地基 ChatModel 组件 → B ADK 函数调用 → C compose 编排归一 → D 状态化执行:任务生命周期 FSM / HITL 中断恢复 / 多智能体) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# Eino 全面采纳迁移方案
|
||||
|
||||
> 目标:从"只借 Eino 的类型"演进为 **Eino-native 的 Agent 编排核心**,充分发挥框架的组件 / ADK / 编排 / 可观测能力。
|
||||
> 原则:**分阶段、不推倒重写、每步保持现有测试绿、可随时回退**。自研 `graph.go` 解释器演进为 `compose.Graph`,而非盲删。
|
||||
|
||||
---
|
||||
|
||||
## 0. 现状审计(2026-06-22)
|
||||
|
||||
实际跑在 `sundynix-dispatcher/internal/` 下:
|
||||
|
||||
| 维度 | 现状 | 用没用 Eino |
|
||||
|---|---|---|
|
||||
| 消息/流类型 | `schema.Message`、`StreamReader`、`Pipe` 全链路在用 | ✅ 真用(承重) |
|
||||
| ChatModel | `llm/pool.go` 自研 OpenAI 兼容客户端(手写 SSE 流解析) | ❌ 直连,绕过框架 |
|
||||
| `eino/model.go` 的 `poolModel` | 实现了 `model.BaseChatModel`,但 `newPoolModel` **从未被调用** | ⚠️ 空接缝 |
|
||||
| 工具调用 | NATS request-reply(`ToolCall`/`ToolResult`),图里**画死** | ❌ 自研,无函数调用 |
|
||||
| 编排 | `eino/graph.go` 自研解释器(拓扑/分支真假边/map 并行),有测试 | ❌ 非 `compose` |
|
||||
| 检索 | `mcp-go` RAG(Milvus/Bleve/Neo4j RRF),经 `wiki_search` 工具 | ❌ 自研 |
|
||||
| 提示词 | `report.go` / `memory_extract.go` 手拼字符串 | ❌ |
|
||||
| 可观测 | 自研 `ExecEvent` 轨迹流 + Prometheus + eval 护栏 | ❌(不缺) |
|
||||
| 人机交互 | 无 | ❌ |
|
||||
|
||||
**结论**:卡在最底层——没有真正的 ChatModel 组件,ADK / 编排都用不起来。采纳必须**自底向上**。
|
||||
|
||||
### Eino v0.9.9 可用包(已核对本地 module)
|
||||
|
||||
```
|
||||
github.com/cloudwego/eino/schema # ✅ 已用
|
||||
github.com/cloudwego/eino/components/model # ChatModel 接口
|
||||
github.com/cloudwego/eino/components/tool # Tool 接口
|
||||
github.com/cloudwego/eino/components/retriever# Retriever 接口
|
||||
github.com/cloudwego/eino/components/prompt # ChatTemplate
|
||||
github.com/cloudwego/eino/compose # Graph / Workflow / branch / tool_node / lambda
|
||||
github.com/cloudwego/eino/flow/agent/react # ReAct agent
|
||||
github.com/cloudwego/eino/flow/agent/multiagent
|
||||
github.com/cloudwego/eino/adk # Agent Development Kit(agent_tool / react / callback)
|
||||
github.com/cloudwego/eino/callbacks # 回调/可观测
|
||||
github.com/cloudwego/eino-ext/... # ⚠️ 官方组件实现(openai 等),尚未拉取,Phase A 新增
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 终态架构
|
||||
|
||||
| 层 | 现在 | 终态 |
|
||||
|---|---|---|
|
||||
| 模型 | 自研 `llm.Pool` | `eino-ext` openai 组件 + 我们的热更新/熔断包一层 |
|
||||
| 工具 | NATS `CallTool`,画死 | 每个 MCP 工具包成 `components/tool.InvokableTool`,`BindTools` 给模型动态选 |
|
||||
| 检索 | `wiki_search` 工具 | `mcp-go` RAG 包成 `components/retriever.Retriever` |
|
||||
| 提示词 | 手拼 | `components/prompt.ChatTemplate` |
|
||||
| 编排 | 自研 `graph.go` | `compose.Graph`(流式 reduce/branch + 类型化边) |
|
||||
| 智能体 | 无 | `flow/agent/react` 或 `adk` 的 ReAct agent;后续多智能体 |
|
||||
| 可观测 | ExecEvent + Prom | `callbacks` 桥接到现有 ExecEvent,统一 |
|
||||
| 人机交互 | 无 | 中断/恢复(审批场景,需 checkpoint store) |
|
||||
|
||||
---
|
||||
|
||||
## Phase A · 地基:接真 ChatModel 组件 〔P0〕
|
||||
|
||||
**目标**:模型调用走 Eino 官方 ChatModel 组件,接上空着的 `poolModel` 接缝;行为对现有用例不变。
|
||||
|
||||
**依赖**:`go get github.com/cloudwego/eino-ext/components/model/openai`(确认与 eino v0.9.9 兼容版本)。
|
||||
|
||||
**改动**:
|
||||
- `sundynix-dispatcher/internal/llm/pool.go`
|
||||
- 内部把手写 HTTP/SSE 换成 eino openai 组件作为 backend;`SetConfig` 时用激活配置 `New` 一个 ChatModel 实例(热更新 = 重建实例,加读写锁)。
|
||||
- 保留对外签名:`Chat` / `ChatStream` / `StreamText` / `Ready` / `ModelName`,让 `graph.go`/`report.go`/`memory_extract.go` **零改动**。
|
||||
- 熔断器(`harness.CircuitBreaker`)仍包在 `Pool` 这层。
|
||||
- `sundynix-dispatcher/internal/eino/model.go`
|
||||
- 让 `poolModel` 真正包住组件后的 Pool(或直接暴露底层 `model.BaseChatModel`),供 Phase B/C 用。
|
||||
|
||||
**验收**:
|
||||
- `make test-go`(含 `eino/graph_test.go`、`integration_test.go`、`memory_extract_test.go`)全绿。
|
||||
- 桌面端跑一次编排 / 一次报告 / 触发一次记忆 consolidate,输出与现状一致。
|
||||
- 「服务状态」面板 dispatcher 仍显示模型名 + 运行时长。
|
||||
|
||||
**风险/回退**:低。出问题回退到手写客户端(保留旧代码一版,绿后再删)。
|
||||
|
||||
---
|
||||
|
||||
## Phase B · 质变:函数调用 + ADK 单智能体 〔P1〕
|
||||
|
||||
**目标**:模型能**自主选择并调用** MCP 工具(ReAct),而非只跑画死的工具节点。这是"工作流执行器 → Agent 平台"的关键一跳。
|
||||
|
||||
**改动**:
|
||||
- 新增 `sundynix-dispatcher/internal/eino/tools.go`
|
||||
- 把每个 MCP 工具包成 `components/tool.InvokableTool` 适配器:`InvokableRun` 内部走 `subscriber.CallTool(ToolSubjectGo/Py, ToolCall)`。
|
||||
- 工具 schema(参数)从哪来:① 先手写少量核心工具的 JSON Schema;② 后续让 MCP `list_tools` 连参数 schema 一起上报(已有中文名/作用,扩字段即可)。
|
||||
- 新增 `agent` 节点类型
|
||||
- `dsl/compile.go` 识别 `kind=="agent"` 且开启"自主工具"开关 → 走 ReAct(`flow/agent/react` 或 `adk`)。
|
||||
- agent 绑定:ChatModel(Phase A)+ 一组 InvokableTool(按节点配置或 owner 可用工具集)。
|
||||
- `graph.go`:`agent` 节点分支委托给 ReAct runner,复用现有 ExecEvent 回流。
|
||||
|
||||
**验收**:
|
||||
- 画一个「agent + 若干工具」的图,给一句需要检索/记忆的提问,观测**模型自己决定调了哪个 MCP 工具**(ExecEvent 里出现 tool 调用轨迹)。
|
||||
- 旧的静态工具流不受影响。
|
||||
|
||||
**风险**:中。ReAct 多轮会放大 token 成本与时延 → 设最大步数 + 复用熔断器;工具 schema 不准会导致乱调 → 先小工具集灰度。
|
||||
|
||||
---
|
||||
|
||||
## Phase C · 编排归一:迁到 compose.Graph 〔P2〕
|
||||
|
||||
**目标**:自研解释器退役,DSL 图编译为 `compose.Graph`,吃到流式 reduce/branch、类型化边、自动并发、callbacks。
|
||||
|
||||
**改动**:
|
||||
- `sundynix-dispatcher/internal/dsl/compile.go`(兑现文件头那句 TODO:"演进为 compose.NewGraph 的完整多节点编译")
|
||||
- 写 `DSL Flow → compose.Graph` 编译器:节点映射为 ChatModel / ToolNode / Retriever / `Lambda`;连线 → 边;branch 真假 → `compose` 分支;map → 并发分支。
|
||||
- `callbacks`:实现 handler 把 Eino 回调桥接到现有 `ExecEvent`(节点 start/end/error + 耗时),统一可观测,不重复造。
|
||||
- `report.go`:报告多步流水线改用 compose(章节并行 + 汇聚天然契合)。
|
||||
- 检索节点 → `components/retriever`(包 mcp-go RAG);提示词 → `components/prompt.ChatTemplate`。
|
||||
- **对齐策略**:compose 版与 graph.go 版**并存**,用 `graph_test.go`/`integration_test.go` 做等价回归;全绿且灰度通过后,`graph.go` 才退役。
|
||||
|
||||
**验收**:分支路由、map 并行、报告流水线在 compose 版下与旧版**输出等价**;ExecEvent 轨迹不丢。
|
||||
|
||||
**风险**:高(动编排核心)。靠"并存 + 等价测试 + 灰度"控制,绝不一刀切。
|
||||
|
||||
---
|
||||
|
||||
## Phase D · 状态化执行 〔later,按场景〕
|
||||
|
||||
主题:把"执行"从一次性 DAG 升级为**可持久化、可恢复的状态机**。三件事同一条线,一起做。
|
||||
|
||||
- **任务生命周期 FSM** 🆕:现在 `Task.Status` 只写死 `submitted`、全仓从不流转(`store/models.go` + `pgsql.go:96`),是个摆设——这正是"卡运行中看不出来"的根因。
|
||||
- 设计:`submitted → running → done / failed / timeout` 显式状态机。
|
||||
- dispatcher 开跑/跑完/出错 经 NATS 回写状态(新增 `sundynix.tasks.status` 或复用 exec 流),网关落 PG 并推给 UI。
|
||||
- 收益:管理端「服务状态」/ 桌面端能看到任务真实进度,超时自动翻红,无需人工猜。
|
||||
- 与下面同源:Eino compose 的 graph state + 节点级状态正好承载它。
|
||||
- **中断/恢复(HITL)**:审批型工业流程(生成中途人工确认)。需 checkpoint 持久化(PG/Redis)。等有具体审批用例再做。
|
||||
- **多智能体协同**(`flow/agent/multiagent`):出现真实多角色编排需求时再上,现在无用例。
|
||||
|
||||
---
|
||||
|
||||
## 暂时不做
|
||||
|
||||
- **Ollama 官方组件**:与"开发期不拉本地 Ollama"策略冲突(见记忆 llm-provider-strategy)。
|
||||
- **拿 callbacks 当唯一理由迁移**:已有 ExecEvent + Prometheus + eval 护栏,callbacks 仅在 Phase C 顺带桥接。
|
||||
|
||||
---
|
||||
|
||||
## 落地顺序与依赖
|
||||
|
||||
```
|
||||
A(ChatModel 组件)── 地基,解锁全部
|
||||
└─> B(Tool 适配 + ADK ReAct)── 质变:模型自主调工具
|
||||
└─> C(compose 编排 + callbacks + retriever/prompt)── 编排归一
|
||||
└─> D(状态化执行:任务生命周期 FSM / HITL 中断恢复 / 多智能体)── 按场景
|
||||
```
|
||||
|
||||
逐项实现,每 Phase 一个(或多个)提交,跑 `make test-go` + 桌面端冒烟后再进下一阶段。
|
||||
|
||||
---
|
||||
|
||||
## 总验收/回归基线(每阶段都要过)
|
||||
|
||||
1. `make test-go`:shared / gateway / dispatcher / mcp-go 全绿。
|
||||
2. 桌面端冒烟:编排运行(含分支/并行)、报告生成+导出、记忆 consolidate、知识库检索。
|
||||
3. 管理端「服务状态」:四服务 + 五基建 + 工具注册正常。
|
||||
4. 行为等价:迁移前后同输入输出一致(Phase C 重点)。
|
||||
Reference in New Issue
Block a user