Files
sundynix-agentix/EINO_ADOPTION.md
T
Blizzard 763646d5c5 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>
2026-06-22 16:38:24 +08:00

161 lines
9.3 KiB
Markdown
Raw 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.
# 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` RAGMilvus/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 Kitagent_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 绑定:ChatModelPhase 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 顺带桥接。
---
## 落地顺序与依赖
```
AChatModel 组件)── 地基,解锁全部
└─> BTool 适配 + ADK ReAct)── 质变:模型自主调工具
└─> Ccompose 编排 + 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 重点)。