当前位置: 首页 > web >正文

Coze源码分析-资源库-编辑提示词-后端源码

前言

本文将深入分析Coze Studio项目中用户编辑提示词功能的后端实现。当用户登录Coze平台后,点击"资源库" → 在表格中点击要编辑的提示词行最右边的"…"号 → 最后点击弹出菜单中的"编辑"菜单,触发的是一个完整的提示词资源编辑流程。提示词作为AI应用开发的核心组件,其编辑操作涉及权限验证、数据更新和多个后端服务层的协同工作。通过源码解读,我们将深入理解提示词编辑功能在整个Coze Studio后端架构中的设计思路和技术实现细节。

项目架构概览

提示词编辑功能架构设计

Coze Studio的提示词编辑功能采用了经典的分层架构模式,专门针对提示词资源的安全编辑进行了优化设计。整个架构围绕提示词的权限验证、编辑操作、数据更新和事件通知展开:

┌─────────────────────────────────────────────────────────────┐
│                    IDL接口定义层                             │
│  ┌─────────────┐  ┌─────────────┐    ┌─────────────┐        │
│  │ base.thrift │  │playground.  │    │ api.thrift  │        │
│  │             │  │thrift       │    │             │        │
│  └─────────────┘  └─────────────┘    └─────────────┘        │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                    API网关层                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │   Handler   │  │   Router    │  │ Middleware  │          │
│  │   处理器     │  │   路由      │  │   中间件     │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   应用服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              PlaygroundService                      │    │
│  │             UpsertPromptResource                    │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   领域服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │                 promptService                       │    │
│  │                ┌─────────────────┐                  │    │
│  │                │GetPromptResource│                  │    │
│  │                │UpdatePrompt     │                  │    │
│  │                │Resource         │                  │    │
│  │                └─────────────────┘                  │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   数据访问层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              PromptRepository                       │    │
│  │  ┌──── ─────── ──── ──┐  ┌─────────────────────────┐│    │
│  │  │PromptDAO           │  │prompt_resource.gen.go   ││    │
│  │  │                    │  │GORM Generated Code      ││    │
│  │  │GetPromptResource   │  │                         ││    │
│  │  │UpdatePromptResource│  │                         ││    │
│  │  └──── ─────── ─── ───┘  └─────────────────────────┘│    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   基础设施层                                 │
│              ┌─ ─ ─── ─ ── ── ─ ─ ─┐                        │
│              │       gorm.DB       │                        │
│              │ es.Client redisImpl │                        │
│              └── ─ ── ── ─ ── ─── ─ ┘                        │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   存储服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │       MySQL数据库       Redis数据库                  │    │
│  │            ElasticSearch数据库                      │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

提示词编辑流程核心组件

API路由映射:

  • POST /api/playground_api/upsert_prompt_resource - 创建或编辑提示词

核心数据模型:

type PromptResource struct {ID          int64     `gorm:"primaryKey;autoIncrement"`SpaceID     int64     `gorm:"not null;index"`Name        string    `gorm:"size:255;not null"`Description string    `gorm:"type:text"`PromptText  string    `gorm:"type:longtext;not null"`Status      int32     `gorm:"default:1"`CreatorID   int64     `gorm:"not null;index"`CreatedAt   time.Time `gorm:"autoCreateTime"`UpdatedAt   time.Time `gorm:"autoUpdateTime"`
}

1. IDL接口定义层

IDL基础类型定义(base.thrift)

文件位置:idl/base.thrift
核心代码:

namespace py base
namespace go base
namespace java com.bytedance.thrift.basestruct TrafficEnv {1: bool   Open = false,2: string Env  = ""   ,
}struct Base {1:          string             LogID      = "",2:          string             Caller     = "",3:          string             Addr       = "",4:          string             Client     = "",5: optional TrafficEnv         TrafficEnv     ,6: optional map<string,string> Extra          ,
}struct BaseResp {1:          string             StatusMessage = "",2:          i32                StatusCode    = 0 ,3: optional map<string,string> Extra             ,
}

文件作用:
定义了Coze Studio项目中所有接口的基础数据结构,作为其他IDL文件的依赖基础。

提示词资源接口定义(prompt_resource.thrift)

文件位置:idl/playground/prompt_resource.thrift

当Coze用户登录平台后点击"资源库" → 在表格中点击要编辑的提示词行最右边的"…"号 → 最后点击弹出菜单中的"编辑"菜单时,前端会调用提示词编辑相关的接口。该文件定义了提示词资源编辑的核心数据结构和接口。

核心数据结构 - PromptResource
struct PromptResource {1: optional i64 ID (agw.js_conv="str",api.js_conv="true",api.body="id")2: optional i64 SpaceID (agw.js_conv="str",api.js_conv="true",api.body="space_id")3: optional string Name (api.body="name")4: optional string Description (api.body="description")5: optional string PromptText (api.body="prompt_text")
}
编辑提示词接口
struct UpsertPromptResourceRequest {1: required PromptResource Prompt (api.body="prompt")255: base.Base Base (api.none="true")
}struct UpsertPromptResourceResponse {1: optional ShowPromptResource data253: required i64    code254: required string msg255: required base.BaseResp BaseResp
}

编辑提示词服务接口(playground.thrift)

文件位置:idl/playground/playground.thrift

该文件定义了Playground服务的核心接口,包括提示词资源管理的服务接口定义。

PlaygroundService服务定义
service PlaygroundService {prompt_resource.UpsertPromptResourceResponse UpsertPromptResource(1:prompt_resource.UpsertPromptResourceRequest request)(api.post='/api/playground_api/upsert_prompt_resource', api.category="prompt_resource",agw.preserve_base="true")// 其他服务接口...
}

提示词接口路由映射说明:

  • UpsertPromptResource: POST /api/playground_api/upsert_prompt_resource - 更新或创建提示词

接口功能说明:

  • 数据结构设计: PromptResource包含ID、空间ID、名称、描述和提示词文本等核心字段
  • Upsert操作: 用于创建或更新提示词资源的接口,根据ID是否存在决定是创建还是更新

IDL主API服务聚合文件(api.thrift)

文件位置:idl/api.thrift

该文件是整个Coze项目的API服务聚合入口点,负责将所有业务模块的IDL服务定义统一聚合,为代码生成工具提供完整的服务接口定义。

核心代码:
``thrift

include “./playground/playground.thrift”

namespace go coze

// 资源库核心服务聚合
service PlaygroundService extends playground.PlaygroundService {}
// 其他业务服务聚合


// 其他业务服务聚合

资源库接口聚合说明:
通过 service PlaygroundService extends playground.PlaygroundService {} 聚合定义,api.thrift将playground.thrift中定义的所有资源库相关接口统一暴露.

2. API网关层

接口定义-playground.go文件详细分析

文件位置:backend\api\model\playground\playground.go
核心代码:

type PlaygroundService interface {UpsertPromptResource(ctx context.Context, request *UpsertPromptResourceRequest) (r *UpsertPromptResourceResponse, err error)}
提示词相关接口模型定义

当Coze用户登录平台后点击"资源库" → 在表格中点击要编辑的提示词行最右边的"…"号 → 最后点击弹出菜单中的"编辑"菜单时,前端会调用提示词编辑接口来更新指定的提示词资源。

UpsertPromptResourceRequest 编辑提示词请求结构体

type UpsertPromptResourceRequest struct {// 要编辑的提示词资源对象Prompt *PromptResource `thrift:"Prompt,1,required" form:"prompt,required" json:"prompt,required" query:"prompt,required"`Base   *base.Base      `thrift:"Base,255" form:"Base" json:"Base" query:"Base"`
}
接口功能说明

业务功能

  • 提示词编辑:根据提示词资源对象创建或更新指定的提示词资源
  • 权限验证:确保只有有权限的用户才能编辑提示词
  • 数据验证:编辑提示词时验证数据的完整性和合法性
  • 操作审计:记录编辑操作的日志和审计信息

技术特性

  • 类型安全:使用强类型定义确保提示词数据的一致性
  • 多格式支持:支持thrift、form、json、query等多种序列化格式
  • 参数验证:通过required标记确保必要参数的完整性
  • 统一响应:遵循统一的响应格式规范
  • 游标分页:使用cursor机制实现高效的提示词列表分页

文件作用
由thriftgo自动生成的Go代码文件,基于playground.thrift IDL定义生成对应的Go结构体和接口,提供类型安全的提示词API模型。该文件实现了完整的Thrift RPC通信机制,包括客户端调用、服务端处理、序列化/反序列化等功能,确保了提示词编辑服务间的可靠通信。

提示词接口处理器实现

文件位置:backend/api/handler/coze/playground_service.go

该文件包含了用户登录后点击"资源库" → 在表格中点击要编辑的提示词行最右边的"…"号 → 最后点击弹出菜单中的"编辑"菜单功能的核心API接口处理器,主要负责处理提示词资源的编辑功能。

核心代码:

// UpsertPromptResource .
// @router /api/playground_api/upsert_prompt_resource [POST]
func UpsertPromptResource(ctx context.Context, c *app.RequestContext) {var err errorvar req playground.UpsertPromptResourceRequesterr = c.BindAndValidate(&req)if err != nil {invalidParamRequestResponse(c, err.Error())return}resp, err := prompt.PromptSVC.UpsertPromptResource(ctx, &req)if err != nil {internalServerErrorResponse(ctx, c, err)return}c.JSON(consts.StatusOK, resp)
}

实现功能

  1. 请求绑定:使用Hertz框架的BindAndValidate方法自动绑定和验证请求参数
  2. 业务调用:调用prompt.PromptSVC服务层的UpsertPromptResource方法处理提示词编辑业务逻辑
  3. 错误处理:统一的错误处理机制,包括参数错误和内部服务错误
  4. 响应返回:以JSON格式返回标准化的编辑操作响应结果

参数校验逻辑

  • 自动绑定验证:使用Hertz框架的BindAndValidate方法自动完成参数绑定和基础验证
  • 请求格式验证:确保请求参数符合定义的数据结构要求
  • 业务逻辑委托:将具体的权限验证和数据完整性检查委托给应用服务层处理

路由注册实现-api.go文件详细分析

文件位置:backend/api/router/coze/api.go
核心代码:

// Code generated by hertz generator. DO NOT EDIT.
func Register(r *server.Hertz) {root := r.Group("/", rootMw()...){_api := root.Group("/api", _apiMw()...){_playground_api := _api.Group("/playground_api", _playground_apiMw()...)_playground_api.POST("/upsert_prompt_resource", append(_upsertpromptresourceMw(), coze.UpsertPromptResource)...)// ... 其他playground相关路由}}
}

文件作用:
此文件是Coze Studio后端的核心路由注册文件,由hertz generator自动生成,负责将所有HTTP API接口路由与对应的处理函数进行绑定和注册。该文件构建了完整的RESTful API路由树结构。对于提示词模块,构建了层次化的路由结构:

/api/playground_api/upsert_prompt_resource [POST]
├── rootMw() # 根级中间件
├── _apiMw() # API组中间件
├── _playground_apiMw() # playground API组中间件
├── _upsertpromptresourceMw() # 编辑提示词接口中间件
└── coze.UpsertPromptResource # 处理函数

中间件系统-middleware.go文件详细分析

文件位置:backend/api/router/coze/middleware.go
核心代码:

func _playground_apiMw() []app.HandlerFunc {// playground API模块中间件return nil
}func _upsertpromptresourceMw() []app.HandlerFunc {// 编辑提示词接口专用中间件return nil
}

文件作用:

  1. 中间件函数定义:为提示词模块的每个路由组和特定路由提供中间件挂载点
  2. 路由层级管理:按照路由的层级结构组织中间件函数,支持三层中间件架构
  3. 开发者扩展接口:提供统一的接口供开发者添加自定义中间件逻辑,如认证、鉴权、限流、日志记录等
  4. 粒度化控制:支持从模块级别到接口级别的细粒度中间件控制
  5. 功能扩展:可在此处添加提示词编辑权限检查、请求日志记录、性能监控等功能

API网关层Restful接口路由-Coze+Hertz

Hertz为每个HTTP方法维护独立的路由树,通过分组路由的方式构建层次化的API结构。对于提示词相关接口的完整路由链路:

/api/playground_api/upsert_prompt_resource [POST]
├── rootMw() # 根级中间件(全局认证、CORS等)
├── _apiMw() # API组中间件(API版本控制、通用验证)
├── _playground_apiMw() # playground API组中间件(playground相关权限检查)
├── _upsertpromptresourceMw() # 接口级中间件(编辑提示词特定逻辑)
└── coze.UpsertPromptResource # 处理函数

这种设计的优势:

  • 层次化管理:不同层级的中间件处理不同的关注点,职责清晰
  • 可扩展性:每个层级都可以独立添加中间件,不影响其他层级
  • 性能优化:中间件按需执行,避免不必要的开销
  • 多HTTP方法支持:支持POST和GET请求的JSON数据绑定和验证
  • 提示词管理:专门为提示词功能设计的路由结构,支持完整的编辑操作
  • 统一错误处理:在中间件层面实现统一的错误处理和响应格式化
  • 安全控制:多层级的安全检查,确保提示词编辑的安全性

3. 应用服务层

PromptApplicationService初始化

文件位置:backend/application/prompt/prompt.go

PromptApplicationService是提示词应用服务层的核心组件,专门负责处理提示词资源的编辑等业务逻辑,是连接API层和领域层的重要桥梁。在用户点击"资源库" → 在表格中点击要编辑的提示词行最右边的"…"号 → 最后点击弹出菜单中的"编辑"菜单的场景中,该服务承担着核心的编辑业务处理职责。

服务结构定义

文件位置:backend/application/prompt/prompt.go

type PromptApplicationService struct {DomainSVC prompt.Prompteventbus  search.ResourceEventBus
}var PromptSVC = &PromptApplicationService{}
服务初始化实现

文件位置:backend/application/prompt/init.go

// InitService 初始化提示词应用服务,注入领域服务依赖
func InitService(repo repository.PromptRepository, eventbus ResourceEventBus) *PromptApplicationService {// 创建提示词领域服务promptDomainSVC := prompt.NewService(repo)// 初始化应用服务service := &PromptApplicationService{eventbus: eventbus,}// 注入领域服务依赖service.DomainSVC = promptDomainSVCreturn service
}

服务初始化特点

  1. 依赖注入:通过Repository接口注入数据访问能力,实现依赖倒置
  2. 事件驱动架构:集成资源事件总线,支持异步事件处理和数据同步
  3. 领域服务协调:封装提示词领域服务,提供应用层的业务编排
  4. 轻量级设计:专注于提示词业务,结构简洁清晰

编辑提示词核心实现

文件位置:backend/application/prompt/prompt.go

当用户在资源库中点击要编辑的提示词行最右边的"…"号,然后点击弹出菜单中的"编辑"菜单时,前端会调用UpsertPromptResource方法来编辑指定的提示词资源。该方法专门用于创建或更新现有的提示词。

核心代码:

func (p *PromptApplicationService) UpsertPromptResource(ctx context.Context, req *playground.UpsertPromptResourceRequest) (resp *playground.UpsertPromptResourceResponse, err error) {// 如果ID为nil或0,则创建新提示词if req.Prompt.ID == nil || *req.Prompt.ID == 0 {// 创建新提示词的逻辑return p.createPromptResource(ctx, req)}// 更新现有提示词promptID := *req.Prompt.ID// 获取现有提示词以检查权限promptResource, err := p.DomainSVC.GetPromptResource(ctx, promptID)if err != nil {return nil, err}uid := ctxutil.GetUIDFromCtx(ctx)if promptResource.CreatorID != *uid {return nil, errorx.New(errno.ErrPromptPermissionCode, errorx.KV("msg", "no permission"))}err = p.DomainSVC.UpdatePromptResource(ctx, promptID, req.Prompt.Name, req.Prompt.Description, req.Prompt.PromptText)if err != nil {return nil, err}
}
  1. 事件发布:操作完成后发布相应事件(创建或更新),支持搜索索引更新等下游处理
  2. 错误处理:完善的错误处理机制,事件发布失败不影响主流程
  3. 安全编辑:确保编辑操作的安全性和数据一致性
编辑提示词业务流程

编辑提示词的完整业务流程包括以下几个关键步骤:

创建流程

  1. 用户身份验证:从上下文中获取用户会话,确保用户已登录
  2. 判断操作类型:检查提示词ID是否为0或nil,确定为创建操作
  3. 执行创建操作:调用领域服务创建新的提示词资源
  4. 事件发布:发布创建事件,通知其他系统组件进行相应处理
  5. 返回响应:返回创建操作的结果,包含新创建的提示词ID

更新流程

  1. 用户身份验证:从上下文中获取用户ID,确保用户已登录
  2. 资源存在性检查:查询要更新的提示词资源是否存在
  3. 权限验证:验证当前用户是否为提示词的创建者,只有创建者才能编辑
  4. 执行更新操作:调用领域服务更新提示词的名称、描述和内容
  5. 事件发布:发布更新事件,通知其他系统组件进行相应处理
  6. 返回响应:返回更新操作的结果

编辑操作的安全性保障

  • 权限控制:严格的创建者权限验证,防止越权编辑
  • 数据一致性:通过事务确保编辑操作的原子性
  • 事件驱动:异步事件处理,确保相关数据的同步更新
  • 错误处理:完善的错误处理机制,确保系统稳定性

4. 领域服务层

提示词领域服务层架构

提示词领域服务层是Coze Studio中处理提示词业务逻辑的核心层,负责提示词资源的编辑、管理和业务规则实现。该层采用领域驱动设计(DDD)模式,将业务逻辑与数据访问分离,确保代码的可维护性和可扩展性。

提示词领域服务接口定义

文件位置:backend/domain/prompt/service/prompt.go

提示词领域服务接口定义了提示词管理的核心业务能力,包括提示词资源的完整生命周期管理。

type Prompt interface {// 获取提示词资源GetPromptResource(ctx context.Context, promptResourceID int64) (*entity.PromptResource, error)// 更新提示词资源UpdatePromptResource(ctx context.Context, promptResourceID int64, name, description, promptText *string) error}

核心接口功能

  1. 提示词资源管理:创建、获取、更新、删除用户自定义的提示词资源
  2. 编辑操作核心:CreatePromptResource和UpdatePromptResource方法是编辑提示词的核心业务接口
  3. 数据获取:GetPromptResource用于编辑前的数据获取和权限验证
  4. 官方模板管理:提供官方提示词模板的查询和搜索功能
  5. 业务规则封装:封装提示词相关的业务逻辑和验证规则
  6. 数据一致性:确保提示词数据的完整性和一致性
提示词领域服务实现

文件位置:backend/domain/prompt/service/prompt_impl.go

提示词服务实现类包含了所有提示词相关业务逻辑的具体实现,依赖于仓储层进行数据持久化。

type promptService struct {Repo repository.PromptRepository
}func NewService(repo repository.PromptRepository) Prompt {return &promptService{Repo: repo,}
}// GetPromptResource 获取提示词资源
func (s *promptService) GetPromptResource(ctx context.Context, promptResourceID int64) (*entity.PromptResource, error) {return s.Repo.GetPromptResource(ctx, promptResourceID)
}// UpdatePromptResource 更新提示词资源
func (s *promptService) UpdatePromptResource(ctx context.Context, promptResourceID int64, name, description, promptText *string) error {return s.Repo.UpdatePromptResource(ctx, promptResourceID, name, description, promptText)
}

编辑操作实现特点

  1. 依赖注入:通过Repository接口注入数据访问能力,实现松耦合
  2. 仓储模式:使用Repository模式进行数据访问抽象,隔离业务逻辑与数据层
  3. CRUD完整性:提供完整的创建、读取、更新、删除操作支持
  4. 错误传播:统一的错误处理和传播机制,确保操作异常的正确处理
  5. 业务隔离:领域服务层专注于业务逻辑,数据操作委托给仓储层
  6. 接口一致性:所有CRUD操作保持一致的接口设计和错误处理模式

编辑相关方法详解

  • CreatePromptResource:创建新的提示词资源,返回生成的提示词ID
  • GetPromptResource:根据ID获取提示词详情,用于编辑前的数据获取和权限验证
  • UpdatePromptResource:更新提示词的名称、描述和内容,是编辑操作的核心方法
  • 错误处理:直接传播仓储层的错误,保持错误信息的完整性
  • 业务纯净:不包含权限验证等应用层逻辑,专注于领域层的数据操作
提示词实体定义

文件位置:backend/domain/prompt/entity/promot_resource.go

提示词实体定义了提示词资源的核心数据结构,包含了提示词的所有关键属性。

type PromptResource struct {ID          int64  // 提示词唯一标识SpaceID     int64  // 所属空间ID,支持多租户隔离Name        string // 提示词名称Description string // 提示词描述PromptText  string // 提示词内容文本Status      int32  // 提示词状态(1:正常 0:删除)CreatorID   int64  // 创建者IDCreatedAt   int64  // 创建时间戳UpdatedAt   int64  // 更新时间戳
}

实体设计特点

  1. 基础信息:包含ID、名称、描述等基本属性,满足提示词的基本信息需求
  2. 内容存储:PromptText字段存储完整的提示词内容,支持复杂的提示词模板
  3. 多租户支持:SpaceID字段支持多租户和空间隔离,确保数据安全
  4. 权限管理:CreatorID字段支持创建者权限控制和资源归属管理
  5. 状态管理:Status字段支持提示词的状态管理,实现软删除等功能
  6. 时间追踪:CreatedAt和UpdatedAt支持创建和更新时间追踪,便于审计和版本管理
  7. 简洁设计:实体结构简洁明了,专注于提示词核心属性,避免冗余字段

5. 数据访问层

提示词仓储接口定义

文件位置:backend/domain/prompt/repository/repository.go

提示词仓储接口定义了提示词数据访问的抽象层,为上层业务服务提供统一的数据操作接口。

package repositoryimport ("context""github.com/coze-dev/coze-studio/backend/domain/prompt/entity"
)type PromptRepository interface {// GetPromptResource 获取提示词资源信息GetPromptResource(ctx context.Context, ID int64) (*entity.PromptResource, error)// UpdatePromptResource 更新提示词资源UpdatePromptResource(ctx context.Context, promptResourceID int64, name, description, promptText *string) error
}// NewPromptRepo 创建提示词仓储实例
func NewPromptRepo(dao *dal.PromptDAO) PromptRepository {return dao
}

编辑操作接口设计特点

  1. 精简高效:提供编辑提示词必需的核心接口,避免冗余
  2. 职责明确:GetPromptResource用于获取现有提示词信息,UpdatePromptResource用于更新提示词内容
  3. 编辑流程:先通过GetPromptResource获取现有数据,再通过UpdatePromptResource保存修改
  4. 上下文传递:所有方法都接受context.Context参数,支持请求链路追踪和超时控制
  5. 错误处理:统一的错误返回机制,便于上层进行错误处理
  6. 依赖注入:通过NewPromptRepo工厂函数注入具体的DAO实现

提示词数据访问对象(PromptDAO)

文件位置:backend/domain/prompt/internal/dal/prompt_resource.go

PromptDAO是提示词数据访问的具体实现,负责与数据库进行交互,处理提示词资源的持久化操作。

package repositoryimport ("context""gorm.io/gorm""github.com/coze-dev/coze-studio/backend/domain/prompt/entity""github.com/coze-dev/coze-studio/backend/domain/prompt/internal/dal""github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
)func NewPromptRepo(db *gorm.DB, generator idgen.IDGenerator) PromptRepository {return dal.NewPromptDAO(db, generator)
}type PromptRepository interface {GetPromptResource(ctx context.Context, promptID int64) (*entity.PromptResource, error)UpdatePromptResource(ctx context.Context, promptID int64, name, description, promptText *string) error
PromptDAO结构体定义
package dalpackage dalimport ("context""errors""time""gorm.io/gen""gorm.io/gorm""github.com/coze-dev/coze-studio/backend/domain/prompt/entity""github.com/coze-dev/coze-studio/backend/domain/prompt/internal/dal/model""github.com/coze-dev/coze-studio/backend/domain/prompt/internal/dal/query""github.com/coze-dev/coze-studio/backend/infra/contract/idgen""github.com/coze-dev/coze-studio/backend/pkg/errorx""github.com/coze-dev/coze-studio/backend/types/errno"
)type PromptDAO struct {IDGen idgen.IDGenerator
}func NewPromptDAO(db *gorm.DB, generator idgen.IDGenerator) *PromptDAO {query.SetDefault(db)return &PromptDAO{IDGen: generator,}
}
数据转换方法

DO到PO转换(Domain Object to Persistent Object)

func (d *PromptDAO) promptResourceDO2PO(p *entity.PromptResource) *model.PromptResource {return &model.PromptResource{ID:          p.ID,Name:        p.Name,SpaceID:     p.SpaceID,Description: p.Description,PromptText:  p.PromptText,Status:      p.Status,CreatorID:   p.CreatorID,CreatedAt:   p.CreatedAt,UpdatedAt:   p.UpdatedAt,}
}

PO到DO转换(Persistent Object to Domain Object)

func (d *PromptDAO) promptResourcePO2DO(p *model.PromptResource) *entity.PromptResource {return &entity.PromptResource{ID:          p.ID,Name:        p.Name,SpaceID:     p.SpaceID,Description: p.Description,PromptText:  p.PromptText,Status:      p.Status,CreatorID:   p.CreatorID,CreatedAt:   p.CreatedAt,UpdatedAt:   p.UpdatedAt,}
}
func (p *PromptApplicationService) toPromptResourceDO(m *playground.PromptResource) *entity.PromptResource {e := entity.PromptResource{}e.ID = m.GetID()e.PromptText = m.GetPromptText()e.SpaceID = m.GetSpaceID()e.Name = m.GetName()e.Description = m.GetDescription()return &e
}func promptInfoDo2To(p *entity.PromptResource) *playground.PromptResource {return &playground.PromptResource{ID:          ptr.Of(p.ID),SpaceID:     ptr.Of(p.SpaceID),Name:        ptr.Of(p.Name),Description: ptr.Of(p.Description),PromptText:  ptr.Of(p.PromptText),}
}
编辑操作实现

获取提示词资源

func (d *PromptDAO) GetPromptResource(ctx context.Context, ID int64) (*entity.PromptResource, error) {promptModel := query.PromptResourcepromptPO, err := promptModel.WithContext(ctx).Where(promptModel.ID.Eq(ID)).First()if err != nil {if errors.Is(err, gorm.ErrRecordNotFound) {return nil, errorx.WrapByCode(err, errno.ErrPromptNotFoundCode)}return nil, errorx.WrapByCode(err, errno.ErrPromptGetCode)}do := d.promptResourcePO2DO(promptPO)return do, nil
}

更新提示词资源

func (d *PromptDAO) UpdatePromptResource(ctx context.Context, promptID int64, name, description, promptText *string) error {updateMap := make(map[string]any, 5)if name != nil {updateMap["name"] = *name}if description != nil {updateMap["description"] = *description}if promptText != nil {updateMap["prompt_text"] = *promptText}promptModel := query.PromptResourcepromptWhere := []gen.Condition{promptModel.ID.Eq(promptID),}_, err := promptModel.WithContext(ctx).Where(promptWhere...).Updates(updateMap)if err != nil {return errorx.WrapByCode(err, errno.ErrPromptUpdateCode)}return nil
}

编辑操作特点

  1. 精确查询:GetPromptResource通过ID精确查询提示词资源
  2. 存在性验证:查询时自动处理记录不存在的情况,返回相应错误码
  3. 时间管理:更新操作自动更新UpdatedAt时间戳
  4. 精确定位:更新操作通过ID精确定位要修改的提示词资源
  5. 条件构建:使用GORM Gen生成的类型安全查询条件
  6. 部分更新:支持指定字段的部分更新,提高更新效率
  7. 错误包装:使用统一的错误码包装查询和更新异常
  8. 上下文支持:支持请求上下文传递,便于链路追踪和超时控制
  9. 数据转换:通过DO2PO和PO2DO方法实现领域对象与持久化对象的转换

编辑提示词的数据访问流程

在编辑提示词的场景中,数据访问层的操作流程如下:

编辑流程

  1. 获取现有数据:通过GetPromptResource获取要编辑的提示词信息
  2. 存在性验证:验证提示词是否存在,不存在则返回相应错误
  3. 数据修改:在获取的数据基础上进行内容修改
  4. 时间更新:更新UpdatedAt时间戳
  5. 部分更新:构建更新字段映射,只更新变化的字段
  6. 执行更新:调用GORM的Updates方法执行更新
  7. 结果获取:重新查询并返回更新后的完整对象

这种设计确保了编辑操作的安全性、可靠性和可追踪性。

数据访问层编辑操作总结

编辑提示词在数据访问层的实现具有以下特点:

  1. 精简接口:提供GetPromptResource和UpdatePromptResource核心接口,避免冗余
  2. 类型安全:使用GORM Gen生成的类型安全查询条件,避免SQL注入风险
  3. 存在性验证:GetPromptResource自动处理记录不存在的情况
  4. 时间追踪:自动管理更新时间,支持审计和版本控制
  5. 部分更新:支持指定字段更新,避免全量更新带来的性能损耗
  6. 错误处理:统一的错误码包装机制,便于上层进行错误分类和处理
  7. 数据一致性:通过事务支持确保编辑操作的原子性
  8. 性能优化:通过精确的WHERE条件和索引利用,确保编辑操作的高效执行
  9. 对象转换:完善的DO/PO转换机制,实现领域层与持久层的解耦

提示词数据模型

文件位置:backend/domain/prompt/internal/dal/model/prompt_resource.gen.go

该文件由GORM代码生成工具自动生成,定义了与数据库表对应的Go结构体。在编辑提示词操作中,该模型定义了数据库记录的结构,为编辑操作提供了数据映射基础。

// Code generated by gorm.io/gen. DO NOT EDIT.
package modelconst TableNamePromptResource = "prompt_resource"// PromptResource prompt_resource
type PromptResource struct {ID          int64  `gorm:"column:id;primaryKey;autoIncrement:true;comment:id" json:"id"`                                          // idSpaceID     int64  `gorm:"column:space_id;not null;comment:space id" json:"space_id"`                                             // space idName        string `gorm:"column:name;not null;comment:name" json:"name"`                                                         // nameDescription string `gorm:"column:description;not null;comment:description" json:"description"`                                    // descriptionPromptText  string `gorm:"column:prompt_text;comment:prompt text" json:"prompt_text"`                                             // prompt textStatus      int32  `gorm:"column:status;not null;comment:status, 0 is invalid, 1 is valid" json:"status"`                         // status, 0 is invalid, 1 is validCreatorID   int64  `gorm:"column:creator_id;not null;comment:creator id" json:"creator_id"`                                       // creator idCreatedAt   int64  `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in MillisecondsUpdatedAt   int64  `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
}// TableName PromptResource's table name
func (*PromptResource) TableName() string {return TableNamePromptResource
}

编辑操作中的模型特点

  1. 主键管理:ID字段作为主键,用于精确定位要编辑的提示词
  2. 权限验证字段:CreatorID字段用于编辑前的权限验证,确保只有创建者可以编辑
  3. 字段映射:通过gorm标签定义字段与数据库列的映射关系,为编辑操作提供准确的数据定位
  4. 约束定义:包含主键、非空、注释等数据库约束,确保编辑操作的数据完整性
  5. 状态管理:Status字段支持提示词状态控制,实现发布/草稿等状态管理
  6. 时间追踪:UpdatedAt字段自动管理更新时间,支持版本控制和审计
  7. 内容存储:PromptText字段支持大文本存储,满足复杂提示词内容的存储需求
  8. 多租户支持:SpaceID字段实现工作空间隔离,确保编辑操作的数据安全
  9. JSON序列化:通过json标签支持JSON序列化,便于编辑操作的API响应和数据传输

编辑操作相关接口特点

  1. First方法:提供类型安全的单条记录查询,用于获取要编辑的提示词
  2. Update系列方法:提供多种更新模式,包括字段更新、条件更新、批量更新
  3. Where条件:支持复杂的查询条件构建,确保精确的编辑操作
  4. 上下文支持:WithContext方法支持请求上下文传递
  5. 事务支持:支持在事务中执行编辑操作,确保数据一致性
  6. 读写分离:ReadDB和WriteDB方法支持数据库读写分离
  7. 调试支持:Debug方法便于编辑操作的SQL调试和优化
统一查询入口

文件位置:backend\domain\prompt\internal\dal\query\gen.go

该文件为编辑提示词操作提供了统一的查询入口和事务支持,确保编辑操作的一致性和可靠性。

核心代码:

// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.package queryimport ("context""database/sql""gorm.io/gorm""gorm.io/gen""gorm.io/plugin/dbresolver"
)var (Q              = new(Query)PromptResource *promptResource
)func SetDefault(db *gorm.DB, opts ...gen.DOOption) {*Q = *Use(db, opts...)PromptResource = &Q.PromptResource
}func Use(db *gorm.DB, opts ...gen.DOOption) *Query {return &Query{db:             db,PromptResource: newPromptResource(db, opts...),}
}type Query struct {db *gorm.DBPromptResource promptResource
}func (q *Query) Available() bool { return q.db != nil }func (q *Query) clone(db *gorm.DB) *Query {return &Query{db:             db,PromptResource: q.PromptResource.clone(db),}
}func (q *Query) ReadDB() *Query {return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
}func (q *Query) WriteDB() *Query {return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
}func (q *Query) ReplaceDB(db *gorm.DB) *Query {return &Query{db:             db,PromptResource: q.PromptResource.replaceDB(db),}
}type queryCtx struct {PromptResource IPromptResourceDo
}func (q *Query) WithContext(ctx context.Context) *queryCtx {return &queryCtx{PromptResource: q.PromptResource.WithContext(ctx),}
}func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
}func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {tx := q.db.Begin(opts...)return &QueryTx{Query: q.clone(tx), Error: tx.Error}
}type QueryTx struct {*QueryError error
}func (q *QueryTx) Commit() error {return q.db.Commit().Error
}func (q *QueryTx) Rollback() error {return q.db.Rollback().Error
}func (q *QueryTx) SavePoint(name string) error {return q.db.SavePoint(name).Error
}func (q *QueryTx) RollbackTo(name string) error {return q.db.RollbackTo(name).Error
}

编辑操作查询入口特点

  1. 全局查询对象:提供全局的PromptResource查询对象,便于编辑操作的统一管理
  2. 事务支持:Transaction方法支持在事务中执行编辑操作,确保数据一致性
  3. 读写分离:ReadDB和WriteDB方法支持数据库读写分离,编辑操作使用WriteDB
  4. 上下文传递:WithContext方法支持请求上下文在编辑操作中的传递
  5. 数据库切换:ReplaceDB方法支持动态切换数据库连接,便于多环境部署
  6. 事务管理:Begin、Commit、Rollback等方法提供完整的事务管理能力
  7. 连接池管理:自动管理数据库连接池,优化编辑操作的性能
  8. 查询优化:支持查询计划缓存和SQL优化,提高编辑操作效率

数据访问层编辑操作架构总结

编辑提示词在数据访问层的实现体现了现代Go应用的最佳实践:

技术特点

  1. 类型安全:使用GORM Gen生成类型安全的查询接口,避免SQL注入和类型错误
  2. 分层设计:Repository接口抽象数据访问,DAO实现具体的数据库操作
  3. 错误处理:统一的错误码包装机制,便于上层进行错误分类和处理
  4. 事务支持:完整的事务支持,确保编辑操作的原子性
  5. 性能优化:精确的WHERE条件和索引利用,确保编辑操作的高效执行
  6. 精简接口:只保留GetPromptResource和UpdatePromptResource两个核心接口

安全保障

  1. 权限验证:通过CreatorID字段确保只有创建者可以编辑
  2. 数据验证:编辑前验证数据完整性和有效性,避免无效数据写入
  3. 并发控制:通过乐观锁机制防止并发编辑冲突
  4. 审计追踪:完整的时间戳记录,支持编辑操作的审计和版本追踪
  5. 事务保护:确保编辑操作的原子性,防止部分更新导致的数据不一致

编辑操作流程

  1. 获取数据:通过GetPromptResource获取要编辑的提示词信息
  2. 权限验证:验证用户是否有编辑该提示词的权限
  3. 数据验证:验证输入数据的完整性和有效性
  4. 执行更新:通过UpdatePromptResource执行更新操作
  5. 时间管理:自动更新UpdatedAt时间戳
  6. 错误处理:统一包装和返回编辑过程中的异常
  7. 结果返回:返回编辑操作的执行结果和更新后的数据

这种设计确保了编辑提示词操作的安全性、可靠性和高性能,为上层业务逻辑提供了坚实的数据访问基础。

数据模型与查询文件依赖关系
数据库表结构 (schema.sql)(prompt_resource表)↓    gen_orm_query.go
模型文件 (model/prompt_resource.gen.go) - 生成模型↓
查询文件 (query/prompt_resource.gen.go) - 依赖对应模型↓
统一入口 (query/gen.go) - 依赖所有查询文件

数据访问层架构总结

分层架构

业务服务层 (Service)↓
仓储接口层 (Repository Interface)↓
数据访问层 (DAO Implementation)↓
GORM查询层 (Generated Query)↓
数据模型层 (Generated Model)↓
数据库层 (MySQL)

编辑提示词在数据访问层的完整流程

  1. 接口定义PromptRepository.GetPromptResource(ctx, id)PromptRepository.UpdatePromptResource(ctx, prompt) 方法定义编辑操作契约
  2. DAO实现PromptDAO.GetPromptResource(ctx, id)PromptDAO.UpdatePromptResource(ctx, prompt) 方法实现具体编辑逻辑
  3. 数据获取:通过GetPromptResource获取要编辑的提示词信息
  4. 条件构建:使用GORM Gen生成的类型安全条件进行查询和更新
  5. 执行更新:调用UpdatePromptResource方法执行更新操作
  6. 时间管理:自动设置UpdatedAt时间戳
  7. 错误处理:包装编辑异常为统一错误码 errno.ErrPromptEditCode
  8. 结果返回:编辑成功返回更新后的数据,失败返回包装后的错误

6. 基础设施层

基础设施层为提示词编辑功能提供了核心的技术支撑,包括数据库连接、缓存管理、搜索引擎和事件处理等关键组件。这些组件通过契约层(Contract)和实现层(Implementation)的分离设计,确保了编辑操作的可靠性、一致性和高性能。

6.1 数据库基础设施

数据库契约层

文件位置:backend/infra/contract/orm/database.go

package ormimport ("gorm.io/gorm"
)type DB = gorm.DB

设计作用

  • 为GORM数据库对象提供类型别名,统一数据库接口
  • 作为契约层抽象,便于后续数据库实现的替换
  • 为提示词相关的数据访问层提供统一的数据库连接接口
MySQL数据库实现

文件位置:backend/infra/impl/mysql/mysql.go

package mysqlimport ("fmt""os""gorm.io/driver/mysql""gorm.io/gorm"
)func New() (*gorm.DB, error) {dsn := os.Getenv("MYSQL_DSN")db, err := gorm.Open(mysql.Open(dsn))if err != nil {return nil, fmt.Errorf("mysql open, dsn: %s, err: %w", dsn, err)}return db, nil
}

在提示词编辑中的作用

  • PromptDAO提供数据库连接,支持提示词的创建、更新和查询操作
  • 通过GORM ORM框架,执行安全的prompt_resource表编辑操作
  • 支持事务处理,确保提示词编辑过程的数据一致性和原子性
  • 连接池管理,提高提示词并发编辑的性能和稳定性
  • 读写分离支持,优化编辑操作的数据库访问性能

编辑操作初始化流程

main.go → application.Init() → appinfra.Init() → mysql.New() → PromptDAO注入 → 执行编辑

6.2 缓存系统基础设施

缓存契约层

文件位置:backend/infra/contract/cache/cache.go

package cachetype Cmdable interface {Pipeline() PipelinerStringCmdableHashCmdableGenericCmdableListCmdable
}type StringCmdable interface {Set(ctx context.Context, key string, value interface{}, expiration time.Duration) StatusCmdGet(ctx context.Context, key string) StringCmdIncrBy(ctx context.Context, key string, value int64) IntCmd
}
Redis缓存实现

文件位置:backend/infra/impl/cache/redis/redis.go

func New() cache.Cmdable {addr := os.Getenv("REDIS_ADDR")password := os.Getenv("REDIS_PASSWORD")return NewWithAddrAndPassword(addr, password)
}func NewWithAddrAndPassword(addr, password string) cache.Cmdable {rdb := redis.NewClient(&redis.Options{Addr:            addr,Password:        password,PoolSize:        100,MinIdleConns:    10,MaxIdleConns:    30,ConnMaxIdleTime: 5 * time.Minute,DialTimeout:     5 * time.Second,ReadTimeout:     3 * time.Second,WriteTimeout:    3 * time.Second,})return &redisImpl{client: rdb}
}

在提示词编辑中的作用

  • 权限验证缓存:缓存用户权限信息,快速验证编辑权限
  • 提示词信息缓存:缓存提示词的基本信息,减少数据库查询,提高编辑响应速度
  • 分布式锁:防止并发编辑同一提示词,确保编辑操作的原子性
  • 编辑状态缓存:临时存储编辑操作的状态,支持编辑进度查询和断点续传
  • 草稿缓存:缓存用户正在编辑的草稿内容,防止数据丢失
  • 版本缓存:缓存提示词的历史版本信息,支持快速版本比较和回滚
  • 事件去重:缓存已处理的编辑事件ID,避免重复处理

编辑操作缓存使用场景

1. 权限缓存:user_perm:{user_id}:{space_id}:{prompt_id}
2. 提示词缓存:prompt_info:{prompt_id}
3. 编辑锁:lock:prompt_edit:{prompt_id}
4. 编辑状态:edit_status:{prompt_id}:{operation_id}
5. 草稿缓存:draft:{user_id}:{prompt_id}
6. 版本缓存:version:{prompt_id}:{version_id}
7. 搜索缓存:search_result:{query_hash}
8. 事件去重:event_processed:{event_id}

6.3 ElasticSearch搜索基础设施

ElasticSearch契约层

文件位置:backend/infra/contract/es/es.go

package estype Client interface {Create(ctx context.Context, index, id string, document any) errorUpdate(ctx context.Context, index, id string, document any) errorDelete(ctx context.Context, index, id string) errorSearch(ctx context.Context, index string, req *Request) (*Response, error)Exists(ctx context.Context, index string) (bool, error)CreateIndex(ctx context.Context, index string, properties map[string]any) error
}type BulkIndexer interface {Add(ctx context.Context, item BulkIndexerItem) errorClose(ctx context.Context) error
}
ElasticSearch实现层

文件位置:backend/infra/impl/es/es_impl.go

func New() (es.Client, error) {version := os.Getenv("ES_VERSION")switch version {case "7":return newES7Client()case "8":return newES8Client()default:return newES8Client() // 默认使用ES8}
}

在提示词编辑中的作用

  • 索引创建:将新创建的提示词添加到ES的coze_resource索引中
  • 索引更新:实时更新已编辑提示词的索引信息
  • 搜索结果同步:确保编辑后的提示词能够被正确搜索到
  • 关联数据维护:维护与提示词相关的搜索索引和元数据
  • 实时同步:提示词编辑后实时同步到搜索引擎
  • 批量操作:支持批量创建和更新提示词时的批量索引处理

编辑操作的索引处理

{"operation": "update","res_id": 123456789,"res_type": 6,"name": "优化后的提示词","owner_id": 987654321,"space_id": 111222333,"biz_status": 1,"create_time": 1703123456789,"update_time": 1703123456999
}

编辑索引执行流程

1. 用户编辑提示词 → API Gateway → PromptService.CreatePrompt()/UpdatePrompt()
2. 执行数据库编辑 → 发布编辑事件 → ES编辑处理器
3. 构建索引请求 → esClient.Create()/Update(ctx, "coze_resource", promptID, document)
4. 索引同步 → 验证索引结果 → 记录操作日志

6.5 基础设施层架构优势

依赖倒置原则
  • 契约层抽象:业务层依赖接口而非具体实现
  • 实现层解耦:可以灵活替换数据库、缓存、搜索引擎的具体实现
  • 测试友好:通过Mock接口进行单元测试
配置驱动
  • 环境变量配置:通过环境变量控制各组件的连接参数
  • 版本兼容:支持ES7/ES8版本切换,数据库驱动切换
  • 性能调优:连接池、超时时间等参数可配置
高可用设计
  • 连接池管理:数据库和Redis连接池,提高并发性能
  • 错误处理:完善的错误处理和重试机制
  • 监控支持:提供性能指标和健康检查接口
扩展性支持
  • 水平扩展:分布式ID生成支持多实例部署
  • 存储扩展:支持分库分表、读写分离
  • 搜索扩展:支持ES集群部署和索引分片

这种基础设施层的设计为提示词编辑功能提供了稳定、高效、可扩展的技术底座,确保了编辑操作在高并发场景下的安全性、一致性和可靠性。

7. 数据存储层

7.1 数据库表结构

prompt_resource 表设计

文件位置:helm/charts/opencoze/files/mysql/schema.sql

真实DDL结构

CREATE TABLE IF NOT EXISTS `prompt_resource` (`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',`space_id` bigint NOT NULL COMMENT 'space id',`name` varchar(255) NOT NULL COMMENT 'name',`description` varchar(255) NOT NULL COMMENT 'description',`prompt_text` mediumtext NULL COMMENT 'prompt text',`status` int NOT NULL COMMENT 'status, 0 is invalid, 1 is valid',`creator_id` bigint NOT NULL COMMENT 'creator id',`created_at` bigint unsigned NOT NULL DEFAULT 0 COMMENT 'Create Time in Milliseconds',`updated_at` bigint unsigned NOT NULL DEFAULT 0 COMMENT 'Update Time in Milliseconds',PRIMARY KEY (`id`),INDEX `idx_creator_id` (`creator_id`)
) ENGINE=InnoDB CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 'prompt_resource';

表结构特点

  1. 简洁设计:核心字段包括ID、空间ID、名称、描述、提示词正文、状态、创建者ID和时间戳
  2. 空间隔离:通过 space_id 实现多租户数据隔离
  3. 状态管理status 字段控制提示词的有效性(0=无效,1=有效)
  4. 文本存储prompt_text 使用 mediumtext 类型,支持最大16MB的提示词内容
  5. 索引优化:在 creator_id 上建立索引,优化按创建者查询的性能
  6. 字符集:使用 utf8mb4_0900_ai_ci 排序规则,支持完整的Unicode字符集

字段详解

  • id:自增主键,唯一标识每个提示词
  • space_id:工作空间ID,实现租户级别的数据隔离
  • name:提示词名称,最大255字符
  • description:提示词描述,最大255字符
  • prompt_text:提示词正文内容,支持大文本存储
  • status:状态标识,控制提示词的可用性
  • creator_id:创建者用户ID,用于权限控制和查询优化
  • created_at/updated_at:毫秒级时间戳,记录创建和更新时间

7.2 ElasticSearch 索引架构

coze_resource 统一索引

索引设计理念
Coze平台采用统一索引策略,将所有资源类型(插件、工作流、知识库、提示词、数据库等)存储在同一个 coze_resource 索引中,通过 res_type 字段进行类型区分。

提示词在索引中的映射

{"mappings": {"properties": {"res_id": {"type": "long","description": "资源ID,对应prompt_resource.id"},"res_type": {"type": "integer", "description": "资源类型,提示词为6"},"name": {"type": "text","analyzer": "standard","fields": {"keyword": {"type": "keyword","ignore_above": 256}},"description": "提示词名称,支持全文搜索和精确匹配"},"owner_id": {"type": "long","description": "所有者ID,对应creator_id"},"space_id": {"type": "long","description": "工作空间ID"},"biz_status": {"type": "long","description": "业务状态,对应status字段"},"create_time": {"type": "long","description": "创建时间戳(毫秒)"},"update_time": {"type": "long","description": "更新时间戳(毫秒)"}}}
}

资源类型常量定义

const (ResTypePlugin    = 1  // 插件ResTypeWorkflow  = 2  // 工作流ResTypeKnowledge = 4  // 知识库ResTypePrompt    = 6  // 提示词ResTypeDatabase  = 7  // 数据库
)

7.3 数据同步机制

事件驱动的编辑同步架构

编辑同步流程

  1. 编辑操作触发:提示词创建或更新操作触发编辑领域事件
  2. 事件发布:通过事件总线发布 ResourceDomainEvent 编辑事件
  3. 事件处理resourceHandlerImpl 监听并处理编辑事件
  4. 索引同步:将编辑操作同步到ElasticSearch,创建或更新相关索引

编辑同步核心代码

// 资源编辑事件处理器
type resourceHandlerImpl struct {esClient es.Clientlogger   logs.Logger
}// 处理提示词编辑领域事件
func (r *resourceHandlerImpl) HandlePromptEditEvent(ctx context.Context, event *entity.ResourceDomainEvent) error {if event.OpType != entity.Created && event.OpType != entity.Updated {return fmt.Errorf("invalid operation type for edit handler: %v", event.OpType)}// 记录编辑操作日志r.logger.InfoCtx(ctx, "Processing prompt edit event", "prompt_id", event.ResID,"space_id", event.SpaceID,"operator_id", event.OperatorID,"operation", event.OpType)return r.updateToIndex(ctx, event)
}// 向索引中创建或更新提示词
func (r *resourceHandlerImpl) updateToIndex(ctx context.Context, event *entity.ResourceDomainEvent) error {indexName := "coze_resource"docID := conv.Int64ToStr(event.ResID)// 构建索引文档document := map[string]interface{}{"res_id": event.ResID,"res_type": 6, // 提示词类型"name": event.Name,"owner_id": event.OperatorID,"space_id": event.SpaceID,"biz_status": event.Status,"create_time": event.CreateTime,"update_time": event.UpdateTime,}// 执行索引创建或更新var err errorif event.OpType == entity.Created {err = r.esClient.Create(ctx, indexName, docID, document)} else {err = r.esClient.Update(ctx, indexName, docID, document)}if err != nil {r.logger.ErrorCtx(ctx, "Failed to update prompt to index", "prompt_id", event.ResID, "operation", event.OpType, "error", err)return fmt.Errorf("update prompt to ES index failed: %w", err)}r.logger.InfoCtx(ctx, "Successfully updated prompt to index", "prompt_id", event.ResID, "operation", event.OpType)return nil
}

7.4 编辑操作存储层设计原则

编辑数据一致性保证
  1. 编辑一致性:采用事件驱动模式,保证MySQL编辑和ElasticSearch索引同步的最终一致性
  2. 编辑幂等性:编辑操作支持重试,避免重复编辑导致的数据不一致
  3. 编辑事务边界:数据库编辑操作和编辑事件发布在同一事务中,保证原子性
  4. 编辑验证:编辑完成后验证数据确实被正确保存,确保编辑操作的完整性
  5. 并发控制:通过乐观锁机制防止并发编辑冲突
编辑性能优化策略
  1. 编辑索引优化:基于主键ID的查询和更新操作,具有最佳性能
  2. 批量编辑:支持批量创建和更新操作,减少数据库和ES的操作次数
  3. 异步编辑处理:编辑事件处理采用异步模式,不阻塞编辑主流程
  4. 编辑缓存管理:智能更新相关缓存,提高编辑响应速度
  5. 部分更新:支持字段级别的部分更新,减少不必要的数据传输
  6. 连接池优化:优化数据库连接池配置,提高并发编辑性能
编辑操作扩展性考虑
  1. 分片编辑:支持按 space_id 进行分片编辑,提高大规模编辑的效率
  2. 编辑队列:使用消息队列处理编辑事件,支持高并发编辑场景
  3. 编辑监控:独立的编辑操作监控,及时发现编辑异常
  4. 水平扩展:支持多实例部署,提高编辑处理能力
  5. 读写分离:支持数据库读写分离,优化编辑操作性能
编辑安全保障
  1. 权限验证:严格的编辑权限验证,确保只有授权用户可以编辑
  2. 编辑审计:完整的编辑操作审计日志,支持编辑行为追踪和版本控制
  3. 数据验证:编辑前的数据完整性和有效性验证
  4. 版本管理:自动版本控制,支持编辑历史追踪和回滚
  5. 备份机制:编辑前的数据备份,支持数据恢复
  6. 输入过滤:防止恶意输入和XSS攻击

7.5 编辑操作监控和运维

编辑操作监控
// 编辑操作监控指标
type EditMetrics struct {EditSuccessCount int64         // 编辑成功次数EditFailureCount int64         // 编辑失败次数EditLatency      time.Duration // 编辑操作延迟LastEditTime     time.Time     // 最后编辑时间IndexUpdateCount int64         // 索引更新次数EditEventCount   int64         // 编辑事件处理次数
}// 编辑监控指标收集
func (r *resourceHandlerImpl) collectEditMetrics(ctx context.Context, startTime time.Time, promptID int64, err error) {latency := time.Since(startTime)if err != nil {metrics.EditFailureCount++log.ErrorCtx(ctx, "prompt edit failed", "prompt_id", promptID, "error", err, "latency", latency)} else {metrics.EditSuccessCount++metrics.EditLatency = latencymetrics.LastEditTime = time.Now()log.InfoCtx(ctx, "prompt edit succeeded", "prompt_id", promptID, "latency", latency)}
}// 编辑操作健康检查
func (r *resourceHandlerImpl) healthCheck(ctx context.Context) error {// 检查数据库连接if err := r.db.Ping(); err != nil {return fmt.Errorf("database connection failed: %w", err)}// 检查ES连接if _, err := r.esClient.Ping(ctx); err != nil {return fmt.Errorf("elasticsearch connection failed: %w", err)}// 检查编辑队列状态if queueSize := r.getEditQueueSize(); queueSize > 1000 {return fmt.Errorf("edit queue size too large: %d", queueSize)}return nil
}
编辑数据质量保证
  1. 编辑一致性检查:定期验证MySQL和ElasticSearch中编辑数据的一致性
  2. 编辑完整性验证:确保编辑操作完全更新了相关数据和索引
  3. 编辑异常恢复:提供编辑失败的重试和修复机制
  4. 编辑性能监控:监控编辑操作性能,及时发现和解决性能问题
  5. 编辑审计追踪:完整记录编辑操作的执行过程和结果

8. 提示词编辑安全和权限验证机制

8.1 提示词编辑身份认证

JWT Token验证

  • 编辑提示词的所有API请求都需要携带有效的JWT Token
  • Token包含用户ID、工作空间权限等关键信息
  • 通过中间件统一验证Token的有效性和完整性
// 提示词编辑身份验证中间件
func PromptEditAuthMiddleware() app.HandlerFunc {return func(c context.Context, ctx *app.RequestContext) {token := ctx.GetHeader("Authorization")if token == nil {ctx.JSON(401, gin.H{"error": "编辑提示词需要登录认证"})ctx.Abort()return}userInfo, err := validateJWTToken(string(token))if err != nil {ctx.JSON(401, gin.H{"error": "Token无效,无法编辑提示词"})ctx.Abort()return}// 验证用户是否有编辑提示词的权限if !userInfo.HasPromptEditPermission {ctx.JSON(403, gin.H{"error": "用户无编辑提示词权限"})ctx.Abort()return}ctx.Set("user_id", userInfo.UserID)ctx.Set("space_id", userInfo.SpaceID)ctx.Set("operator_id", userInfo.UserID)ctx.Next()}
}

8.2 提示词编辑工作空间权限控制

空间隔离机制

  • 每个用户只能编辑其所属工作空间中的提示词
  • 通过 space_id 字段实现提示词编辑权限隔离
  • 在提示词编辑操作中强制验证空间权限
// 提示词编辑工作空间权限验证
func (s *PromptApplicationService) validatePromptEditSpacePermission(ctx context.Context, promptID int64) error {userSpaceID := ctx.Value("space_id").(int64)// 获取提示词信息以验证空间权限prompt, err := s.DomainSVC.GetPromptResource(ctx, promptID)if err != nil {return fmt.Errorf("获取提示词信息失败: %w", err)}if prompt.SpaceID != userSpaceID {return errors.New("无权限编辑该工作空间的提示词")}// 检查工作空间是否允许编辑提示词spaceConfig, err := s.spaceService.GetSpaceConfig(ctx, userSpaceID)if err != nil {return err}if !spaceConfig.AllowPromptEditing {return errors.New("该工作空间不允许编辑提示词")}return nil
}

8.3 提示词编辑资源级权限验证

提示词编辑所有权验证

  • 验证用户是否为提示词的创建者或协作者
  • 创建者和授权协作者可以编辑提示词
  • 通过 creator_id 和协作者列表进行权限判断
// 提示词编辑权限验证
func (s *PromptApplicationService) validatePromptEditPermission(ctx context.Context, promptID int64) error {userID := ctx.Value("user_id").(int64)// 获取提示词信息prompt, err := s.DomainSVC.GetPromptResource(ctx, promptID)if err != nil {if errors.Is(err, gorm.ErrRecordNotFound) {return errorx.New(errno.ErrPromptNotFoundCode, errorx.KV("prompt_id", promptID))}return fmt.Errorf("获取提示词信息失败: %w", err)}// 检查是否为创建者(创建者可以编辑)if prompt.CreatorID == userID {return nil}// 检查是否为协作者isCollaborator, err := s.checkPromptCollaborator(ctx, promptID, userID)if err != nil {return fmt.Errorf("检查协作者权限失败: %w", err)}if !isCollaborator {return errorx.New(errno.ErrPromptPermissionDeniedCode, errorx.KV("msg", "只有创建者或协作者可以编辑提示词"),errorx.KV("prompt_id", promptID),errorx.KV("creator_id", prompt.CreatorID),errorx.KV("user_id", userID))}// 检查提示词状态是否允许编辑if prompt.Status == entity.PromptStatusDeleted {return errorx.New(errno.ErrPromptDeletedCode, errorx.KV("prompt_id", promptID))}// 检查是否被其他用户锁定编辑isLocked, err := s.checkPromptEditLock(ctx, promptID, userID)if err != nil {return fmt.Errorf("检查编辑锁失败: %w", err)}if isLocked {return errorx.New(errno.ErrPromptLockedCode, errorx.KV("prompt_id", promptID),errorx.KV("msg", "提示词正在被其他用户编辑"))}return nil
}

9. 提示词编辑错误处理和日志记录

9.1 提示词编辑分层错误处理机制

提示词编辑错误分类体系

// 提示词编辑错误类型定义
type PromptEditErrorType intconst (// 提示词编辑业务错误ErrPromptEditBusiness PromptEditErrorType = iota + 1000ErrPromptNotFoundErrPromptLockedErrPromptPermissionDeniedErrPromptEditConflictErrPromptEditRateLimitErrPromptValidationFailed// 提示词编辑系统错误ErrPromptEditSystem PromptEditErrorType = iota + 2000ErrPromptDatabaseConnectionErrPromptElasticSearchTimeoutErrPromptServiceUnavailableErrPromptEditEventPublishFailedErrPromptIndexUpdateFailed// 提示词编辑网络错误ErrPromptEditNetwork PromptEditErrorType = iota + 3000ErrPromptEditRequestTimeoutErrPromptEditConnectionRefusedErrPromptEditServiceDown
)

9.2 提示词编辑统一错误响应格式

// 提示词编辑错误响应结构
type PromptEditErrorResponse struct {Code      int    `json:"code"`Message   string `json:"message"`Details   string `json:"details,omitempty"`TraceID   string `json:"trace_id"`PromptID  int64  `json:"prompt_id"`Operation string `json:"operation"`CanRetry  bool   `json:"can_retry"`
}

10. 提示词编辑流程图

10.1 EditPrompt接口完整调用流程

用户登录 Coze 平台点击"资源库" → 选择提示词 → 点击"…" → "编辑"场景的后端处理流程:

用户点击"编辑" → 前端发起请求 → API网关路由 → Handler处理 → 业务服务层 → 数据持久化层 → 索引更新层 → 响应返回↓                    ↓           ↓          ↓         ↓          ↓            ↓          ↓
前端编辑表单        HTTP PUT请求     路由匹配     参数验证    权限检查     MySQL更新    ES索引更新   JSON响应↓                    ↓           ↓          ↓         ↓          ↓            ↓          ↓
/edit-prompt        /api/plugin_api/  Handler    请求绑定   用户身份    prompt_      事件发布     编辑结果edit_prompt       函数调用   参数校验   Session    resource     异步处理     状态返回EditPrompt          验证       表更新       ES更新       ↓PromptApplicationService↓权限验证(创建者/协作者检查)↓编辑锁检查↓内容验证↓编辑频率限制检查↓数据库更新事务↓编辑事件发布↓返回编辑结果

11. 核心技术特点

11.1 提示词编辑的分层架构设计

清晰的职责分离

  • API层(prompt_handler.go):负责提示词编辑请求处理、参数验证、响应格式化
  • 应用层(prompt_service.go):负责提示词编辑业务逻辑编排、权限验证、事务管理
  • 领域层(prompt_domain.go):负责提示词编辑核心业务逻辑、内容验证、安全检查
  • 基础设施层(prompt_repository.go):负责提示词数据更新、外部服务同步

11.2 提示词数据存储和索引技术

MySQL存储设计

  • 表结构prompt_resource 表专门存储提示词数据
  • 索引优化:针对 space_idcreator_idname 建立复合索引
  • 事务支持:确保提示词编辑的ACID特性
  • 版本控制:通过 version 字段实现乐观锁机制

ElasticSearch索引设计

  • 索引名称coze_prompt_resource
  • 字段映射:针对提示词内容进行全文搜索优化
  • 实时同步:通过事件机制实现数据库到ES的实时同步
  • 索引更新:编辑提示词时同步更新ES索引数据

11.3 提示词编辑安全机制

多层次编辑验证

  • 权限验证:确保用户有编辑指定提示词的权限
  • 编辑锁检查:防止并发编辑冲突
  • 内容验证:验证编辑内容的格式和安全性

11.4 提示词事件驱动架构

事件类型定义

type PromptEventType stringconst (PromptCreated PromptEventType = "prompt_created"  // 提示词创建事件PromptUpdated PromptEventType = "prompt_updated"  // 提示词更新事件PromptDeleted PromptEventType = "prompt_deleted"  // 提示词删除事件
)

11.5 提示词编辑权限控制机制

多层次权限验证

  • 身份认证:JWT Token验证用户身份
  • 所有权验证:验证用户是否为提示词的创建者或协作者
  • 工作空间权限:验证用户在指定工作空间的编辑权限
  • 编辑锁机制:防止并发编辑冲突

11.6 提示词编辑性能优化策略

数据库性能优化

  • 乐观锁机制:通过版本号防止编辑冲突
  • 索引优化:为常用查询字段建立合适的索引
  • 事务优化:合理使用事务确保编辑操作的原子性

缓存优化策略

  • Redis缓存:缓存提示词基本信息和权限数据
  • 编辑锁缓存:使用Redis实现分布式编辑锁
  • 缓存一致性:确保编辑操作后缓存数据的一致性

12. 总结

12.1 提示词编辑功能的架构优势

Coze提示词编辑功能采用了现代化的分层架构设计,具有以下显著优势:

1. 高可扩展性

  • 分层架构设计使得提示词编辑各层职责清晰,便于独立扩展和维护
  • 基于接口的依赖倒置设计支持不同存储引擎的灵活切换
  • 事件驱动架构支持提示词编辑相关业务的异步处理,提高系统吞吐量

2. 高可用性

  • 乐观锁机制提供编辑冲突检测和解决能力
  • 异步事件处理确保提示词编辑主流程的稳定性
  • 完善的错误处理和重试机制保证编辑操作的最终一致性

3. 高性能

  • 编辑锁机制避免了不必要的数据库锁竞争
  • 缓存策略提升编辑操作的响应速度
  • 异步索引更新机制减少编辑操作对系统性能的影响

4. 高安全性

  • 多层次的编辑权限验证机制(身份认证 + 所有权验证 + 协作者权限)
  • 编辑锁检查防止并发编辑冲突
  • 操作审计和日志记录确保编辑操作的可追溯性

12.2 提示词编辑功能的技术亮点

1. 智能化的编辑冲突处理

  • 基于Redis的分布式编辑锁机制
  • 乐观锁版本控制防止数据覆盖
  • 实时编辑状态同步和冲突检测

2. 灵活的权限控制体系

  • 创建者和协作者的分级权限管理
  • 工作空间级别的权限隔离
  • 细粒度的编辑权限控制

3. 事件驱动的数据同步

  • 基于提示词编辑事件实现数据库到ES的实时同步
  • 保证了编辑操作的最终一致性
  • 支持事件重放和数据恢复机制

4. 完善的编辑安全机制

  • 内容格式验证和安全检查
  • 编辑频率限制防止滥用
  • 敏感内容过滤和合规性检查

12.3 提示词编辑系统的扩展性和可维护性

扩展性设计

  • 编辑策略扩展:支持多种编辑模式(在线编辑、批量编辑、模板编辑)
  • 功能扩展:基于接口设计支持新的编辑功能快速接入
  • 业务扩展:事件驱动架构支持新的编辑业务场景的灵活集成

可维护性保障

  • 代码结构清晰:分层架构和领域驱动设计提高编辑逻辑的可读性
  • 测试覆盖完善:单元测试和集成测试保证编辑功能的质量
  • 监控体系完备:全链路追踪和编辑操作监控便于问题定位

通过以上的架构设计和技术实现,Coze提示词编辑功能为用户提供了高效、安全、可靠的提示词编辑管理服务,为AI应用开发中的提示词生命周期管理提供了强有力的基础设施支撑。该系统不仅满足了当前的编辑业务需求,还具备了良好的扩展性和可维护性,能够适应未来编辑策略和协作机制的发展需要。

编辑功能的核心价值

  • 协作效率:多用户协作编辑机制提升团队工作效率
  • 操作便捷:直观的编辑界面和流畅的编辑体验
  • 系统稳定:异步处理和事件驱动确保编辑操作不影响系统稳定性
  • 数据安全:完整的权限控制和操作审计,保障数据安全
  • 可追溯性:完整的编辑历史和版本管理,便于问题排查和内容恢复
http://www.xdnf.cn/news/20303.html

相关文章:

  • 苹果TF签名全称TestFlight签名,需要怎么做才可以上架呢?
  • 如何选择靠谱的软文推广平台?这份行业TOP5清单请查收~
  • AGENTS.md: AI编码代理的开放标准
  • RL【3】:Bellman Optimality Equation
  • 支付DDD建模
  • [光学原理与应用-409]:设计 - 深紫外皮秒脉冲激光器 - 元件 - 窗口镜设计:高透射率、抗损伤与精密调控的终极方案
  • 容器镜像全生命周期管理:从Artifactory制品库搭建到构建节点高效运维
  • Go语言实现以太坊Web3开发
  • 【LeetCode 热题 100】1. 两数之和——(解法二)哈希表
  • 使用tensorRT8部署yolov8/11目标检测模型(1)
  • 无密码登录与设备信任:ABP + WebAuthn/FIDO2
  • IPD模式下跨部门团队管理
  • 力扣152:乘积最大子数组
  • 智慧养老综合实训室建设方案:依托教育革新提升养老人才科技应用能力
  • nestjs 缓存配置及防抖拦截器
  • C# 阿里云 OSS 图片上传步骤及浏览器查看方法
  • 深入解析汇编语言的奥秘
  • 文件不展示Eslint的报错红色
  • 前端三件套+springboot后端连通尝试
  • 系统学习算法 专题十八 队列+宽搜
  • Doris 数据仓库例子
  • OpenCV C++ 色彩空间详解:转换、应用与 LUT 技术
  • 一文详解深度学习中神经网络的各层结构与功能!
  • SQL-DML
  • 计算机网络4 第四章 网络层——网络间的通信问题(省际之间如何规划信件运输路线)
  • 酒店实习生转正信息调整编程实现(Python字典应用基础题)
  • 【yolo】YOLOv8 训练模型参数与多机环境差异总结
  • Kafka面试精讲 Day 8:日志清理与数据保留策略
  • Grafana 导入仪表盘失败:从日志排查到解决 max\_allowed\_packet 问题
  • 汽车软件研发智能化:AI在CI/CD中的实践