大家好,我是十三!欢迎来到十三Tech。

上一篇我们探索了 Agent 的"记忆系统"。但一个强大的 Agent 不仅要能"记住",更要能"做到"——它需要与外部世界交互的能力。今天的主角是 Coze 的 plugin 模块,Agent 的"行动系统"。它给出了一个优雅的答案:以 OpenAPI 3.0 为基石,集成多层次认证与智能执行引擎的通用插件架构,一次性解决标准化、安全性和执行力三大挑战。


1. 插件的"契约":基于 OpenAPI 3.0 的标准化设计

Coze 插件体系全面拥抱 OpenAPI 3.0 规范,并将其作为整个系统的通用语言与核心"契约"。无论是官方插件还是用户自定义工具,本质都是一份 OpenAPI 文档——这种选择为系统带来了无与伦比的标准化和扩展性。

插件的"身份证":PluginManifest

每个插件由 PluginManifest(插件清单)定义,描述了一切元信息:

// api/model/crossdomain/plugin/plugin_manifest.go:32-42
type PluginManifest struct {
	SchemaVersion string `json:"schema_version"`
	NameForModel string `json:"name_for_model"`
	NameForHuman string `json:"name_for_human"`
	DescriptionForModel string `json:"description_for_model"`
	DescriptionForHuman string `json:"description_for_human"`
	// 核心:认证配置
	Auth *AuthV2 `json:"auth"`
	LogoURL string `json:"logo_url"`
	// 核心:API 定义类型
	API APIDesc `json:"api"`
	// 核心:全局参数
	CommonParams map[HTTPParamLocation][]*api.CommonParamSchema `json:"common_params"`
}

关键设计点:

  • 给谁看NameForModel/DescriptionForModel 帮助大模型理解插件功能、决定何时调用;NameForHuman/DescriptionForHuman 展示给用户。
  • 如何认证Auth 字段定义认证类型,下一节详述。
  • 通用参数CommonParams 定义全局参数,例如在每个请求的 Header 中自动加入 User-Agent

工具的"说明书":ToolInfo 与 OpenAPI Operation

插件中每一个可执行的动作(Tool),其"说明书"就是 OpenAPI 中的 Operation 对象:

// api/model/crossdomain/plugin/toolinfo.go:34-47
type ToolInfo struct {
	ID int64
	PluginID int64
	Name string
	Desc string
	SubURL *string
	Method *string
	// 核心:OpenAPI 操作定义
	Operation *Openapi3Operation `json:"operation"`
}

type Openapi3Operation = openapi3.Operation

Operation 字段详细描述了 API 的一切:Parameters(参数位置、类型、是否必需)、RequestBody(请求体结构与媒体类型)、Responses(响应码与响应体)。通过这种方式,Coze 把外部世界五花八门的 API 统一到了 OpenAPI 这门"世界语言"之上。


2. 安全的"守卫":深入多层次认证体系

当 Agent 与外部 API 交互时,安全是头等大事。Coze 在 PluginManifest 中通过 AuthV2 字段,设计了一套覆盖绝大多数 API 认证场景的灵活体系:

AuthV2 三种认证模式:覆盖从公开 API 到用户授权

// api/model/crossdomain/plugin/plugin_manifest.go:44-53
type AuthV2 struct {
	Type AuthType `json:"type"`
	AuthorizationType AuthorizationType `json:"authorization_type"`
	AuthorizationContent map[string]string `json:"authorization_content"`
	CredentialLocation CredentialLocation `json:"credential_location"`
	CustomHeaders map[string]string `json:"custom_headers"`
	CredentialSchema *openapi3.SchemaRef `json:"credential_schema"`
	OAuthProvider *OAuthProviderSchema `json:"oauth_provider"`
}

type AuthType string

const (
	AuthTypeNone AuthType = "none"
	AuthTypeServiceToken AuthType = "service_token" // API Key
	AuthTypeOAuth AuthType = "oauth"
)

Type 字段像一个开关,定义了三种截然不同的认证模式。

模式一:AuthTypeNone - 开放的门户

最简单的模式,适用于无需认证的公开 API(天气、资讯、开放数据源)。type=none 时,Coze 调用 API 不附加任何认证信息。零配置,直接调用第三方。

模式二:AuthTypeServiceToken - API Key 认证

最常见的 API 认证方式(Bearer Token / Service Token)。Coze 的设计非常灵活:

  • AuthorizationType:Key 的类型,通常是 bearerbasic
  • CredentialLocation:Key 的位置,header 还是 query
  • AuthorizationContentmap[string]string,精确指定 Key-Value 模板,例如 {Authorization: "Bearer {{bstudio_api_key}}"}

{{bstudio_api_key}} 是占位符,Coze 在实际请求时将用户为该插件配置的安全凭证动态填充进去。定义(manifest)与凭证(credentials)物理分离,既保证模板通用,又确保敏感信息隔离存储。

模式三:AuthTypeOAuth - 授权的艺术

对于代表用户操作资源的场景(读取用户的 Google Drive、以用户名义发推),OAuth 2.0 授权码模式是事实标准。OAuthProvider 字段定义了完整的第三方配置,Coze 实现了完整流程:

OAuth 2.0 授权码流程:代表用户访问第三方资源

核心步骤:GetOAuthURL 生成授权页 URL → 用户授权 → OAuthCodecodeclient_secretaccess_token + refresh_token → 安全存储 → access_token 过期时用 refresh_token 自动刷新,对用户和上层应用完全透明


3. 智能执行引擎:Tool Calling 的实现艺术

认证机制保证了"谁可以调用",执行引擎则决定了"如何调用"。核心问题是:如何将大模型输出的"意图"(Tool Calling 参数),精确转换为可执行的 HTTP 请求?

答案在 ExecuteTool 这一核心领域服务中——它是连接 AI "思维"与现实世界"动作"的桥梁。

ExecuteTool 五步流水线:从 LLM 意图到 HTTP 请求

// domain/plugin/service/exec_tool.go:25-40
func (p *pluginService) ExecuteTool(ctx context.Context, req *entity.ExecuteToolRequest) (*entity.ExecuteToolResponse, error) {
	// 1. 构建工具执行器 - 获取正确的插件和工具版本
	toolExecutor, err := p.buildToolExecutor(ctx, req)
	if err != nil {
		return nil, err
	}

	// 2. 预处理参数 - 将 LLM 的 JSON 参数转换为结构化对象
	arguments, err := p.preprocessArgumentsInJson(ctx, toolExecutor.Tool.Operation, req.Arguments)
	if err != nil {
		return nil, err
	}

	// 3. 构建 HTTP 请求 - 将参数映射到具体的 HTTP 请求
	httpReq, err := p.buildHTTPRequest(ctx, toolExecutor, arguments)
	if err != nil {
		return nil, err
	}

	// 4. 注入认证信息 - 根据插件的认证配置添加凭证
	if err := p.injectAuthInfo(ctx, httpReq, toolExecutor); err != nil {
		return nil, err
	}

	// 5. 执行 HTTP 请求并返回结果
	return p.executeHTTPRequest(ctx, httpReq)
}

关键步骤拆解

第一步 buildToolExecutor 按场景选择版本:根据 Scene 字段智能选择——SceneDraft 用草稿版(调试)、SceneOnline 用线上版(生产)。开发者可安全测试新功能,不影响线上用户。

第二步 preprocessArgumentsInJson 解析验证 LLM 参数:把 JSON 字符串映射到 OpenAPI Operation 定义的结构。不仅做 JSON 解析,还包括类型验证(确保值符合 Schema)、必填校验(required: true)、默认值填充。

// domain/plugin/service/exec_tool.go:85-120
func (p *pluginService) preprocessArgumentsInJson(ctx context.Context, operation *openapi3.Operation, argumentsJson string) (map[string]interface{}, error) {
	var arguments map[string]interface{}
	if err := json.Unmarshal([]byte(argumentsJson), &arguments); err != nil {
		return nil, fmt.Errorf("invalid arguments JSON: %w", err)
	}

	for _, param := range operation.Parameters {
		paramName := param.Value.Name
		if value, exists := arguments[paramName]; exists {
			if err := p.validateAndConvertParam(param.Value, value); err != nil {
				return nil, fmt.Errorf("parameter %s validation failed: %w", paramName, err)
			}
		} else if param.Value.Required {
			return nil, fmt.Errorf("required parameter %s is missing", paramName)
		}
	}

	return arguments, nil
}

第三步 buildHTTPRequest 精确映射:这是最复杂的一步。通过标准化的参数位置描述(in: pathin: queryin: header),Coze 能机械而精确地把任意参数放置到 HTTP 请求的正确位置——路径参数替换 URL 占位符、查询参数拼到 query string、请求体序列化为 JSON、Header 参数设到请求头。

第四步 injectAuthInfo 安全注入凭证:读取 AuthV2 配置,按类型(None 跳过、ServiceToken 读 API Key、OAuth 读 access_token)将凭证注入到请求的正确位置。占位符 {{bstudio_api_key}} 在此处被替换为真实凭证。配置与实现分离——插件作者只声明"认证应该如何被使用",凭证获取与注入由 Coze 统一处理。

此外,每一步的执行结果都会被详细记录(参数解析错误位置、HTTP 请求详情、第三方响应、认证失败类型),为调试和运维提供强支持。


4. 草稿与线上的双版本哲学

与 memory 模块类似,插件体系同样采用"草稿"(Draft)与"线上"(Online)双版本设计。这不是简单的版本管理,而是对安全部署持续迭代的深层思考。

实体层面的双版本设计

// domain/plugin/entity/plugin.go:15-25
type PluginInfo struct {
	ID int64 `json:"id"`
	CreatorID int64 `json:"creator_id"`
	Name string `json:"name"`
	Description string `json:"description"`
	Version PluginVersion `json:"version"` // Draft 或 Online
	Status PluginStatus `json:"status"`
	Manifest *PluginManifest `json:"manifest"`
	// 版本关联
	DraftID *int64 `json:"draft_id,omitempty"`
	OnlineID *int64 `json:"online_id,omitempty"`
	Tools []*ToolInfo `json:"tools,omitempty"`
}

type PluginVersion string

const (
	PluginVersionDraft PluginVersion = "draft"
	PluginVersionOnline PluginVersion = "online"
)

每个插件物理上存在两份独立记录:草稿版(version="draft",开发测试预览)和线上版(version="online",生产稳定运行)。DraftIDOnlineID 建立双向关联,形成"影子版本"架构模式。

发布流程的原子化同步

插件发布流程:草稿到线上的原子化同步

// application/plugin/plugin.go:150-180
func (p *PluginApplicationService) PublishPlugin(ctx context.Context, req *plugin.PublishPluginRequest) (*plugin.PublishPluginResponse, error) {
	// 1. 获取草稿版本插件
	draftPlugin, err := p.pluginService.GetPluginByID(ctx, req.DraftPluginID)
	if err != nil {
		return nil, fmt.Errorf("draft plugin not found: %w", err)
	}

	if draftPlugin.Version != entity.PluginVersionDraft {
		return nil, fmt.Errorf("plugin %d is not a draft version", req.DraftPluginID)
	}

	// 2. 检查是否已有线上版本
	if draftPlugin.OnlineID != nil {
		// 更新现有线上版本
		return p.updateOnlinePlugin(ctx, draftPlugin)
	} else {
		// 创建新的线上版本
		return p.createOnlinePlugin(ctx, draftPlugin)
	}
}

PublishPlugin 的核心逻辑简洁清晰:先 GetPluginByID 取得草稿插件,然后检查 OnlineID 字段——已存在走 updateOnlinePlugin 分支(复制草稿配置到线上),不存在走 createOnlinePlugin 分支(创建新线上记录、回填 OnlineID 到草稿、同步工具定义)。整个流程在事务中,原子化——要么完全成功要么完全回滚。 DraftIDOnlineID 的双向指针让版本追溯变得简单。

场景驱动的版本选择策略

回到 §3 的 buildToolExecutor,版本选择逻辑因此清晰:

  • 开发者体验:Coze Studio 插件编辑器测试时自动用草稿版
  • 用户体验:Agent 在实际对话中调用工具始终用稳定线上版
  • 灰度发布:可让特定用户先体验草稿版,验证无误后全量发布

这为 CI/CD 提供了天然支持。


5. 架构层次的优雅流转

完整的 Tool Calling 请求遵循本系列第一篇解析过的 DDD + 整洁架构分层:接口层api)做 HTTP 适配与转换,应用层application)编排用例、协调权限检查与日志记录、不含核心业务逻辑,领域层domain)承载纯粹的执行逻辑(版本选择、参数验证、请求构建、认证注入),基础设施层infra)处理所有"脏活累活"——数据库查询、HTTP 客户端、缓存连接池、第三方集成,并实现领域层定义的所有接口,但绝不向上"泄露"技术细节。

每一层只依赖接口而非实现,整个系统耦合度降到最低、可测试性达到最高。无论插件体系如何复杂化、认证方式如何扩展、第三方服务如何增加,核心业务逻辑始终保持清晰稳定


总结

Coze 插件体系展现了三个层面的架构艺术:通过 OpenAPI 3.0 实现标准化,把千变万化的外部 API 统一到一门"世界语言"之上;通过 AuthV2 实现多层次安全保障,配置与实现分离既灵活又安全;通过草稿/线上双版本与场景驱动选择实现安全迭代,让 CI/CD 天然落地。这些设计思想不仅适用于 AI Agent 平台,对任何需要集成第三方 API 的系统都具有重要参考价值。

正如《整洁架构》所言:"好的架构让系统易于理解、易于开发、易于维护、易于部署。" Coze 的插件架构,正是这一理念的完美诠释。


关于十三Tech

资深服务端研发工程师,AI 编程实践者。 专注分享真实的技术实践经验,相信 AI 是程序员的最佳搭档。 希望能和大家一起写出更优雅的代码!

联系方式569893882@qq.com GitHub@TriTechAI VX:TriTechAI(备注:十三 Tech)