diff --git a/content/zh/docs/eino/_index.md b/content/zh/docs/eino/_index.md
index 008d8e7db1..33ffd2fb9b 100644
--- a/content/zh/docs/eino/_index.md
+++ b/content/zh/docs/eino/_index.md
@@ -1,6 +1,6 @@
---
Description: Eino 是基于 Golang 的 AI 应用开发框架
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
linktitle: Eino
menu:
diff --git a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/call_option_capabilities.md b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/call_option_capabilities.md
index 8c8e2f7e4d..9188158019 100644
--- a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/call_option_capabilities.md
+++ b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/call_option_capabilities.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: CallOption 能力与规范'
@@ -10,7 +10,7 @@ weight: 0
**CallOption**: 对 Graph 编译产物进行调用时,直接传递数据给特定的一组节点(Component、Implementation、Node)的渠道
- 和 节点 Config 的区别: 节点 Config 是实例粒度的配置,也就是从实例创建到实例消除,Config 中的值一旦确定就不需要改变了
- CallOption:是请求粒度的配置,不同的请求,其中的值是不一样的。更像是节点入参,但是这个入参是直接由 Graph 的入口直接传入,而不是上游节点传入。
-- 举例:LarkDocLoader 中,需要提供请求粒度的 RefreshToken,这个 RefreshToken 每个用户每次使用后,都需要更换
+- 举例:给一个 ChatModel 节点传入 Temperature 配置;给一个 Lambda 节点传入自定义 option。
## 组件 CallOption 形态
@@ -31,12 +31,12 @@ eino/components/model
// 抽象实现所在代码位置
eino-ext/components/model
-├── maas
-│ ├── call_option.go
-│ └── Implementation.go
-├── openai
+├── claude
+│ ├── option.go // Component 的一种实现的 CallOption 入参
+│ └── chatmodel.go
+├── ollama
│ ├── call_option.go // Component 的一种实现的 CallOption 入参
-│ ├── Implementation.go
+│ ├── chatmodel.go
```
### Model 抽象
@@ -60,11 +60,18 @@ type ChatModel interface {
}
// 此结构体是【组件抽象CallOption】的统一定义。 组件的实现可根据自己的需要取用【组件抽象CallOption】的信息
+// Options is the common options for the model.
type Options struct {
- Temperature float32
- MaxTokens int
- Model string
- TopP float32
+ // Temperature is the temperature for the model, which controls the randomness of the model.
+ Temperature *float32
+ // MaxTokens is the max number of tokens, if reached the max tokens, the model will stop generating, and mostly return an finish reason of "length".
+ MaxTokens *int
+ // Model is the model name.
+ Model *string
+ // TopP is the top p for the model, which controls the diversity of the model.
+ TopP *float32
+ // Stop is the stop words for the model, which controls the stopping condition of the model.
+ Stop []string
}
// Option is the call option for ChatModel component.
@@ -78,34 +85,47 @@ type Option struct {
implSpecificOptFn any
}
+// WithTemperature is the option to set the temperature for the model.
func WithTemperature(temperature float32) Option {
return Option{
apply: func(opts *Options) {
- opts.Temperature = temperature
+ opts.Temperature = &temperature
},
}
}
+// WithMaxTokens is the option to set the max tokens for the model.
func WithMaxTokens(maxTokens int) Option {
return Option{
apply: func(opts *Options) {
- opts.MaxTokens = maxTokens
+ opts.MaxTokens = &maxTokens
},
}
}
+// WithModel is the option to set the model name.
func WithModel(name string) Option {
return Option{
apply: func(opts *Options) {
- opts.Model = name
+ opts.Model = &name
},
}
}
+// WithTopP is the option to set the top p for the model.
func WithTopP(topP float32) Option {
return Option{
apply: func(opts *Options) {
- opts.TopP = topP
+ opts.TopP = &topP
+ },
+ }
+}
+
+// WithStop is the option to set the stop words for the model.
+func WithStop(stop []string) Option {
+ return Option{
+ apply: func(opts *Options) {
+ opts.Stop = stop
},
}
}
@@ -156,149 +176,116 @@ func GetImplSpecificOptions[T any](base *T, opts ...Option) *T {
}
```
-### OpenAI 实现
+### Claude 实现
-> 组件的实现均类似 OpenAI 的实现
->
-> 注:此处为样例,eino-ext/components/model 中暂时没有此场景
+[https://github.com/cloudwego/eino-ext/blob/main/components/model/claude/option.go](https://github.com/cloudwego/eino-ext/blob/main/components/model/claude/option.go)
```go
-package openai
+package claude
import (
"github.com/cloudwego/eino/components/model"
)
-// openAIOptions 实现粒度的 CallOption 配置
-type requestOptions struct {
- APIKey string
- Stop []string
- PresencePenalty float32
+type options struct {
+ TopK *int32
}
-// openai 下的 WithXX() 方法,只能对 openai 这一种实现生效
-func WithAPIKey(apiKey string) model.Option {
- return model.WrapImplSpecificOptFn[requestOptions](func(o *requestOptions) {
- o.APIKey = apiKey
- })
-}
-
-func WithStop(stop []string) model.Option {
- return model.WrapImplSpecificOptFn[requestOptions](func(o *requestOptions) {
- o.Stop = stop
- })
-}
-
-func WithPresencePenalty(presencePenalty float32) model.Option {
- return model.WrapImplSpecificOptFn[requestOptions](func(o *requestOptions) {
- o.PresencePenalty = presencePenalty
+func WithTopK(k int32) model.Option {
+ return model.WrapImplSpecificOptFn(func(o *options) {
+ o.TopK = &k
})
}
```
-model/openai/Implementation.go
+[https://github.com/cloudwego/eino-ext/blob/main/components/model/claude/claude.go](https://github.com/cloudwego/eino-ext/blob/main/components/model/claude/claude.go)
```go
-type ChatModel struct {}
+func (c *claude) genMessageNewParams(input []*schema.Message, opts ...model.Option) (anthropic.MessageNewParams, error) {
+ if len(input) == 0 {
+ return anthropic.MessageNewParams{}, fmt.Errorf("input is empty")
+ }
-func (cm *ChatModel) Generate(ctx context.Context, in []*schema.Message, opts ...model.Option) (
-
- cmOpts := model.GetCommonOptions(&model.Options{
- Model: "gpt-3.5-turbo",
- MaxTokens: 1024,
- Temperature: 0.7,
- }, opts...)
-
- implOpts := model.GetImplSpecificOptions[requestOptions](&requestOptions{
- Stop: nil,
- PresencePenalty: 1,
+ commonOptions := model.GetCommonOptions(&model.Options{
+ Model: &c.model,
+ Temperature: c.temperature,
+ MaxTokens: &c.maxTokens,
+ TopP: c.topP,
+ Stop: c.stopSequences,
}, opts...)
+ claudeOptions := model.GetImplSpecificOptions(&options{TopK: c.topK}, opts...)
- // 在这里开发 OpenAI 的 Model 逻辑
- _ = cmOpts
- _ = implOpts
+ // omit mulple lines...
+ return nil, nil
}
+```
+
+## 编排中的 CallOption
-func (cm *ChatModel) Stream(ctx context.Context, in []*schema.Message,
- opts ...model.Option) (outStream *schema.StreamReader[*schema.Message], err error) {
- // 同 Generate 接口
+[https://github.com/cloudwego/eino/blob/main/compose/runnable.go](https://github.com/cloudwego/eino/blob/main/compose/runnable.go)
+
+Graph 编译产物是 Runnable
+
+```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)
}
```
-### Graph 编译产物
+Runnable 各方法均接收 compose.Option 列表。
-> Graph 的编译产物是 Runnable[I, O]
+[https://github.com/cloudwego/eino/blob/main/compose/graph_call_options.go](https://github.com/cloudwego/eino/blob/main/compose/graph_call_options.go)
-option.go
+包括 graph run 整体的配置,各类组件的配置,特定 Lambda 的配置等。
```go
+// Option is a functional option type for calling a graph.
type Option struct {
- options []any
- nodeHandler []callbacks.Handler
- keys []string
+ options []any
+ handler []callbacks.Handler
- graphHandler []callbacks.Handler
- graphOption []GraphRunOption
-}
+ paths []*NodePath
-// 可指定 NodeKey 定点生效 CallOption
-func (o Option) DesignateNode(key ...string) Option {
- o.keys = append(o.keys, key...)
- return o
+ maxRunSteps int
}
-func WithChatModelOption(opts ...model.Option) Option {
- o := make([]any, 0, len(opts))
- for i := range opts {
- o = append(o, opts[i])
- }
- return Option{
- options: o,
- keys: make([]string, 0),
+// DesignateNode set the key of the node which will the option be applied to.
+// notice: only effective at the top graph.
+// e.g.
+//
+// embeddingOption := compose.WithEmbeddingOption(embedding.WithModel("text-embedding-3-small"))
+// runnable.Invoke(ctx, "input", embeddingOption.DesignateNode("my_embedding_node"))
+func (o Option) DesignateNode(key ...string) Option {
+ nKeys := make([]*NodePath, len(key))
+ for i, k := range key {
+ nKeys[i] = NewNodePath(k)
}
+ return o.DesignateNodeWithPath(nKeys...)
}
-```
-
-runnable.go
-```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)
+// DesignateNodeWithPath sets the path of the node(s) to which the option will be applied to.
+// You can make the option take effect in the subgraph by specifying the key of the subgraph.
+// e.g.
+// DesignateNodeWithPath({"sub graph node key", "node key within sub graph"})
+func (o Option) DesignateNodeWithPath(path ...*NodePath) Option {
+ o.paths = append(o.paths, path...)
+ return o
}
-```
-
-Graph 调用
-```go
-g := NewGraph[map[string]any, *schema.Message]()
-
-_nodeOfModel := &openai.ChatModel{}_
-
-err = g.AddChatModelNode("openAIModel", _nodeOfModel_)
-
-r, err := g.Compile()
-
-// 默认情况下,WithXXX() 的 Option 方法是按照 Component 的类型进行分发的
-// 同一个 WithXXX() 会对同一种 Component 的不同实例同时生效
-// 必要情况下可通过指定 NodeKey,仅针对一个 Node 生效 WithXXX() 方法
-out, err = r.Invoke(ctx, in, WithChatModelOption(
- openai.WithAKSK("ak", "sk"),
- openai.WithURL("url"),
- ),
- // 这组 CallOption 仅针对 openAIModel 这个节点生效
- WithChatModelOption(
- model.WithModel("gpt-3.5-turto"),
- openai.WithAPIKey("xxxx"),
- ).DesignateNode("openAIModel"),
- )
+// WithEmbeddingOption is a functional option type for embedding component.
+// e.g.
+//
+// embeddingOption := compose.WithEmbeddingOption(embedding.WithModel("text-embedding-3-small"))
+// runnable.Invoke(ctx, "input", embeddingOption)
+func WithEmbeddingOption(opts ...embedding.Option) Option {
+ return withComponentOption(opts...)
+}
```
-## 编排中的 CallOption
-
-CallOption 可以按需分配给 Graph 中不同的节点。
+compose.Option 可以按需分配给 Graph 中不同的节点。
![](/img/eino/graph_runnable_after_compile.png)
diff --git a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/callback_manual.md b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/callback_manual.md
index 1dbda21c92..d4f7ac0929 100644
--- a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/callback_manual.md
+++ b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/callback_manual.md
@@ -1,19 +1,12 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Callback 用户手册'
weight: 0
---
-> 💡
-> TL;DR
->
-> 长文,用意是“明确的、无歧义的、充分的”说明 Eino Callback 设计、实现和使用方式的各方面,可用作解决某个具体问题的工具参考,也可以作为入门后想要更进一步了解细节的一个途径。
->
-> 快速入门请移步 :[Eino: 公共切面 - Callbacks](/zh/docs/eino/core_modules/chain_and_graph_orchestration/callbacks_common_aspects)
-
## 解决的问题
Component(包括 Lambda)、Graph 编排共同解决“把业务逻辑定义出来”的问题。而 logging, tracing, metrics, 上屏展示等横切面性质的功能,需要有机制把功能注入到 Component(包括 Lambda)、Graph 中。
@@ -121,8 +114,6 @@ type CallbackInput struct {
Messages []*schema.Message
// Tools is the tools to be used in the model.
Tools []*schema.ToolInfo
- // ToolChoice is the tool choice, which controls the tool to be used in the model.
- ToolChoice any // string / *schema.ToolInfo
// Config is the config for the model.
Config *Config
// Extra is the extra information for the callback.
@@ -194,6 +185,8 @@ Graph 会为内部所有的 Node 自动注入 RunInfo。机制是每个 Node 的
## 触发方式
+![](/img/eino/graph_node_callback_run_place.png)
+
### 组件实现内部触发(Component Callback)
在组件实现的代码中,调用 callbacks 包中的 `OnStart(), OnEnd(), OnError(), OnStartWithStreamInput(), OnEndWithStreamInput()`。以 Ark 的 ChatModel 实现为例,在 Generate 方法中:
@@ -444,3 +437,15 @@ Handler 内不建议修改 input / output。原因是:
不同 Handler 之间,没有执行顺序的保证,因此不建议通过上面的机制在不同 Handler 间传递信息。本质上是无法保证某一个 Handler 返回的 context,一定会进入下一个 Handler 的函数执行中。
如果需要在不同 Handler 之间传递信息,建议的方式是在最外层的 context(如 graph 执行时传入的 context)中,设置一个全局的、请求维度的变量作为公共信息的存取空间,在各个 Handler 中按需读取和更新这个公共变量。在有 stream 的情况下,可能需要格外注意和保证这个公共变量的并发安全。
+
+### 流切记要 Close
+
+以存在 ChatModel 这种具有真流输出的节点为例,当存在 Callback 切面时,ChatModel 的输出流:
+- 既要被下游节点作为输入来消费,又要被 Callback 切面来消费
+- 一个流中的一个帧(Chunk),只能被一个消费方消费到,即流不是广播模型
+
+所以此时需要将流进行复制,其复制关系如下:
+
+![](/img/eino/graph_stream_chunk_copy.png)
+
+- 如果其中一个 Callback n 没有 Close 对应的流,可能导致原始 Stream 无法 Close 和释放资源。
diff --git a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/callbacks_common_aspects.md b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/callbacks_common_aspects.md
deleted file mode 100644
index 9196d78973..0000000000
--- a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/callbacks_common_aspects.md
+++ /dev/null
@@ -1,402 +0,0 @@
----
-Description: ""
-date: "2025-01-15"
-lastmod: ""
-tags: []
-title: 'Eino: 公共切面 - Callbacks'
-weight: 0
----
-
-## 切面
-
-Eino 切面(Eino Callback)是 Eino 框架对开发提供的扩展 Eino 框架,丰富横向治理的能力
-
-可以从以下几个方面,认识 Eino 切面:
-
-- 切面位置:即能在哪些点位添加切面逻辑
-- 切面注入:可通过哪些方式,注入对应的切面逻辑
-- 切面角色
- - 切面机制:由 Eino 框架提供了,扩展 Eino 自身功能的机制
- - 切面扩展者:基于 Eino 的扩展能力,设计和提供各种各样的独立于 Graph 执行的扩展能力
- - 例如:Langfuse Trace 等
- - 切面使用者:真正使用切面扩展能力的终端业务
- - 例如:针对业务编排的 Graph 图,添加 Langfuse Trace 切面能力。方便对编排产物的执行进行观测
-
-### 切面位置
-
-![](/img/eino/callback_in_graph.png)
-
-- 组件切面(Component Callback):组件自带的切面
- - 实现在组件内部的切面执行点位,而不是在加入到 Node 时,由 Node 在组件之外添加的切面点位
- - 组件切面既可应用于 **Graph 编排场景**,也可应用于**组件的独立使用**场景
- - 组件切面、节点切面一般二选一。
- - 当组件声明自己提供组件切面时,节点切面会被自动关闭。
-- 节点切面(Node Callback):组件加入到节点时,由 Node 在组件之外添加的切面点位
- - 由于是在组件之外,只能见到组件的 input/output,无法感知组件运行时的内部状态
- - 仅可应用于 **Graph 编排场景**,在组件独立使用时,无法生效
-- 图切面(Graph Callback):把整张图视为一个整体,在图的前后添加的切面点位
-
-切面生效位置有三种:
-
-- **所有图**的 Graph Callback 和 Node Callback 生效
-- **指定图及其嵌套子图**的 Graph Callback 和 Node Callback 生效
-- **指定图的指定节点**的 Node Callback 生效
-
-### 切面注入
-
-切面的注入方式,有以下三种:
-
-- 全局注入:对所有图的所有节点生效
-- 请求粒度注入:在请求时注入,仅对本次请求所经过的节点均生效
-- 组件实例注入:针对实现了 Component Callback 的组件,可针对该组件实例,单独注入切面
-
-> 注意:不同的注入时机,其对应的 Callback 的生效位置有所不同
-
-#### 全局注入(进程粒度)
-
-- 生效位置: **所有图**的所有节点或组件的 Callback 均生效 + 所有图的 Graph Callback 生效
- - 针对节点、组件哪一个生效的问题,取决于组件是否声明自己实现了 Component Callback。若声明,则仅 Component Callback 生效;若未声明,则 Node Callback 生效
-- 生效时机: Graph 编译产物的**任意一次执行**
-- 注入方式:
- - 通过 callbacks.InitCallbackHandlers() 注入。一个进程中,仅最后一次调用生效。建议放在 main 入口函数中进行初始化
-
-```go
-import "github.com/cloudwego/eino/callbacks"
-
-func main() {
- // 设置全局生效的 Callback Handlers。
- // 一个进程内仅最后一次调用的 callbacks.InitCallbackHandlers() 会生效
- callbacks.InitCallbackHandlers([]callbacks.Handler{&loggerCallbacks{}})
-}
-
-type loggerCallbacks struct{
- *callbacks.HandlerBuilder
-}
-
-func (l *loggerCallbacks) OnStart(ctx context.Context, info *callbacks.RunInfo, input callbacks.CallbackInput) context.Context {
- logs.Infof("name: %v, type: %v, component: %v, input: %v", info.Name, info.Type, info.Component, input)
- return ctx
-}
-
-func (l *loggerCallbacks) OnEnd(ctx context.Context, info *callbacks.RunInfo, output callbacks.CallbackOutput) context.Context {
- logs.Infof("name: %v, type: %v, component: %v, output: %v", info.Name, info.Type, info.Component, output)
- return ctx
-}
-```
-
-#### 请求粒度注入
-
-- 生效的切面位置: **本地调用涉及图及其嵌套子图**的 Graph Callback 和 Node Callback
-- 生效时机: Graph 编译产物的本次调用
-- 注入时机:
- - 调用 Graph 编译产物 Runnable 方法时,例如调用 Invoke()、Stream()方法,通过 Graph Call Option 传入。
- - GraphCallOption:compose.WithCallbacks(handler)
-
-**Graph 示例:**
-
-```go
-package main
-
-import (
- "context"
-
- "github.com/cloudwego/eino/callbacks"
- "github.com/cloudwego/eino/compose"
- "github.com/cloudwego/eino/schema"
-)
-
-func main() {
-
- ctx := context.Background()
-
- // create an instance of your implementation of callbacks.Handler
- handler := &callbacks.HandlerBuilder{}
-
- // create an instance of Graph
- // input type is 1st Graph Node's input type, that is ChatTemplate's input type: map[string]any
- // output type is last Graph Node's output type, that is ToolsNode's output type: []*schema.Message
- g := compose.NewGraph[[]*schema.Message, *schema.Message]()
-
- // add node and edge here
- // err = g.AddChatModelNode("chat_model", chatTpl)
- // if err != nil {
- // logs.Errorf("AddChatTemplateNode failed, err=%v", err)
- // return
- // }
-
- // compile Graph[I, O] to Runnable[I, O]
- r, err := g.Compile()
- if err != nil {
- logs.Errorf("Compile failed, err=%v", err)
- return
- }
-
- _, err = r.Invoke(ctx,
- []*schema.Message{
- schema.SystemMessage("you are a helpful assistant"),
- schema.UserMessage("我叫 zhangsan, 邮箱是 zhangsan@bytedance.com, 帮我推荐一处房产"),
- },
- compose.WithCallbacks(handler),
- )
-
- _, err = r.Stream(ctx, []*schema.Message{
- schema.SystemMessage("you are a helpful assistant"),
- schema.UserMessage("我叫 zhangsan, 邮箱是 zhangsan@bytedance.com, 帮我推荐一处房产"),
- },
- compose.WithCallbacks(handler),
- )
-}
-```
-
-**Chain 示例:**
-
-> 使用方式和 Graph 是一模一样的
-
-```go
-package main
-
-import (
- "context"
-
- "github.com/cloudwego/eino/callbacks"
- "github.com/cloudwego/eino/compose"
- "github.com/cloudwego/eino/schema"
-)
-
-func main() {
-
- ctx := context.Background()
-
- // create an instance of your implementation of callbacks.Handler
- handler := &callbacks.HandlerBuilder{}
-
- // create an instance of Graph
- // input type is 1st Graph Node's input type, that is ChatTemplate's input type: map[string]any
- // output type is last Graph Node's output type, that is ToolsNode's output type: []*schema.Message
- ch := compose.NewChain[[]*schema.Message, *schema.Message]()
-
- // append node here
- // err = ch.AppendChatModel(chatTpl)
- // if err != nil {
- // logs.Errorf("AddChatTemplateNode failed, err=%v", err)
- // return
- // }
-
- // compile Graph[I, O] to Runnable[I, O]
- r, err := ch.Compile()
- if err != nil {
- logs.Errorf("Compile failed, err=%v", err)
- return
- }
-
- _, err = r.Invoke(ctx,
- []*schema.Message{
- schema.SystemMessage("you are a helpful assistant"),
- schema.UserMessage("我叫 zhangsan, 邮箱是 zhangsan@bytedance.com, 帮我推荐一处房产"),
- },
- compose.WithCallbacks(handler),
- )
-
- _, err = r.Stream(ctx, []*schema.Message{
- schema.SystemMessage("you are a helpful assistant"),
- schema.UserMessage("我叫 zhangsan, 邮箱是 zhangsan@bytedance.com, 帮我推荐一处房产"),
- },
- compose.WithCallbacks(handler),
- )
-
-}
-```
-
-## 定制切面
-
-从定制切面的场景出发,会有两种定制需求:
-
-- **切面数据消费**:消费各切面点位上报的切面信息,实现业务定制化的横向治理能力
-- **组件切面上报**:实现一个组件时,定制切面上报的点位,定制上报的切面数据内容
-
-### 切面数据消费
-
-1. 切面数据的消费接口定义
- - CallbackInput 在接口定义中是一个 any, 推荐采用组件抽象定义的结构体进行上报。以 model 组件为例,推荐使用 model.CallbackInput{}
- - CallbackOutput 同 CallbackInput,推荐采用组件抽象定义的结构体上报。
- - 采用推荐的预定义的结构体,有利于切面消费数据时,解析和理解数据内容
-
-```go
-// RunInfo is the info of run node.
-type RunInfo struct {
- Name string
- Type string
- Component components.Component
-}
-
-// CallbackInput is the input of the callback.
-// the type of input is defined by the component.
-// using type Assert or convert func to convert the input to the right type you want.
-// e.g.
-//
-// CallbackInput in components/model/interface.go is:
-// type CallbackInput struct {
-// Messages []*schema.Message
-// Config *Config
-// Extra map[string]any
-// }
-//
-// and provide a func of model.ConvCallbackInput() to convert CallbackInput to *model.CallbackInput
-// in callback handler, you can use the following code to get the input:
-//
-// modelCallbackInput := model.ConvCallbackInput(in)
-// if modelCallbackInput == nil {
-// // is not a model callback input, just ignore it
-// return
-// }
-type CallbackInput any
-
-type CallbackOutput any
-
-type Handler interface {
- OnStart(ctx context.Context, info *RunInfo, input CallbackInput) context.Context
- OnEnd(ctx context.Context, info *RunInfo, output CallbackOutput) context.Context
-
- OnError(ctx context.Context, info *RunInfo, err error) context.Context
-
- OnStartWithStreamInput(ctx context.Context, info *RunInfo,
- input *schema.StreamReader[CallbackInput]) context.Context
- OnEndWithStreamOutput(ctx context.Context, info *RunInfo,
- output *schema.StreamReader[CallbackOutput]) context.Context
-}
-```
-
-1. 定义一个结构体,实现上面的 Handler 接口
- - **WARN****:OnStartWithStreamInput、OnEndWithStreamOutput 中的两个 input/output 流****必须要要关闭****,否则会导致流无法关闭回收,从而导致 Goroutine 或内存缓****慢泄露****。 **
- - 即在这两个函数中一定要调用:input.Close()、output.Close()
- - 考虑到用户可能仅消费部分接口,并且对应的两个流式接口又必须要求 Close(),推荐采用实例化 callbacks.HandlerBuilder{} 的方式,可选实现其中的某几个 OnXXXFn 字段
-
-```go
-import (
- "context"
-
- "github.com/cloudwego/eino/callbacks"
- "github.com/cloudwego/eino/components/model"
-)
-
-var callbackHandler1 = &callbacks.HandlerBuilder{
-
- OnErrorFn: func(ctx context.Context, info *callbacks.RunInfo, err error) context.Context {
- return ctx
- },
-
- OnStartFn: func(ctx context.Context, info *callbacks.RunInfo, input callbacks.CallbackInput) context.Context {
- // 以 ChatModel 为例,将 input 转换为 model.CallbackInput{}
- in := model.ConvCallbackInput(info)
- _ = in
- return ctx
- },
-
- OnStartWithStreamInputFn: func(ctx context.Context, info *callbacks.RunInfo, input *schema.StreamReader[callbacks.CallbackInput]) context.Context {
- // 必须要关闭这个流,否则会导致 Goroutine 溢出
- defer input.Close()
- // implement
- return ctx
- },
-
- OnEndWithStreamOutputFn: func(ctx context.Context, info *callbacks.RunInfo, output *schema.StreamReader[callbacks.CallbackOutput]) context.Context {
- // 必须要关闭这个流,否则会导致 Goroutine 溢出
- defer output.Close()
- // implement
- return ctx
- },
-}
-```
-
-1. 按照 [切面注入](/zh/docs/eino/core_modules/chain_and_graph_orchestration/callbacks_common_aspects) 章节,选择合适的方式,将定制的消费切面注入到 Graph/Chain 即可
-
-#### WARN:Callback 流切记要 Close
-
-以存在 ChatModel 这种具有真流输出的节点为例,当存在 Callback 切面时,ChatModel 的输出流:
-- 既要被下游节点作为输入来消费,又要被 Callback 切面来消费
-- 一个流中的一个帧(Chunk),只能被一个消费方消费到,即流不是广播模型
-
-所以此时需要将流进行复制,其复制关系如下:
-
-![](/img/eino/stream_copy_in_callback.png)
-
-- 如果其中一个 Callback n 没有 Close 对应的流,因此 Stream Coper 可能一直阻塞生产,无法退出,从而导致 Stream Coper 的资源无法及时释放。
-
-### 组件切面上报
-
-当用户定制实现一个组件时,可能因为需要 定制切面上报点位、定制切面上报内容等原因,导致不使用 Node Callback,而是选择定制实现 Component Callback。
-- Node Callback 仅能上报组件抽象的输入输出信息,无法获取更多的组件内部信息。
-
-组件切面定制上报逻辑的示例,以 ChatModel 为例:
-
-```go
-import (
- "context"
- "errors"
- "fmt"
- "io"
- "net/http"
- "runtime/debug"
- "time"
-
-
- "github.com/cloudwego/eino/callbacks"
- "github.com/cloudwego/eino/components/model"
- "github.com/cloudwego/eino/schema"
-)
-
-
-type ChatModel struct {}
-
-func (cm *ChatModel) Generate(ctx context.Context, in []*schema.Message, opts ...model.Option) (
- outMsg *schema.Message, err error) {
-
- var (
- // 从 ctx 中获取 Node 执行时,由 Eino 框架注入的 CallbackManager(cbm)
- cbm, cbmOK = callbacks.ManagerFromCtx(ctx)
- )
-
- defer func() {
- // 如果 cbm 存在,并且产生错误,则在此处上报错误信息
- if err != nil && cbmOK {
- _ = cbm.OnError(ctx, err)
- }
- }()
-
- // TODO: 在这里处理用户请求参数
-
- // 如果 cbm 存在,则在组件逻辑真正执行前,上报请求信息
- if cbmOK {
- ctx = cbm.OnStart(ctx, &model.CallbackInput{
- Messages: in,
- Config: reqConf,
- })
- }
-
- resp, err := cm.cli.CreateChatCompletion(ctx, *req)
- if err != nil {
- return nil, err
- }
-
- // TODO: 在这里处理响应信息,并实现转换
-
- // 在组件逻辑执行结束后,上报组件的处理结果
- if cbmOK {
- _ = cbm.OnEnd(ctx, &model.CallbackOutput{
- Message: outMsg,
- Config: reqConf,
- TokenUsage: usage,
- })
- }
-
- return outMsg, nil
-}
-```
-
-注:当涉及到流式数据的切面上报时,需要将原来的流,Copy 出两份,一份作为输出,一份留作为 Callback 消费(CallbackManager 会根据 Callback Handler 的数量再次进行 Copy)。 针对流的相关操作,可参考 [Stream 流](/zh/docs/eino/overview) 章节
-
-## 常见问题
-
-- 调试环境问题
-- 采样率问题
-- 为什么出现了 goroutine 泄露?
diff --git a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/chain_graph_introduction.md b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/chain_graph_introduction.md
index d14f8c8b7c..3fd948f9b8 100644
--- a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/chain_graph_introduction.md
+++ b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/chain_graph_introduction.md
@@ -1,69 +1,99 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Chain/Graph 编排介绍'
weight: 1
---
+> 本文所有代码样例都在:[https://github.com/cloudwego/eino-examples/tree/main/compose](https://github.com/cloudwego/eino-examples/tree/main/compose)
+
## Graph 编排
### Graph
```go
+package main
+
import (
+ "context"
+ "fmt"
+ "io"
+
+ "github.com/cloudwego/eino/components/model"
+ "github.com/cloudwego/eino/components/prompt"
"github.com/cloudwego/eino/compose"
+ "github.com/cloudwego/eino/schema"
)
const (
- _nodeOfModel _= "model"
- _nodeOfPrompt _= "prompt"
+ nodeOfModel = "model"
+ nodeOfPrompt = "prompt"
)
func main() {
ctx := context.Background()
g := compose.NewGraph[map[string]any, *schema.Message]()
-
+
pt := prompt.FromMessages(
- schema.HumanMessage("what's the weather in {location}?"),
+ schema.FString,
+ schema.UserMessage("what's the weather in {location}?"),
)
-
- err := g.AddChatTemplateNode(_nodeOfPrompt_, pt)
- assert.NoError(t, err)
-
- cm := &chatModel{
- msgs: []*schema.Message{
- {
- Role: schema._AI_,
- Content: "the weather is good",
- },
- },
+
+ _ = g.AddChatTemplateNode(nodeOfPrompt, pt)
+ _ = g.AddChatModelNode(nodeOfModel, &mockChatModel{}, compose.WithNodeName("ChatModel"))
+ _ = g.AddEdge(compose.START, nodeOfPrompt)
+ _ = g.AddEdge(nodeOfPrompt, nodeOfModel)
+ _ = g.AddEdge(nodeOfModel, compose.END)
+
+ r, err := g.Compile(ctx, compose.WithMaxRunSteps(10))
+ if err != nil {
+ panic(err)
}
-
- err = g.AddChatModelNode(_nodeOfModel_, cm, WithNodeName("MockChatModel"))
- assert.NoError(t, err)
-
- err = g.AddEdge(_START_, _nodeOfPrompt_)
- assert.NoError(t, err)
-
- err = g.AddEdge(_nodeOfPrompt_, _nodeOfModel_)
- assert.NoError(t, err)
-
- err = g.AddEdge(_nodeOfModel_, _END_)
- assert.NoError(t, err)
-
- r, err := g.Compile(WithMaxRunSteps(10))
- assert.NoError(t, err)
-
+
in := map[string]any{"location": "beijing"}
ret, err := r.Invoke(ctx, in)
- assert.NoError(t, err)
- t.Logf("invoke result: %v", ret)
-
+ fmt.Println("invoke result: ", ret)
+
// stream
s, err := r.Stream(ctx, in)
- assert.NoError(t, err)
+ if err != nil {
+ panic(err)
+ }
+
+ defer s.Close()
+ for {
+ chunk, err := s.Recv()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ panic(err)
+ }
+
+ fmt.Println("stream chunk: ", chunk)
+ }
+}
+
+type mockChatModel struct{}
+
+func (m *mockChatModel) Generate(ctx context.Context, input []*schema.Message, opts ...model.Option) (*schema.Message, error) {
+ return schema.AssistantMessage("the weather is good", nil), nil
+}
+
+func (m *mockChatModel) Stream(ctx context.Context, input []*schema.Message, opts ...model.Option) (*schema.StreamReader[*schema.Message], error) {
+ sr, sw := schema.Pipe[*schema.Message](0)
+ go func() {
+ defer sw.Close()
+ sw.Send(schema.AssistantMessage("the weather is", nil), nil)
+ sw.Send(schema.AssistantMessage("good", nil), nil)
+ }()
+ return sr, nil
+}
+
+func (m *mockChatModel) BindTools(tools []*schema.ToolInfo) error {
+ panic("implement me")
}
```
@@ -88,37 +118,35 @@ import (
"github.com/cloudwego/eino/components/tool/utils"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
+
+ "github.com/cloudwego/eino-examples/internal/gptr"
+ "github.com/cloudwego/eino-examples/internal/logs"
)
func main() {
- accessKey := os.Getenv("OPENAI_API_KEY")
+ openAIBaseURL := os.Getenv("OPENAI_BASE_URL")
+ openAIAPIKey := os.Getenv("OPENAI_API_KEY")
+ modelName := os.Getenv("MODEL_NAME")
ctx := context.Background()
-
- callbacks.InitCallbackHandlers([]callbacks.Handler{&loggerCallbacks{}})
- const (
- _messageHistories _= "message_histories"
- _messageUserQuery _= "user_query"
- )
+ callbacks.InitCallbackHandlers([]callbacks.Handler{&loggerCallbacks{}})
// 1. create an instance of ChatTemplate as 1st Graph Node
systemTpl := `你是一名房产经纪人,结合用户的薪酬和工作,使用 user_info API,为其提供相关的房产信息。邮箱是必须的`
- chatTpl := prompt.FromMessages(schema._FString_,
+ chatTpl := prompt.FromMessages(schema.FString,
schema.SystemMessage(systemTpl),
- schema.MessagesPlaceholder(_messageHistories_, true),
- schema.MessagesPlaceholder(_messageUserQuery_, false),
+ schema.MessagesPlaceholder("message_histories", true),
+ schema.UserMessage("{user_query}"),
)
- baseURL := "https://search.bytedance.net/gpt/openapi/online/multimodal/crawl"
-
modelConf := &openai.ChatModelConfig{
- BaseURL: baseURL,
- APIKey: accessKey,
+ BaseURL: openAIBaseURL,
+ APIKey: openAIAPIKey,
ByAzure: true,
- Model: "gpt-4o-2024-05-13",
- Temperature: 0.7,
+ Model: modelName,
+ Temperature: gptr.Of(float32(0.7)),
APIVersion: "2024-06-01",
}
@@ -134,7 +162,7 @@ func main() {
&schema.ToolInfo{
Name: "user_info",
Desc: "根据用户的姓名和邮箱,查询用户的公司、职位、薪酬信息",
- Params: map[string]*schema.ParameterInfo{
+ ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
"name": {
Type: "string",
Desc: "用户的姓名",
@@ -143,7 +171,7 @@ func main() {
Type: "string",
Desc: "用户的邮箱",
},
- },
+ }),
},
func(ctx context.Context, input *userInfoRequest) (output *userInfoResponse, err error) {
return &userInfoResponse{
@@ -160,6 +188,7 @@ func main() {
logs.Errorf("Get ToolInfo failed, err=%v", err)
return
}
+
// 4. bind ToolInfo to ChatModel. ToolInfo will remain in effect until the next BindTools.
err = chatModel.BindForcedTools([]*schema.ToolInfo{info})
if err != nil {
@@ -177,9 +206,9 @@ func main() {
}
const (
- _nodeKeyOfTemplate _= "template"
- _nodeKeyOfChatModel _= "chat_model"
- _nodeKeyOfTools _= "tools"
+ nodeKeyOfTemplate = "template"
+ nodeKeyOfChatModel = "chat_model"
+ nodeKeyOfTools = "tools"
)
// 6. create an instance of Graph
@@ -188,50 +217,22 @@ func main() {
g := compose.NewGraph[map[string]any, []*schema.Message]()
// 7. add ChatTemplate into graph
- err = g.AddChatTemplateNode(_nodeKeyOfTemplate_, chatTpl)
- if err != nil {
- logs.Errorf("AddChatTemplateNode failed, err=%v", err)
- return
- }
+ _ = g.AddChatTemplateNode(nodeKeyOfTemplate, chatTpl)
// 8. add ChatModel into graph
- err = g.AddChatModelNode(_nodeKeyOfChatModel_, chatModel)
- if err != nil {
- logs.Errorf("AddChatModelNode failed, err=%v", err)
- return
- }
+ _ = g.AddChatModelNode(nodeKeyOfChatModel, chatModel)
// 9. add ToolsNode into graph
- err = g.AddToolsNode(_nodeKeyOfTools_, toolsNode)
- if err != nil {
- logs.Errorf("AddToolsNode failed, err=%v", err)
- return
- }
+ _ = g.AddToolsNode(nodeKeyOfTools, toolsNode)
// 10. add connection between nodes
- err = g.AddEdge(compose._START_, _nodeKeyOfTemplate_)
- if err != nil {
- logs.Errorf("AddEdge failed,start=%v, end=%v, err=%v", compose._START_, _nodeKeyOfTemplate_, err)
- return
- }
+ _ = g.AddEdge(compose.START, nodeKeyOfTemplate)
- err = g.AddEdge(_nodeKeyOfTemplate_, _nodeKeyOfChatModel_)
- if err != nil {
- logs.Errorf("AddEdge failed,start=%v, end=%v, err=%v", _nodeKeyOfTemplate_, _nodeKeyOfChatModel_, err)
- return
- }
+ _ = g.AddEdge(nodeKeyOfTemplate, nodeKeyOfChatModel)
- err = g.AddEdge(_nodeKeyOfChatModel_, _nodeKeyOfTools_)
- if err != nil {
- logs.Errorf("AddEdge failed,start=%v, end=%v, err=%v", _nodeKeyOfChatModel_, _nodeKeyOfTools_, err)
- return
- }
+ _ = g.AddEdge(nodeKeyOfChatModel, nodeKeyOfTools)
- err = g.AddEdge(_nodeKeyOfTools_, compose._END_)
- if err != nil {
- logs.Errorf("AddEdge failed,start=%v, end=%v, err=%v", _nodeKeyOfTools_, compose._END_, err)
- return
- }
+ _ = g.AddEdge(nodeKeyOfTools, compose.END)
// 9. compile Graph[I, O] to Runnable[I, O]
r, err := g.Compile(ctx)
@@ -241,10 +242,8 @@ func main() {
}
out, err := r.Invoke(ctx, map[string]any{
- _messageHistories_: []*schema.Message{},
- _messageUserQuery_: []*schema.Message{
- schema.UserMessage("我叫 zhangsan, 邮箱是 zhangsan@bytedance.com, 帮我推荐一处房产"),
- },
+ "message_histories": []*schema.Message{},
+ "user_query": "我叫 zhangsan, 邮箱是 zhangsan@bytedance.com, 帮我推荐一处房产",
})
if err != nil {
logs.Errorf("Invoke failed, err=%v", err)
@@ -304,21 +303,24 @@ import (
"context"
"errors"
"io"
- "log"
+ "runtime/debug"
"strings"
"unicode/utf8"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
+ "github.com/cloudwego/eino/utils/safe"
+
+ "github.com/cloudwego/eino-examples/internal/logs"
)
func main() {
ctx := context.Background()
const (
- _nodeOfL1 _= "invokable"
- _nodeOfL2 _= "streamable"
- _nodeOfL3 _= "transformable"
+ nodeOfL1 = "invokable"
+ nodeOfL2 = "streamable"
+ nodeOfL3 = "transformable"
)
type testState struct {
@@ -345,18 +347,15 @@ func main() {
return out, nil
}
- err := sg.AddLambdaNode(_nodeOfL1_, l1,
+ _ = sg.AddLambdaNode(nodeOfL1, l1,
compose.WithStatePreHandler(l1StateToInput), compose.WithStatePostHandler(l1StateToOutput))
- if err != nil {
- log.Printf("sg.AddLambdaNode failed, err=%v", err)
- return
- }
l2 := compose.StreamableLambda(func(ctx context.Context, input string) (output *schema.StreamReader[string], err error) {
outStr := "StreamableLambda: " + input
sr, sw := schema.Pipe[string](utf8.RuneCountInString(outStr))
+ // nolint: byted_goroutine_recover
go func() {
for _, field := range strings.Fields(outStr) {
sw.Send(field+" ", nil)
@@ -372,11 +371,7 @@ func main() {
return out, nil
}
- err = sg.AddLambdaNode(_nodeOfL2_, l2, compose.WithStatePostHandler(l2StateToOutput))
- if err != nil {
- log.Printf("sg.AddLambdaNode failed, err=%v", err)
- return
- }
+ _ = sg.AddLambdaNode(nodeOfL2, l2, compose.WithStatePostHandler(l2StateToOutput))
l3 := compose.TransformableLambda(func(ctx context.Context, input *schema.StreamReader[string]) (
output *schema.StreamReader[string], err error) {
@@ -385,6 +380,16 @@ func main() {
sr, sw := schema.Pipe[string](20)
go func() {
+
+ defer func() {
+ panicErr := recover()
+ if panicErr != nil {
+ err := safe.NewPanicErr(panicErr, debug.Stack())
+ logs.Errorf("panic occurs: %v\n", err)
+ }
+
+ }()
+
for _, field := range strings.Fields(prefix) {
sw.Send(field+" ", nil)
}
@@ -395,8 +400,8 @@ func main() {
if err == io.EOF {
break
}
- // _TODO: how to trace this kind of error in the goroutine of processing sw_
-_ _sw.Send(chunk, err)
+ // TODO: how to trace this kind of error in the goroutine of processing sw
+ sw.Send(chunk, err)
break
}
@@ -411,59 +416,39 @@ _ _sw.Send(chunk, err)
l3StateToOutput := func(ctx context.Context, out string, state *testState) (string, error) {
state.ms = append(state.ms, out)
- log.Printf("state result: ")
+ logs.Infof("state result: ")
for idx, m := range state.ms {
- log.Printf(" %vth: %v", idx, m)
+ logs.Infof(" %vth: %v", idx, m)
}
return out, nil
}
- err = sg.AddLambdaNode(_nodeOfL3_, l3, compose.WithStatePostHandler(l3StateToOutput))
- if err != nil {
- log.Printf("sg.AddLambdaNode failed, err=%v", err)
- return
- }
+ _ = sg.AddLambdaNode(nodeOfL3, l3, compose.WithStatePostHandler(l3StateToOutput))
- err = sg.AddEdge(compose._START_, _nodeOfL1_)
- if err != nil {
- log.Printf("sg.AddEdge failed, err=%v", err)
- return
- }
+ _ = sg.AddEdge(compose.START, nodeOfL1)
- err = sg.AddEdge(_nodeOfL1_, _nodeOfL2_)
- if err != nil {
- log.Printf("sg.AddEdge failed, err=%v", err)
- return
- }
+ _ = sg.AddEdge(nodeOfL1, nodeOfL2)
- err = sg.AddEdge(_nodeOfL2_, _nodeOfL3_)
- if err != nil {
- log.Printf("sg.AddEdge failed, err=%v", err)
- return
- }
+ _ = sg.AddEdge(nodeOfL2, nodeOfL3)
- err = sg.AddEdge(_nodeOfL3_, compose._END_)
- if err != nil {
- log.Printf("sg.AddEdge failed, err=%v", err)
- return
- }
+ _ = sg.AddEdge(nodeOfL3, compose.END)
run, err := sg.Compile(ctx)
if err != nil {
- log.Printf("sg.Compile failed, err=%v", err)
+ logs.Errorf("sg.Compile failed, err=%v", err)
return
}
out, err := run.Invoke(ctx, "how are you")
if err != nil {
- log.Printf("run.Invoke failed, err=%v", err)
+ logs.Errorf("run.Invoke failed, err=%v", err)
return
}
- log.Printf("invoke result: %v", out)
+ logs.Infof("invoke result: %v", out)
stream, err := run.Stream(ctx, "how are you")
if err != nil {
- log.Printf("run.Stream failed, err=%v", err)
+ logs.Errorf("run.Stream failed, err=%v", err)
return
}
@@ -474,11 +459,11 @@ _ _sw.Send(chunk, err)
if errors.Is(err, io.EOF) {
break
}
- log.Printf("stream.Recv() failed, err=%v", err)
+ logs.Infof("stream.Recv() failed, err=%v", err)
break
}
- log.Printf(chunk)
+ logs.Tokenf("%v", chunk)
}
stream.Close()
@@ -488,10 +473,10 @@ _ _sw.Send(chunk, err)
stream, err = run.Transform(ctx, sr)
if err != nil {
- log.Printf("run.Transform failed, err=%v", err)
+ logs.Infof("run.Transform failed, err=%v", err)
return
}
-
+
for {
chunk, err := stream.Recv()
@@ -499,11 +484,11 @@ _ _sw.Send(chunk, err)
if errors.Is(err, io.EOF) {
break
}
- log.Printf("stream.Recv() failed, err=%v", err)
+ logs.Infof("stream.Recv() failed, err=%v", err)
break
}
- log.Printf(chunk)
+ logs.Infof("%v", chunk)
}
stream.Close()
}
@@ -527,23 +512,21 @@ import (
"github.com/cloudwego/eino/components/prompt"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
-)
-
-func init() {
- apiKey := os.Getenv("OPENAI_API_KEY")
- baseURL := os.Getenv("OPENAI_BASE_URL") // using azure
- if apiKey == "" || baseURL != "" {
- return
- }
-}
+ "github.com/cloudwego/eino-examples/internal/gptr"
+ "github.com/cloudwego/eino-examples/internal/logs"
+)
func main() {
+ openAPIBaseURL := os.Getenv("OPENAI_BASE_URL")
+ openAPIAK := os.Getenv("OPENAI_API_KEY")
+ modelName := os.Getenv("MODEL_NAME")
+
ctx := context.Background()
- // 分支节点
- const _randLimit _= 2
+ // build branch func
+ const randLimit = 2
branchCond := func(ctx context.Context, input map[string]any) (string, error) { // nolint: byted_all_nil_return
- if rand.Intn(_randLimit_) == 1 {
+ if rand.Intn(randLimit) == 1 {
return "b1", nil
}
@@ -551,7 +534,7 @@ func main() {
}
b1 := compose.InvokableLambda(func(ctx context.Context, kvs map[string]any) (map[string]any, error) {
- fmt.Println("hello in branch lambda 01")
+ logs.Infof("hello in branch lambda 01")
if kvs == nil {
return nil, fmt.Errorf("nil map")
}
@@ -561,7 +544,7 @@ func main() {
})
b2 := compose.InvokableLambda(func(ctx context.Context, kvs map[string]any) (map[string]any, error) {
- fmt.Println("hello in branch lambda 02")
+ logs.Infof("hello in branch lambda 02")
if kvs == nil {
return nil, fmt.Errorf("nil map")
}
@@ -570,7 +553,7 @@ func main() {
return kvs, nil
})
- // 并发节点
+ // build parallel node
parallel := compose.NewParallel()
parallel.
AddLambda("role", compose.InvokableLambda(func(ctx context.Context, kvs map[string]any) (string, error) {
@@ -586,8 +569,17 @@ func main() {
return "你的叫声是怎样的?", nil
}))
- // 顺序节点
- cm, err := openai.NewChatModel(context.Background(), nil)
+ modelConf := &openai.ChatModelConfig{
+ BaseURL: openAPIBaseURL,
+ APIKey: openAPIAK,
+ ByAzure: true,
+ Model: modelName,
+ Temperature: gptr.Of(float32(0.7)),
+ APIVersion: "2024-06-01",
+ }
+
+ // create chat model node
+ cm, err := openai.NewChatModel(context.Background(), modelConf)
if err != nil {
log.Panic(err)
return
@@ -595,25 +587,25 @@ func main() {
rolePlayerChain := compose.NewChain[map[string]any, *schema.Message]()
rolePlayerChain.
- AppendChatTemplate(prompt.FromMessages(schema._FString_, schema.SystemMessage(`You are a {role}.`), schema.UserMessage(`{input}`))).
+ AppendChatTemplate(prompt.FromMessages(schema.FString, schema.SystemMessage(`You are a {role}.`), schema.UserMessage(`{input}`))).
AppendChatModel(cm)
- // =========== 构建 chain ===========
+ // =========== build chain ===========
chain := compose.NewChain[map[string]any, string]()
chain.
AppendLambda(compose.InvokableLambda(func(ctx context.Context, kvs map[string]any) (map[string]any, error) {
// do some logic to prepare kv as input val for next node
// just pass through
- fmt.Println("in view lambda: ", kvs)
+ logs.Infof("in view lambda: %v", kvs)
return kvs, nil
})).
AppendBranch(compose.NewChainBranch(branchCond).AddLambda("b1", b1).AddLambda("b2", b2)). // nolint: byted_use_receiver_without_nilcheck
+ AppendPassthrough().
AppendParallel(parallel).
AppendGraph(rolePlayerChain).
AppendLambda(compose.InvokableLambda(func(ctx context.Context, m *schema.Message) (string, error) {
// do some logic to check the output or something
- fmt.Println("in view of messages: ", m.Content)
-
+ logs.Infof("in view of messages: %v", m.Content)
return m.Content, nil
}))
@@ -630,7 +622,6 @@ func main() {
return
}
- fmt.Println("output is : ", output)
-
+ logs.Infof("output is : %v", output)
}
```
diff --git a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/orchestration_design_principles.md b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/orchestration_design_principles.md
index b02ddb4271..eb983437fb 100644
--- a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/orchestration_design_principles.md
+++ b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/orchestration_design_principles.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: 编排的设计理念'
@@ -127,7 +127,6 @@ parallel 节点的输出一定是一个 `map[string]any`,其中的 key 则是
```go
func TestParallel() {
chain := compose.NewChain[map[string]any, map[string]*schema.Message]()
- templateNode := &fakeTemplateNode{} // input: map[string]any, output: []*schema.Message
parallel := compose.NewParallel()
model01 := &fakeChatModel{} // input: []*schema.Message, output: *schema.Message
@@ -171,58 +170,72 @@ Workflow 的类型对齐的维度,由整体的 Input & Output 改成了字段
### invoke 和 stream 下的类型对齐方式
-在 eino 中,编排的结果是 graph 或 chain,若要运行,则需要使用 `Compile()` 来生成一个 `Runnable` 接口。
+在 Eino 中,编排的结果是 graph 或 chain,若要运行,则需要使用 `Compile()` 来生成一个 `Runnable` 接口。
-Runnable 的一个重要作用就是提供了 `invoke`、`stream`、`collect`、`transform` 几种调用方式的降级兼容。
+Runnable 的一个重要作用就是提供了 `I``nvoke`、`S``tream`、`C``ollect`、`T``ransform` 四种调用方式。
> 上述几种调用方式的介绍以及详细的 Runnable 介绍可以查看: [Eino: 基础概念介绍](/zh/docs/eino/overview)
-以我们最常见的 invoke 和 stream 模式为例,其接口签名如下:
+假设我们有一个 `Graph[[]*schema.Message, []*schema.Message]`,里面有一个 ChatModel 节点,一个 Lambda 节点,Compile 之后是一个 `Runnable[[]*schema.Message, []*schema.Message]`。
```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)
-}
-```
-
-以 chat model 的场景为例,Runnable 加上 I,O 类型后签名如下:
-
-```go
-type Runnable interface {
- Invoke(ctx context.Context, input []*schema.Message, opts ...Option) (output *schema.Message, err error)
- Stream(ctx context.Context, input []*schema.Message, opts ...Option) (output *schema.StreamReader[*schema.Message], err error)
-}
-```
-
-在 Invoke 模式下,返回的 output 的类型为 `*schema.Message`; 在 Stream 模式下,其返回的 output 类型必须为 `*schema.StreamReader[*schema.Message]`。也就是 stream 的每一帧的类型和 invoke 的结果类型是相同的。
-
-一般来说,Stream 得到的每一帧合并起来应当和 invoke 的结果相同,在上面这个场景中,也即要求:
-
-```go
-func TestInvokeAndStream() {
- var r Runnable[[]*schema.Message, *schema.Message]
-
- reader, err := r.Stream(...)
- allFrames := make([]*schema.Message, 0)
+package main
+
+import (
+ "context"
+ "io"
+ "testing"
+
+ "github.com/cloudwego/eino/compose"
+ "github.com/cloudwego/eino/schema"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestTypeMatch(t *testing.T) {
+ ctx := context.Background()
+
+ g1 := compose.NewGraph[[]*schema.Message, string]()
+ _ = g1.AddChatModelNode("model", &mockChatModel{})
+ _ = g1.AddLambdaNode("lambda", compose.InvokableLambda(func(_ context.Context, msg *schema.Message) (string, error) {
+ return msg.Content, nil
+ }))
+ _ = g1.AddEdge(compose.START, "model")
+ _ = g1.AddEdge("model", "lambda")
+ _ = g1.AddEdge("lambda", compose.END)
+
+ runner, err := g1.Compile(ctx)
+ assert.NoError(t, err)
+
+ c, err := runner.Invoke(ctx, []*schema.Message{
+ schema.UserMessage("what's the weather in beijing?"),
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, "the weather is good", c)
+
+ s, err := runner.Stream(ctx, []*schema.Message{
+ schema.UserMessage("what's the weather in beijing?"),
+ })
+ assert.NoError(t, err)
+
+ var fullStr string
for {
- frame, err := reader.Recev()
- ...
- allFrames = append(allFrames, frame)
- ...
+ chunk, err := s.Recv()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ panic(err)
+ }
+
+ fullStr += chunk
}
-
- invokeRes, err := r.Invoke(...)
-
- // allFrames 合并后需要和 invokeRes 相同
+ assert.Equal(t, c, fullStr)
}
```
-在 stream 模式下,`合并帧` 是一个非常常见的操作,例如在和大模型的交互中,可以把已经接收到的所有帧拼接起来(Concatenate),得到一个完整的输出。
-
-另外,在框架中,当一个仅提供了 Stream 接口的节点,被编排后使用 Invoke 调用,框架则会把 Stream 降级为 Invoke,此时的操作是 底层调用开发者提供的 Stream 接口,获取完整的帧后,把所有帧合并,得到的结果再流转到下一节点。 这个过程中,也是使用的 `拼接``帧` 。
+当我们以 Stream 方式调用上面编译好的 Runnable 时,model 节点会输出 `*schema.StreamReader[*Message]`,但是 lambda 节点是 InvokableLambda,只接收非流式的 `*schema.Message` 作为输入。这也符合类型对齐规则,因为 Eino 框架会自动把流式的 Message 拼接成完整的 Message。
-拼接时,会先把 `*StreamReader[T] ` 中的所有元素取出来转成 `[]T`。框架内已经内置支持了如下类型的拼接:
+在 stream 模式下,`拼接``帧` 是一个非常常见的操作,拼接时,会先把 `*StreamReader[T] ` 中的所有元素取出来转成 `[]T`,再尝试把 `[]T` 拼接成一个完整的 `T`。框架内已经内置支持了如下类型的拼接:
- `*schema.Message`: 详情见 `schema.ConcatMessages()`
- `string`: 实现逻辑等同于 `+=`
@@ -251,7 +264,7 @@ func concatTStreamForTest(items []*tStreamConcatItemForTest) (*tStreamConcatItem
return &tStreamConcatItemForTest{s: s}, nil
}
-func init() {
+func Init() {
// 注册到全局的拼接方法中
compose.RegisterStreamChunkConcatFunc(concatTStreamForTest)
}
@@ -269,16 +282,6 @@ eino 的 Graph 类型对齐检查,会在 `err = graph.AddEdge("node1", "node2"
这种场景适用于开发者能自行处理好上下游类型对齐的情况,可根据不同类型选择下游执行节点。
-## 大模型场景的编排
-
-eino 在编排中的是以大模型应用为核心场景的编排系统,因此在 eino 的编排设计中,是直接把 `component` 作为了编排的直接主体,封装了在大模型应用中最常用的组件,详细的 API 查看: [Eino: 基础概念介绍](/zh/docs/eino/overview)
-
-大多数情况下,业务的实现应当把自己的组件实现为上述组件中的一种,或者直接使用 eino-ext 中已经封装好的组件。
-
-当然,除了上述标准的组件外,还有很多场景我们需要实现一些自定义的代码逻辑,在 eino 中,这就是 `Lambda` 组件。这是一个很泛化的组件,可以基于这个基础组件实现几乎所有的需求,实际上,在 eino 内部,上述的组件也都是使用 lambda 来实现的。
-
-> 更多信息可以参考: [Eino: Components 抽象&实现](/zh/docs/eino/core_modules/components)
-
## 带有明确倾向性的设计选择
### 扇入与合并
diff --git a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/stream_programming_essentials.md b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/stream_programming_essentials.md
index e559bfb6b9..d2251ec4dd 100644
--- a/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/stream_programming_essentials.md
+++ b/content/zh/docs/eino/core_modules/chain_and_graph_orchestration/stream_programming_essentials.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Eino 流式编程要点
@@ -44,6 +44,7 @@ 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)
+ // other methods omitted...
}
```
@@ -101,7 +102,7 @@ Collect 和 Transform 两种流式范式,目前只在编排场景有用到。
上面的 Concat message stream 是 Eino 框架自动提供的能力,即使不是 message,是任意的 T,只要满足特定的条件,Eino 框架都会自动去做这个 StreamReader[T] 到 T 的转化,这个条件是:**在编排中,当一个组件的上游输出是 StreamReader[T],但是组件只提供了 T 作为输入的业务接口时,框架会自动将 StreamReader[T] concat 成 T,再输入给这个组件。**
> 💡
-> 框架自动将 StreamReader[T] concat 成 T 的过程,可能需要用户提供一个 Concat function。详见 [Eino: 编排的设计理念](/zh/docs/eino/core_modules/chain_and_graph_orchestration/orchestration_design_principles) 中关于“合并帧”的章节。
+> 框架自动将 StreamReader[T] concat 成 T 的过程,可能需要用户提供一个 Concat function。详见 [Eino: 编排的设计理念](/zh/docs/eino/core_modules/chain_and_graph_orchestration/orchestration_design_principles#share-FaVnd9E2foy4fAxtbTqcsgq3n5f) 中关于“合并帧”的章节。
另一方面,考虑一个相反的例子。还是 React Agent,这次是一个更完整的编排示意图:
diff --git a/content/zh/docs/eino/core_modules/components/_index.md b/content/zh/docs/eino/core_modules/components/_index.md
index efafb2eea8..6c06618b7a 100644
--- a/content/zh/docs/eino/core_modules/components/_index.md
+++ b/content/zh/docs/eino/core_modules/components/_index.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Components 组件'
@@ -44,17 +44,17 @@ weight: 1
3. Embedding 之后将数据索引进行存储的组件抽象: `Indexer`
-> 详见 [Eino: Indexer & Retriever 使用说明](/zh/docs/eino/core_modules/components/indexer_and_retriever_guide)
+> 详见 [Eino: Indexer 使用说明](/zh/docs/eino/core_modules/components/indexer_guide)
4. 将语义相关文本文档进行索引和召回的组件抽象: `Retriever`
-> 详见 [Eino: Indexer & Retriever 使用说明](/zh/docs/eino/core_modules/components/indexer_and_retriever_guide)
+> 详见 [Eino: Retriever 使用说明](/zh/docs/eino/core_modules/components/retriever_guide)
**决策执行类组件**:
1. 大模型能够做决策并调用工具的组件抽象:`ToolsNode`
-> 详见 [Eino: Tool & ToolsNode 使用说明](/zh/docs/eino/core_modules/components/tool_and_tools_node_guide)
+> 详见 [Eino: ToolsNode 使用说明](/zh/docs/eino/core_modules/components/tools_node_guide)
**自定义组件:**
diff --git a/content/zh/docs/eino/core_modules/components/chat_model_guide.md b/content/zh/docs/eino/core_modules/components/chat_model_guide.md
index 652ba5c0b6..d9bd5bc861 100644
--- a/content/zh/docs/eino/core_modules/components/chat_model_guide.md
+++ b/content/zh/docs/eino/core_modules/components/chat_model_guide.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: ChatModel 使用说明'
@@ -57,8 +57,6 @@ type ChatModel interface {
### **Message 结构体 **
-> ### **[TODO, 放到专门的结构体说明文档中]**
-
```go
type Message struct {
// Role 表示消息的角色(system/user/assistant/tool)
diff --git a/content/zh/docs/eino/core_modules/components/chat_template_guide.md b/content/zh/docs/eino/core_modules/components/chat_template_guide.md
index 2b430cd979..52bf30f06c 100644
--- a/content/zh/docs/eino/core_modules/components/chat_template_guide.md
+++ b/content/zh/docs/eino/core_modules/components/chat_template_guide.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: ChatTemplate 使用说明'
@@ -40,20 +40,19 @@ type ChatTemplate interface {
Prompt 组件内置支持三种模板化方式:
-1. String 格式 (schema.FString)
+1. FString 格式 (schema.FString)
- 使用 `{variable}` 语法进行变量替换
- 简单直观,适合基础文本替换场景
- 示例:`"你是一个{role},请帮我{task}。"`
-2. Template 格式 (schema.FTemplate)
+2. GoTemplate 格式 (schema.GoTemplate)
- 使用 Go 标准库的 text/template 语法
- 支持条件判断、循环等复杂逻辑
- 示例:`"{{if .expert}}作为专家{{end}}请{{.action}}"`
-3. Jinja2 格式 (schema.FJinja2)
+3. Jinja2 格式 (schema.Jinja2)
- 使用 Jinja2 模板语法
- - 支持丰富的过滤器和控制结构
- 示例:`"{% if level == 'expert' %}以专家的角度{% endif %}分析{{topic}}"`
### **公共 Option**
diff --git a/content/zh/docs/eino/core_modules/components/document_loader_guide/document_parser_interface_guide.md b/content/zh/docs/eino/core_modules/components/document_loader_guide/document_parser_interface_guide.md
index ede90f81e8..a51a0d0f55 100644
--- a/content/zh/docs/eino/core_modules/components/document_loader_guide/document_parser_interface_guide.md
+++ b/content/zh/docs/eino/core_modules/components/document_loader_guide/document_parser_interface_guide.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-06"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Document Parser 接口使用说明'
@@ -19,7 +19,14 @@ Document Parser 是一个用于解析文档内容的工具包。它不是一个
### **Parser 接口**
+> 代码位置:eino/components/document/parser/interface.go
+
```go
+import (
+ "github.com/cloudwego/eino/schema"
+)
+
+// Parser is a document parser, can be used to parse a document from a reader.
type Parser interface {
Parse(ctx context.Context, reader io.Reader, opts ...Option) ([]*schema.Document, error)
}
@@ -59,49 +66,76 @@ type Options struct {
最基础的文本解析器,将输入内容直接作为文档内容:
+> 代码位置:eino-examples/components/document/parser/textparser
+
```go
-// 使用示例
-docs, err := TextParser{}.Parse(ctx, strings.NewReader("hello world"))
-if err != nil {
- return err
-}
-fmt.Println(docs[0].Content) // 输出: hello world
+import "github.com/cloudwego/eino/components/document/parser"
+
+textParser := parser.TextParser{}
+docs, _ := textParser.Parse(ctx, strings.NewReader("hello world"))
+
+logs.Infof("text content: %v", docs[0].Content)
```
### **ExtParser**
基于文件扩展名的解析器,可以根据文件扩展名自动选择合适的解析器:
+> 代码位置:eino-examples/components/document/parser/extparser
+
```go
-// 创建扩展解析器
-parser, err := NewExtParser(ctx, &ExtParserConfig{
- // 注册特定扩展名的解析器
- Parsers: map[string]Parser{
- ".html": html.NewParser(&html.ParserConfig{
- // HTML 解析器的配置
- RemoveScript: true, // 移除脚本标签
- RemoveStyle: true, // 移除样式标签
- }),
- ".pdf": pdf.NewParser(&pdf.ParserConfig{
- // PDF 解析器的配置
- ExtractImages: false, // 不提取图片
- }),
- },
- // 设置默认解析器,用于处理未知格式
- FallbackParser: TextParser{},
-})
-if err != nil {
- return err
-}
+package main
+
+import (
+ "context"
+ "os"
-// 使用解析器
-file, _ := os.Open("./document.html")
-docs, err := parser.Parse(ctx, file,
- WithURI("./document.html"), // 必须提供 URI 以便选��正确的解析器
- WithExtraMeta(map[string]any{
- "source": "local",
- }),
+ "github.com/cloudwego/eino-ext/components/document/parser/html"
+ "github.com/cloudwego/eino-ext/components/document/parser/pdf"
+ "github.com/cloudwego/eino/components/document/parser"
+
+ "github.com/cloudwego/eino-examples/internal/gptr"
+ "github.com/cloudwego/eino-examples/internal/logs"
)
+
+func main() {
+ ctx := context.Background()
+
+ textParser := parser.TextParser{}
+
+ htmlParser, _ := html.NewParser(ctx, &html.Config{
+ Selector: gptr.Of("body"),
+ })
+
+ pdfParser, _ := pdf.NewPDFParser(ctx, &pdf.Config{})
+
+ // 创建扩展解析器
+ extParser, _ := parser.NewExtParser(ctx, &parser.ExtParserConfig{
+ // 注册特定扩展名的解析器
+ Parsers: map[string]parser.Parser{
+ ".html": htmlParser,
+ ".pdf": pdfParser,
+ },
+ // 设置默认解析器,用于处理未知格式
+ FallbackParser: textParser,
+ })
+
+ // 使用解析器
+ filePath := "./testdata/test.html"
+ file, _ := os.Open(filePath)
+
+ docs, _ := extParser.Parse(ctx, file,
+ // 必须提供 URI ExtParser 选择正确的解析器进行解析
+ parser.WithURI(filePath),
+ parser.WithExtraMeta(map[string]any{
+ "source": "local",
+ }),
+ )
+
+ for idx, doc := range docs {
+ logs.Infof("doc_%v content: %v", idx, doc.Content)
+ }
+}
```
### 其他实现
diff --git a/content/zh/docs/eino/core_modules/components/document_transformer_guide.md b/content/zh/docs/eino/core_modules/components/document_transformer_guide.md
index aa6a5c7f23..c704f75e00 100644
--- a/content/zh/docs/eino/core_modules/components/document_transformer_guide.md
+++ b/content/zh/docs/eino/core_modules/components/document_transformer_guide.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-06"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Document Transformer 使用说明'
@@ -39,8 +39,6 @@ type Transformer interface {
### **Document 结构体**
-【TODO】 可把所有的公共结构体放到一个特定的地方
-
```go
type Document struct {
// ID 是文档的唯一标识符
diff --git a/content/zh/docs/eino/core_modules/components/embedding_guide.md b/content/zh/docs/eino/core_modules/components/embedding_guide.md
index 1a3b7050ea..4c776fdaa1 100644
--- a/content/zh/docs/eino/core_modules/components/embedding_guide.md
+++ b/content/zh/docs/eino/core_modules/components/embedding_guide.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Embedding 使用说明'
@@ -60,7 +60,7 @@ WithModel(model string) Option
```go
// 初始化 embedder (以 openai 为例)
-embedder, err := openai.NewEmbedder(ctx, &openai.EmbedderConfig{
+embedder, err := openai.NewEmbedding(ctx, &openai.Config{
// 配置参数
})
if err != nil {
diff --git a/content/zh/docs/eino/core_modules/components/indexer_guide.md b/content/zh/docs/eino/core_modules/components/indexer_guide.md
index 57649787b0..db71b142f0 100644
--- a/content/zh/docs/eino/core_modules/components/indexer_guide.md
+++ b/content/zh/docs/eino/core_modules/components/indexer_guide.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Indexer 使用说明'
@@ -142,7 +142,7 @@ result, err := runnable.Invoke(ctx, docs, compose.WithCallbacks(helper))
## **已有实现**
-1. Volc VikingDB Indexer: 基于火山引擎 VikingDB 实现的向量数据库索引器 [Indexer - VikingDB](/zh/docs/eino/ecosystem_integration/indexer_volc_vikingdb)
+1. Volc VikingDB Indexer: 基于火山引擎 VikingDB 实现的向量数据库索引器 [Indexer - VikingDB](/zh/docs/eino/ecosystem_integration/indexer/indexer_volc_vikingdb)
## **自行实现参考**
diff --git a/content/zh/docs/eino/core_modules/components/retriever_guide.md b/content/zh/docs/eino/core_modules/components/retriever_guide.md
index 72113a58bb..abfb1bba0d 100644
--- a/content/zh/docs/eino/core_modules/components/retriever_guide.md
+++ b/content/zh/docs/eino/core_modules/components/retriever_guide.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Retriever 使用说明'
@@ -174,7 +174,7 @@ result, err := runnable.Invoke(ctx, "查询内容", compose.WithCallbacks(helper
## **已有实现**
-- Volc VikingDB Retriever: 基于火山引擎 VikingDB 的检索实现 [Retriever - VikingDB](/zh/docs/eino/ecosystem_integration/retriever_volc_vikingdb)
+- Volc VikingDB Retriever: 基于火山引擎 VikingDB 的检索实现 [Retriever - VikingDB](/zh/docs/eino/ecosystem_integration/retriever/retriever_volc_vikingdb)
## **自行实现参考**
diff --git a/content/zh/docs/eino/core_modules/devops/_index.md b/content/zh/docs/eino/core_modules/devops/_index.md
new file mode 100644
index 0000000000..3542f237fd
--- /dev/null
+++ b/content/zh/docs/eino/core_modules/devops/_index.md
@@ -0,0 +1,10 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: 'EinoDev: 应用开发工具链'
+weight: 4
+---
+
+🚀 Eino 是 Go AI 集成组件的研发框架,提供了 AI 应用相关的常用组件以及集成组件编排能力,为了更好的辅助开发者使用 Eino,我们提供了 「GoLand Eino IDE 插件」 ,现在就安装插件 ( [EinoDev 插件安装指南](/zh/docs/eino/core_modules/devops/ide_plugin_guide)),助你高效开发 🚀
diff --git a/content/zh/docs/eino/core_modules/devops/ide_plugin_guide.md b/content/zh/docs/eino/core_modules/devops/ide_plugin_guide.md
new file mode 100644
index 0000000000..7a694874d8
--- /dev/null
+++ b/content/zh/docs/eino/core_modules/devops/ide_plugin_guide.md
@@ -0,0 +1,64 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: Eino IDE 插件安装指南
+weight: 1
+---
+
+## 背景
+
+> [Eino: 概述](/zh/docs/eino/overview)
+>
+> **🚀 Eino 是 Go AI 集成组件的研发框架,提供了 AI 应用相关的常用组件以及集成组件编排能力,为了更好的辅助开发者使用 Eino,我们提供了 GoLand Eino IDE 插件,助你高效开发 🚀**
+
+## 简介
+
+![](/img/eino/eino_dev_ability_introduction_page.png)
+
+## 安装插件
+
+
+
+1. 进入GoLand,点击设置,选择Plugin 插件
+
+
+ |
+
+1. 通过Marketplace,搜索Eino Dev 插件并按照
+
+
+ |
+
+
+> 💡
+> **插件安装完毕可以在 IDE 右侧插件列表中 EinoDev 调试插件图标啦,接下来就可以体验插件提供的调试与编排能力啦**
+
+![](/img/eino/eino_dev_enter_page.png)
+
+## 功能简介
+
+### **EinoDev Graph 编排**
+
+
+
+
+ |
+
+
+ |
+
+
+### **EinoDev Graph 调试**
+
+
+
+
+ |
+
+
+ |
+
+
+##
diff --git a/content/zh/docs/eino/core_modules/devops/visual_debug_plugin_guide.md b/content/zh/docs/eino/core_modules/devops/visual_debug_plugin_guide.md
new file mode 100644
index 0000000000..8cf8091753
--- /dev/null
+++ b/content/zh/docs/eino/core_modules/devops/visual_debug_plugin_guide.md
@@ -0,0 +1,272 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: EinoDev 可视化调试插件功能指南
+weight: 3
+---
+
+# 简介
+
+> 💡
+> 对使用 Eino 框架编写的编排产物(Graph,Chain)进行可视化调试,包括:
+>
+> 1. 编排产物可视化渲染;
+> 2. 从可操作的任意节点开始,mock 输入进行调试。
+
+# 快速开始
+
+## 下载 eino-example
+
+> github 仓库:_[https://github.com/cloudwego/eino-examples](https://github.com/cloudwego/eino-examples)_
+
+```bash
+# HTTPS
+git clone https://github.com/cloudwego/eino-examples.git
+
+# SSH
+git clone git@github.com:cloudwego/eino-examples.git
+```
+
+## 安装依赖
+
+在项目目录下依次执行以下指令
+
+```bash
+# 1. Pull latest devops repository
+go get github.com/cloudwego/eino-ext/devops@latest
+
+# 2. Cleans and updates go.mod and go.sum
+go mod tidy
+```
+
+## 运行 Demo
+
+进入 `eino-examples/devops/debug/main.go`,运行 `main.go`。因为插件会同时在本地启动一个 HTTP 服务用于连接用户服务进程,所以会弹出接入网络警告,点击允许。
+![](/img/eino/eino_debug_enter_config_page.png)
+
+## 配置调试地址
+
+
+
+
+1.点击左侧或正中间调试功能进入调试配置
+
+
+ |
+
+
+2.点击配置调试地址
+
+
+ |
+
+
+
+
+
+3.填入 127.0.0.1:52538
+
+
+ |
+
+
+4.点击确认进入调试界面,选择要调试的 Graph
+
+
+ |
+
+
+## 开始调试
+
+
+
+
+1.点击Test Run 从 start 节点开始执行
+
+
+ |
+
+
+2.输入"hello eino" ,点击确认
+
+
+ |
+
+
+
+
+
+3.在调试区域展示有各个节点的输入和输出
+
+
+ |
+
+
+4.点击 Input 和 Output 切换查看节点信息
+
+
+ |
+
+
+# 功能一览
+
+## 本地或远程调试
+
+目标调试编排产物无论是在本地电脑还是在远程服务器,都可以通过配置 IP:Port ,主动连接到目标调试对象所在的服务器。
+![](/img/eino/eino_debug_run_config_page.png)
+
+## 编排拓扑可视化
+
+支持 Graph 和 Chain 编排拓扑可视化。
+![](/img/eino/eino_debug_list_nodes_page.png)
+
+## 从任意节点开始调试
+
+![](/img/eino/eino_debug_test_run_of_one_node_page.png)
+
+## 查看节点执行结果
+
+每个节点执行结果都会按执行顺序展示在调试区域,包括:输入、输出、执行耗时
+![](/img/eino/eino_debug_run_detail_v2_page.png)
+
+# 从零开始调试
+
+## 使用 Eino 进行编排
+
+插件支持对 Graph 和 Chain 的编排产物进行调试,假设你已经有编排代码如下
+
+```go
+func RegisterSimpleGraph(ctx context.Context) {
+ g := compose.NewGraph[string, string]()
+ _ = g.AddLambdaNode("node_1", compose.InvokableLambda(func(ctx context.Context, input string) (output string, err error) {
+ return input + " process by node_1,", nil
+ }))
+ _ = g.AddLambdaNode("node_2", compose.InvokableLambda(func(ctx context.Context, input string) (output string, err error) {
+ return input + " process by node_2,", nil
+ }))
+ _ = g.AddLambdaNode("node_3", compose.InvokableLambda(func(ctx context.Context, input string) (output string, err error) {
+ return input + " process by node_3,", nil
+ }))
+
+ _ = g.AddEdge(compose.START, "node_1")
+ _ = g.AddEdge("node_1", "node_2")
+ _ = g.AddEdge("node_2", "node_3")
+ _ = g.AddEdge("node_3", compose.END)
+
+ _, err := g.Compile(ctx)
+ if err != nil {
+ logs.Errorf("compile graph failed, err=%v", err)
+ return
+ }
+}
+```
+
+## 安装依赖
+
+在项目目录下依次执行以下指令
+
+```bash
+# 1. Pull latest devops repository
+go get github.com/cloudwego/eino-ext/devops@latest
+
+# 2. Cleans and updates go.mod and go.sum
+go mod tidy
+```
+
+## 调用调试初始化函数
+
+因为调试需要在用户主进程中启动一个 HTTP 服务,以用作与本地调试插件交互,所以用户需要主动调用一次 _github.com/cloudwego/eino-ext/devops_ 中的 `Init()` 来启动调试服务。
+
+> 💡
+> 注意事项
+>
+> 1. 确保目标调试的编排产物至少执行过一次 `Compile()`。
+> 2. `devops.Init()` 的执行必须要在 Graph/Chain 调用 `Compile()` 之前。
+> 3. 用户需要保证 `devops.Init()` 执行后主进程不能退出。
+
+如在 `main()` 函数中增加调试服务启动代码
+
+```go
+// 1.调用调试服务初始化函数
+err := devops.Init(ctx)
+if err != nil {
+ logs.Errorf("[eino dev] init failed, err=%v", err)
+ return
+}
+
+// 2.编译目标调试的编排产物
+RegisterSimpleGraph(ctx)
+```
+
+## 运行用户进程
+
+在本地电脑或者远程环境中运行你的进程,并保证主进程不会退出。
+
+在 _github.com/cloudwego/eino-examples/devops/debug/main.go__ _中,`main()` 代码如下
+
+```go
+func main() {
+ ctx := context.Background()
+ // Init eino devops server
+ err := devops.Init(ctx)
+ if err != nil {
+ logs.Errorf("[eino dev] init failed, err=%v", err)
+ return
+ }
+
+ // Register chain, graph and state_graph for demo use
+ chain.RegisterSimpleChain(ctx)
+ graph.RegisterSimpleGraph(ctx)
+ graph.RegisterSimpleStateGraph(ctx)
+
+ // Blocking process exits
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+ <-sigs
+
+ // Exit
+ logs.Infof("[eino dev] shutting down\n")
+}
+```
+
+## 配置调试地址
+
+- **IP**:用户进程所在服务器的 IP 地址。
+ - 用户进程运行在本地电脑,则填写 `127.0.0.1`;
+ - 用户进程运行在远程服务器上,则填写远程服务器的 IP 地址,兼容 IPv4 和 IPv6 。
+- **Port**:调试服务监听的端口,默认是 `52538`,可通过 WithDevServerPort 这一 option 方法进行修改
+
+> 💡
+> 注意事项
+>
+> - 本地电脑调试:系统可能会弹出网络接入警告,允许接入即可。
+> - 远程服务器调试:需要你保证端口可访问。
+
+IP 和 Port 配置完成后,点击确认,调试插件会自动连接到目标调试服务器。如果成功连接,连接状态指示器会变成绿色。
+![](/img/eino/eino_debug_ip_port_show_page.png)
+
+## 选择目标调试编排产物
+
+确保你目标调试的编排产物至少执行过一次 `Compile()`。因为调试设计是面向编排产物实例,所以如果多次执行 `Compile()`,会在调试服务中注册多个编排产物,继而在选择列表中看到多个可调试目标。
+![](/img/eino/eino_debug_list_graph_and_show_page.png)
+
+## 开始调试
+
+调试支持从任意节点开始调试,包括 start 节点和其他中间节点。
+
+1. 从 START 节点开始调试:直接点击 Test Run,然后输入 mock 的 input(如果 input 是复杂结构的话,会自动对 input 的结构进行推断)然后点击确定,开始执行你的 graph,每个 node 的结果会在下方显示。
+ ![](/img/eino/eino_debug_enter_test_run_page.png)
+ ![](/img/eino/eino_debug_run_input_mock_data_2_page.png)
+2. 从任意的可操作节点开始调试:比如,从第二个 node 开始执行。
+ ![](/img/eino/eino_debug_test_run_from_node_page.png)
+ ![](/img/eino/eino_debug_run_of_mock_input_of_page.png)
+
+## 查看执行结果
+
+从 START 节点开始调试,点击 Test Run 后,在插件下方查看调试结果。
+![](/img/eino/eino_debug_test_run_result_page.png)
+
+从任意的可操作节点进行调试,在插件下方查看调试结果。
+![](/img/eino/eino_debug_run_detail_page.png)
diff --git a/content/zh/docs/eino/core_modules/devops/visual_orchestration_plugin_guide.md b/content/zh/docs/eino/core_modules/devops/visual_orchestration_plugin_guide.md
new file mode 100644
index 0000000000..4d55a0c769
--- /dev/null
+++ b/content/zh/docs/eino/core_modules/devops/visual_orchestration_plugin_guide.md
@@ -0,0 +1,132 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: EinoDev 可视化编排插件功能指南
+weight: 2
+---
+
+# 简介
+
+> 💡
+> Goland 提供的 Eino 可视化编排插件, 在 GoLand 中可以通过组件拖拽实现 Graph 的编排生成代码,并支持导入导出
+
+## 初认插件
+
+### 插件功能介绍
+
+![](/img/eino/eino_orchestration_describtion_page.png)
+
+## 编排组件介绍
+
+## 图 ( Graph )
+
+- 与 Eino 中的 Graph 概念一致,指最终由插件侧生成的 Graph,可在以下界面添加 Graph。
+- 点击添加插件,则弹出创建对话框,根据字段说明补充配置信息,即可生成一个 Graph 编排对象。
+
+
+
+### 节点 ( Node )
+
+- 与 Eino 中的 Node 一致,创建 Graph 完成后,通过界面右上角 AddNodes ,添加不同类型 Node 到画布。
+- 添加到 Graph 中 Node 插件会默认填写 NodeKey ,此外可展开 More config 为 Node 配置可选配置。
+
+
+
+### 组件 ( Component )
+
+- Component 是组成 Node 的必要信息,不同的 Component 对应不同的 Node 类型,并且提供了内置的官方 Official Components 与 Custom Components 。
+- 完成添加 Node 操作后,可按需配置组件的 Runtime Config 信息。
+
+
+
+
+ |
+
+
+ |
+
+
+### 插槽 ( Slot )
+
+- 不同类型的 Component 的生成会依赖其他组件,将其作为自身配置依赖的一部分,这部分依赖被称作插槽( Slot )。
+- 比如官方提供的 volc_vikingDB 组件,其依赖了 Embeding Component 作为插槽;再比如官方提供的 ToolsNode 组件,其依赖了多个 Tool Component。
+
+
+
+
+ |
+
+
+ |
+
+
+## 开始编排
+
+### 初始化插件
+
+点击进入 Eino Dev 插件,会展示如下界面,可点击图中圈选框进入编排。
+![](/img/eino/eino_orchestration_enter_page.png)
+
+### 创建并编排 Graph
+
+- 界面左下角新增 Graph,在弹窗对话框填写 Graph 相关配置,生成 Graph 画布。
+- 按需从 AddNodes 选择合适的 Node 组件,添加的画布。
+- 依据业务编排逻辑将 Node 组件连接,完成 Graph 业务编排逻辑。
+
+
+
+- 点击 “Generate as code” 并填写指定路径,将编排的 Graph 生成代码并保存到指定路径。
+
+
+
+
+ |
+
+
+ |
+
+
+- 特别的当添加的 Component 为 Graph 类型时,添加的 嵌套 Graph 可展开做 Node 组件的配置,配置完成后,通过顶层面包屑路径跳回首页界面。
+
+
+
+
+ |
+
+
+ |
+
+
+##
diff --git a/content/zh/docs/eino/core_modules/flow_integration_components/_index.md b/content/zh/docs/eino/core_modules/flow_integration_components/_index.md
index a1793a3535..d93d7bcf79 100644
--- a/content/zh/docs/eino/core_modules/flow_integration_components/_index.md
+++ b/content/zh/docs/eino/core_modules/flow_integration_components/_index.md
@@ -1,19 +1,15 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: Flow 集成组件'
weight: 3
---
-大模型应用是存在**通用场景和模式**的,若把这些场景进行抽象,就能提供一些可以帮助开发者快速构建大模型应用的工具。Eino 的 Flow 模块就是在做这件事。
+大模型应用是存在**通用场景和模式**的,若把这些场景进行抽象,就能提供一些可以帮助开发者快速构建大模型应用的模版。Eino 的 Flow 模块就是在做这件事。
-目前 Eino 已经集成了 `react agent`、`host multi agent` 两个常用的模式。
+目前 Eino 已经集成了 `react agent`、`host multi agent` 两个常用的 Agent 模式,以及 MultiQueryRetriever, ParentIndexer 等。
- React Agent: [Eino: React Agent 使用手册](/zh/docs/eino/core_modules/flow_integration_components/react_agent_manual)
- Multi Agent: [Eino Tutorial: Host Multi-Agent ](/zh/docs/eino/core_modules/flow_integration_components/multi_agent_hosting)
-
-> 另外一些常用的模式例如 `retriever agent`、`chat agent`、`summary agent`、`DB agent` 等等,如果你有这类需求,希望 Eino 提供对他们的封装,请联系并和我们交流
-
-# 子目录
diff --git a/content/zh/docs/eino/core_modules/flow_integration_components/multi_agent_hosting.md b/content/zh/docs/eino/core_modules/flow_integration_components/multi_agent_hosting.md
index 5cb916a094..b3ce12d1f0 100644
--- a/content/zh/docs/eino/core_modules/flow_integration_components/multi_agent_hosting.md
+++ b/content/zh/docs/eino/core_modules/flow_integration_components/multi_agent_hosting.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-17"
lastmod: ""
tags: []
title: 'Eino Tutorial: Host Multi-Agent '
@@ -11,9 +11,11 @@ Host Multi-Agent 是一个 Host 做意图识别后,跳转到某个专家 agent
以一个简单的“日记助手”做例子:可以写日记、读日记、根据日记回答问题。
+完整样例参见:[https://github.com/cloudwego/eino-examples/tree/main/flow/agent/multiagent/host/journal](https://github.com/cloudwego/eino-examples/tree/main/flow/agent/multiagent/host/journal)
+
Host:
-```Go
+```go
func newHost(ctx context.Context, baseURL, apiKey, modelName string) (*host.Host, error) {
chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: baseURL,
diff --git a/content/zh/docs/eino/core_modules/flow_integration_components/react_agent_manual.md b/content/zh/docs/eino/core_modules/flow_integration_components/react_agent_manual.md
index 232016d0c0..6980a67331 100644
--- a/content/zh/docs/eino/core_modules/flow_integration_components/react_agent_manual.md
+++ b/content/zh/docs/eino/core_modules/flow_integration_components/react_agent_manual.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-16"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: React Agent 使用手册'
@@ -14,15 +14,19 @@ Eino React Agent 是实现了 [React 逻辑](https://react-lm.github.io/) 的智
> 💡
> 代码实现详见:[实现代码目录](https://github.com/cloudwego/eino/tree/main/flow/agent/react)
+Example 代码路径:[https://github.com/cloudwego/eino-examples/blob/main/flow/agent/react/react.go](https://github.com/cloudwego/eino-examples/blob/main/flow/agent/react/react.go)
+
## 节点拓扑&数据流图
-react agent 底层使用 `compose.StateGraph` 作为编排方案,仅有 2 个节点: ChatModel、Tools,中间运行过程中的所有历史消息都会放入 state 中,在将所有历史消息传递给 ChatModel 之前,会 copy 消息交由 MessageModifier 进行处理,处理的结果再传递给 ChatModel。直到 ChatModel 返回的消息中不再有 tool call,则返回最终消息。
+react agent 底层使用 `compose.Graph` 作为编排方案,一般来说有 2 个节点: ChatModel、Tools,中间运行过程中的所有历史消息都会放入 state 中,在将所有历史消息传递给 ChatModel 之前,会 copy 消息交由 MessageModifier 进行处理,处理的结果再传递给 ChatModel。直到 ChatModel 返回的消息中不再有 tool call,则返回最终消息。
![](/img/eino/react_agent_graph.png)
+当 Tools 列表中至少有一个 Tool 配置了 ReturnDirectly 时,ReAct Agent 结构会更复杂:在 ToolsNode 之后会增加一个 Branch,判断是否调用了一个 ReturnDirectly 的 Tool,如果是,直接 END,否则照旧进入 ChatModel。
+
## 初始化
-提供了 ReactAgent 初始化函数,必填参数为 Model 和 ToolsConfig,选填参数为 MessageModifier 和 MaxStep.
+提供了 ReactAgent 初始化函数,必填参数为 Model 和 ToolsConfig,选填参数为 MessageModifier, MaxStep, ToolReturnDirectly 和 StreamToolCallChecker.
```bash
go get github.com/cloudwego/eino-ext/components/model/openai@latest
@@ -73,7 +77,7 @@ type ChatModel interface {
}
```
-目前,eino 提供了 openai 和 ark 的实现,只要底层模型支持 tool call 即可。
+目前,eino 提供了 openai, ark 等实现,只要底层模型支持 tool call 即可。
```bash
go get github.com/cloudwego/eino-ext/components/model/openai@latest
diff --git a/content/zh/docs/eino/ecosystem_integration/_index.md b/content/zh/docs/eino/ecosystem_integration/_index.md
index 084f26711e..9204b2f675 100644
--- a/content/zh/docs/eino/ecosystem_integration/_index.md
+++ b/content/zh/docs/eino/ecosystem_integration/_index.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-06"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: 生态集成'
@@ -11,7 +11,7 @@ weight: 0
### ChatModel
-- openai: [ChatModel OpenAI](/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai)
+- openai: [ChatModel - OpenAI](/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai)
- ark: [ChatModel - ARK](/zh/docs/eino/ecosystem_integration/chat_model/chat_model_ark)
- ollama: [ChatModel - Ollama](/zh/docs/eino/ecosystem_integration/chat_model/chat_model_ollama)
@@ -19,35 +19,35 @@ weight: 0
#### Loader
-- file: [[🚧]Loader - local file](/zh/docs/eino/ecosystem_integration/document/loader_local_file)
-- s3: [[🚧]Loader - amazon s3](/zh/docs/eino/ecosystem_integration/document/loader_amazon_s3)
-- web url: [[🚧]Loader - web url](/zh/docs/eino/ecosystem_integration/document/loader_web_url)
+- file: [Loader - local file](/zh/docs/eino/ecosystem_integration/document/loader_local_file)
+- s3: [Loader - amazon s3](/zh/docs/eino/ecosystem_integration/document/loader_amazon_s3)
+- web url: [Loader - web url](/zh/docs/eino/ecosystem_integration/document/loader_web_url)
#### Parser
-- html: [[🚧]Parser - html](/zh/docs/eino/ecosystem_integration/document/parser_html)
-- pdf: [[🚧]Parser - pdf](/zh/docs/eino/ecosystem_integration/document/parser_pdf)
+- html: [Parser - html](/zh/docs/eino/ecosystem_integration/document/parser_html)
+- pdf: [Parser - pdf](/zh/docs/eino/ecosystem_integration/document/parser_pdf)
#### Transformer
-- markdown splitter: [[🚧]Splitter - markdown](/zh/docs/eino/ecosystem_integration/document/splitter_markdown)
-- recursive splitter: [[🚧]Splitter - recursive](/zh/docs/eino/ecosystem_integration/document/splitter_recursive)
-- semantic splitter: [[🚧]Splitter - semantic](/zh/docs/eino/ecosystem_integration/document/splitter_semantic)
+- markdown splitter: [Splitter - markdown](/zh/docs/eino/ecosystem_integration/document/splitter_markdown)
+- recursive splitter: [Splitter - recursive](/zh/docs/eino/ecosystem_integration/document/splitter_recursive)
+- semantic splitter: [Splitter - semantic](/zh/docs/eino/ecosystem_integration/document/splitter_semantic)
### Embedding
-- ark: [[🚧]Embedding - ARK](/zh/docs/eino/ecosystem_integration/embedding/embedding_ark)
-- openai: [[🚧]Embedding - OpenAI](/zh/docs/eino/ecosystem_integration/embedding/embedding_openai)
+- ark: [Embedding - ARK](/zh/docs/eino/ecosystem_integration/embedding/embedding_ark)
+- openai: [Embedding - OpenAI](/zh/docs/eino/ecosystem_integration/embedding/embedding_openai)
### Indexer
-- volc vikingdb: [[🚧]Indexer - volc VikingDB](/zh/docs/eino/ecosystem_integration/indexer_volc_vikingdb)
+- volc vikingdb: [Indexer - volc VikingDB](/zh/docs/eino/ecosystem_integration/indexer/indexer_volc_vikingdb)
### Retriever
-- volc vikingdb: [[🚧]Retriever - volc VikingDB](/zh/docs/eino/ecosystem_integration/retriever_volc_vikingdb)
+- volc vikingdb: [Retriever - volc VikingDB](/zh/docs/eino/ecosystem_integration/retriever/retriever_volc_vikingdb)
### Tools
-- googlesearch: [[🚧]Tool - Googlesearch](/zh/docs/eino/ecosystem_integration/tool/tool_googlesearch)
-- duckduckgo search: [[🚧]Tool - DuckDuckGoSearch](/zh/docs/eino/ecosystem_integration/tool/tool_duckduckgo_search)
+- googlesearch: [Tool - Googlesearch](/zh/docs/eino/ecosystem_integration/tool/tool_googlesearch)
+- duckduckgo search: [Tool - DuckDuckGoSearch](/zh/docs/eino/ecosystem_integration/tool/tool_duckduckgo_search)
diff --git a/content/zh/docs/eino/ecosystem_integration/callbacks/_index.md b/content/zh/docs/eino/ecosystem_integration/callbacks/_index.md
new file mode 100644
index 0000000000..7347689761
--- /dev/null
+++ b/content/zh/docs/eino/ecosystem_integration/callbacks/_index.md
@@ -0,0 +1,10 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: Callbacks
+weight: 0
+---
+
+
diff --git a/content/zh/docs/eino/ecosystem_integration/callbacks/callback_langfuse.md b/content/zh/docs/eino/ecosystem_integration/callbacks/callback_langfuse.md
new file mode 100644
index 0000000000..4544af248b
--- /dev/null
+++ b/content/zh/docs/eino/ecosystem_integration/callbacks/callback_langfuse.md
@@ -0,0 +1,39 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: Callback - Langfuse
+weight: 0
+---
+
+Eino 基于 [graph callback](/zh/docs/eino/core_modules/chain_and_graph_orchestration/callback_manual) 能力封装了 langfuse 的 trace 能力(参见 [https://langfuse.com/docs/get-started](https://langfuse.com/docs/get-started)),使用示例如下:
+
+```go
+package main
+
+import (
+ "github.com/cloudwego/eino-ext/callbacks/langfuse"
+ "github.com/cloudwego/eino/callbacks"
+)
+
+func main() {
+ cbh, flusher := NewLangfuseHandler(&_Config_{
+ Host: "https://cloud.langfuse.com",
+ PublicKey: "pk-xxx",
+ SecretKey: "sk-xxx",
+ })
+
+ **callbacks**.InitCallbackHandlers([]**callbacks**._Handler_{cbh}) // 设置langfuse为全局callback
+
+ g := NewGraph[string,string]()
+ /*
+ * compose and run graph
+ */
+
+ flusher() // 等待所有trace上报完成后退出
+}
+```
+
+可以在 Langfuse project 中查看 trace:
+![](/img/eino/eino_callback_langfuse_usage.gif)
diff --git a/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_ollama.md b/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_ollama.md
index 7ed67e3028..1c7a689cb0 100644
--- a/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_ollama.md
+++ b/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_ollama.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: ChatModel - Ollama
@@ -18,7 +18,9 @@ Ollama 模型是 ChatModel 接口的一个实现,用于与 Ollama 本地大语
Ollama 模型通过 `NewChatModel` 函数进行初始化,主要配置参数如下:
```go
-model, err := NewChatModel(ctx, &ChatModelConfig{
+import "github.com/cloudwego/eino-ext/components/model/ollama"
+
+model, err := ollama.NewChatModel(ctx, &ollama.ChatModelConfig{
// 基础配置
BaseURL: "http://localhost:11434", // Ollama 服务地址
Timeout: 30 * time.Second, // 请求超时时间
diff --git a/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai.md b/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai.md
index beac147621..e68b67a50b 100644
--- a/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai.md
+++ b/content/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: ChatModel - OpenAI
@@ -22,6 +22,8 @@ OpenAI 模型是 ChatModel 接口的一个实现,用于与 OpenAI 的 GPT 系
OpenAI 模型通过 `NewChatModel` 函数进行初始化,主要配置参数如下:
```go
+import "github.com/cloudwego/eino-ext/components/model/openai"
+
func main() {
model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
// Azure OpenAI Service 配置(可选)
diff --git a/content/zh/docs/eino/ecosystem_integration/document/loader_amazon_s3.md b/content/zh/docs/eino/ecosystem_integration/document/loader_amazon_s3.md
index 5ac99e004b..7817230955 100644
--- a/content/zh/docs/eino/ecosystem_integration/document/loader_amazon_s3.md
+++ b/content/zh/docs/eino/ecosystem_integration/document/loader_amazon_s3.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Loader - amazon s3
@@ -22,13 +22,19 @@ Amazon Simple Storage Service (Amazon S3) 是一种对象存储服务,提供
S3 文档加载器通过 `NewS3Loader` 函数进行初始化,主要配置参数如下:
```go
-loader, err := NewS3Loader(ctx, &LoaderConfig{
- Region: aws.String("us-east-1"), // AWS 区域
- AWSAccessKey: aws.String("your-access-key"), // AWS 访问密钥ID
- AWSSecretKey: aws.String("your-secret-key"), // AWS 访问密钥
- UseObjectKeyAsID: true, // 是否使用对象键作为文档ID
- Parser: &parser.TextParser{}, // 文档解析器,默认为 TextParser
-})
+import (
+ "github.com/cloudwego/eino-ext/components/document/loader/s3"
+)
+
+func main() {
+ loader, err := s3.NewS3Loader(ctx, &s3.LoaderConfig{
+ Region: aws.String("us-east-1"), // AWS 区域
+ AWSAccessKey: aws.String("your-access-key"), // AWS 访问密钥ID
+ AWSSecretKey: aws.String("your-secret-key"), // AWS 访问密钥
+ UseObjectKeyAsID: true, // 是否使用对象键作为文档ID
+ Parser: &parser.TextParser{}, // 文档解析器,默认为 TextParser
+ })
+}
```
配置参数说明:
@@ -71,15 +77,14 @@ import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
- s3loader "github.com/cloudwego/eino-ext/components/document/loader/s3"
+ "github.com/cloudwego/eino-ext/components/document/loader/s3"
"github.com/cloudwego/eino/components/document"
)
func main() {
ctx := context.Background()
-
- // 初始化加��器
- loader, err := s3loader.NewS3Loader(ctx, &s3loader.LoaderConfig{
+
+ loader, err := s3.NewS3Loader(ctx, &s3.LoaderConfig{
Region: aws.String("us-east-1"),
AWSAccessKey: aws.String("your-access-key"),
AWSSecretKey: aws.String("your-secret-key"),
diff --git a/content/zh/docs/eino/ecosystem_integration/document/loader_local_file.md b/content/zh/docs/eino/ecosystem_integration/document/loader_local_file.md
index a01cd45863..fcdd008412 100644
--- a/content/zh/docs/eino/ecosystem_integration/document/loader_local_file.md
+++ b/content/zh/docs/eino/ecosystem_integration/document/loader_local_file.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Loader - local file
@@ -27,10 +27,16 @@ local file 文件加载器是 Document Loader 接口的一个实现,用于从
本地文件加载器通过 `NewFileLoader` 函数进行初始化,主要配置参数如下:
```go
-loader, err := NewFileLoader(ctx, &FileLoaderConfig{
- UseNameAsID: true, // 是否使用文件名作为文档ID
- Parser: &parser.TextParser{}, // 可选:指定自定义解析器
-})
+import (
+ "github.com/cloudwego/eino/components/document/loader/file"
+)
+
+func main() {
+ loader, err := file.NewFileLoader(ctx, &FileLoaderConfig{
+ UseNameAsID: true, // 是否使用文件名作为文档ID
+ Parser: &parser.TextParser{}, // 可选:指定自定义解析器
+ })
+}
```
配置参数说明:
@@ -70,7 +76,7 @@ package main
import (
"context"
- fileloader "github.com/cloudwego/eino-ext/components/document/loader/file"
+ file "github.com/cloudwego/eino-ext/components/document/loader/file"
"github.com/cloudwego/eino/components/document"
)
@@ -78,7 +84,7 @@ func main() {
ctx := context.Background()
// 初始化加载器
- loader, err := fileloader.NewFileLoader(ctx, &fileloader.FileLoaderConfig{
+ loader, err := file.NewFileLoader(ctx, &file.FileLoaderConfig{
UseNameAsID: true,
})
if err != nil {
@@ -97,9 +103,9 @@ func main() {
for _, doc := range docs {
println(doc.Content)
// 访问元数据
- fileName := doc.MetaData[fileloader.MetaKeyFileName]
- extension := doc.MetaData[fileloader.MetaKeyExtension]
- source := doc.MetaData[fileloader.MetaKeySource]
+ fileName := doc.MetaData[file.MetaKeyFileName]
+ extension := doc.MetaData[file.MetaKeyExtension]
+ source := doc.MetaData[file.MetaKeySource]
}
}
```
diff --git a/content/zh/docs/eino/ecosystem_integration/document/loader_web_url.md b/content/zh/docs/eino/ecosystem_integration/document/loader_web_url.md
index 648160f8ca..00cd396511 100644
--- a/content/zh/docs/eino/ecosystem_integration/document/loader_web_url.md
+++ b/content/zh/docs/eino/ecosystem_integration/document/loader_web_url.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Loader - web url
@@ -26,11 +26,17 @@ URL 文档加载器具有以下特点:
URL 文档加载器通过 `NewLoader` 函数进行初始化,主要配置参数如下:
```go
-loader, err := NewLoader(ctx, &LoaderConfig{
- Parser: parser, // 可选:自定义解析器,默认使用 HTML 解析器
- Client: httpClient, // 可选:自定义 HTTP 客户端
- RequestBuilder: requestBuilder, // 可选:自定义请求构建器
-})
+import (
+ "github.com/cloudwego/eino-ext/components/document/loader/url"
+)
+
+func main() {
+ loader, err := url.NewLoader(ctx, &url.LoaderConfig{
+ Parser: parser,
+ Client: httpClient,
+ RequestBuilder: requestBuilder,
+ })
+}
```
配置参数说明:
@@ -65,7 +71,7 @@ package main
import (
"context"
- urlloader "github.com/cloudwego/eino-ext/components/document/loader/url"
+ "github.com/cloudwego/eino-ext/components/document/loader/url"
"github.com/cloudwego/eino/components/document"
)
@@ -73,7 +79,7 @@ func main() {
ctx := context.Background()
// 使用默认配置初始化加载器
- loader, err := urlloader.NewLoader(ctx, nil)
+ loader, err := url.NewLoader(ctx, nil)
if err != nil {
panic(err)
}
@@ -103,7 +109,7 @@ import (
"net/http"
"time"
- urlloader "github.com/cloudwego/eino-ext/components/document/loader/url"
+ "github.com/cloudwego/eino-ext/components/document/loader/url"
"github.com/cloudwego/eino/components/document"
)
@@ -127,7 +133,7 @@ func main() {
}
// 初始化加载器
- loader, err := urlloader.NewLoader(ctx, &urlloader.LoaderConfig{
+ loader, err := url.NewLoader(ctx, &url.LoaderConfig{
Client: client,
RequestBuilder: requestBuilder,
})
diff --git a/content/zh/docs/eino/ecosystem_integration/document/parser_html.md b/content/zh/docs/eino/ecosystem_integration/document/parser_html.md
index d2a875e707..5197b8e95d 100644
--- a/content/zh/docs/eino/ecosystem_integration/document/parser_html.md
+++ b/content/zh/docs/eino/ecosystem_integration/document/parser_html.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Parser - html
@@ -29,7 +29,11 @@ HTML 解析器具有以下特点:
HTML 解析器通过 `NewParser` 函数进行初始化,主要配置参数如下:
```go
-parser, err := NewParser(ctx, &Config{
+import (
+ "github.com/cloudwego/eino-ext/components/document/parser/html"
+)
+
+parser, err := html.NewParser(ctx, &html.Config{
Selector: &selector, // 可选:内容选择器,默认为 body
})
```
@@ -61,7 +65,7 @@ import (
"context"
"strings"
- htmlparser "github.com/cloudwego/eino-ext/components/document/parser/html"
+ "github.com/cloudwego/eino-ext/components/document/parser/html"
"github.com/cloudwego/eino/components/document/parser"
)
@@ -69,7 +73,7 @@ func main() {
ctx := context.Background()
// 初始化解析器
- p, err := htmlparser.NewParser(ctx, nil) // 使用默认配置
+ p, err := html.NewParser(ctx, nil) // 使用默认配置
if err != nil {
panic(err)
}
@@ -105,9 +109,9 @@ func main() {
// 使用解析结果
doc := docs[0]
println("内容:", doc.Content)
- println("标题:", doc.MetaData[htmlparser.MetaKeyTitle])
- println("描述:", doc.MetaData[htmlparser.MetaKeyDesc])
- println("语言:", doc.MetaData[htmlparser.MetaKeyLang])
+ println("标题:", doc.MetaData[html.MetaKeyTitle])
+ println("描述:", doc.MetaData[html.MetaKeyDesc])
+ println("语言:", doc.MetaData[html.MetaKeyLang])
}
```
@@ -119,7 +123,7 @@ package main
import (
"context"
- htmlparser "github.com/cloudwego/eino-ext/components/document/parser/html"
+ "github.com/cloudwego/eino-ext/components/document/parser/html"
)
func main() {
@@ -127,7 +131,7 @@ func main() {
// 指定只提取 id 为 content 的元素内容
selector := "#content"
- p, err := htmlparser.NewParser(ctx, &htmlparser.Config{
+ p, err := html.NewParser(ctx, &html.Config{
Selector: &selector,
})
if err != nil {
diff --git a/content/zh/docs/eino/ecosystem_integration/document/parser_pdf.md b/content/zh/docs/eino/ecosystem_integration/document/parser_pdf.md
index c2d85ba051..0ba183b0f0 100644
--- a/content/zh/docs/eino/ecosystem_integration/document/parser_pdf.md
+++ b/content/zh/docs/eino/ecosystem_integration/document/parser_pdf.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Parser - pdf
@@ -36,9 +36,15 @@ PDF 解析器具有以下特点:
PDF 解析器通过 `NewPDFParser` 函数进行初始化,主要配置参数如下:
```go
-parser, err := NewPDFParser(ctx, &Config{
- ToPages: true, // 是否按页面分割文档
-})
+import (
+ "github.com/cloudwego/eino-ext/components/document/parser/pdf"
+)
+
+func main() {
+ parser, err := pdf.NewPDFParser(ctx, &pdf.Config{
+ ToPages: true, // 是否按页面分割文档
+ })
+}
```
配置参数说明:
@@ -69,7 +75,7 @@ import (
"context"
"os"
- pdfparser "github.com/cloudwego/eino-ext/components/document/parser/pdf"
+ "github.com/cloudwego/eino-ext/components/document/parser/pdf"
"github.com/cloudwego/eino/components/document/parser"
)
@@ -77,7 +83,7 @@ func main() {
ctx := context.Background()
// 初始化解析器
- p, err := pdfparser.NewPDFParser(ctx, &pdfparser.Config{
+ p, err := pdf.NewPDFParser(ctx, &pdf.Config{
ToPages: false, // 不按页面分割
})
if err != nil {
@@ -95,7 +101,7 @@ func main() {
docs, err := p.Parse(ctx, file,
parser.WithURI("document.pdf"),
parser.WithExtraMeta(map[string]any{
- "source": "local",
+ "source": "./document.pdf",
}),
)
if err != nil {
diff --git a/content/zh/docs/eino/ecosystem_integration/document/splitter_recursive.md b/content/zh/docs/eino/ecosystem_integration/document/splitter_recursive.md
index 8a116824d5..776b19f0bd 100644
--- a/content/zh/docs/eino/ecosystem_integration/document/splitter_recursive.md
+++ b/content/zh/docs/eino/ecosystem_integration/document/splitter_recursive.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Splitter - recursive
@@ -134,8 +134,6 @@ splitter, err := recursive.NewSplitter(ctx, &recursive.Config{
"\n\n", // 空行(段落分隔)
"\n", // 换行
"。", // 句号
- ";", // 分号
- ",", // 逗号
},
})
```
diff --git a/content/zh/docs/eino/ecosystem_integration/document/splitter_semantic.md b/content/zh/docs/eino/ecosystem_integration/document/splitter_semantic.md
index 85b2d1706f..e0c059f10b 100644
--- a/content/zh/docs/eino/ecosystem_integration/document/splitter_semantic.md
+++ b/content/zh/docs/eino/ecosystem_integration/document/splitter_semantic.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Splitter - semantic
@@ -18,7 +18,7 @@ weight: 0
1. 首先使用基本分隔符(如换行符、句号等)将文档分割成始片段
2. 使用向量嵌入模型为每个片段生成语义向量
3. 计算相邻片段之间的余弦相似度
-4. 根据相似度阈值(由百分位数控制)决定是否在两个片段之间进行分割
+4. 根据相似度阈值决定是否在两个片段之间进行分割
5. 对小于最小大小的片段进行合并
## **使用方式**
diff --git a/content/zh/docs/eino/ecosystem_integration/embedding/embedding_ark.md b/content/zh/docs/eino/ecosystem_integration/embedding/embedding_ark.md
index 3b6e456e32..22396aaa8d 100644
--- a/content/zh/docs/eino/ecosystem_integration/embedding/embedding_ark.md
+++ b/content/zh/docs/eino/ecosystem_integration/embedding/embedding_ark.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Embedding - ARK
@@ -18,7 +18,9 @@ Ark Embedding 是 Eino Embedding 接口的一个实现,用于将文本转换
Ark 向量嵌入器通过 `NewEmbedder` 函数进行初始化,主要配置参数如下:
```go
-embedder, err := NewEmbedder(ctx, &EmbeddingConfig{
+import "github.com/cloudwego/eino-ext/components/embedding/ark"
+
+embedder, err := ark.NewEmbedder(ctx, &ark.EmbeddingConfig{
// 认证配置(二选一)
APIKey: "your-api-key", // 使用 API Key 认证
// 或使用 AK/SK 认证
diff --git a/content/zh/docs/eino/ecosystem_integration/embedding/embedding_openai.md b/content/zh/docs/eino/ecosystem_integration/embedding/embedding_openai.md
index 7b5d37db57..e8883842f1 100644
--- a/content/zh/docs/eino/ecosystem_integration/embedding/embedding_openai.md
+++ b/content/zh/docs/eino/ecosystem_integration/embedding/embedding_openai.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Embedding - OpenAI
@@ -22,7 +22,9 @@ OpenAI 向量嵌入器是 Eino Embedding 接口的一个实现,用于将文本
OpenAI 向量嵌入器通过 `NewEmbedder` 函数进行初始化,主要配置参数如下:
```go
-embedder, err := NewEmbedder(ctx, &EmbeddingConfig{
+import "github.com/cloudwego/eino-ext/components/embedding/openai"
+
+embedder, err := openai.NewEmbedder(ctx, &openai.EmbeddingConfig{
// OpenAI API 配置
APIKey: "your-api-key",
Model: "text-embedding-ada-002",
@@ -32,8 +34,7 @@ embedder, err := NewEmbedder(ctx, &EmbeddingConfig{
ByAzure: true,
BaseURL: "https://your-resource.openai.azure.com",
APIVersion: "2023-05-15",
-
- // 可选:高级配置
+
EncodingFormat: &format, // 编码格式
Dimensions: &dimension, // 向量维度
User: &user, // 用户标识
diff --git a/content/zh/docs/eino/ecosystem_integration/indexer/_index.md b/content/zh/docs/eino/ecosystem_integration/indexer/_index.md
new file mode 100644
index 0000000000..b37e9ddda2
--- /dev/null
+++ b/content/zh/docs/eino/ecosystem_integration/indexer/_index.md
@@ -0,0 +1,10 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: Indexer
+weight: 0
+---
+
+Indexer 为把文本进行索引存储,一般使用 [Embedding](/zh/docs/eino/ecosystem_integration/embedding) 做语义化索引,也可做分词索引等,以便于 [Retriever](/zh/docs/eino/ecosystem_integration/retriever) 中召回使用
diff --git a/content/zh/docs/eino/ecosystem_integration/indexer_volc_vikingdb.md b/content/zh/docs/eino/ecosystem_integration/indexer/indexer_volc_vikingdb.md
similarity index 92%
rename from content/zh/docs/eino/ecosystem_integration/indexer_volc_vikingdb.md
rename to content/zh/docs/eino/ecosystem_integration/indexer/indexer_volc_vikingdb.md
index 0c89a0351d..e8567464b7 100644
--- a/content/zh/docs/eino/ecosystem_integration/indexer_volc_vikingdb.md
+++ b/content/zh/docs/eino/ecosystem_integration/indexer/indexer_volc_vikingdb.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Indexer - volc VikingDB
@@ -25,8 +25,10 @@ weight: 0
火山引擎 VikingDB 索引器通过 `NewIndexer` 函数进行初始化,主要配置参数如下:
```go
-indexer, err := NewIndexer(ctx, &IndexerConfig{
- Host: "api.volcengineapi.com", // 服务地址
+import "github.com/cloudwego/eino-ext/components/indexer/volc_vikingdb"
+
+indexer, err := volc_vikingdb.NewIndexer(ctx, &volc_vikingdb.IndexerConfig{
+ Host: "api-vikingdb.volces.com", // 服务地址
Region: "cn-beijing", // 区域
AK: "your-ak", // Access Key
SK: "your-sk", // Secret Key
@@ -35,7 +37,7 @@ indexer, err := NewIndexer(ctx, &IndexerConfig{
Collection: "your-collection", // 集合名称
- EmbeddingConfig: EmbeddingConfig{
+ EmbeddingConfig: volc_vikingdb.EmbeddingConfig{
UseBuiltin: true, // 是否使用内置向量化
ModelName: "text2vec-base", // 模型名称
UseSparse: true, // 是否使用稀疏向量
@@ -65,7 +67,7 @@ func main() {
// 初始化索引器
idx, err := volcvikingdb.NewIndexer(ctx, &volcvikingdb.IndexerConfig{
- Host: "api.volcengineapi.com",
+ Host: "api-vikingdb.volces.com",
Region: "cn-beijing",
AK: "your-ak",
SK: "your-sk",
@@ -130,7 +132,7 @@ func main() {
// 初始化索引器
idx, err := volcvikingdb.NewIndexer(ctx, &volcvikingdb.IndexerConfig{
- Host: "api.volcengineapi.com",
+ Host: "api-vikingdb.volces.com",
Region: "cn-beijing",
AK: "your-ak",
SK: "your-sk",
diff --git a/content/zh/docs/eino/ecosystem_integration/retriever/_index.md b/content/zh/docs/eino/ecosystem_integration/retriever/_index.md
new file mode 100644
index 0000000000..cd054e9756
--- /dev/null
+++ b/content/zh/docs/eino/ecosystem_integration/retriever/_index.md
@@ -0,0 +1,10 @@
+---
+Description: ""
+date: "2025-01-20"
+lastmod: ""
+tags: []
+title: Retriever
+weight: 0
+---
+
+Retriever 用于把 [Indexer](/zh/docs/eino/ecosystem_integration/indexer) 构建索引之后的内容进行召回,在 AI 应用中,一般使用 [Embedding](/zh/docs/eino/ecosystem_integration/embedding) 进行语义相似性召回。
diff --git a/content/zh/docs/eino/ecosystem_integration/retriever_volc_vikingdb.md b/content/zh/docs/eino/ecosystem_integration/retriever/retriever_volc_vikingdb.md
similarity index 91%
rename from content/zh/docs/eino/ecosystem_integration/retriever_volc_vikingdb.md
rename to content/zh/docs/eino/ecosystem_integration/retriever/retriever_volc_vikingdb.md
index d46b7010b2..b6d3f719dc 100644
--- a/content/zh/docs/eino/ecosystem_integration/retriever_volc_vikingdb.md
+++ b/content/zh/docs/eino/ecosystem_integration/retriever/retriever_volc_vikingdb.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Retriever - volc VikingDB
@@ -18,9 +18,11 @@ weight: 0
火山引擎 VikingDB 检索器通过 `NewRetriever` 函数进行初始化,主要配置参数如下:
```go
-retriever, err := NewRetriever(ctx, &RetrieverConfig{
+import "github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb"
+
+retriever, err := volc_vikingdb.NewRetriever(ctx, &volc_vikingdb.RetrieverConfig{
// 服务配置
- Host: "api.volcengineapi.com", // 服务地址
+ Host: "api-vikingdb.volces.com", // 服务地址
Region: "cn-beijing", // 区域
AK: "your-ak", // 访问密钥 ID
SK: "your-sk", // 访问密钥密码
@@ -32,7 +34,7 @@ retriever, err := NewRetriever(ctx, &RetrieverConfig{
Index: "index-name", // 索引名称
// 向量化配置
- EmbeddingConfig: EmbeddingConfig{
+ EmbeddingConfig: volc_vikingdb.EmbeddingConfig{
UseBuiltin: true, // 是否使用内置向量化
ModelName: "model-name",// 模型名称
UseSparse: true, // 是否使用稀疏向量
@@ -80,7 +82,7 @@ func main() {
// 初始化检索器
r, err := volc_vikingdb.NewRetriever(ctx, &volc_vikingdb.RetrieverConfig{
- Host: "api.volcengineapi.com",
+ Host: "api-vikingdb.volces.com",
Region: "cn-beijing",
AK: "your-ak",
SK: "your-sk",
@@ -136,7 +138,7 @@ func main() {
// 初始化检索器
r, err := volc_vikingdb.NewRetriever(ctx, &volc_vikingdb.RetrieverConfig{
- Host: "api.volcengineapi.com",
+ Host: "api-vikingdb.volces.com",
Region: "cn-beijing",
AK: "your-ak",
SK: "your-sk",
diff --git a/content/zh/docs/eino/ecosystem_integration/tool/tool_duckduckgo_search.md b/content/zh/docs/eino/ecosystem_integration/tool/tool_duckduckgo_search.md
index baa7cde1a6..9550d910e2 100644
--- a/content/zh/docs/eino/ecosystem_integration/tool/tool_duckduckgo_search.md
+++ b/content/zh/docs/eino/ecosystem_integration/tool/tool_duckduckgo_search.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-06"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Tool - DuckDuckGoSearch
@@ -18,7 +18,9 @@ DuckDuckGo 搜索工具是 Tool InvokableTool 接口的一个实现,用于通
DuckDuckGo 搜索工具通过 `NewTool` 函数进行初始化,主要配置参数如下:
```go
-tool, err := NewTool(ctx, &Config{
+import "github.com/cloudwego/eino-ext/components/tool/duckduckgo"
+
+tool, err := duckduckgo.NewTool(ctx, &duckduckgo.Config{
ToolName: "duckduckgo_search", // 工具名称
ToolDesc: "search web for information by duckduckgo", // 工具描述
Region: ddgsearch.RegionWT, // 搜索地区
diff --git a/content/zh/docs/eino/ecosystem_integration/tool/tool_googlesearch.md b/content/zh/docs/eino/ecosystem_integration/tool/tool_googlesearch.md
index 3954fc6fa4..0ab0ea98d3 100644
--- a/content/zh/docs/eino/ecosystem_integration/tool/tool_googlesearch.md
+++ b/content/zh/docs/eino/ecosystem_integration/tool/tool_googlesearch.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Tool - Googlesearch
@@ -18,7 +18,9 @@ Google 搜索工具是 Eino InvokableTool 接口的一个实现,用于通过 G
Google 搜索工具通过 `NewGoogleSearchTool` 函数进行初始化,主要配置参数如下:
```go
-tool, err := NewGoogleSearchTool(ctx, &Config{
+import "github.com/cloudwego/eino-ext/components/tool/googlesearch"
+
+tool, err := googlesearch.NewTool(ctx, &googlesearch.Config{
APIKey: "your-api-key", // Google API 密钥
SearchEngineID: "your-engine-id", // 搜索引擎 ID
BaseURL: "custom-base-url", // 可选:自定义 API 基础 URL, default: https://customsearch.googleapis.com
@@ -58,7 +60,7 @@ func main() {
ctx := context.Background()
// 初始化搜索工具
- searchTool, err := googlesearch.NewGoogleSearchTool(ctx, &googlesearch.Config{
+ searchTool, err := googlesearch.NewTool(ctx, &googlesearch.Config{
APIKey: "your-api-key",
SearchEngineID: "your-engine-id",
Lang: "zh-CN",
diff --git a/content/zh/docs/eino/overview/_index.md b/content/zh/docs/eino/overview/_index.md
index 07e03aa430..bba9fff4b4 100644
--- a/content/zh/docs/eino/overview/_index.md
+++ b/content/zh/docs/eino/overview/_index.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-16"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: 概述'
@@ -24,8 +24,6 @@ Eino 可在 AI 应用开发周期中的不同阶段,规范、简化和提效
- Deployment: 提供丰富的对 AI 应用的评测能力
- Maintenance: 提供丰富的切面对 AI 应用进行观测、监控
-![](/img/eino/eino_project_structure_and_modules.png)
-
完整 API Reference:[https://pkg.go.dev/github.com/cloudwego/eino](https://pkg.go.dev/github.com/cloudwego/eino)
## 快速上手
@@ -83,6 +81,8 @@ runnable.Stream(ctx, []*Message{UserMessage("help me plan my weekend")})
现在,我们来创建一个 Workflow,它能在字段级别灵活映射输入与输出:
+![](/img/eino/graph_node_type1.png)
+
```go
wf := NewWorkflow[[]*Message, *Message]()
wf.AddChatModelNode("model", model).AddInput(NewMapping(START))
@@ -439,10 +439,9 @@ func (g *graph) AddLambdaNode(key string, node *Lambda, opts ...GraphAddNodeOpt)
return g.addNode(key, toLambdaNode(key, node, opts...))
}
-// AddGraphNode add one kind of Graph[I, O]、Chain[I, O]、StateChain[I, O, S] as a node.
+// AddGraphNode add one kind of Graph[I, O]、Chain[I, O] as a node.
// for Graph[I, O], comes from NewGraph[I, O]()
// for Chain[I, O], comes from NewChain[I, O]()
-// for StateGraph[I, O, S], comes from NewStateGraph[I, O, S]()
func (g *graph) AddGraphNode(key string, node AnyGraph, opts ...GraphAddNodeOpt) error {
return g.addNode(key, toAnyGraphNode(key, node, opts...))
}
@@ -498,7 +497,7 @@ func (g *graph) AddBranch(startNode string, branch *GraphBranch) (err error) {}
###### **Parallel**
- 将多个 Node 平行并联, 形成多个节点并发执行的节点
-- 无 AddParallel 方法,通过 AddEdge 构建并联的多条拓扑路径,以次形成 **Parallel **
+- 无 AddParallel 方法,通过 AddEdge 构建并联的多条拓扑路径,以此形成 **Parallel **
![](/img/eino/input_keys_output_keys_in_parallel.png)
@@ -553,7 +552,7 @@ parallel := NewParallel()
parallel.AddChatModel("output_key01", chat01)
parallel.AddChatModel("output_key01", chat02)
-chain := NewChain[any,any]()
+chain := NewChain[[]*schema.Message,*schema.Message]()
chain.AppendParallel(parallel)
```
@@ -572,14 +571,17 @@ chain.AppendParallel(parallel)
// that wraps the provided cond to handle type assertions and error checking.
// eg.
-condition := func(ctx context.Context, in string, opts ...any) (endNode string, err error) {
+condition := func(ctx context.Context, in string) (endNode string, err error) {
// logic to determine the next node
- return "some_next_node_key", nil
+ if len(in) == 0 {
+ return "node_1", nil
+ }
+ return "node_2", nil
}
cb := NewChainBranch[string](condition)
-cb.AddPassthrough("next_node_key_01", xxx) // node in branch, represent one path of branch
-cb.AddPassthrough("next_node_key_02", xxx) // node in branch
+cb.AddLambda("node_1", lambda1) // node in branch, represent one path of branch
+cb.AddLambda("node_2", lambda2) // node in branch
chain := NewChain[string, string]()
chain.AppendBranch(cb)
diff --git a/content/zh/docs/eino/overview/eino_open_source.md b/content/zh/docs/eino/overview/eino_open_source.md
index 5b07913dba..67e23b87b4 100644
--- a/content/zh/docs/eino/overview/eino_open_source.md
+++ b/content/zh/docs/eino/overview/eino_open_source.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 大语言模型应用开发框架 —— Eino 正式开源!
@@ -177,7 +177,7 @@ Eino 框架的设计开发过程,扎根于 “满足真实需求” 与 “实
项目地址:[https://github.com/cloudwego/eino](https://github.com/cloudwego/eino),[https://github.com/cloudwego/eino-ext](https://github.com/cloudwego/eino-ext)
-项目官网:[https://www.cloudwego.io](https://www.cloudwego.io)
+项目官网:__[https://www.cloudwego.io](https://www.cloudwego.io)__
扫描二维码加入飞书社群:
![](/img/eino/eino_lark_qr_code.png)
diff --git a/content/zh/docs/eino/quick_start/_index.md b/content/zh/docs/eino/quick_start/_index.md
index ac5a07290d..afc6571ffb 100644
--- a/content/zh/docs/eino/quick_start/_index.md
+++ b/content/zh/docs/eino/quick_start/_index.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-15"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 'Eino: 快速开始'
@@ -33,16 +33,6 @@ AI 的应用中,最基础的场景就是 prompt + chat model 的场景,这
- [Agent-让大模型拥有双手](/zh/docs/eino/quick_start/agent_llm_with_tools)
-### 示例:用编排构建复杂自定义应用
-
-人工智能(AI) 的一项历史使命,就是把人从一些重复性的劳动中解放出来,而几乎任何一项劳动都是由多个流程和工序组合而成的,用 AI 完成这些相互串联的工作,这就是 “工作流”。由各种 AI 组件组合、编排而成的工作流,才是真正生产场景中的应用形态。
-
-Eino 中,提供了以组件为第一编排对象,同时提供具有极强扩展能力的 Lambda 节点作为编排对象,能够实现快速上手和定制扩展的双优势。Eino 的编排还有一些其他特点: 编排过程中最重要的话题 “数据流” 在 Eino 中被强化,callbacks 提供了观测和调试的基础能力,call option 为运行时的扩展性提供了无限可能...
-
-这个示例中,我们将实现一个应用了编排能力的示例,结合 callbacks 和 call option 来实现观测和请求粒度的扩展能力。
-
-- [复杂业务逻辑的利器-编排](/zh/docs/eino/quick_start/complex_business_logic_orchestration)
-
## 下一步探索
- 理解 Eino 的核心模块和概念: [Eino: 核心模块](/zh/docs/eino/core_modules),这是你自如玩转使用 Eino 做应用开发的关键信息。
diff --git a/content/zh/docs/eino/quick_start/agent_llm_with_tools.md b/content/zh/docs/eino/quick_start/agent_llm_with_tools.md
index e3257405d1..013f651746 100644
--- a/content/zh/docs/eino/quick_start/agent_llm_with_tools.md
+++ b/content/zh/docs/eino/quick_start/agent_llm_with_tools.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-07"
+date: "2025-01-20"
lastmod: ""
tags: []
title: Agent-让大模型拥有双手
@@ -119,8 +119,8 @@ import (
)
func main() {
-// 创建 duckduckgo Search 工具
-searchTool, err := duckduckgo.NewTool(ctx, &duckduckgo.Config{})
+ // 创建 duckduckgo Search 工具
+ searchTool, err := duckduckgo.NewTool(ctx, &duckduckgo.Config{})
if err != nil {
log.Fatal(err)
}
@@ -150,10 +150,10 @@ func main() {
func main() {
// 初始化 tools
todoTools := []tool.BaseTool{
- getAddTodoTool(), // 使用 NewTool 方式
+ getAddTodoTool(), // 使用 NewTool 方式
updateTool, // 使用 InferTool 方式
- &ListTodoTool{},
- searchTool, // 使用结构体实现方式, 此处未实现底层逻辑
+ &ListTodoTool{}, // 使用结构体实现方式, 此处未实现底层逻辑
+ searchTool,
}
// 创建并配置 ChatModel
@@ -205,10 +205,10 @@ func main() {
}
// 运行示例
- resp, err := agent.Invoke(context.Background(), []*schema.Message{
+ resp, err := agent.Invoke(ctx, []*schema.Message{
{
- Role: schema.User,
- Content: "添加一个学习 Eino 的 TODO,同时搜索一下 cloudwego/eino 的仓库地址",
+ Role: schema.User,
+ Content: "添加一个学习 Eino 的 TODO,同时搜索一下 cloudwego/eino 的仓库地址",
},
})
if err != nil {
@@ -250,4 +250,3 @@ Agent 是 AI 技术发展的重要方向。它不仅能够理解用户意图,
- 快速开始
- [实现一个最简 LLM 应用-ChatModel](/zh/docs/eino/quick_start/simple_llm_application)
- - [复杂业务逻辑的利器-编排](/zh/docs/eino/quick_start/complex_business_logic_orchestration)
diff --git a/content/zh/docs/eino/quick_start/simple_llm_application.md b/content/zh/docs/eino/quick_start/simple_llm_application.md
index 3e79287e4c..3de1635f3c 100644
--- a/content/zh/docs/eino/quick_start/simple_llm_application.md
+++ b/content/zh/docs/eino/quick_start/simple_llm_application.md
@@ -1,6 +1,6 @@
---
Description: ""
-date: "2025-01-16"
+date: "2025-01-20"
lastmod: ""
tags: []
title: 实现一个最简 LLM 应用
@@ -10,7 +10,7 @@ weight: 1
本指南将帮助你快速上手使用 Eino 框架中的 ChatModel 构建一个简单的 LLM 应用。我们将通过实现一个"程序员鼓励师"的例子,来展示如何使用 ChatModel。
> 💡
-> 本文中示例的代码片段详见:[flow/eino-examples/quickstart/chat/main.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chat/main.go)
+> 本文中示例的代码片段详见:[flow/eino-examples/quickstart/chat](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chat)
## **ChatModel 简介**
@@ -33,65 +33,64 @@ ChatModel 是 Eino 框架中对对话大模型的抽象,它提供了统一的
让我们通过实现一个程序员鼓励师来学习如何使用 ChatModel。这个助手不仅能提供技术建议,还能在程序员感到难过时给予心理支持。
-### **1. 创建对话模板**
+### 创建对话模板并生成消息
-Eino 提供了强大的模板化功能来构建要输入给大模型的消息。你可以使用占位符来插入变量和模板消息:
+Eino 提供了强大的模板化功能来构建要输入给大模型的消息:
-1. 变量占位符:在消息中插入变量,支持三种格式:
+1. 模版渲染,支持三种模版格式:
- - FString: `{variable}`
- - Jinja2: `{{variable}}`
- - GoTemplate: `{{``.variable}}`
-2. 消息占位符:用于插入一组消息(如对话历史)
+ - FString:Python 风格的简单字符串格式化(例如:"你好,{name}!")
+ - Jinja2:支持丰富表达式的 Jinja2 风格模板(例如:"你好,{{name}}!")
+ - GoTemplate:Go 语言内置的 text/template 格式(例如:"你好,{{.name}}!")
+2. 消息占位符:支持插入一组消息(如对话历史)
```go
-// optional=false 表示必需的消息列表,找不到对应变量会报错
+// optional=false 表示必需的消息列表,在模版输入中找不到对应变量会报错
schema.MessagesPlaceholder("chat_history", false)
```
> 更详细的组件介绍可参考: [Eino: ChatTemplate 使用说明](/zh/docs/eino/core_modules/components/chat_template_guide)
-下面是完整的模板创建代码:
+下面是完整的 FString 格式 + 消息占位符的对话模板创建及使用代码:
```go
+// eino-examples/quickstart/chat/template.go
+
import (
+ "context"
+
"github.com/cloudwego/eino/components/prompt"
"github.com/cloudwego/eino/schema"
)
-func main() {
- // 创建模板,使用 FString 格式
- template := prompt.FromMessages(schema.FString,
- // 系统消息模板
- schema.SystemMessage("你是一个{role}。你需要用{style}的语气回答问题。你的目标是帮助程序员保持积极乐观的心态,提供技术建议的同时也要关注他们的心理健康。"),
-
- // 插入需要的对话历史(新对话的话这里不填)
- schema.MessagesPlaceholder("chat_history", true),
-
- // 用户消息模板
- schema.UserMessage("问题: {question}"),
- )
-
- // 使用模板生成消息
- messages, err := template.Format(context.Background(), map[string]any{
- "role": "程序员鼓励师",
- "style": "积极、温暖且专业",
- "question": "我的代码一直报错,感觉好沮丧,该怎么办?",
- // 对话历史(这个例子里模拟两轮对话历史)
- "chat_history": []*schema.Message{
- schema.UserMessage("你好"),
- schema.AssistantMessage("嘿!我是你的程序员鼓励师!记住,每个优秀的程序员都是从 Debug 中成长起来的。有什么我可以帮你的吗?", nil),
- schema.UserMessage("我觉得自己写的代码太烂了"),
- schema.AssistantMessage("每个程序员都经历过这个阶段!重要的是你在不断学习和进步。让我们一起看看代码,我相信通过重构和优化,它会变得更好。记住,Rome wasn't built in a day,代码质量是通过持续改进来提升的。", nil),
- },
- })
- if err != nil {
- log.Fatal(err)
- }
-}
+// 创建模板,使用 FString 格式
+template := prompt.FromMessages(schema.FString,
+ // 系统消息模板
+ schema.SystemMessage("你是一个{role}。你需要用{style}的语气回答问题。你的目标是帮助程序员保持积极乐观的心态,提供技术建议的同时也要关注他们的心理健康。"),
+
+ // 插入需要的对话历史(新对话的话这里不填)
+ schema.MessagesPlaceholder("chat_history", true),
+
+ // 用户消息模板
+ schema.UserMessage("问题: {question}"),
+)
+
+// 使用模板生成消息
+messages, err := template.Format(context.Background(), map[string]any{
+ "role": "程序员鼓励师",
+ "style": "积极、温暖且专业",
+ "question": "我的代码一直报错,感觉好沮丧,该怎么办?",
+ // 对话历史(这个例子里模拟两轮对话历史)
+ "chat_history": []*schema.Message{
+ schema.UserMessage("你好"),
+ schema.AssistantMessage("嘿!我是你的程序员鼓励师!记住,每个优秀的程序员都是从 Debug 中成长起来的。有什么我可以帮你的吗?", nil),
+ schema.UserMessage("我觉得自己写的代码太烂了"),
+ schema.AssistantMessage("每个程序员都经历过这个阶段!重要的是你在不断学习和进步。让我们一起看看代码,我相信通过重构和优化,它会变得更好。记住,Rome wasn't built in a day,代码质量是通过持续改进来提升的。", nil),
+ },
+})
```
-### **2. 创建并使用 ChatModel**
+### 创建 ChatModel
ChatModel 是 Eino 框架中最核心的组件之一,它提供了与各种大语言模型交互的统一接口。Eino 目前支持以下大语言模型的实现:
@@ -104,101 +103,100 @@ ChatModel 是 Eino 框架中最核心的组件之一,它提供了与各种大
下面我们以 OpenAI 和 Ollama 为例,展示如何创建和使用 ChatModel:
-#### **使用 OpenAI (和下方 ollama 2 选 1)**
+#### **OpenAI (和下方 ollama 2 选 1)**
```go
+// eino-examples/quickstart/chat/openai.go
+
import (
+ "os"
+
"github.com/cloudwego/eino-ext/components/model/openai"
)
-func main() {
- // 创建 OpenAI ChatModel, 假设使用 openai 官方服务。
- chatModel, err := openai.NewChatModel(context.Background(), &openai.ChatModelConfig{
- Model: "gpt-4o", // 使用的模型版本
- APIKey: "", // OpenAI API 密钥
-
- // 可选的 Azure OpenAI 配置
- ByAzure: true, // 是否使用 Azure OpenAI
- BaseURL: "",
- })
- if err != nil {
- log.Fatal(err)
- }
-
- // 使用 Generate 获取完整回复
- response, err := chatModel.Generate(context.Background(), messages)
- if err != nil {
- log.Fatal(err)
- }
-
- fmt.Println(response.Content) // 输出模型回复
-}
+chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
+ Model: "gpt-4o", // 使用的模型版本
+ APIKey: os.Getenv("OPENAI_API_KEY"), // OpenAI API 密钥
+})
```
-> OpenAI 相关信息,可以参考:[ChatModel - OpenAI](/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai)
+> OpenAI ChatModel 的详细信息可以参考:[ChatModel - OpenAI](/zh/docs/eino/ecosystem_integration/chat_model/chat_model_openai)
-#### **使用 Ollama(和上方 openai 2 选 1)**
+#### **Ollama(和上方 openai 2 选 1)**
Ollama 支持在本地运行开源模型,适合对数据隐私有要求或需要离线使用的场景。
```go
+// eino-examples/quickstart/chat/ollama.go
+
import (
"github.com/cloudwego/eino-ext/components/model/ollama"
)
-func main() {
- // 创建 Ollama ChatModel
- chatModel, err := ollama.NewChatModel(context.Background(), &ollama.ChatModelConfig{
- BaseURL: "http://localhost:11434", // Ollama 服务地址
- Model: "llama2", // 模型名称
- })
- if err != nil {
- log.Fatal(err)
- }
-
- // 使用 Generate 获取完整回复
- response, err := chatModel.Generate(context.Background(), messages)
- if err != nil {
- log.Fatal(err)
- }
- fmt.Println(response.Content) // 输出模型回复
-}
+
+chatModel, err := ollama.NewChatModel(ctx, &ollama.ChatModelConfig{
+ BaseURL: "http://localhost:11434", // Ollama 服务地址
+ Model: "llama2", // 模型名称
+})
```
> OpenAI 相关信息,可以参考:[ChatModel - Ollama](/zh/docs/eino/ecosystem_integration/chat_model/chat_model_ollama)
无论使用哪种实现,ChatModel 都提供了一致的接口,这意味着你可以轻松地在不同的模型之间切换,而无需修改大量代码。
-### **3. 处理流式响应**
+### 运行 ChatModel
+
+经过前两步得到 ChatModel 的输入 messages 和初始化完成后的 ChatModel 实例后,可以开始尝试运行 ChatModel 了。Eino ChatModel 提供了两种运行模式:输出完整消息(generate)和输出消息流(stream):
-在实际应用中,有很多场景需要使用流式响应,主要的场景例如「提升用户体验」:像 ChatGPT 一样逐字输出,让用户能够更早看到响应开始。
+```go
+// eino-examples/quickstart/chat/generate.go
-对于需要流式输出的场景,可以使用 ChatModel 的 Stream 方法:
+/*** create messages
+* messages, err := xxx
+*/
+
+/*** create chat model
+* chatModel, err := xxx
+*/
+
+result, err := chatModel.Generate(ctx, messages)
+streamResult, err := chatModel.Stream(ctx, messages)
+```
+
+在实际应用中,有很多场景需要使用流式响应,主要的场景例如「提升用户体验」:stream 运行模式让 ChatModel 提供类似打字机的输出效果,使用户更早得到模型响应。
+
+Eino 中对流式输出的处理方式如下:
```go
-func main() {
- // 使用 Stream 获取流式响应
- stream, err := chatModel.Stream(context.Background(), messages)
- if err != nil {
- log.Fatal(err)
- }
-
- // 处理流式响应
+// eino-examples/quickstart/chat/stream.go
+
+import (
+ "io"
+ "log"
+
+ "github.com/cloudwego/eino/schema"
+)
+
+func reportStream(sr *schema.StreamReader[*schema.Message]) {
+ defer sr.Close()
+
+ i := 0
for {
- chunk, err := stream.Recv()
- if err == io.EOF {
- break
- }
- if err != nil {
- log.Fatal(err)
- }
-
- // 处理响应片段
- fmt.Print(chunk.Content)
+ message, err := sr.Recv()
+ if err == io.EOF { // 流式输出结束
+ return
+ }
+ if err != nil {
+ log.Fatalf("recv failed: %v", err)
+ }
+ log.Printf("message[%d]: %+v\n", i, message)
+ i++
}
}
```
+完整实现参见:[flow/eino-examples/quickstart/chat/main.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chat/main.go)
+
## **总结**
本示例通过一个程序员鼓励师的案例,展示了如何使用 Eino 框架构建 LLM 应用。从 ChatModel 的创建到消息模板的使用,再到实际的对话实现,相信你已经对 Eino 框架有了基本的了解。无论是选择 OpenAI、Ollama 还是其他模型实现,Eino 都提供了统一且简单的使用方式。希望这个示例能帮助你快速开始构建自己的 LLM 应用。
@@ -207,4 +205,3 @@ func main() {
- 快速开始
- [Agent-让大模型拥有双手](/zh/docs/eino/quick_start/agent_llm_with_tools)
- - [复杂业务逻辑的利器-编排](/zh/docs/eino/quick_start/complex_business_logic_orchestration)
diff --git a/static/img/eino/edge_of_parallel.png b/static/img/eino/edge_of_parallel.png
index 75959f8258..3c5666136d 100644
Binary files a/static/img/eino/edge_of_parallel.png and b/static/img/eino/edge_of_parallel.png differ
diff --git a/static/img/eino/eino_callback_langfuse_usage.gif b/static/img/eino/eino_callback_langfuse_usage.gif
new file mode 100644
index 0000000000..0e83e3aac5
Binary files /dev/null and b/static/img/eino/eino_callback_langfuse_usage.gif differ
diff --git a/static/img/eino/eino_debug_config_2_page.png b/static/img/eino/eino_debug_config_2_page.png
new file mode 100644
index 0000000000..e2c95f20fe
Binary files /dev/null and b/static/img/eino/eino_debug_config_2_page.png differ
diff --git a/static/img/eino/eino_debug_config_3_page.png b/static/img/eino/eino_debug_config_3_page.png
new file mode 100644
index 0000000000..7cf784c9ee
Binary files /dev/null and b/static/img/eino/eino_debug_config_3_page.png differ
diff --git a/static/img/eino/eino_debug_enter_config_page.png b/static/img/eino/eino_debug_enter_config_page.png
new file mode 100644
index 0000000000..90e164f8f4
Binary files /dev/null and b/static/img/eino/eino_debug_enter_config_page.png differ
diff --git a/static/img/eino/eino_debug_enter_page.png b/static/img/eino/eino_debug_enter_page.png
new file mode 100644
index 0000000000..db669f7fc5
Binary files /dev/null and b/static/img/eino/eino_debug_enter_page.png differ
diff --git a/static/img/eino/eino_debug_enter_test_run_2_page.png b/static/img/eino/eino_debug_enter_test_run_2_page.png
new file mode 100644
index 0000000000..ea1909129c
Binary files /dev/null and b/static/img/eino/eino_debug_enter_test_run_2_page.png differ
diff --git a/static/img/eino/eino_debug_enter_test_run_page.png b/static/img/eino/eino_debug_enter_test_run_page.png
new file mode 100644
index 0000000000..0ae302c50a
Binary files /dev/null and b/static/img/eino/eino_debug_enter_test_run_page.png differ
diff --git a/static/img/eino/eino_debug_index_page.png b/static/img/eino/eino_debug_index_page.png
new file mode 100644
index 0000000000..a622778f5c
Binary files /dev/null and b/static/img/eino/eino_debug_index_page.png differ
diff --git a/static/img/eino/eino_debug_ip_port_show_page.png b/static/img/eino/eino_debug_ip_port_show_page.png
new file mode 100644
index 0000000000..ba3345fd0e
Binary files /dev/null and b/static/img/eino/eino_debug_ip_port_show_page.png differ
diff --git a/static/img/eino/eino_debug_list_graph_and_show_page.png b/static/img/eino/eino_debug_list_graph_and_show_page.png
new file mode 100644
index 0000000000..1cc1d72af6
Binary files /dev/null and b/static/img/eino/eino_debug_list_graph_and_show_page.png differ
diff --git a/static/img/eino/eino_debug_list_nodes_page.png b/static/img/eino/eino_debug_list_nodes_page.png
new file mode 100644
index 0000000000..0e8c98448d
Binary files /dev/null and b/static/img/eino/eino_debug_list_nodes_page.png differ
diff --git a/static/img/eino/eino_debug_run_config_page.png b/static/img/eino/eino_debug_run_config_page.png
new file mode 100644
index 0000000000..cd3a63cb58
Binary files /dev/null and b/static/img/eino/eino_debug_run_config_page.png differ
diff --git a/static/img/eino/eino_debug_run_detail_page.png b/static/img/eino/eino_debug_run_detail_page.png
new file mode 100644
index 0000000000..5a26595d63
Binary files /dev/null and b/static/img/eino/eino_debug_run_detail_page.png differ
diff --git a/static/img/eino/eino_debug_run_detail_v2_page.png b/static/img/eino/eino_debug_run_detail_v2_page.png
new file mode 100644
index 0000000000..2bb196776c
Binary files /dev/null and b/static/img/eino/eino_debug_run_detail_v2_page.png differ
diff --git a/static/img/eino/eino_debug_run_input_mock_data_2_page.png b/static/img/eino/eino_debug_run_input_mock_data_2_page.png
new file mode 100644
index 0000000000..fd60975f08
Binary files /dev/null and b/static/img/eino/eino_debug_run_input_mock_data_2_page.png differ
diff --git a/static/img/eino/eino_debug_run_input_mock_data_page.png b/static/img/eino/eino_debug_run_input_mock_data_page.png
new file mode 100644
index 0000000000..6a6675238f
Binary files /dev/null and b/static/img/eino/eino_debug_run_input_mock_data_page.png differ
diff --git a/static/img/eino/eino_debug_run_of_mock_input_of_page.png b/static/img/eino/eino_debug_run_of_mock_input_of_page.png
new file mode 100644
index 0000000000..5d6a784222
Binary files /dev/null and b/static/img/eino/eino_debug_run_of_mock_input_of_page.png differ
diff --git a/static/img/eino/eino_debug_run_page.png b/static/img/eino/eino_debug_run_page.png
new file mode 100644
index 0000000000..6c01fcc267
Binary files /dev/null and b/static/img/eino/eino_debug_run_page.png differ
diff --git a/static/img/eino/eino_debug_test_run_detail_page.png b/static/img/eino/eino_debug_test_run_detail_page.png
new file mode 100644
index 0000000000..524226e0eb
Binary files /dev/null and b/static/img/eino/eino_debug_test_run_detail_page.png differ
diff --git a/static/img/eino/eino_debug_test_run_from_node_page.png b/static/img/eino/eino_debug_test_run_from_node_page.png
new file mode 100644
index 0000000000..bdc9c414da
Binary files /dev/null and b/static/img/eino/eino_debug_test_run_from_node_page.png differ
diff --git a/static/img/eino/eino_debug_test_run_of_mock_data_page.png b/static/img/eino/eino_debug_test_run_of_mock_data_page.png
new file mode 100644
index 0000000000..0ca96de8c1
Binary files /dev/null and b/static/img/eino/eino_debug_test_run_of_mock_data_page.png differ
diff --git a/static/img/eino/eino_debug_test_run_of_one_node_page.png b/static/img/eino/eino_debug_test_run_of_one_node_page.png
new file mode 100644
index 0000000000..c0a4fb2fec
Binary files /dev/null and b/static/img/eino/eino_debug_test_run_of_one_node_page.png differ
diff --git a/static/img/eino/eino_debug_test_run_result_page.png b/static/img/eino/eino_debug_test_run_result_page.png
new file mode 100644
index 0000000000..82fc7e0882
Binary files /dev/null and b/static/img/eino/eino_debug_test_run_result_page.png differ
diff --git a/static/img/eino/eino_dev_ability_introduction_page.png b/static/img/eino/eino_dev_ability_introduction_page.png
new file mode 100644
index 0000000000..99a33f5a32
Binary files /dev/null and b/static/img/eino/eino_dev_ability_introduction_page.png differ
diff --git a/static/img/eino/eino_dev_chat_model_config.png b/static/img/eino/eino_dev_chat_model_config.png
new file mode 100644
index 0000000000..ecf4be3674
Binary files /dev/null and b/static/img/eino/eino_dev_chat_model_config.png differ
diff --git a/static/img/eino/eino_dev_chat_model_config2.png b/static/img/eino/eino_dev_chat_model_config2.png
new file mode 100644
index 0000000000..11f2355e0a
Binary files /dev/null and b/static/img/eino/eino_dev_chat_model_config2.png differ
diff --git a/static/img/eino/eino_dev_enter_page.png b/static/img/eino/eino_dev_enter_page.png
new file mode 100644
index 0000000000..4809955745
Binary files /dev/null and b/static/img/eino/eino_dev_enter_page.png differ
diff --git a/static/img/eino/eino_install_page.png b/static/img/eino/eino_install_page.png
new file mode 100644
index 0000000000..a4dfbd8978
Binary files /dev/null and b/static/img/eino/eino_install_page.png differ
diff --git a/static/img/eino/eino_install_page_2_page.png b/static/img/eino/eino_install_page_2_page.png
new file mode 100644
index 0000000000..92c7fe7f78
Binary files /dev/null and b/static/img/eino/eino_install_page_2_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_edges_page.png b/static/img/eino/eino_orchestration_add_edges_page.png
new file mode 100644
index 0000000000..8b2941f798
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_edges_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_graph_2_page.png b/static/img/eino/eino_orchestration_add_graph_2_page.png
new file mode 100644
index 0000000000..2c12272905
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_graph_2_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_graph_config_deatil_page.png b/static/img/eino/eino_orchestration_add_graph_config_deatil_page.png
new file mode 100644
index 0000000000..ffd2c98169
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_graph_config_deatil_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_graph_page.png b/static/img/eino/eino_orchestration_add_graph_page.png
new file mode 100644
index 0000000000..5905fc8fb0
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_graph_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_nodes_2_page.png b/static/img/eino/eino_orchestration_add_nodes_2_page.png
new file mode 100644
index 0000000000..9855b287ec
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_nodes_2_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_nodes_3_page.png b/static/img/eino/eino_orchestration_add_nodes_3_page.png
new file mode 100644
index 0000000000..8d49861c0c
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_nodes_3_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_nodes_page.png b/static/img/eino/eino_orchestration_add_nodes_page.png
new file mode 100644
index 0000000000..dc4cb6d9c8
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_nodes_page.png differ
diff --git a/static/img/eino/eino_orchestration_add_slot_page.png b/static/img/eino/eino_orchestration_add_slot_page.png
new file mode 100644
index 0000000000..39eeb790a3
Binary files /dev/null and b/static/img/eino/eino_orchestration_add_slot_page.png differ
diff --git a/static/img/eino/eino_orchestration_describtion_page.png b/static/img/eino/eino_orchestration_describtion_page.png
new file mode 100644
index 0000000000..f637f67d4d
Binary files /dev/null and b/static/img/eino/eino_orchestration_describtion_page.png differ
diff --git a/static/img/eino/eino_orchestration_enter_page.png b/static/img/eino/eino_orchestration_enter_page.png
new file mode 100644
index 0000000000..17d45b54fe
Binary files /dev/null and b/static/img/eino/eino_orchestration_enter_page.png differ
diff --git a/static/img/eino/eino_orchestration_gencode_config_page.png b/static/img/eino/eino_orchestration_gencode_config_page.png
new file mode 100644
index 0000000000..86817152c3
Binary files /dev/null and b/static/img/eino/eino_orchestration_gencode_config_page.png differ
diff --git a/static/img/eino/eino_orchestration_gencode_page.png b/static/img/eino/eino_orchestration_gencode_page.png
new file mode 100644
index 0000000000..7c4f7657f8
Binary files /dev/null and b/static/img/eino/eino_orchestration_gencode_page.png differ
diff --git a/static/img/eino/eino_orchestration_index_2_page.png b/static/img/eino/eino_orchestration_index_2_page.png
new file mode 100644
index 0000000000..aef3504dc4
Binary files /dev/null and b/static/img/eino/eino_orchestration_index_2_page.png differ
diff --git a/static/img/eino/eino_orchestration_index_page.png b/static/img/eino/eino_orchestration_index_page.png
new file mode 100644
index 0000000000..91691e3b41
Binary files /dev/null and b/static/img/eino/eino_orchestration_index_page.png differ
diff --git a/static/img/eino/eino_orchestration_node_add_slots__page.png b/static/img/eino/eino_orchestration_node_add_slots__page.png
new file mode 100644
index 0000000000..8c0044ba26
Binary files /dev/null and b/static/img/eino/eino_orchestration_node_add_slots__page.png differ
diff --git a/static/img/eino/eino_orchestration_node_config_2_page.png b/static/img/eino/eino_orchestration_node_config_2_page.png
new file mode 100644
index 0000000000..f23989f9db
Binary files /dev/null and b/static/img/eino/eino_orchestration_node_config_2_page.png differ
diff --git a/static/img/eino/eino_orchestration_show_nodes_2_page.png b/static/img/eino/eino_orchestration_show_nodes_2_page.png
new file mode 100644
index 0000000000..22ee3d0e2f
Binary files /dev/null and b/static/img/eino/eino_orchestration_show_nodes_2_page.png differ
diff --git a/static/img/eino/eino_orchestration_show_nodes_page.png b/static/img/eino/eino_orchestration_show_nodes_page.png
new file mode 100644
index 0000000000..d13ffe4c92
Binary files /dev/null and b/static/img/eino/eino_orchestration_show_nodes_page.png differ
diff --git a/static/img/eino/eino_orchestration_sub_graph_pos_page.png b/static/img/eino/eino_orchestration_sub_graph_pos_page.png
new file mode 100644
index 0000000000..ef9a1baa6c
Binary files /dev/null and b/static/img/eino/eino_orchestration_sub_graph_pos_page.png differ
diff --git a/static/img/eino/eino_orchestration_subgraph_show_page.png b/static/img/eino/eino_orchestration_subgraph_show_page.png
new file mode 100644
index 0000000000..8fce51379e
Binary files /dev/null and b/static/img/eino/eino_orchestration_subgraph_show_page.png differ
diff --git a/static/img/eino/graph_node_callback_run_place.png b/static/img/eino/graph_node_callback_run_place.png
new file mode 100644
index 0000000000..b1d7bebfbc
Binary files /dev/null and b/static/img/eino/graph_node_callback_run_place.png differ
diff --git a/static/img/eino/graph_node_type1.png b/static/img/eino/graph_node_type1.png
new file mode 100644
index 0000000000..dc664fe7ae
Binary files /dev/null and b/static/img/eino/graph_node_type1.png differ
diff --git a/static/img/eino/graph_nodes.png b/static/img/eino/graph_nodes.png
index 61a3e1bffb..91632f3b91 100644
Binary files a/static/img/eino/graph_nodes.png and b/static/img/eino/graph_nodes.png differ
diff --git a/static/img/eino/graph_runnable_after_compile.png b/static/img/eino/graph_runnable_after_compile.png
index 7abfe7472f..7e7ae017b0 100644
Binary files a/static/img/eino/graph_runnable_after_compile.png and b/static/img/eino/graph_runnable_after_compile.png differ
diff --git a/static/img/eino/graph_stream_chunk_copy.png b/static/img/eino/graph_stream_chunk_copy.png
new file mode 100644
index 0000000000..220157f76b
Binary files /dev/null and b/static/img/eino/graph_stream_chunk_copy.png differ
diff --git a/static/img/eino/input_keys_output_keys_in_parallel.png b/static/img/eino/input_keys_output_keys_in_parallel.png
index 6ac7eeebd4..0dae772451 100644
Binary files a/static/img/eino/input_keys_output_keys_in_parallel.png and b/static/img/eino/input_keys_output_keys_in_parallel.png differ
diff --git a/static/img/eino/invoke_stream_transform_collect.png b/static/img/eino/invoke_stream_transform_collect.png
index 571168d4a2..7217b54a3e 100644
Binary files a/static/img/eino/invoke_stream_transform_collect.png and b/static/img/eino/invoke_stream_transform_collect.png differ
diff --git a/static/img/eino/metrics_token_usage_in_fornax.png b/static/img/eino/metrics_token_usage_in_fornax.png
index d097f02430..fc70fc8290 100644
Binary files a/static/img/eino/metrics_token_usage_in_fornax.png and b/static/img/eino/metrics_token_usage_in_fornax.png differ
diff --git a/static/img/eino/react_agent_graph.png b/static/img/eino/react_agent_graph.png
index d72caf350e..9b1d0ccf31 100644
Binary files a/static/img/eino/react_agent_graph.png and b/static/img/eino/react_agent_graph.png differ
diff --git a/static/img/eino/recommend_way_of_handler.png b/static/img/eino/recommend_way_of_handler.png
index a2945b3667..c37e56c804 100644
Binary files a/static/img/eino/recommend_way_of_handler.png and b/static/img/eino/recommend_way_of_handler.png differ
diff --git a/static/img/eino/run_way_branch_in_graph.png b/static/img/eino/run_way_branch_in_graph.png
index c0d5e04870..cd21a45def 100644
Binary files a/static/img/eino/run_way_branch_in_graph.png and b/static/img/eino/run_way_branch_in_graph.png differ