关于 eachlabs-workflows
eachlabs-workflows 用于通过 EachLabs API 构建和运行多步 AI 工作流,适合组合模型步骤的开发者。支持并行与条件分支、回退模型、版本管理和批量执行。
主要功能
- 01串联多个模型步骤
- 02并行运行或按分支执行
- 03配置回退模型
- 04管理工作流版本
- 05单次触发最多 10 个输入
适用场景
- 01组合图像、视频、音频和文本步骤
- 02根据模型输出选择处理路径
- 03在流程中调用公共 HTTPS API
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ eachlabs/ skills --skill eachlabs-workflows安装后在 Claude Code 中输入/eachlabs-workflows确认已加载。
附带文件references/WORKFLOW-EXAMPLES.md
详细介绍
EachLabs 工作流
构建、管理和执行由多个模型串联而成的多步骤 AI 流水线。each::workflows 完全免费使用——您只需支付底层模型的费用。
身份验证
Header: Authorization: Bearer <your-api-key>
设置 EACHLABS_API_KEY 环境变量。请前往 eachlabs.ai 获取密钥。也支持 X-API-Key 标头。
基础 URL
https://api.eachlabs.ai
端点
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /v1/workflows | 创建工作流(含其第一个版本) |
| GET | /v1/workflows/{workflowID} | 获取工作流(UUID 或 slug)及其版本 |
| PUT | /v1/workflows/{workflowID}/versions/{versionID} | 创建或更新版本 |
| POST | /v1/workflows/trigger/{workflowID}/{versionID} | 运行一个版本 |
| POST | /v1/workflows/bulk-trigger/{workflowID}/{versionID} | 使用 1-10 个输入运行一个版本 |
| GET | /v1/workflows/{workflowID}/executions | 列出运行记录(使用 ?bulk_id= 筛选批次) |
| GET | /v1/workflows/executions/{executionID} | 获取运行状态和结果 |
何时使用工作流
| 任务需要…… | 工作流可以…… |
|---|---|
| 通过一次调用交付 AI 功能 | 提示词、模型和中间文件都保留在 each::labs 上;应用只需发送输入 |
| 无需发布应用即可进行更改 | 在新版本中编辑提示词或更换模型;调用方使用的 workflow ID 不变 |
| 模型故障时仍能继续运行 | 第一个模型出错时,自动运行 fallback 模型 |
| 组合图像、视频、音频和文本 | 将图像编辑串联到视频模型中,然后调整大小、合并片段或添加音乐 |
| 加快运行速度 | 使用 parallel 并行运行独立步骤(每张照片或每个场景对应一个步骤) |
| 让 AI 决定路径 | 向视觉模型提问,然后通过 choice 步骤进行路由 |
| 使用自己的系统 | 在步骤中调用任意公开 HTTPS API,以获取数据或运行自己的代码 |
只使用一个模型和用户编写的提示词时,直接进行预测会更简单。当提示词已固定、需要回退方案或存在第二个步骤时,再使用工作流。
构建工作流
步骤 1:创建工作流
curl -X POST https://api.eachlabs.ai/v1/workflows \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EACHLABS_API_KEY" \
-d '{
"name": "Text to Image Generator",
"definition": {
"input_schema": {
"properties": {
"prompt": { "type": "string", "required": true }
}
},
"steps": [
{
"id": "write_prompt",
"type": "model",
"model": "eachlabs-llm-router",
"params": {
"model": "google/gemini-3.6-flash",
"messages": [
{ "role": "system", "content": "Rewrite the idea as one vivid, detailed image prompt. Reply with the prompt only." },
{ "role": "user", "content": "$.inputs.prompt" }
]
}
},
{
"id": "generate_image",
"type": "model",
"model": "nano-banana-2-text-to-image",
"params": {
"prompt": "$.write_prompt.primary.choices[0].message.content",
"aspect_ratio": "16:9"
}
}
]
}
}'
响应中包含 workflow_id 和 versions[0].version_id(v1)。如果返回
400 invalid argument,请将相同定义作为
{"definition": {...}} 发送到 PUT /v1/workflows/{workflowID}/versions/v1,以查看具体的验证错误。
步骤 2:触发工作流
curl -X POST https://api.eachlabs.ai/v1/workflows/trigger/{workflowID}/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EACHLABS_API_KEY" \
-d '{
"inputs": {"prompt": "A lighthouse on a cliff at sunset"}
}'
响应:
{"execution_id": "exec-123", "status": "queued"}
步骤 3:轮询结果
curl https://api.eachlabs.ai/v1/workflows/executions/{executionID} \
-H "Authorization: Bearer $EACHLABS_API_KEY"
响应(已缩短):
{
"execution_id": "exec-123",
"status": "completed",
"output": "https://cdn-us.eachlabs.ai/uploads/3334048f.png",
"step_outputs": {
"write_prompt": {"status": "completed", "primary": {"choices": [{"message": {"content": "A dramatic wide-angle photograph of a lighthouse..."}}]}},
"generate_image": {"status": "completed", "primary": "https://cdn-us.eachlabs.ai/uploads/3334048f.png"}
}
}
执行状态:running、completed、failed、cancelled
output 是最后一步的结果。如果版本定义了 output_mapping,workflow_output 会包含具名输出。
编写规则
遵循以下规则,工作流即可一次运行成功:
- 使用
$.路径引用值:$.inputs.<name>、$.<step_id>.primary、$.<step_id>.output、嵌套字段,以及用于列表项的方括号($.step.output[0])。{{inputs.prompt}}不是引用;它会作为字面文本发送给模型。 - 如果参数恰好是一个引用,则保留其类型(URL、数字、列表、对象)。如果引用嵌在更长的字符串中,则会作为文本插入:
"A portrait of $.inputs.name in neon light"。 primary是主要结果:图像和视频模型返回文件 URL,eachlabs-llm-router返回聊天补全内容(文本位于$.step.primary.choices[0].message.content),eachlabs-http-step返回响应(JSON 字段位于$.step.primary.output.<field>)。- 如果类似提示词的参数(
prompt、user_prompt、system_prompt、text、content、message、caption、title、description)恰好是$.step.primary或$.step.output,则该值会以 JSON 编码并用引号括起。请引用更深层的字段,或将引用嵌入句子中。 - 每个步骤(包括分支内的步骤)都需要唯一的
id。步骤按从上到下的顺序运行,且只能引用输入和更早执行的步骤。 - 输入放在
input_schema.properties中,每个输入都要有type、required(true/false)以及可选的default_value。每个可选输入都必须设置default_value:如果某个步骤引用了未提供且没有默认值的输入,运行就会失败。空值会从列表中移除,因此当photo2的默认值为""时,["$.inputs.photo1", "$.inputs.photo2"]可以在只有一张或两张照片的情况下正常工作。 - 模型 slug 和参数会在步骤运行时检查,而非保存时检查。使用
GET https://api.eachlabs.ai/v1/models/{slug}查看模型的输入,并在发布前运行一次工作流。
步骤类型
| 类型 | 用途 |
|---|---|
model | 运行模型:model(slug)、params、可选的 fallback、retry、timeout_seconds |
parallel | 同时运行 branches[].steps |
choice | 评估条件并运行 condition_met_branch 或 default_branch |
pass | 返回固定的 result |
HTTP 请求和 Python 代码不是步骤类型。它们会作为模型步骤运行,分别通过
eachlabs-http-step(下文)和 eachlabs-python-step(私有测试版)执行。
模型步骤
{
"id": "restyle",
"type": "model",
"model": "nano-banana-2-edit",
"params": {
"prompt": "Restyle this photo as $.inputs.style. Keep the person's face unchanged.",
"image_urls": ["$.inputs.photo"],
"aspect_ratio": "9:16"
},
"retry": {"max_attempts": 3, "retry_on": ["server_error"]}
}
HTTP 调用
使用 eachlabs-http-step 模型调用任意公共 HTTPS API。参数:url、method、headers、
query_params、body(用于 POST/PUT/PATCH 的 JSON 对象)、timeout_seconds(建议不超过 30)
和 fail_on_status("non_2xx" 会在收到错误响应时停止运行)。
{
"id": "product",
"type": "model",
"model": "eachlabs-http-step",
"params": {
"url": "https://dummyjson.com/products/$.inputs.product_id",
"method": "GET",
"timeout_seconds": 20,
"fail_on_status": "non_2xx"
}
}
后续步骤可将 JSON 正文读取为 $.product.primary.output.title。将凭据放入 headers
(例如 "Authorization": "Bearer <scoped-token>");只能访问公共 URL。若要运行
自己的代码,请将其部署在 HTTPS 端点后,并向其发送 POST 请求。
并行步骤
{
"id": "prepare",
"type": "parallel",
"branches": [
{"steps": [{"id": "edit_a", "type": "model", "model": "nano-banana-2-edit", "params": {"prompt": "Full-body photo of this person as a traveler in a sunny old-town street.", "image_urls": ["$.inputs.photo_a"]}}]},
{"steps": [{"id": "edit_b", "type": "model", "model": "nano-banana-2-edit", "params": {"prompt": "Full-body photo of this person as a traveler in a sunny old-town street.", "image_urls": ["$.inputs.photo_b"]}}]}
]
}
后续步骤通过分支步骤各自的 id 引用它们:$.edit_a.primary、$.edit_b.primary。一个
分支可以包含多个按顺序运行的步骤。
选择步骤(条件路由)
{
"id": "portrait",
"type": "choice",
"condition": {
"expression": "$.subject.primary.choices[0].message.content",
"operator": "string_matches",
"value": "*PET*"
},
"condition_met_branch": {
"name": "pet",
"steps": [{"id": "pet_portrait", "type": "model", "model": "nano-banana-2-edit", "params": {"prompt": "A royal oil-painting portrait of this animal wearing a small crown.", "image_urls": ["$.inputs.photo"]}}]
},
"default_branch": {
"name": "person",
"steps": [{"id": "person_portrait", "type": "model", "model": "nano-banana-2-edit", "params": {"prompt": "A royal oil-painting portrait of this person wearing a crown. Keep their face unchanged.", "image_urls": ["$.inputs.photo"]}}]
}
}
选择步骤之后,$.portrait.primary 是实际运行分支的结果,selected 保存其名称。
条件运算符:
| 类别 | 运算符 |
|---|---|
| 比较 | equals、not_equals(严格区分类型)、greater_than、less_than、greater_than_or_equal、less_than_or_equal |
| 字符串 | string_equals、string_matches(* 通配符模式;不含 * 时必须完全匹配) |
| 存在性 | exists / is_not_null(字段存在)、is_null / not_exists(字段存在且为 null) |
| 逻辑 | and、or、not |
不支持 in 和 not_in;请将 equals 条件与 or 组合使用。
{"or": [
{"expression": "$.inputs.format", "operator": "equals", "value": "mp4"},
{"expression": "$.inputs.format", "operator": "equals", "value": "webm"}
]}
传递步骤
{"id": "config", "type": "pass", "result": {"style": "cinematic"}}
result 中的 $. 引用不会被解析。后续步骤可将其字段读取为 $.config.style。
参数引用
| 引用 | 值 | 示例 |
|---|---|---|
$.inputs.<name> | 工作流输入 | $.inputs.prompt |
$.<step_id>.primary | 步骤的主要结果 | $.restyle.primary |
$.<step_id>.output | 步骤的完整结果 | $.restyle.output |
$.<step_id>.primary.<field> | 对象结果的字段 | $.product.primary.output.title |
$.<choice_id>.primary | 已运行分支的结果 | $.portrait.primary |
条件在 expression 中使用相同的路径。
回退配置
{
"id": "restyle",
"type": "model",
"model": "nano-banana-2-edit",
"params": {"prompt": "Restyle this photo as $.inputs.style.", "image_urls": ["$.inputs.photo"]},
"fallback": {
"enabled": true,
"model": "gpt-image-v2-edit",
"params": {"prompt": "Restyle this photo as $.inputs.style.", "image_urls": ["$.inputs.photo"]}
}
}
如果主模型失败,则使用其自身的 params 运行回退模型,$.restyle.primary 即为其结果。在本次运行的 step_outputs 中,restyle_fallback.fallback.reason 的值为 primary_failed 或 not_triggered。
版本管理
每个版本都包含完整定义,因此你可以更改工作流,同时让调用方继续使用先前的版本。使用 /v1/workflows/trigger/{workflowID}/{versionID} 触发特定版本。在某个版本上设置 locked: true 可阻止后续更改。
创建/更新版本
curl -X PUT https://api.eachlabs.ai/v1/workflows/{workflowID}/versions/v2 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EACHLABS_API_KEY" \
-d '{
"definition": {
"input_schema": {
"properties": {
"prompt": { "type": "string", "required": true },
"aspect_ratio": { "type": "string", "required": false, "default_value": "16:9" }
}
},
"steps": [
{
"id": "write_prompt",
"type": "model",
"model": "eachlabs-llm-router",
"params": {
"model": "google/gemini-3.6-flash",
"messages": [
{ "role": "system", "content": "Rewrite the idea as one vivid, detailed image prompt. Reply with the prompt only." },
{ "role": "user", "content": "$.inputs.prompt" }
]
}
},
{
"id": "generate_image",
"type": "model",
"model": "nano-banana-2-text-to-image",
"params": {
"prompt": "$.write_prompt.primary.choices[0].message.content",
"aspect_ratio": "$.inputs.aspect_ratio"
}
}
]
},
"output_mapping": { "image": "$.generate_image.primary" }
}'
运行 v2 后,图像会作为 workflow_output.image 返回。省略的字段会保留其已存储的值。
批量触发
在单次 API 调用中处理多个输入(最多 10 个):
curl -X POST https://api.eachlabs.ai/v1/workflows/bulk-trigger/{workflowID}/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EACHLABS_API_KEY" \
-d '{
"inputs": [
{"prompt": "A red bicycle against a white wall"},
{"prompt": "A blue bicycle against a white wall"}
]
}'
响应中包含一个 bulk_id,以及每个输入对应的一个 execution_id。使用 GET /v1/workflows/{workflowID}/executions?bulk_id={bulk_id} 列出该批次。可能会出现部分失败。
Webhook
在触发请求中添加 webhook_url(以及可选的 webhook_secret),即可接收结果,而无需轮询:
curl -X POST https://api.eachlabs.ai/v1/workflows/trigger/{workflowID}/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EACHLABS_API_KEY" \
-d '{
"inputs": {"prompt": "A lighthouse on a cliff at sunset"},
"webhook_url": "https://your-server.com/webhook",
"webhook_secret": "your-secret"
}'
Webhook 请求体的结构与执行响应相同。最多会尝试投递 3 次,每次间隔约 10 秒。设置 webhook_secret 后,每次投递都会携带 X-Webhook-Signature: sha256=<hex>,其中 <hex> 是以密钥为键、对 <X-Webhook-Timestamp>.<raw body> 计算得到的小写十六进制 HMAC-SHA256。请与整个标头值进行比较(包括 sha256= 前缀),并对原始请求字节进行哈希,而不是对重新序列化后的 JSON 进行哈希(验证 Webhook 签名)。
通过 each::sense 构建工作流
你也可以通过 each::sense 工作流端点,使用自然语言构建工作流:
curl -X POST https://eachsense-agent.core.eachlabs.run/workflow \
-H "Content-Type: application/json" \
-H "X-API-Key: $EACHLABS_API_KEY" \
-d '{
"message": "Create a workflow that generates an image and then upscales it",
"stream": true,
"session_id": "my-session"
}'
如需更新现有工作流,请包含 workflow_id 和 version_id。
工作流引用示例
请参阅 references/WORKFLOW-EXAMPLES.md,其中包含八个完整工作流,每个工作流都经过端到端运行:单张照片特效、先重新设计再制作动画、由 LLM 编写的提示词、两张照片配乐、可靠的视觉调用、HTTP API 数据、AI 路由和并行场景。