Skip to content

Commit

Permalink
docs: eino image resize (#1219)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuhahalong authored Jan 24, 2025
1 parent 805b4b6 commit dbe848a
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 165 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ func WithEmbeddingOption(opts ...embedding.Option) Option {

compose.Option 可以按需分配给 Graph 中不同的节点。

![](/img/eino/graph_runnable_after_compile.png)
<a href="/img/eino/graph_runnable_after_compile.png" target="_blank"><img src="/img/eino/graph_runnable_after_compile.png" /></a>

```go
// 所有节点都生效的 call option
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Graph 会为内部所有的 Node 自动注入 RunInfo。机制是每个 Node 的

## 触发方式

![](/img/eino/graph_node_callback_run_place.png)
<a href="/img/eino/graph_node_callback_run_place.png" target="_blank"><img src="/img/eino/graph_node_callback_run_place.png" /></a>

### 组件实现内部触发(Component Callback)

Expand Down Expand Up @@ -446,6 +446,6 @@ Handler 内不建议修改 input / output。原因是:

所以此时需要将流进行复制,其复制关系如下:

![](/img/eino/graph_stream_chunk_copy.png)
<a href="/img/eino/graph_stream_chunk_copy.png" target="_blank"><img src="/img/eino/graph_stream_chunk_copy.png" /></a>

- 如果其中一个 Callback n 没有 Close 对应的流,可能导致原始 Stream 无法 Close 和释放资源。
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
Description: ""
date: "2025-01-20"
date: "2025-01-23"
lastmod: ""
tags: []
title: 'Eino: 编排的设计理念'
Expand Down Expand Up @@ -28,7 +28,7 @@ eino 的最基础编排方式为 graph,以及简化的封装 chain。不论是

就如下图:

![](/img/eino/edge_type_validate.png)
<a href="/img/eino/edge_type_validate.png" target="_blank"><img src="/img/eino/edge_type_validate.png" /></a>

对于一个编排而言,只有下游能识别和处理上游的输出,这个编排才能正常运行。 这个基本假设在 eino 中被清晰地表达了出来,让开发者在用 eino 做编排时,能够有十足的信心清楚编排的逻辑是如何运行和流转的,而不是从一系列的 any 中去猜测传过来的值是否正确。

Expand All @@ -42,7 +42,7 @@ eino 的最基础编排方式为 graph,以及简化的封装 chain。不论是

> 这是一个模拟 ① 直接和大模型对话 ② 使用 RAG 模式 的场景,最后结果可用于对比两种模式的效果
![](/img/eino/input_output_type_validate.png)
<a href="/img/eino/input_output_type_validate.png" target="_blank"><img src="/img/eino/input_output_type_validate.png" /></a>

图中绿色的部分,就是普通的 Edge 连接,其要求上游的输出必须能 `assign` 给下游,可以接收的类型有:

Expand All @@ -64,6 +64,8 @@ eino 的最基础编排方式为 graph,以及简化的封装 chain。不论是

> 这是一个模拟 react agent 的运行逻辑
<a href="/img/eino/branch_to_draw_loop.png" target="_blank"><img src="/img/eino/branch_to_draw_loop.png" /></a>

可以看到,一个 branch 本身拥有一个 `condition`, 这个 function 的输入必须和上游类型对齐。同时,一个 branch 后所接的各个节点,也必须和 condition 一样,要能接收上游的输出。

### chain 中的类型对齐
Expand All @@ -72,7 +74,7 @@ eino 的最基础编排方式为 graph,以及简化的封装 chain。不论是

从抽象角度看,chain 就是一个 `链条`,如下所示:

![](/img/eino/what_is_chain.png)
<a href="/img/eino/what_is_chain.png" target="_blank"><img src="/img/eino/what_is_chain.png" /></a>

逻辑节点的类型可以分为 3 类:

Expand Down Expand Up @@ -106,15 +108,15 @@ func TestChain() {

上面的逻辑用图来表示如下:

![](/img/eino/nodes_type_validate.png)
<a href="/img/eino/nodes_type_validate.png" target="_blank"><img src="/img/eino/nodes_type_validate.png" /></a>

若上下游的类型没有对齐,chain 会在 chain.Compile() 时返回错误。而 graph 会在 graph.AddXXXNode() 时就报错。

#### parallel

parallel 在 chain 中是一类特殊的节点,从 chain 的角度看 parallel 和其他的节点没啥区别。在 parallel 内部,其基本拓扑结构如下:

![](/img/eino/same_type_of_parallel.png)
<a href="/img/eino/same_type_of_parallel.png" target="_blank"><img src="/img/eino/same_type_of_parallel.png" /></a>

graph 中的多 edge 形成的结构其中一种就是这个,这里的基本假设是: 一个 parallel 的每一条边上有且仅有一个节点。当然,这一个节点也可以是 graph。但注意,目前框架没有直接提供在 parallel 中嵌套 branch 或 parallel 的能力。

Expand Down Expand Up @@ -150,7 +152,7 @@ func TestParallel() {

> 图中是模拟同一个提问,由不同的大模型去回答,结果可用于对比效果
![](/img/eino/graph_as_chain_node.png)
<a href="/img/eino/graph_as_chain_node.png" target="_blank"><img src="/img/eino/graph_as_chain_node.png" /></a>

> 需要注意的是,这个结构只是逻辑上的视角,由于 chain 本身也是用 graph 实现的,parallel 在底层 graph 中会平铺到图中。
Expand All @@ -172,7 +174,7 @@ Workflow 的类型对齐的维度,由整体的 Input & Output 改成了字段

在 Eino 中,编排的结果是 graph 或 chain,若要运行,则需要使用 `Compile()` 来生成一个 `Runnable` 接口。

Runnable 的一个重要作用就是提供了 `I``nvoke``S``tream``C``ollect``T``ransform` 四种调用方式。
Runnable 的一个重要作用就是提供了 「Invoke」、「Stream」、「Collect」、「Transform」 四种调用方式。

> 上述几种调用方式的介绍以及详细的 Runnable 介绍可以查看: [Eino: 基础概念介绍](/zh/docs/eino/overview)
Expand Down Expand Up @@ -235,7 +237,7 @@ func TestTypeMatch(t *testing.T) {

当我们以 Stream 方式调用上面编译好的 Runnable 时,model 节点会输出 `*schema.StreamReader[*Message]`,但是 lambda 节点是 InvokableLambda,只接收非流式的 `*schema.Message` 作为输入。这也符合类型对齐规则,因为 Eino 框架会自动把流式的 Message 拼接成完整的 Message。

在 stream 模式下,`拼接``帧` 是一个非常常见的操作,拼接时,会先把 `*StreamReader[T] ` 中的所有元素取出来转成 `[]T`,再尝试把 `[]T` 拼接成一个完整的 `T`。框架内已经内置支持了如下类型的拼接:
在 stream 模式下,拼接帧 是一个非常常见的操作,拼接时,会先把 `*StreamReader[T] ` 中的所有元素取出来转成 `[]T`,再尝试把 `[]T` 拼接成一个完整的 `T`。框架内已经内置支持了如下类型的拼接:

- `*schema.Message`: 详情见 `schema.ConcatMessages()`
- `string`: 实现逻辑等同于 `+=`
Expand Down Expand Up @@ -278,7 +280,7 @@ eino 的 Graph 类型对齐检查,会在 `err = graph.AddEdge("node1", "node2"

其结构可见下图:

![](/img/eino/input_type_output_type_in_edge.png)
<a href="/img/eino/input_type_output_type_in_edge.png" target="_blank"><img src="/img/eino/input_type_output_type_in_edge.png" /></a>

这种场景适用于开发者能自行处理好上下游类型对齐的情况,可根据不同类型选择下游执行节点。

Expand Down Expand Up @@ -362,7 +364,7 @@ Eino 支持各种维度的 Call Option 分配方式:

以一个添加了 StatePreHandler、StatePostHandler、InputKey、OutputKey,且内部没有实现 Callback 切面的 InvokableLambda(输入为 string,输出为 int)为例,在图中的流式执行完整时序如下:

![](/img/eino/graph_node_run_wrapper.png)
<a href="/img/eino/graph_node_run_wrapper.png" target="_blank"><img src="/img/eino/graph_node_run_wrapper.png" /></a>

在 workflow 的场景中,字段映射发生在两个位置:

Expand All @@ -376,11 +378,11 @@ Eino 支持各种维度的 Call Option 分配方式:
- 当前执行中的一个或多个节点,所有的后序节点,作为一个 SuperStep,整体一起执行。这时,这些新的节点,会成为“当前”节点。
- 支持 Branch,支持图中有环,但是可能需要人为添加 passthrough 节点,来确保 SuperStep 中的节点符合预期,如下图:

![](/img/eino/graph_steps_in_graph2.png)
<a href="/img/eino/graph_steps_in_graph2.png" target="_blank"><img src="/img/eino/graph_steps_in_graph2.png" /></a>

上图中 Node 4 和 Node 5 按规则被放在一起执行,大概率不符合预期。需要改成:

![](/img/eino/graph_steps_in_graph.png)
<a href="/img/eino/graph_steps_in_graph.png" target="_blank"><img src="/img/eino/graph_steps_in_graph.png" /></a>

`NodeTriggerMode == AllPredecessor` 时,图以 dag 引擎执行,对应的拓扑结构是有向无环图。特点是:

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
Description: ""
date: "2025-01-20"
date: "2025-01-23"
lastmod: ""
tags: []
title: Eino 流式编程要点
Expand All @@ -12,7 +12,7 @@ weight: 0
## 编排流式概述

![](/img/eino/eino_component_runnable.png)
<a href="/img/eino/eino_component_runnable.png" target="_blank"><img src="/img/eino/eino_component_runnable.png" /></a>

编排流式的 Graph 时,需要考虑的几个关键要素:

Expand Down Expand Up @@ -41,9 +41,9 @@ Eino 是个 "component first" 的框架,组件可以独立使用。定组件

```go
type ChatModel interface {
Generate(ctx context.Context**, **input []*schema.Message**, **opts ...Option) (*schema.Message**, **error)
Stream(ctx context.Context**, **input []*schema.Message**, **opts ...Option) (
*schema.StreamReader[*schema.Message]**, **error)
Generate(ctx context.Context, input []*schema.Message, opts ...Option) (*schema.Message, error)
Stream(ctx context.Context, input []*schema.Message, opts ...Option) (
*schema.StreamReader[*schema.Message], error)
// other methods omitted...
}
```
Expand All @@ -52,7 +52,7 @@ type ChatModel interface {

```go
type Retriever interface {
Retrieve(ctx context.Context**, **query string**, **opts ...Option) ([]*schema.Document**, **error)
Retrieve(ctx context.Context, query string, opts ...Option) ([]*schema.Document, error)
}
```

Expand Down Expand Up @@ -93,11 +93,11 @@ Collect 和 Transform 两种流式范式,目前只在编排场景有用到。

但是,一个组件,一旦处在多个组件组合使用的“编排”场景中,它的入参和出参就没那么固定了,而是取决于这个组件在编排场景中的“上游输出”和“下游输入”。比如 React Agent 的典型编排示意图:

![](/img/eino/chatmodel_to_tool.png)
<a href="/img/eino/chatmodel_to_tool.png" target="_blank"><img src="/img/eino/chatmodel_to_tool.png" /></a>

上图中,如果 Tool 是个 StreamableTool,也就是输出是 StreamReader[Message],则 Tool -> ChatModel 就可能是流式的输出。但是 Chat Model 并没有接收流式输入的业务场景,也没有对应的接口。这时 Eino 框架会自动帮助 ChatModel 补足接收流式输入的能力:

![](/img/eino/chatmodel_tool_loop.png)
<a href="/img/eino/chatmodel_tool_loop.png" target="_blank"><img src="/img/eino/chatmodel_tool_loop.png" /></a>

上面的 Concat message stream 是 Eino 框架自动提供的能力,即使不是 message,是任意的 T,只要满足特定的条件,Eino 框架都会自动去做这个 StreamReader[T] 到 T 的转化,这个条件是:**在编排中,当一个组件的上游输出是 StreamReader[T],但是组件只提供了 T 作为输入的业务接口时,框架会自动将 StreamReader[T] concat 成 T,再输入给这个组件。**

Expand All @@ -106,23 +106,23 @@ Collect 和 Transform 两种流式范式,目前只在编排场景有用到。
另一方面,考虑一个相反的例子。还是 React Agent,这次是一个更完整的编排示意图:

![](/img/eino/tool_model_react.png)
<a href="/img/eino/tool_model_react.png" target="_blank"><img src="/img/eino/tool_model_react.png" /></a>

在上图中,branch 接收 chat model 输出的 message,并根据 message 中是否包含 tool call,来选择直接结束 agent 本次运行并将 message 输出,还是调用 Tool 并将调用结果再次给 Chat Model 循环处理。由于这个 Branch 可以通过 message stream 的首个帧就完成逻辑判断,因此我们给这个 Branch 定义的是 Collect 接口,即流式输入,非流式输出:

```go
compose.NewStreamGraphBranch(func(ctx context.Context**, **sr *schema.StreamReader[*schema.Message]) (endNode string**, **err error) {
msg**, **err := sr.Recv()
compose.NewStreamGraphBranch(func(ctx context.Context, sr *schema.StreamReader[*schema.Message]) (endNode string, err error) {
msg, err := sr.Recv()
if err != nil {
return ""**, **err
return "", err
}
defer sr.Close()

if len(msg.ToolCalls) == **0 **{
return compose._END_**, **nil
if len(msg.ToolCalls) == 0 {
return compose._END_, nil
}

return nodeKeyTools**, **nil
return nodeKeyTools, nil
}
```

Expand Down Expand Up @@ -165,11 +165,11 @@ ReactAgent 有两个接口,Generate 和 Stream,分别实现了 Invoke 和 St
- “没有”:整体而言,Graph,Chain 等编排产物,自身是没有业务属性的,只为抽象的编排服务的,因此也就没有符合业务场景的接口范式。同时,编排需要支持各种范式的业务场景。所以,Eino 中代表编排产物的 Runnable[I, O] 接口,不做选择也无法选择,提供了所有流式范式的方法:

```go
type Runnable[I**, **O any] interface {
Invoke(ctx context.Context**, **input I**, **opts ...Option) (output O**, **err error)
Stream(ctx context.Context**, **input I**, **opts ...Option) (output *schema.StreamReader[O]**, **err error)
Collect(ctx context.Context**, **input *schema.StreamReader[I]**, **opts ...Option) (output O**, **err error)
Transform(ctx context.Context**, **input *schema.StreamReader[I]**, **opts ...Option) (output *schema.StreamReader[O]**, **err error)
type Runnable[I, O any] interface {
Invoke(ctx context.Context, input I, opts ...Option) (output O, err error)
Stream(ctx context.Context, input I, opts ...Option) (output *schema.StreamReader[O], err error)
Collect(ctx context.Context, input *schema.StreamReader[I], opts ...Option) (output O, err error)
Transform(ctx context.Context, input *schema.StreamReader[I], opts ...Option) (output *schema.StreamReader[O], err error)
}
```

Expand All @@ -179,27 +179,33 @@ type Runnable[I**, **O any] interface {

从另一个角度看,既然编排产物整体可以被看做“组件”,那“组件”必然有自己的内部实现,比如 ChatModel 的内部实现逻辑,可能是把入参的 []Message 转化成各个模型的 API request,之后调用模型的 API,获取 response 后再转化成出参的 Message。那么类比的话,Graph 这个“组件”的内部实现是什么?是数据在 Graph 内部各个组件间以用户指定的流转方向和流式范式来流转。其中,“流转方向”不在当前讨论范围内,而各组件运行时的流式范式,则由 Graph 整体的触发方式决定,具体来说:

- 如果用户通过 Invoke 来调用 Graph,则 Graph 内部所有组件都以 Invoke 范式来调用。如果某个组件,没有实现 Invoke 范式,则 Eino 框架自动根据组件实现了的流式范式,封装出 Invoke 调用范式,优先顺位如下:
- 若组件实现了 Stream,则通过 Stream 封装 Invoke,即自动 concat 输出流。
如果用户通过 **Invoke** 来调用 Graph,则 Graph 内部所有组件都以 Invoke 范式来调用。如果某个组件,没有实现 Invoke 范式,则 Eino 框架自动根据组件实现了的流式范式,封装出 Invoke 调用范式,优先顺位如下:

- 若组件实现了 Stream,则通过 Stream 封装 Invoke,即自动 concat 输出流。

<a href="/img/eino/invoke_outside_stream_inside.png" target="_blank"><img src="/img/eino/invoke_outside_stream_inside.png" /></a>

![](/img/eino/invoke_outside_stream_inside.png)
- 否则,若组件实现了 Collect,则通过 Collect 封装 Invoke,即非流式入参转单帧流。

![](/img/eino/invoke_outside_collect_inside.png)
<a href="/img/eino/invoke_outside_collect_inside.png" target="_blank"><img src="/img/eino/invoke_outside_collect_inside.png" /></a>

- 如果都没实现,则必须实现 Transform,通过 Transform 封装 Invoke,即入参转单帧流,出参 concat。

![](/img/eino/invoke_outside_transform_inside.png)
<a href="/img/eino/invoke_outside_transform_inside.png" target="_blank"><img src="/img/eino/invoke_outside_transform_inside.png" /></a>

- 如果用户通过 Stream/Collect/Transform 来调用 Graph,则 Graph 内部所有组件都以 Transform 范式来调用。如果某个组件,没有实现 Transform 范式,则 Eino 框架自动根据组件实现了的流式范式,封装出 Transform 调用范式,优先顺位如下:
- 若组件实现了 Stream,则通过 Stream 封装 Transform,即自动 concat 输入流。
如果用户通过 **Stream/Collect/Transform** 来调用 Graph,则 Graph 内部所有组件都以 Transform 范式来调用。如果某个组件,没有实现 Transform 范式,则 Eino 框架自动根据组件实现了的流式范式,封装出 Transform 调用范式,优先顺位如下:

- 若组件实现了 Stream,则通过 Stream 封装 Transform,即自动 concat 输入流。

<a href="/img/eino/transform_inside_stream_inside.png" target="_blank"><img src="/img/eino/transform_inside_stream_inside.png" /></a>

![](/img/eino/transform_inside_stream_inside.png)
- 否则,若组件实现了 Collect,则通过 Collect 封装 Transform,即非流式出参转单帧流。

![](/img/eino/transform_outside_stream_inside.png)
<a href="/img/eino/transform_outside_stream_inside.png" target="_blank"><img src="/img/eino/transform_outside_stream_inside.png" /></a>

- 如果都没实现,则必须实现 Invoke,通过 Invoke 封装 Transform,即入参流 concat,出参转单帧流

![](/img/eino/transform_outside_invoke_inside.png)
<a href="/img/eino/transform_outside_invoke_inside.png" target="_blank"><img src="/img/eino/transform_outside_invoke_inside.png" /></a>

结合上面穷举的各种案例,Eino 框架对 T 和 Stream[T] 的自动转换,可以总结为:

Expand Down
22 changes: 12 additions & 10 deletions content/zh/docs/eino/core_modules/devops/ide_plugin_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,52 @@ weight: 1
## 简介

![](/img/eino/eino_dev_ability_introduction_page.png)
<a href="/img/eino/eino_dev_ability_introduction_page.png" target="_blank"><img src="/img/eino/eino_dev_ability_introduction_page.png" /></a>

## 安装插件

<table><tbody><tr>
<td>
1. 进入<strong>GoLand</strong>,点击<strong>设置,选择Plugin 插件</strong>
<img src="/img/eino/eino_install_page.png" />
<a href="/img/eino/eino_install_page.png" target="_blank"><img src="/img/eino/eino_install_page.png" /></a>

</td>
<td>
1. <strong>通过Marketplace,搜索Eino Dev 插件并按照</strong>
<img src="/img/eino/eino_install_page_2_page.png" />
<a href="/img/eino/eino_install_page_2_page.png" target="_blank"><img src="/img/eino/eino_install_page_2_page.png" /></a>

</td>
</tr></tbody></table>

> 💡
> **插件安装完毕可以在 IDE 右侧插件列表中 EinoDev 调试插件图标啦,接下来就可以体验插件提供的调试与编排能力啦**
![](/img/eino/eino_dev_enter_page.png)
<a href="/img/eino/eino_dev_enter_page.png" target="_blank"><img src="/img/eino/eino_dev_enter_page.png" /></a>

## 功能简介

### **EinoDev Graph 编排**

<table><tbody><tr>
<td>
<img src="/img/eino/eino_orchestration_index_page.png" />
<a href="/img/eino/eino_orchestration_index_page.png" target="_blank"><img src="/img/eino/eino_orchestration_index_page.png" /></a>

</td>
<td>
<img src="/img/eino/eino_orchestration_show_nodes_2_page.png" />
<a href="/img/eino/eino_orchestration_show_nodes_2_page.png" target="_blank"><img src="/img/eino/eino_orchestration_show_nodes_2_page.png" /></a>

</td>
</tr></tbody></table>

### **EinoDev Graph 调试**

<table><tbody><tr>
<td>
<img src="/img/eino/eino_debug_run_page.png" />
<a href="/img/eino/eino_debug_run_page.png" target="_blank"><img src="/img/eino/eino_debug_run_page.png" /></a>

</td>
<td>
<img src="/img/eino/eino_debug_test_run_of_mock_data_page.png" />
<a href="/img/eino/eino_debug_test_run_of_mock_data_page.png" target="_blank"><img src="/img/eino/eino_debug_test_run_of_mock_data_page.png" /></a>

</td>
</tr></tbody></table>

##
Loading

0 comments on commit dbe848a

Please sign in to comment.