字节跳动扣子Coze 开源coze Studio (2)

Coze Studio后端遵循领域驱动设计(DDD)的原则,将业务逻辑组织到清晰定义的领域边界中。本文档深入探讨了核心领域实体的结构、它们之间的关系以及它们如何协同工作以支持应用程序的功能。
根:应用实体
组件:连接器、发布记录
工作流聚合:
根:工作流实体
组件:Meta、CanvasInfo、节点
对话聚合:
根:对话实体
组件:消息、运行记录

领域服务

领域服务实现不属于特定实体的业务逻辑。它们协调跨多个实体的操作并维护领域不变性。

Coze Studio中的关键领域服务包括:
应用服务:
管理应用生命周期(创建、更新、发布)
处理应用资源管理
工作流服务:
管理工作流版本和草稿
验证工作流配置
处理工作流执行
对话服务:
管理对话流程
处理传入消息
协调代理运行

领域仓库

每个领域都有相应的仓库来处理持久化问题。仓库遵循一致的接口模式:

type Repository interface {    Create(ctx context.Context, entity *Entity) error    Get(ctx context.Context, id int64) (*Entity, error)    Update(ctx context.Context, entity *Entity) error    Delete(ctx context.Context, id int64) error}
这种抽象确保领域逻辑与特定的存储实现保持解耦。

来源:app/repository, workflow/repository

资源类型

Coze Studio定义了多种可以在应用和工作流中使用的资源类型:

type ResourceType stringconst (ResourceTypeOfPlugin    ResourceType = "plugin"ResourceTypeOfWorkflow  ResourceType = "workflow"ResourceTypeOfKnowledge ResourceType = "knowledge"ResourceTypeOfDatabase  ResourceType = "database")这些资源类型代表了可以集成到Coze Studio应用程序中的不同组件。

领域交互示例:应用发布

为了说明领域实体如何交互,让我们考察应用发布过程:
用户发起应用的发布(包含工作流、插件等)
应用的PublishStatus设置为PublishStatusOfPacking
与应用关联的资源被打包
如果打包失败,状态变为PublishStatusOfPackFailed
否则,状态进展到PublishStatusOfAuditing
审核后,状态变为PublishStatusOfAuditNotPass或PublishStatusOfConnectorPublishing
连接器发布成功后,状态变为PublishStatusOfPublishDone

此过程涉及多个领域实体和服务协同工作,确保正确的状态转换和业务规则得到遵循。

结论

Coze Studio的领域模型展示了清晰的关注点分离和不同领域之间明确的边界。领域实体设计用于捕捉核心业务概念,同时避免不必要的耦合。

在扩展系统时,重要的是维护这些领域边界,并确保新功能与现有架构保持一致。通过理解领域模型的构建方式,您将更好地装备自己,以做出维护系统完整性的更改。

服务实现

Coze Studio后端采用结构化的、领域驱动的方法来实现服务。本指南解释了在平台上实现服务的模式、架构和最佳实践,提供了概念理解和实际实施指导。

Coze Studio采用分层服务架构,促进了关注点分离、依赖管理和领域隔离。系统将服务组织成三个层级:

字节跳动扣子Coze 开源coze Studio (2)

这种架构确保了不同系统方面的清晰依赖和分离。让我们详细探讨每个组件。

服务层级

服务实现遵循结构化的层级,有助于管理依赖和初始化顺序:
基础服务:仅依赖于基础设施组件(如数据库、缓存和外部客户端)的核心服务。
主要服务:基于基础服务构建,提供更复杂功能的服务。
复杂服务:协调主要服务以实现最终用户功能的高级服务。

这一层级在应用初始化代码中定义清晰,服务按顺序初始化:

// 服务初始化流程func Init(ctx context.Context) (err error) {// 1. 初始化基础设施infra, err := appinfra.Init(ctx)// 2. 初始化基础服务basicServices, err := initBasicServices(ctx, infra, eventbus)// 3. 初始化主要服务primaryServices, err := initPrimaryServices(ctx, basicServices)// 4. 初始化复杂服务complexServices, err := initComplexServices(ctx, primaryServices)// 5. 注册跨领域服务crossconnector.SetDefaultSVC(connectorImpl.InitDomainService(…))// … 更多跨领域服务注册}

服务组件模式

每个服务使用ServiceComponents结构体来清晰管理依赖。这种模式:
使依赖关系明确
通过依赖注入实现清晰的测试
在服务间保持一致的初始化模式

以下是会话服务的典型示例:

// 服务组件包含所有依赖type ServiceComponents struct {IDGen     idgen.IDGeneratorDB        *gorm.DBTosClient storage.StorageImageX    imagex.ImageXSingleAgentDomainSVC singleagent.SingleAgent}// 使用组件初始化服务func InitService(s *ServiceComponents) *ConversationApplicationService {// 使用依赖初始化领域服务messageDomainSVC := message.NewService(&message.Components{MessageRepo: msgRepo.NewMessageRepo(s.DB, s.IDGen),})// 配置并返回应用服务ConversationSVC.MessageDomainSVC = messageDomainSVC// … 更多配置return ConversationSVC}

领域服务与应用服务

服务实现遵循领域驱动设计方法,明确区分:

领域服务

领域服务实现核心业务逻辑和领域规则:
位于/backend/domain/{domain}/service
专注于特定业务领域
使用仓库进行数据访问
通过明确定义的接口暴露领域操作
操作领域实体,而非API模型

应用服务

应用服务协调各领域并向API层暴露功能:
位于/backend/application/{domain}
使用多个领域服务实现功能
处理跨领域关注点,如授权和验证
在API模型和领域实体之间转换
暴露直接映射到API端点的方法

实现示例:会话服务

让我们看看这种架构在会话服务中的实际应用:
服务结构:
ConversationApplicationService:协调领域服务
使用领域服务:AgentRunDomainSVC、ConversationDomainSVC、MessageDomainSVC
方法实现:
API处理程序调用应用服务方法
应用服务方法使用领域服务
示例:CreateConversation方法:

func (c *ConversationApplicationService) CreateConversation(ctx context.Context,agentID int64, connectorID int64) (*conversation.CreateConversationResponse, error) {// 1. 提取认证信息apiKeyInfo := ctxutil.GetApiAuthFromCtx(ctx)userID := apiKeyInfo.UserID// 2. 应用业务规则if connectorID != consts.WebSDKConnectorID {connectorID = apiKeyInfo.ConnectorID}// 3. 使用领域实体调用领域服务conversationData, err := c.ConversationDomainSVC.Create(ctx, &entity.CreateMeta{AgentID:     agentID,UserID:      userID,ConnectorID: connectorID,Scene:       common.Scene_SceneOpenApi,})// 4. 将领域实体转换为API响应resp.ConversationData = &conversation.ConversationData{Id:            conversationData.ID,LastSectionID: &conversationData.SectionID,ConnectorID:   &conversationData.ConnectorID,CreatedAt:     conversationData.CreatedAt,}return resp, nil}

跨领域服务通信

服务通常需要跨领域边界通信。Coze Studio通过跨领域服务注册表处理:
跨领域契约:定义在/backend/crossdomain/contract的接口
跨领域实现:位于/backend/crossdomain/impl的适配器
全局注册表:在初始化期间注册默认实现

// 跨领域服务注册crossconnector.SetDefaultSVC(connectorImpl.InitDomainService(basicServices.connectorSVC.DomainSVC))crossdatabase.SetDefaultSVC(databaseImpl.InitDomainService(primaryServices.memorySVC.DatabaseDomainSVC))// … 更多注册 这种模式允许领域保持解耦,同时仍能实现跨领域通信。
这种方法保持了清晰的架构,有助于防止领域逻辑泄露到应用服务中。

服务初始化过程

向系统中添加新服务时,遵循以下步骤:
确定服务级别:是基础、主要还是复杂服务?
定义服务组件:为依赖创建ServiceComponents结构体
实现领域服务:在领域服务中实现核心逻辑
创建应用服务:协调各领域
添加到初始化链:更新相应的初始化函数
注册跨领域服务:如需,添加到跨领域注册表

// 示例:添加新的主要服务func initPrimaryServices(ctx context.Context, basicServices *basicServices) (*primaryServices, error) {// 现有服务…// 添加你的新服务myNewSVC := mynewservice.InitService(basicServices.toMyNewServiceComponents())return &primaryServices{// 现有服务…myNewSVC: myNewSVC,}, nil}

测试服务

服务实现架构支持清晰的测试方法:
单元测试领域服务:隔离测试领域逻辑
模拟依赖:使用组件模式方便模拟
集成测试:使用真实或模拟的领域服务测试应用服务

示例测试结构:

func TestMyService(t *testing.T) {// 创建模拟依赖mockRepo := &MockRepository{}// 使用模拟组件初始化服务svc := NewService(&Components{Repo: mockRepo,})// 测试服务方法result, err := svc.DoSomething(ctx, input)// 断言结果assert.NoError(t, err)assert.Equal(t, expected, result)}

结论

Coze Studio中的服务实现架构提供了一种清晰、可维护的方法来构建后端功能。通过遵循既定模式——服务层级、组件模式和领域驱动设计——你可以创建结构良好、可测试和可维护的服务。

在实现新功能时,首先理解领域模型,然后构建实现核心业务逻辑的领域服务,最后创建协调各领域的应用服务,以向用户交付功能。

API结构

Coze Studio的API基于分层架构,使用Hertz网络框架构建,这是一个适用于Go语言的高性能HTTP框架。API遵循层次组织模式,不同功能域之间有明确的关注点分离。

字节跳动扣子Coze 开源coze Studio (2)

API围绕核心业务域组织,端点按功能分组,公网API和内部API之间有明确的分隔。

API路由组织

Coze Studio的API路由遵循层次结构,包含几个顶层组:

字节跳动扣子Coze 开源coze Studio (2)

每个API组包含特定领域的子组,封装了相关功能。这种组织方式使API更易于发现,并保持了关注点的清晰分离。

核心API组

Coze Studio的主要功能组织成以下API组:

字节跳动扣子Coze 开源coze Studio (2)

每个组处理系统内的特定功能域:
对话APIs (/api/conversation):管理聊天交互、消息和对话历史
知识APIs (/api/knowledge):处理知识库、文档和数据检索
内存APIs (/api/memory):管理数据库连接和变量存储
插件APIs (/api/plugin_api):集成和管理外部插件和API
工作流APIs (/api/workflow_api):创建、执行和管理代理工作流

HTTP方法和请求模式

Coze Studio的API主要使用两种HTTP方法:
POST:用于大多数操作,包括数据创建、更新和复杂查询
GET:用于简单的数据检索操作

API端点通常遵循以下命名模式:

字节跳动扣子Coze 开源coze Studio (2)

认证和授权

API包含几种认证机制:
基于会话的认证,适用于网页界面用户
个人访问令牌(PAT),用于API集成
OAuth,用于第三方集成

这些通过中间件实现,在请求到达处理器之前进行处理:

字节跳动扣子Coze 开源coze Studio (2)

与认证相关的端点主要位于/api/passport和/api/permission_api组中。

OpenAPI兼容端点

对于公网API访问,Coze Studio在/v1路径下提供OpenAPI兼容端点:
/v1/conversations- 管理对话
/v1/conversation/:id- 操作特定对话
/v1/workflow- 运行和管理工作流
/v1/files- 处理文件上传

这些端点遵循更标准的RESTful约定,专为外部集成设计。

核心功能APIs

对话管理

对话APIs处理聊天交互和消息管理:

字节跳动扣子Coze 开源coze Studio (2)

知识库

知识APIs管理文档存储和检索:

字节跳动扣子Coze 开源coze Studio (2)

工作流系统

工作流APIs支持创建和执行代理工作流:

字节跳动扣子Coze 开源coze Studio (2)

插件系统

插件APIs处理外部工具的集成和管理:

字节跳动扣子Coze 开源coze Studio (2)

错误处理

API通过一致的响应格式实现标准化错误处理:

{  "code": 400,  "msg": "错误消息详情",  "data": null}
错误响应包括:
HTTP状态码
内部错误码
描述性错误消息
可选的上下文数据

API实现

API端点作为处理器实现在backend/api/handler/coze目录中。每个处理器遵循一致的模式:
请求验证
参数提取
业务逻辑执行
响应格式化

处理器与应用层和领域层交互以执行业务逻辑,同时保持关注点分离。

API中间件

API使用多个中间件组件处理横切关注点:

字节跳动扣子Coze 开源coze Studio (2)

摘要

Coze Studio API提供了一个全面且结构化的接口,用于与平台的所有方面交互。关键特性包括:
按功能域的层次组织
一致的命名和操作模式
多种认证机制
OpenAPI兼容端点
全面的中间件支持
标准化错误处理

理解这一结构使开发者能够高效地定位、使用和扩展API,以应对各种集成场景。

组件架构

Coze Studio的前端基于模块化、组织良好的组件架构构建,支持可扩展开发和一致的用户体验。本文档探讨了Coze Studio前端组件的组织结构、设计模式和最佳实践。

Coze Studio前端采用Rush构建的单一代码库(monorepo)结构,组件根据其用途和功能组织到不同的包中。组件架构遵循现代React模式,重点在于可重用性、组合性和可维护性。

字节跳动扣子Coze 开源coze Studio (2)

核心组件库

UI 组件

主要组件组织在packages/components目录中,每个组件设计为独立的包,具有一致的结构:

字节跳动扣子Coze 开源coze Studio (2)

每个组件包遵循一致的结构:
src/- 组件源代码
_tests_/- 单元和集成测试
stories/- 组件文档示例
配置文件(TypeScript, ESLint等)

设计系统实现

Coze Studio基于Semi Design UI框架构建,并在bot-semi包中进行定制。这种方法在提供一致性的同时,也允许满足应用特定的设计需求。

bot-semi包包括:
带有应用特定样式的自定义UI组件
增强功能的Semi组件包装器
一致的主题和样式模式

字节跳动扣子Coze 开源coze Studio (2)

架构模式

组件组织

组件按照层级结构组织:
原子组件:基本的UI元素,如按钮、输入框和图标
复合组件:由原子组件组合而成的更复杂的UI
功能组件:与应用业务逻辑相关的特定组件
页面组件:代表完整页面的顶层组件

适配器模式

前端架构广泛使用适配器模式,这在以下包中尤为明显:
account-adapter
space-store-adapter
bot-hooks-adapter

这种模式将组件与具体实现解耦,使得以下操作更容易:
替换底层库或服务
测试时模拟依赖
在不同实现之间提供一致的接口

组件通信

组件通过以下方式通信:
Props:传统的父子通信
Context:用于共享状态,避免属性钻取
基于Store的状态管理:用于全局应用状态
基于事件的通信:用于松耦合组件

状态管理

组件架构包括多种状态管理方法:

字节跳动扣子Coze 开源coze Studio (2)

样式架构

Coze Studio采用混合样式方法:
CSS Modules:组件特定样式,自动作用域

// CSS Modules示例用法import styles from './component.module.less';function Component() {return <div className={styles.container}>内容</div>;}Tailwind CSS:面向实用性的CSS,用于快速UI开发

// Tailwind示例用法function Component() {  return <div className="flex p-4 bg-white rounded shadow">内容</div>;}
Semi Design主题化:通过设计系统实现一致的主题

组件开发工作流

创建新组件
位置:确定组件属于现有包还是需要新包
结构:遵循既定的包结构,包括src、测试和文档
实现:按照项目模式和最佳实践构建组件
测试:为组件创建单元和集成测试
文档:添加展示组件用法的示例或故事

组件最佳实践
组合优于继承:使用组件组合而非继承层级
Props接口:为组件Props定义清晰的TypeScript接口
受控与不受控:在适当的情况下支持两种模式
性能优化:谨慎使用React.memo、useCallback和useMemo
可访问性:确保组件符合可访问性标准

应用集成

主应用(apps/coze-studio)集成来自各个包的组件,构建完整的用户界面:

字节跳动扣子Coze 开源coze Studio (2)

应用使用路由系统组织页面组件,并管理应用不同部分之间的导航。

开发工具和扩展

前端包括多个开发工具,以增强组件开发体验:
类似Storybook的预览:通过预览文件进行组件文档和测试
测试工具:组件测试的辅助函数和模拟
构建配置:共享配置以实现一致的构建和打包

结论

Coze Studio的组件架构遵循React应用的现代最佳实践,重点在于模块化、可重用性和可维护性。通过理解这一架构,开发者可以有效地为项目做出贡献,创建无缝集成的全新组件,并在整个应用中保持一致性。

关键要点:
组件按职责明确地组织到不同的包中
Semi Design为UI提供基础,bot-semi中进行定制
适配器模式将组件与具体实现解耦
状态管理通过多种方法组合处理
样式使用CSS Modules、Tailwind和Semi Design系统

应用结构

Coze Studio使用Rush.js进行包管理,构建为单一代码库,采用模块化架构,分离关注点并促进代码复用。

字节跳动扣子Coze 开源coze Studio (2)

架构遵循几个关键原则:
基于功能的组织:代码按功能/领域组织
模块化设计:功能划分为可复用的包
适配器模式:模块间的集成通过适配器包管理
懒加载:组件按需加载以提高性能

主应用程序结构

主应用程序位于apps/coze-studio目录,是整个系统的入口点。

入口点与启动过程

应用程序从index.tsx开始,执行以下步骤:
初始化功能标志
设置国际化(i18n)
加载必要的样式
渲染根App组件

// index.tsx的简化版本const main = () => {// 初始化功能标志initFlags();// 初始化i18ninitI18nInstance({lng: (localStorage.getItem('i18next') ?? (IS_OVERSEA ? 'en' : 'zh-CN'))});// 加载样式dynamicImportMdBoxStyle();const $root = document.getElementById('root');const root = createRoot($root);root.render(<App />);};main();App组件随后设置路由提供者和代码拆分的悬念边界:

// app.tsx的简化版本export function App() {  return (    <Suspense fallback={<Loading />}>      <RouterProvider router={router} fallbackElement={<div>加载中…</div>} />    </Suspense>  );}

路由结构

Coze Studio使用React Router,采用嵌套结构组织导航。路由在routes.tsx中定义,遵循层次模式:

路由系统通过lazy()函数实现代码拆分,按需加载组件,提高初始加载性能。每个路由定义加载器,指定:
认证要求
布局配置
侧边栏偏好
菜单选择

布局系统

应用程序使用分层的布局系统,包含不同级别的布局组件:
全局布局:管理整体应用程序结构
空间布局:处理特定工作区的布局
功能特定布局:如Agent IDE等专业区域

// 主布局组件export const Layout = () => {  useAppInit(); // 初始化应用程序状态/数据  return <GlobalLayout />;};此布局系统在保持UI模式一致性的同时,为应用程序的不同部分提供灵活性。

包组织

前端在packages目录中组织为多个包,每个包有特定的职责:

核心包

字节跳动扣子Coze 开源coze Studio (2)

功能包

字节跳动扣子Coze 开源coze Studio (2)

集成包

许多包遵循适配器模式,以-adapter后缀的包作为不同模块间的集成点。这种模式促进松耦合,便于修改实现细节而不影响使用者。

模块架构

以studio包为例,看看模块是如何组织的:

字节跳动扣子Coze 开源coze Studio (2)

每个模块通常遵循标准结构:
src/- 源代码
_tests_/- 单元测试
配置文件(TypeScript, ESLint等)
包定义

代码拆分与懒加载

为了优化性能,Coze Studio广泛使用代码拆分和懒加载。这通过React的lazy()函数和Suspense组件实现:

// routes.tsx中的示例const AgentIDE = lazy(() =>import('@coze-agent-ide/entry-adapter').then(res => ({default: res.BotEditor,})),);// 在路由中使用{path: 'bot/:bot_id',Component: AgentIDELayout,children: [{index: true,Component: AgentIDE, // 懒加载组件},// …]}这种方法确保用户仅下载正在使用的功能代码,减少初始加载时间。

配置系统

前端使用强大的配置系统,针对不同工具有专门的配置:

字节跳动扣子Coze 开源coze Studio (2)

这种模块化配置方法确保代码库的一致性,同时允许必要的灵活性。

总结

Coze Studio的前端架构遵循现代React模式,重点在于:
模块化设计:将功能划分为专注的包
代码拆分:按需加载代码以提高性能
适配器模式:使用适配器进行模块间集成
基于功能的组织:按领域/功能分组代码

理解这一结构将帮助您导航代码库,定位特定功能,并在添加新功能或进行更改时遵循既定模式。

状态管理

在Coze Studio中,状态管理对于处理跨组件的复杂应用数据和UI状态至关重要。本文档解释了前端使用的状态管理架构,为开发者提供了一个全面指南,以有效管理应用状态。

Coze Studio采用了一种混合状态管理方法,结合Zustand进行存储创建和React Context进行存储分发。这种模式提供了一种强大且灵活的方式来管理整个应用的状态。

字节跳动扣子Coze 开源coze Studio (2)

这种架构提供了多项好处:
模块化状态管理,针对特定领域有专门的存储
性能提升,通过细粒度更新
强类型,提升开发者体验
Devtools集成,便于调试

核心状态管理模式
使用Zustand创建存储

Zustand是一个轻量级状态管理库,为Coze Studio的状态管理提供动力。存储通过工厂函数创建,封装了状态和操作。

// 存储工厂模式export const createSomeStore = (initialState) =>create<StateType & ActionsType>()(devtools((set, get) => ({// 初始状态…initialState,// 修改状态的操作someAction: () => {set({ /* 更新后的状态 */ });}})),);代码库中的示例:

export const createProcessingKnowledgeStore = () =>  create<ProcessingKnowledgeInfo & ProcessingKnowledgeInfoAction>()(    devtools((set, get) => ({      …defaultState,      getIsProcessing: (datasetId: string) => {        const { processingDatasets } = get();        return processingDatasets.has(datasetId);      },      addProcessingDataset: (datasetId: string) => {        const { processingDatasets } = get();        processingDatasets.add(datasetId);        set({          processingDatasets,        });      },      // 更多操作…    })),  );
Context提供者模式

存储实例通过React Context提供者分发,允许树中的任何组件访问它们。

// 示例Context提供者export const SomeStoreProvider: FC<Props> = ({ children, initialState }) => {const storeRef = useRef<StoreType>();if (!storeRef.current) {storeRef.current = createSomeStore(initialState);}return (<SomeStoreContext.Provider value={{ someStore: storeRef.current }}>{children}</SomeStoreContext.Provider>);};在Coze Studio中,KnowledgeParamsStoreProvider展示了这种模式:

export const KnowledgeParamsStoreProvider: FC<PropsWithChildren<{params: IParams;onUpdateDisplayName?: (displayName: string) => void;onStatusChange?: (status: WidgetUIState) => void;resourceNavigate: PluginNavType;}>> = ({children,params,onUpdateDisplayName,onStatusChange,resourceNavigate,}) => {const paramsStoreRef = useRef<ParamsStore>();const knowledgeStoreRef = useRef<KnowledgePreviewStore>();const processingStoreRef = useRef<ProcessingKnowledgeStore>();paramsStoreRef.current = createParamsStore(params);if (!knowledgeStoreRef.current) {knowledgeStoreRef.current = createKnowledgePreviewStore({version: params.version,});}if (!processingStoreRef.current) {processingStoreRef.current = createProcessingKnowledgeStore();}return (<KnowledgeParamsStoreContext.Providervalue={{paramsStore: paramsStoreRef.current,knowledgeStore: knowledgeStoreRef.current,processingKnowledge: processingStoreRef.current,callbacks: { onUpdateDisplayName, onStatusChange },resourceNavigate,}}>{children}</KnowledgeParamsStoreContext.Provider>);};
自定义钩子访问存储

自定义钩子为组件访问存储状态和操作提供了一个干净的API:

export const useSomeStore = <T>(selector: (store: StoreType) => T): T => {const context = useContext(SomeStoreContext);if (!context.someStore) {throw new Error('存储不可用');}return useStoreWithEqualityFn(context.someStore, selector, shallow);};项目中通过类似useKnowledgeParamsStore的钩子实现这种模式:

export const useKnowledgeParamsStore: <T>(selector: (store: IParamsStore) => T,) => T = selector => {const context = useContext(KnowledgeParamsStoreContext);if (!context.paramsStore) {throw new CustomError(REPORT_EVENTS.normalError, 'params store context');}return useStoreWithEqualityFn(context.paramsStore, selector, shallow);};

在组件中使用状态

访问和更新状态

要在组件中访问状态,使用自定义钩子并传入选择器函数:

// 访问特定状态片段const isProcessing = useProcessingStore(store =>store.getIsProcessing(datasetId));// 访问多个状态值const { processingDatasets } = useProcessingStore(store => ({processingDatasets: store.processingDatasets}));// 通过调用操作更新状态const { addProcessingDataset } = useProcessingStore(store => ({addProcessingDataset: store.addProcessingDataset}));// 在组件中稍后const handleProcess = () => {addProcessingDataset(datasetId);};

状态组织

Coze Studio将状态组织到特定领域的存储中:

字节跳动扣子Coze 开源coze Studio (2)

高级状态管理技术

中间件集成

Zustand支持中间件以增强存储功能。Coze Studio使用:
devtools- 用于Redux DevTools集成
subscribeWithSelector- 用于订阅特定状态变化

状态切片

对于复杂状态,Coze Studio使用切片来组织相关状态和操作:

调试状态

Redux DevTools集成

Coze Studio中的Zustand存储集成了Redux DevTools,允许你:
检查状态变化
通过状态历史进行时间旅行
查看操作负载

要启用此功能:
安装Redux DevTools浏览器扩展
使用devtools中间件时,状态变化将自动跟踪

常见调试模式

调试状态问题时:
检查存储初始化- 确保提供者正确设置
验证选择器使用- 确保选择器提取正确的状态
检查组件渲染- 使用React DevTools检查不必要的渲染
检查操作调用- 验证操作是否使用正确参数调用

最佳实践
保持存储专注- 为不同领域创建单独的存储
使用选择性状态选择- 只选择需要的部分以最小化重新渲染
组合相关状态- 将相关状态分组在同一存储中
类型化一切- 使用TypeScript接口为状态和操作定型
明智使用中间件- 仅在需要时添加以优化性能
创建抽象层- 使用自定义钩子抽象存储访问

总结

Coze Studio的状态管理架构结合了Zustand的简洁性和React Context的分发能力。这种混合方法允许:
领域特定存储,封装相关状态和逻辑
类型安全的状态访问,通过自定义钩子
性能优化,通过选择性状态订阅
开发者友好的调试,通过DevTools集成

代理开发

代理开发是Coze Studio的核心能力,允许你创建具有自定义行为、知识和技能的AI助手。本指南将引导你了解在Coze Studio平台中构建、测试和部署智能代理的过程。

在Coze Studio中,代理是一个具有特定目的、个性和能力的自主AI助手。每个代理包括:
核心身份:名称、描述和视觉标识
模型配置:驱动代理推理的底层LLM
提示词工程:塑造代理行为和响应的指令
插件/工具:代理可以用来执行操作的外部能力
知识库:代理可以参考的信息来源
工作流集成:代理可以执行的结构化流程

创建你的第一个代理

Coze Studio中的代理开发遵循草稿-发布工作流。你首先创建和配置一个草稿,彻底测试后,再将其发布以供使用。

基本代理创建
创建一个新的代理草稿,包含核心属性:
名称:代理的描述性标题
描述:代理目的的解释
图标:代理的视觉表示

// 创建代理的后端实现func CreateSingleAgentDraft(ctx context.Context, creatorID int64, draft *entity.SingleAgent) (agentID int64, err error) {    return s.AgentDraftRepo.Create(ctx, creatorID, draft)}

配置代理组件

Coze Studio的代理-IDE提供了一个综合界面,用于配置代理的所有方面。

模型选择和配置

选择适合代理需求的适当语言模型:
模型类型:从各种LLM选项中选择
参数:配置温度、最大令牌数和其他模型特定设置
系统消息:定义代理的基础指令

字节跳动扣子Coze 开源coze Studio (2)

提示词工程

提示词是塑造代理行为的核心指令集。Coze Studio提供了一个专门的提示词编辑器,允许你:
定义代理的个性和语气
设置边界和限制
结构化代理对各种输入的响应方式
包含供代理学习的示例

集成插件和工具

插件扩展了代理的对话能力,使其能够执行操作和访问外部数据:
导航到代理配置中的插件部分
浏览可用插件或创建自定义工具
配置插件参数和权限
在代理工作流中测试插件集成

字节跳动扣子Coze 开源coze Studio (2)

知识库集成

通过集成知识库,增强代理的特定知识:
在知识部分创建或选择知识库
配置知识检索参数:
相关性阈值
包含的结果数量
引用偏好

工作流集成

对于复杂的、多步骤的过程,集成工作流,引导代理通过结构化决策树:
在工作流编辑器中设计工作流
连接工作流节点以创建逻辑流程
将工作流链接到你的代理
定义工作流激活的触发条件

测试和调试

Coze Studio提供了全面的工具,用于在部署前测试你的代理:

聊天调试器

使用内置聊天界面测试代理的响应:
向代理发送测试消息
查看详细的执行跟踪
监控插件调用和响应
识别并修复代理配置中的问题

执行跟踪

运行代理时,你可以访问详细的事件日志,了解其处理请求的方式:

// 代理执行的后端实现func StreamExecute(ctx context.Context, req *entity.ExecuteRequest) (events *schema.StreamReader[*entity.AgentEvent], err error) {    // 实现细节…}
执行跟踪包括以下事件:
模型响应
工具/插件调用
知识检索
工作流步骤

发布和版本管理

创建和测试完代理后,你可以将其发布以供使用:

发布过程
完成代理配置
审查所有组件的完整性
提交发布

系统会创建代理的版本化快照:

// 列出已发布版本func ListAgentPublishHistory(ctx context.Context, agentID int64, pageIndex, pageSize int32, connectorID *int64) ([]*entity.SingleAgentPublish, error) {    // 实现细节…}

版本管理

Coze Studio为每个代理维护已发布版本的历史记录:
每个版本一旦发布即不可变
你可以访问以前版本以供参考
用户可以选择使用你的代理的哪个版本

高级代理功能

建议回复

配置代理以向用户提供上下文相关的建议回复,增强对话流程并引导用户进行有效互动。

来源:single_agent.go#L78

背景图配置

通过背景图自定义代理聊天界面的视觉外观。

来源:single_agent.go#L80, chat-background/

快捷命令

创建自定义命令,用户可以通过输入这些命令来触发特定的代理行为:

// 代理包含快捷命令type SingleAgent struct {    // 其他字段…    ShortcutCommand []string}

代理开发的最佳实践
从明确的目的开始

在配置前定义代理的特定目的。专注的代理比通用型代理表现更好。
迭代测试

用各种输入测试你的代理,包括:
常见问题
边缘案例
可能的有问题输入
多轮对话
提示词工程技巧
对期望行为要具体明确
包含理想响应的示例
定义护栏和边界
使用清晰简洁的语言
性能优化
只集成必要的插件
仔细配置知识检索
根据性能监控和调整模型参数
定期更新
定期审查和更新代理
结合用户反馈
逐步扩展能力

结论

Coze Studio中的代理开发结合了提示词工程、插件集成、知识管理和工作流编排,以创建强大的AI助手。通过遵循本指南中的实践,你可以创建为用户带来价值的同时保持可靠性和性能的代理。

对于复杂的代理场景,考虑探索工作流系统文档,以构建扩展代理能力的复杂多步骤过程。

工作流系统

Coze Studio中的工作流系统是一个强大的编排引擎,允许用户通过可视化画布界面创建、测试和执行复杂的自动化工作流。本文探讨了工作流系统的功能、架构以及开发者如何利用它构建复杂的AI驱动应用。

核心上,工作流系统提供了一个可视化编程环境,用户可以在此定义一系列相互连接的节点来表示具体操作或逻辑。这些工作流可以执行从简单文本处理到集成AI模型的复杂决策树等多种任务。

该系统基于一个全面的领域模型构建,包括工作流定义、执行引擎、节点类型以及一个用于持久化的健壮存储库。它支持同步和流式执行模式,适用于实时应用。

核心组件

工作流实体

系统的基本构建块是“工作流”实体,包括:
基本标识符:用于跟踪和版本控制的ID和CommitID
元数据:名称、描述、创建者信息和其他属性
画布信息:包含节点和连接的实际工作流定义
版本控制:草稿和发布状态的版本跟踪

每个工作流属于特定的空间,并可选择性关联到一个应用。

画布架构

画布是工作流的可视化设计场所,表示一个有向图:
节点:具有特定功能的单个工作单元
边:定义数据和控制流的节点间连接
数据流:通过节点的输入和输出传递信息

字节跳动扣子Coze 开源coze Studio (2)

该结构灵活,支持分支逻辑、循环和并行执行路径。

节点类型

工作流系统提供了丰富的节点类型用于不同操作:

字节跳动扣子Coze 开源coze Studio (2)

每个节点类型通过其“输入”结构具有特定的配置选项,并产生可供下游节点使用的输出。

工作流执行

工作流的执行由“工作流运行器”协调:
准备:生成执行ID并设置事件通道
上下文创建:构建包含必要依赖的执行上下文
图遍历:按顺序执行工作流图中的节点
状态管理:维护节点执行间的状态
事件处理:处理中断和完成等事件
输出收集:收集节点执行结果

系统支持同步执行和流式输出,允许与长时间运行的工作流进行实时交互。

中断和恢复机制

工作流系统的一个重要特性是能够处理中断并恢复执行。这对于以下工作流尤其有价值:
执行过程中需要人工输入
需要等待外部事件或回调
经历可重试的临时故障

中断机制工作原理如下:

字节跳动扣子Coze 开源coze Studio (2)

这支持复杂的交互模式,如确认步骤、人工审查或外部服务回调。

前端集成

工作流系统的前端部分提供了用于创建和管理工作流的可视化编辑器:
画布编辑器:拖放界面进行工作流设计
节点配置:表单和面板用于设置节点属性
变量管理:工具用于定义和使用工作流中的变量
测试界面:实时执行可视化和调试

画布编辑器使用基于fabric的实现,允许直观地操作节点和连接。

存储库模式

工作流系统使用存储库模式进行持久化:
工作流元数据:存储基本工作流信息
画布持久化:将工作流定义保存为结构化文档
版本控制:管理草稿和发布版本
执行历史:记录执行痕迹用于调试和审计

存储库接口抽象了存储实现,允许根据部署需求使用不同的后端。

工作流作为工具

系统的一个强大功能是将工作流暴露为工具,供其他组件或工作流使用:
工具注册:将工作流发布为可重用工具
参数定义:指定工具的输入和输出
封装:隐藏实现细节,提供简洁接口
重用:将工作流作为子组件包含在其他工作流中

这促进了模块化和可重用性,允许从更简单的构建块构建复杂工作流。

构建工作流:最佳实践

在使用工作流系统时,考虑以下最佳实践:
从简单开始:从基本流程开始,逐步增加复杂性
使用变量:适当利用变量在节点间传递数据,而非直接连接
错误处理:为可能失败的节点配置错误路径和回退
测试:使用测试执行功能验证工作流行为
模块化:将复杂工作流分解为子工作流以提高可维护性
版本控制:使用版本管理功能跟踪变更

扩展工作流系统

开发者可以通过以下方式扩展工作流系统:
创建自定义节点:实现新节点类型以提供特定功能
构建工作流模板:为常见场景创建可重用的工作流模式
集成外部服务:连接到额外的API和服务
增强执行引擎:添加分布式执行或高级监控等能力

结论

Coze Studio中的工作流系统提供了一个强大的框架,通过可视化编程创建复杂的AI驱动流程。通过理解其架构和能力,开发者可以利用该系统构建结合AI模型、数据处理和外部集成的复杂应用,且具有可维护性和可扩展性。

无论你是在构建对话代理、数据处理管道还是复杂决策系统,工作流系统都提供了足够的灵活性和强大功能,将你的想法变为现实。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片