Agent Platform Self-Host 开源项目对比 - Coze Studio
使用模型:为了省钱,用的本地部署的模型
本来想直接把 Coze Studio 和 Dify 都写完的,由于都写完工期太长,可能导致吃屎都赶不上热乎的,所以先发 Coze Studio
Coze Studio
基于 v0.2.6编写,截止 2025-08,后续发布与本文无关。(比如 Chatflow 目前处于 beta 版本)
视频主要演示功能,因此整体录制较快。
(Youtube 视频)
基础依赖
- 机器最低要求:2C4G
Dockerfile: https://github.com/coze-dev/coze-studio/blob/main/docker/docker-compose.yml
服务 | 版本 | 用途 |
---|---|---|
MySQL | 8.4.5 | 主数据库 |
Redis | 8.0 | 缓存服务 |
Elasticsearch | 8.18.0 | 搜索引擎 (支持中文分词) |
Milvus | 2.5.10 | 向量数据库 (用于 embeddings) |
MinIO | 对象存储 | |
NSQ | 消息队列 | |
etcd | 配置管理 | |
另外,Helm 中默认使用的是 RocketMQ: | ||
https://github.com/coze-dev/coze-studio/blob/main/helm/charts/opencoze/values.yaml |
可兼容的模块配置,只需要改环境变量配置就能切换(https://github.com/coze-dev/coze-studio/blob/main/docker/.env.example):
- 上传组件:火山云 ImageX / 文件存储
- 文件存储(实际上这三者 API 是兼容的): minio / tos / s3
- MQ: nsq (Docker 版本默认使用) / kafka / rmq (Helm 版本默认使用)
- 向量存储:milvus / vikingdb
- Embedding:ark / openai / ollama / gemini / http
- Rerank (default=rrf):vikingdb / rrf
- OCR:ve / paddleocr
- Document Parser:builtin / paddleocr
- 模型:openai / ark / deepseek / ollama / qwen / gemini
- Code Runner Mode: sandbox(deno + pyodide) / local (venv)
和 Coze 的功能对比
大量残缺的残疾版……迭代速度也不尽如人意。
功能 | Coze Studio | Coze |
---|---|---|
工作空间 | × | √ |
智能体 - 单 Agent | √ | √ |
智能体 - Chatflow | × | √ |
智能体 - 多 Agent | × | √ |
智能体调试 | × | √ |
智能体版本控制 | × | √ |
应用创建 | √ | √ |
资源库-工作流 | √ | √ |
资源库-对话流 | × | √ |
资源库 - 插件 | √ | √ |
资源库 - 卡片 | × | √ |
资源库 - 提示词 | √ | √ |
资源库 - 数据库 | √ | √ |
资源库 - 音色 | × | √ |
知识库添加 - 本地文档 | √ | √ |
知识库添加 - 自定义 | √ | √ |
知识库添加 - 在线数据 | × | √ |
知识库添加 - 飞书 | × | √ |
知识库添加 - 公众号 | × | √ |
知识库添加 - Notion | × | √ |
发布管理 | × | √ |
模型管理 | × | √ |
效果评测 | × | √ |
项目商店 | × | √ |
OpenAPI | 部分支持 | √ |
回调管理 | × | √ |
OpenAPI Playground | × | √ |
授权管理 | × | √ |
通用管理 | × | √ |
配置
Coze 整体灵活度一般,从部署配置就能看出来。
模型
- 部署前需要人工 copy 一个你需要的模型模版,配置完成后再启动。由于是本地模型,好巧不巧我 copy 了一个
model_template_basic.yaml
成功踩到了第一个坑:Protocol 是有枚举值的,而 template_basic 刚好不在枚举值中:
1const (
2 ProtocolOpenAI Protocol = "openai"
3 ProtocolClaude Protocol = "claude"
4 ProtocolDeepseek Protocol = "deepseek"
5 ProtocolGemini Protocol = "gemini"
6 ProtocolArk Protocol = "ark"
7 ProtocolOllama Protocol = "ollama"
8 ProtocolQwen Protocol = "qwen"
9 ProtocolErnie Protocol = "ernie" // ernie 虽然出现在枚举中,但没有 builder 实现,所以也不能用
10)
11
要扩展也是可以扩展的,backend/infra/impl/chatmodel/default_factory.go
进行修改:
1// 新增 Factory,代码里对应 DefaultFactory 替换成 CustomFactory
2func NewCustomFactory() chatmodel.Factory {
3 return NewFactory(customFactoryMap)
4}
5
这里你遇到了本项目的第一个槽点:明明都这么抽象成工厂了,却不是顶层依赖注入,而有整整三个地方调用了,全都需要修改:https://github.com/coze-dev/coze-studio/blob/f19761fa31fed69290d21ecabe34f1265a785b3d/backend/infra/impl/chatmodel/default_factory.go#L40
实际上大部分我们都是兼容 OpenAI 的接口,直接用 OpenAI 模版改起来更快……这是后面看到的。
另外,Coze 目前对 Think 标签的显示处理是有 Bug 的,试用时未修复。
插件
插件分为官方插件市场和 Space 级插件增删改查,全局官方插件市场走的是配置化,https://github.com/coze-dev/coze-studio/tree/main/backend/conf/plugin/pluginproduct
同样的需要新增一个配置 yaml,完成后重启服务。而且在很久之前就有人提出集成插件管理的 issue,但无人处理。
Space 级别的插件支持配置 HTTP 插件,就和官方线上版本类似了。
知识库
知识库需要配置 embedding model,同样需要配置在 .env。如果定完了一个模型后你需要换一个模型,或者模型维度配置有误,需要把旧知识库删除后重建后续才能正常使用。
Space
目前不支持多空间,但是预留了数据表。部署后发现只有个人空间,如何支持共享空间,据说 Q3 支持。
改造
账号体系
用户信息通过 SessionAuth Middleware 进行验证。
为了方便兼容,主要需要处理一下实现,将 backend/application/user/user.go
中从自己想要替换的账号体系中映射出来。
简单的一个思路是如果需要替换成 SSO 登录,替换原有的登录界面改成 SSO 登录,回调后自动注册一个账号或者登录已有账号,本系统还是走自己的一套 Session 体系,这样处理起来会比兼容一堆接口和数据结构简单很多。SessionAuth
,User
表和相关关联都不需要修改了。
1type Session struct {
2 UserID int64
3 Locale string
4 CreatedAt time.Time
5 ExpiresAt time.Time
6}
7
8type User struct {
9 UserID int64
10
11 Name string // nickname
12 UniqueName string // unique name
13 Email string // email
14 Description string // user description
15 IconURI string // avatar URI
16 IconURL string // avatar URL
17 UserVerified bool // Is the user authenticated?
18 Locale string
19 SessionKey string // session key
20
21 CreatedAt int64 // creation time
22 UpdatedAt int64 // update time
23}
24
25
CodeRunner 语言扩展
目前还只支持 Python,官方在线版本实际可以支持 Python + JavaScript。目前前端界面选项未放出,放出 JavaScript 后还需要修改服务端的 infra/coderunner
自行实现一套 JS Runner:
1func (runner *runner) Run(ctx context.Context, request *coderunner.RunRequest) (*coderunner.RunResponse, error) {
2 if request.Language == coderunner.JavaScript {
3 return nil, fmt.Errorf("js not supported yet")
4 }
5 // ...
6}
7
Workflow 节点
Workflow 和节点可能是 Coze 最有技术含量写得最好的部分了,但一大部分应该有赖于 Eino 的抽象而不是 Coze 本身的研发……
要新增一个节点可以参考:https://github.com/coze-dev/coze-studio/wiki/11.-新增工作流节点类型(后端)
简单概括一下,首先需要实现 Invoke,Invoke 为节点的执行逻辑,比如代码节点就是:
1type Runner struct {
2 outputConfig map[string]*vo.TypeInfo
3 code string
4 language coderunner.Language
5 runner coderunner.Runner
6 importError error
7}
8
9func (c *Runner) Invoke(ctx context.Context, input map[string]any) (ret map[string]any, err error) {
10 if c.importError != nil {
11 return nil, vo.WrapError(errno.ErrCodeExecuteFail, c.importError, errorx.KV("detail", c.importError.Error()))
12 }
13 response, err := c.runner.Run(ctx, &coderunner.RunRequest{Code: c.code, Language: c.language, Params: input})
14 if err != nil {
15 return nil, vo.WrapError(errno.ErrCodeExecuteFail, err, errorx.KV("detail", err.Error()))
16 }
17
18 result := response.Result
19 ctxcache.Store(ctx, coderRunnerRawOutputCtxKey, result)
20
21 output, ws, err := nodes.ConvertInputs(ctx, result, c.outputConfig)
22 if err != nil {
23 return nil, vo.WrapIfNeeded(errno.ErrCodeExecuteFail, err, errorx.KV("detail", err.Error()))
24 }
25
26 if ws != nil && len(*ws) > 0 {
27 logs.CtxWarnf(ctx, "convert inputs warnings: %v", *ws)
28 ctxcache.Store(ctx, coderRunnerWarnErrorLevelCtxKey, *ws)
29 }
30
31 return output, nil
32
33}
34
然后在 backend/domain/workflow/entity/node_meta.go
定义节点信息:
1NodeTypeCodeRunner: {
2 ID: 5,
3 Key: NodeTypeCodeRunner,
4 DisplayKey: "Code",
5 Name: "代码",
6 Category: "logic",
7 Desc: "编写代码,处理输入变量来生成返回值",
8 Color: "#00B2B2",
9 IconURL: "https://lf3-static.bytednsdoc.com/obj/eden-cn/dvsmryvd_avi_dvsm/ljhwZthlaukjlkulzlp/icon/icon-Code-v2.jpg",
10 SupportBatch: false,
11 ExecutableMeta: ExecutableMeta{
12 PreFillZero: true,
13 PostFillNil: true,
14 UseCtxCache: true,
15 },
16 EnUSName: "Code",
17 EnUSDescription: "Write code to process input variables to generate return values.",
18 }
19
然后每个节点需要 Config 和 NodeAdapt 用来做前端画布 Schema 到服务端运行时 Schema 的转换:
1type Config struct {
2 Code string
3 Language coderunner.Language
4
5 Runner coderunner.Runner
6}
7
8func (c *Config) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
9 ns := &schema.NodeSchema{
10 Key: vo.NodeKey(n.ID),
11 Type: entity.NodeTypeCodeRunner,
12 Name: n.Data.Meta.Title,
13 Configs: c,
14 }
15 inputs := n.Data.Inputs
16
17 code := inputs.Code
18 c.Code = code
19
20 language, err := convertCodeLanguage(inputs.Language)
21 if err != nil {
22 return nil, err
23 }
24 c.Language = language
25
26 if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
27 return nil, err
28 }
29
30 if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
31 return nil, err
32 }
33
34 return ns, nil
35}
36
domain/workflow/internal/canvas/adaptor/to_schema.go
中注册 Adapt,实现前端和服务端 Node 的关联:
1nodes.RegisterNodeAdaptor(entity.NodeTypeCodeRunner, func() nodes.NodeAdaptor {
2 return &code.Config{}
3})
4
还需要为 Config 实现 NodeBuilder,Builder 将配置转化为可执行的节点实例。
1func (c *Config) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
2
3 if c.Language != coderunner.Python {
4 return nil, errors.New("only support python language")
5 }
6
7 importErr := validatePythonImports(c.Code)
8
9 return &Runner{
10 code: c.Code,
11 language: c.Language,
12 outputConfig: ns.OutputTypes,
13 runner: code2.GetCodeRunner(),
14 importError: importErr,
15 }, nil
16}
17
此时,我们就实现了一个 Invoke 模式的 Code,由于 Coze Studio 底层使用的是 Enio,所以同样你可以实现其他三种节点。
函数名 | 模式说明 | 交互模式名称 | Lambda 构造方法 |
---|---|---|---|
Invoke | 输入非流式、输出非流式 | Ping-Pong 模式 | compose.InvokableLambda() |
Stream | 输入非流式、输出流式 | Server-Streaming 模式 | compose.StreamableLambda() |
Collect | 输入流式、输出非流式 | Client-Streaming | compose.CollectableLambda() |
Transform | 输入流式、输出流式 | Bidirectional-Streaming | compose.TransformableLambda() |
前端也要新增一个节点,前端这里使用的是 flowgram,迭代比起 Coze Studio 要积极很多,我之前也提过好多 issue 修复和处理速度很快,但是 Coze 基于 flowgram 实际上还是做了一些能力增强的,可以参考:https://github.com/coze-dev/coze-studio/wiki/10.-新增工作流节点类型(前端)
支持的 OpenAPI
由于本身是个阉割版本,因此支持的 OpenAPI 也相当有限。官方 API 太多,而开源版本太少,就不像功能对比一样列对比表了。
Reference:https://github.com/coze-dev/coze-studio/wiki/6.-API-参考
功能 | API |
---|---|
创建会话 | /v1/conversation/create |
查看会话列表 | /v1/conversations |
发起会话 | /v3/chat |
查看消息列表 | /v1/conversation/message/list |
清除上下文 | /v1/conversations/:conversation_id/clear |
执行工作流 | /v1/workflow/run |
执行工作流(流式响应) | /v1/workflow/stream_run |
恢复运行中的工作流 | /v1/workflow/stream_resume |
执行对话流(流式响应) | /v1/workflows/chat |
总结
半玩具级别开源,如果需要公司级投产使用,才能满足老板心中所谓的「我就想要和 Coze」一模一样,属于 Coze Lily。
其中还有一些录屏中也能看到的 Bug 以及上文提到的问题,都是已有 issue,比如 Think 标签无法正常解析。
如果想要使用,首先得先克服 Lily 版本同时进行二开,还要承担 Coze Studio 本身 Bug 的修复工作,从慈善的角度这确实是个贡献开源的大好机会,但是站在牛马的角度可能得因此重新衡量一下,使用这样一个开源版本到底能节约多少时间,其实还是个谜(个人感觉不如直接抄 Workflow 的部分其他不要)。
附录:Workflow 整体设计
如上面所说的,Workflow 可能是最有技术含量的部分,因此看下 Workflow 的整体架构。
实话:以下由 AI 撰写。
核心设计理念
- 前后端分离的架构转换: 前端的可视化画布(Canvas)数据通过适配器转换为后端的执行架构(Schema)
- 事件驱动的执行引擎: 基于回调和事件机制实现异步执行和流式响应
- 插件化的节点系统: 通过统一的节点接口支持各种业务逻辑扩展
- 状态持久化和恢复: 支持工作流中断、恢复和检查点机制
- 多种执行模式: 同步/异步/流式执行,支持调试和生产环境
整体架构
数据流转过程
Workflow 的执行是一个复杂的数据流转过程,从前端的可视化画布到后端的执行引擎,经历了多个转换层:
核心组件详解
1. Canvas 到 Schema 的转换
Coze Studio 最巧妙的设计之一是将前端的可视化画布数据无缝转换为后端可执行的工作流架构。这个过程通过 canvas/adaptor
模块实现:
1// 前端画布数据结构
2type Canvas struct {
3 Nodes []*Node `json:"nodes"`
4 Edges []*Edge `json:"edges"`
5}
6
7// 后端执行架构
8type WorkflowSchema struct {
9 Nodes []*NodeSchema `json:"nodes"`
10 Connections []*Connection `json:"connections"`
11 Hierarchy map[NodeKey]NodeKey `json:"hierarchy"`
12 Branches map[NodeKey]*BranchSchema `json:"branches"`
13}
14
转换过程包括:
- 节点适配: 每种节点类型都有对应的
NodeAdaptor
实现 - 连接规范化: 处理端口映射和分支逻辑
- 层次结构构建: 处理嵌套工作流和批处理模式
- 验证和优化: 移除孤立节点,验证连接有效性
2. 执行引擎
执行引擎采用事件驱动架构,通过上下文管理、事件处理和回调系统协调工作流的执行:
执行流程:
- 上下文设置: 初始化根、子工作流和节点上下文
- 事件分发: 根据节点执行状态发送相应事件
- 回调处理: 通过处理器响应事件并更新状态
- 结果收集: 聚合执行结果并持久化状态
- 流式响应: 实时推送执行进度和结果
3. 节点系统架构
节点系统是 Workflow 的核心执行单元,支持多种执行模式和业务逻辑:
4.节点执行模式
接口类型 | 输入模式 | 输出模式 | 典型应用 | 使用场景 |
---|---|---|---|---|
InvokableNode |
非流式 | 非流式 | Plugin、Code、HTTP | 简单的输入输出处理 |
StreamableNode |
非流式 | 流式 | LLM、实时生成 | 需要实时响应的场景 |
CollectableNode |
流式 | 非流式 | 聚合处理 | 收集流式数据并处理 |
TransformableNode |
流式 | 流式 | 数据转换、过滤 | 流式数据的实时处理 |
Coze Studio 支持三种主要的执行模式,每种模式适用于不同的业务场景:
模式特点对比:
执行模式 | 数据源 | 持久化 | 监控 | 适用场景 |
---|---|---|---|---|
TestRun | 草稿版本 | 最小化 | 基础 | 开发调试、功能验证 |
Production | 发布版本 | 完整 | 全面 | 生产环境、用户服务 |
NodeDebug | 草稿版本 | 临时 | 详细 | 节点开发、问题排查 |
5. 状态管理与流转
工作流执行过程中的状态管理采用有限状态机模式,支持复杂的状态转换和恢复机制:
状态持久化机制:
- 检查点(Checkpoint): 关键节点执行前保存状态
- 中断事件存储: 记录中断位置和上下文
- 恢复策略: 支持从任意检查点恢复执行
- 状态同步: 多实例间的状态一致性保证
Workflow 提供了完善的错误处理和重试机制,确保系统的稳定性和可靠性:
错误处理配置示例:
1type ExceptionConfig struct {
2 TimeoutMS int64 `json:"timeout_ms"` // 超时时间
3 MaxRetry int64 `json:"max_retry"` // 最大重试次数
4 DataOnErr string `json:"data_on_err"` // 错误时返回的默认数据
5 ProcessType *ErrorProcessType `json:"process_type"` // 错误处理类型
6}
7
技术特色与创新点
1. 基于 Eino 的抽象层设计
Coze Studio 巧妙地利用了 Eino 框架的抽象能力,实现了统一的节点执行接口。这种设计使得:
- 节点扩展变得简单: 只需实现对应的接口即可
- 执行模式灵活切换: 同一节点可支持多种执行模式
- 流式处理原生支持: 无需额外的流式处理层
2. 前后端架构分离
通过 Canvas 到 Schema 的转换机制,实现了前后端的完全解耦:
- 前端专注可视化: 画布设计、用户交互、可视化展示
- 后端专注执行: 工作流调度、状态管理、性能优化
- 数据结构转换: 自动处理前后端数据格式差异
3. 事件驱动的响应式架构
采用事件驱动模式,实现了:
- 实时状态推送: 执行进度实时可见
- 异步执行管理: 长时间运行的工作流不阻塞界面
- 错误快速响应: 问题发生时立即反馈
4. 灵活的批处理机制
支持节点级别的批处理配置,自动生成批处理包装器:
1// 自动将普通节点包装为批处理节点
2func parseBatchMode(n *vo.Node) (*vo.Node, bool, error) {
3 // 创建父级批处理节点
4 parentN := &vo.Node{
5 Type: entity.NodeTypeBatch.IDStr(),
6 Blocks: []*vo.Node{innerN}, // 包含原始节点
7 }
8 return parentN, true, nil
9}
10
评论 (0)