本篇是"动手"导向。从零跑通 Bot、从零搭工作流、从零写插件、新加一个工作流节点四个完整流程,所有步骤基于源码确认。
主文档:01 - 原理与使用 系列前篇:02 - 会话与执行 · 03 - 工程化与扩展 · 04 - 生态对比与排错
目录
1. 实战 1:从零创建一个 Bot
1.1 启动并注册账号
# 启动完整 Docker 栈
make web
# 等待镜像拉起后访问
http://localhost:8888/sign
注册接口在 idl/passport/passport.thrift:
| 操作 | 端点 | 必填字段 |
|---|---|---|
| 注册 | POST /api/passport/web/email/register/v2/ | email、password |
| 登录 | POST /api/passport/web/email/login/ | email、password |
| 当前账户 | POST /api/passport/account/info/v2/ | (cookie) |
1.2 配置模型(必做,否则 Bot 不能用)
模板位于 backend/conf/model/template/,含 20+ 个 YAML 模板:
model_template_ark.yaml # 火山方舟(豆包)
model_template_openai.yaml # OpenAI
model_template_claude.yaml # Anthropic Claude
model_template_gemini.yaml # Google Gemini
model_template_qwen.yaml # 通义千问
model_template_deepseek.yaml # DeepSeek
model_template_ollama.yaml # 本地 Ollama
...
步骤
- 选一个模板,复制到
backend/conf/model/(去掉 template_) - 填写关键字段(以 Ark 为例):
id: 60001 # 自己分配的唯一 ID
name: doubao-1-5-pro-32k # 展示名
meta:
protocol: ark # 协议(ark/openai/claude/gemini/qwen/deepseek/ollama)
capability:
function_call: true # 是否支持工具调用
input_tokens: 32768
max_tokens: 4096
conn_config:
base_url: https://ark.cn-beijing.volces.com/api/v3/
api_key: ${ARK_API_KEY} # 从环境变量读
model: ep-20240xxxxxxx # 端点 ID
temperature: 0.7
default_parameters:
- { name: temperature, type: float, min: "0", max: "1" }
- { name: max_tokens, type: int, min: "1", max: "4096" }
- 重启 coze-server(
docker compose restart coze-server或make server) - 浏览器访问
http://localhost:8888/admin/#model-management,新模型应已显示
1.3 创建 Bot
UI 路径:工作空间 → 创建 → "智能体"
接口(IDL 在 idl/app/intelligence.thrift、idl/app/project.thrift):
POST /api/intelligence_api/draft_project/create
{
"space_id": 7xxx,
"name": "My First Bot",
"description": "我的第一个 Bot",
"icon_uri": "default_icon/agent_default.jpeg"
}
响应里的 project_id 就是 Bot ID。
1.4 Bot 编辑器五大区域
每个区域对应一个或多个前端包:
| 区域 | 配置内容 | 前端包 |
|---|---|---|
| Persona | 人设、风格 | agent-ide/space-bot/ |
| Prompt | 系统提示词 | agent-ide/prompt/ + prompt-adapter |
| Tools | 挂插件、工作流 | agent-ide/tool/、agent-ide/tool-config/ |
| Knowledge | 挂知识库 | data/knowledge-data-set-for-agent/ |
| Variables | 全局变量 | agent-ide/bot-config-area/ 内的 dialogue-config-view |
1.5 调试
右侧"预览与调试"面板,组件:BotDebugChatArea,在 agent-ide/chat-debug-area/。
1.6 发布到 OpenAPI
- Bot 编辑器右上角"发布",选择 API Connector
- 进入"API Token"页面,创建一个 PAT(
pat_xxx,只显示一次) - 调用:
curl -N -X POST http://localhost:8888/v3/chat \
-H "Authorization: Bearer pat_xxx" \
-H "Content-Type: application/json" \
-d '{
"bot_id": "7xxxxx",
"user_id": "test_user_001",
"stream": true,
"additional_messages": [
{ "role": "user", "type": "question", "content": "你好" }
]
}'
-N 关键:让 curl 不缓冲,SSE 才能实时显示。
2. 实战 2:从零搭一个工作流
2.1 创建
接口在 backend/api/handler/coze/workflow_service.go:
| 操作 | 端点 |
|---|---|
| 创建 | POST /api/workflow_api/create |
| 保存 | POST /api/workflow_api/save |
| 获取画布 | POST /api/workflow_api/canvas |
| 测试运行 | POST /api/workflow_api/test_run |
| 中断后恢复 | POST /api/workflow_api/test_resume |
UI:工作空间 → 资源 → 工作流 → 创建。
2.2 最简工作流:Entry → LLM → Exit
Entry 节点
- 类型:
NodeTypeEntry(ID=1) - 配置:声明输入字段(如
question: string)
LLM 节点
- 类型:
NodeTypeLLM(ID=3) - 关键配置:
- 选模型(从 1.2 配的列表里挑)
- 系统 Prompt 模板,引用上游变量
- 用户 Prompt:
{{question}}(直接用 Entry 输出的字段) - 输出格式:Text / Markdown / JSON
Exit 节点
- 类型:
NodeTypeExit(ID=2) - 配置:声明输出字段(如
answer),引用 LLM 节点输出
2.3 变量引用语法
源码:backend/domain/workflow/entity/vo/canvas.go
两种引用方式共存:
方式 1:结构化 ref(画布 JSON 中)
{
"type": "ref",
"value": {
"content": {
"blockID": "100001", // 上游节点 ID
"name": "answer", // 上游输出字段名
"source": "block-output"
}
}
}
方式 2:模板渲染(字符串字段中)
请基于以下问题作答:{{question}}_{{user_info.name}}
{{xxx}} 由运行时引擎替换为节点入参对应值。
2.4 测试运行
POST /api/workflow_api/test_run
{
"workflow_id": "7xxxxx",
"input": {
"question": "什么是 RAG?"
}
}
响应是 SSE 流,前端按节点逐个渲染状态。
2.5 工作流挂为 Bot 的工具
- 工作流编辑器 → 发布(同 Bot)
- 进 Bot 编辑器,Tools 区域 → 添加工作流
- LLM 在对话中自动决定何时调用此工作流(走 Function Call)
技术细节:工作流被包装成 Eino BaseTool,作为 LLM 节点的工具集传入 ReAct Agent。代码:backend/domain/workflow/internal/compose/workflow_tool.go
3. 实战 3:开发一个自定义插件
3.1 参考官方模板
backend/conf/plugin/pluginproduct/ 有 18 个示例:
| 插件 | 用途 |
|---|---|
| bocha_search.yaml | 博查全网搜索 |
| gaode_map.yaml | 高德地图(地点、导航) |
| lark_*.yaml(8 个) | 飞书全家桶(表格/日历/文档/消息/Wiki…) |
| library_search.yaml | 文库检索 |
| image_compression.yaml | 图片压缩 |
| sky_eye_check.yaml | 天眼查企业信息 |
| plugin_meta.yaml | 总注册表(所有官方插件的入口) |
3.2 Manifest + OpenAPI 完整字段
- plugin_id: 100 # 自分配 ID
version: v1.0.0
manifest:
schema_version: v1
name_for_model: weather_query # LLM 可见名(英文,LLM 通过此匹配)
name_for_human: 天气查询 # 用户可见名
description_for_model: 输入城市名,返回该城市当天天气
auth:
type: service_http # none / service_http / oauth
key: Authorization
sub_type: token/api_key
payload: '{"key":"Authorization","service_token":"","location":"Header"}'
logo_url: my_plugin_icon/weather.png
api:
type: openapi
common_params:
header:
- { name: User-Agent, value: Coze/1.0 }
tools:
- tool_id: 10001
method: get
sub_url: /weather
3.3 OpenAPI Operation(描述每个 tool)
OpenAPI 3.0 标准片段(可单独成 yaml,也可内嵌):
paths:
/weather:
get:
operationId: getWeather
parameters:
- name: city
in: query
required: true
schema: { type: string }
description: 城市名,如"北京"
responses:
"200":
description: 天气信息
content:
application/json:
schema:
type: object
properties:
temp: { type: number }
desc: { type: string }
3.4 三种导入方式(选一)
实现:backend/domain/plugin/internal/openapi/convert_protocol.go
| 方式 | 函数 | 用法 |
|---|---|---|
| OpenAPI 3.0 直接导入 | ToOpenapi3Doc | 最规范 |
| Swagger 2.0 | SwaggerToOpenapi3Doc | 自动转 3.0 |
| cURL 命令 | CurlToOpenapi3Doc | 把 curl 粘进去自动反推 |
| Postman 集合 | PostmanToOpenapi3Doc | 把 Postman 导出 JSON 粘进去 |
底层用开源库 getkin/kin-openapi。
3.5 OAuth 配置(需要时)
OAuth schema 模板:backend/conf/plugin/common/oauth_schema.json
支持 4 种鉴权模式:
| AuthzType | AuthzSubType | 说明 |
|---|---|---|
| none | - | 无 |
| api_key | - | API Key(在 header/query/body) |
| basic_auth | - | HTTP Basic |
| oauth | authorization_code | 标准三段式 OAuth |
| oauth | client_credentials | 服务端凭证 |
授权码模式所需字段:client_id、client_secret、authorization_url、token_url、scope、client_url。
3.6 在 UI 中创建/调试
接口在 idl/plugin/plugin_develop.thrift:
| 操作 | 端点 |
|---|---|
| 注册插件 | POST /api/plugin_api/register |
| 注册元数据 | POST /api/plugin_api/register_plugin_meta |
| 创建 API(tool) | POST /api/plugin_api/create_api |
| 调试 API | POST /api/plugin_api/debug_api |
| 发布插件 | POST /api/plugin_api/publish_plugin |
UI:工作空间 → 资源 → 插件 → 创建插件 → 选导入方式 → 填鉴权 → 添加 tool → 调试 → 发布。
3.7 在 Bot 中使用
Bot 编辑器 → Tools → 添加插件 → 选刚发布的 → 保存。
LLM 会在对话中按需调用,Function Call 输出的参数自动按 OpenAPI 映射到 path/query/header/body。
4. 实战 4:二次开发——新增一个工作流节点
需求示例:加一个 RegexExtract 节点(用正则从字符串中提取)。
4.1 后端改动
Step 1:注册 NodeType
文件:backend/domain/workflow/entity/node_meta.go
const (
NodeTypeEntry NodeType = "Entry"
// ...
NodeTypeRegexExtract NodeType = "RegexExtract" // 👈 新增
)
var NodeTypeMetas = map[NodeType]*NodeTypeMeta{
// ...
NodeTypeRegexExtract: {
ID: 50,
Key: NodeTypeRegexExtract,
Name: "正则提取",
Category: "utilities",
SupportBatch: false,
ExecutableMeta: ExecutableMeta{
IsComposite: false,
PreFillZero: true,
PostFillNil: true,
IncrementalOutput: false,
},
},
}
Step 2:实现节点
新文件:backend/domain/workflow/internal/nodes/regexextract/regex_extract.go
package regexextract
import (
"context"
"regexp"
"coze-studio/backend/domain/workflow/entity"
"coze-studio/backend/domain/workflow/entity/vo"
"coze-studio/backend/domain/workflow/internal/schema"
)
// Config: 节点的"设计期"配置(画布 → 后端 schema)
type Config struct {
Pattern string // 正则表达式
}
// Adapt: 把前端画布 Node 转成后端 NodeSchema
func (c *Config) Adapt(ctx context.Context, n *vo.Node, others ...any) (*schema.NodeSchema, error) {
return &schema.NodeSchema{
Key: vo.NodeKey(n.ID),
Type: entity.NodeTypeRegexExtract,
Name: n.Data.Meta.Title,
Configs: c,
}, nil
}
// Build: 在执行期把 NodeSchema 实例化为可运行对象
func (c *Config) Build(ctx context.Context, ns *schema.NodeSchema, others ...any) (any, error) {
re, err := regexp.Compile(c.Pattern)
if err != nil {
return nil, err
}
return &RegexExtract{re: re}, nil
}
// 运行期对象
type RegexExtract struct {
re *regexp.Regexp
}
// Invoke: 节点真正执行的代码
func (r *RegexExtract) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
text, _ := input["text"].(string)
matches := r.re.FindStringSubmatch(text)
return map[string]any{
"matched": len(matches) > 0,
"groups": matches,
}, nil
}
Step 3:挂注册表
文件:backend/domain/workflow/internal/canvas/adaptor/to_schema.go 的 init()
func init() {
nodes.RegisterNodeAdaptor(entity.NodeTypeLLM, func() nodes.NodeAdaptor {
return &llm.Config{}
})
// ...
nodes.RegisterNodeAdaptor(entity.NodeTypeRegexExtract, func() nodes.NodeAdaptor {
return ®exextract.Config{}
})
}
4.2 前端改动
Step 1:NodeType 枚举
文件:frontend/packages/workflow/base/src/types/node-type.ts
export enum StandardNodeType {
Start = '1',
End = '2',
LLM = '3',
// ...
RegexExtract = '50', // 👈 与后端 ID 对齐
}
Step 2:节点元数据 + 表单
新目录:frontend/packages/workflow/playground/src/node-registries/regex-extract/
regex-extract/
├── index.ts # 注册入口
├── meta.ts # 节点 meta(图标、分类)
├── form-meta.tsx # 表单 schema
└── form.tsx # 表单 React 组件(可选,默认有)
meta.ts 简化样例:
import { type NodeRegistry } from '@flowgram-adapter/free-layout-editor';
import { StandardNodeType } from '@coze-workflow/base';
export const RegexExtractNodeRegistry: NodeRegistry = {
type: StandardNodeType.RegexExtract,
meta: {
label: 'Regex Extract',
icon: '/assets/regex.svg',
description: '正则提取',
category: 'utilities',
},
formMeta: () => import('./form-meta').then(m => m.formMeta),
};
Step 3:加 i18n 文案
文件:frontend/packages/arch/resources/studio-i18n-resource/src/locales/
// zh-CN.json
{ "node_regex_extract": "正则提取", "node_regex_extract_desc": "用正则从字符串中提取" }
// en.json
{ "node_regex_extract": "Regex Extract", "node_regex_extract_desc": "Extract from string by regex" }
Step 4:在节点列表注册
通常在 playground 包的节点注册聚合文件中加一行 RegexExtractNodeRegistry。
4.3 验证
make server重启后端cd frontend/apps/coze-studio && npm run dev重启前端- 新建工作流,左侧节点面板应能看到"正则提取"
- 拖到画布,配置 pattern,连上 Entry/Exit,测试运行
5. 典型场景实现思路
源码里没有现成的场景模板目录。下列是基于源码能力的推荐方案。
5.1 客服机器人
| 组件 | 实现 |
|---|---|
| 知识来源 | 知识库:产品手册 PDF + FAQ Markdown,索引到 Milvus + ES |
| 角色 | Bot Persona + Prompt:"你是某产品客服,语气友好,只回答产品相关问题" |
| 实时数据 | 工作流挂订单查询 Plugin(查 OMS API) |
| 上下文 | 用户 ID 作为 user_id 传入,Memory.Variables 存用户偏好 |
| 多轮 | Conversation 自动维护 Section,默认 SSE 流式 |
| 兜底 | Prompt 加"无法回答时,引导转人工" |
| 发布 | API Connector → 在自家网站接 /v3/chat |
5.2 代码审查助手
| 组件 | 实现 |
|---|---|
| 主链路 | 工作流:Entry(代码片段) → LLM(初步审查) → Code(执行 lint/static analyze) → LLM(综合) → Exit |
| 知识 | 知识库挂"代码规范"文档 |
| 工具 | Plugin:对接 GitHub PR API,可直接评论 |
| 发布 | OpenAPI,在 CI 里 curl 调用 |
5.3 数据分析助手
| 组件 | 实现 |
|---|---|
| 数据源 | Memory.Database:把分析需要的表导入 Coze 内置库 |
| 自然语言查询 | NL2SQL 节点(infra/nl2sql/)→ Database 节点 |
| 可视化 | LLM 节点输出 markdown 表格,前端渲染 |
| 发布 | WebSDK 嵌入数据看板页面 |
关键路径速查
| 主题 | 路径 |
|---|---|
| Passport IDL | idl/passport/passport.thrift |
| Bot/Project IDL | idl/app/intelligence.thrift、idl/app/project.thrift |
| Plugin IDL | idl/plugin/plugin_develop.thrift |
| Workflow Handler | backend/api/handler/coze/workflow_service.go |
| 模型模板 | backend/conf/model/template/ |
| 插件模板 | backend/conf/plugin/pluginproduct/ |
| OAuth Schema | backend/conf/plugin/common/oauth_schema.json |
| OpenAPI 解析 | backend/domain/plugin/internal/openapi/convert_protocol.go |
| NodeType 枚举 | backend/domain/workflow/entity/node_meta.go |
| Node 注册表 | backend/domain/workflow/internal/canvas/adaptor/to_schema.go |
| TextProcessor 实现(参考) | backend/domain/workflow/internal/nodes/textprocessor/ |
| 前端 NodeType | frontend/packages/workflow/base/src/types/node-type.ts |
| 前端节点注册根 | frontend/packages/workflow/playground/src/node-registries/ |
| Workflow as Tool | backend/domain/workflow/internal/compose/workflow_tool.go |