研发需求排期引擎
> 版本 1.2.0 · 服务地址 https://flyingfish.cloud/sched/schedule
能力说明
把一份需求清单(多个需求 × 各职能工时)和一支人力队伍,算成一份可直接执行的排期计划。
典型使用场景:
- 手上有 30-50 个需求要抢同一批美术/客户端/服务端人力,想知道现有队伍能不能在交付墙内做完
- 想看清哪个岗位是瓶颈、哪个人的空闲期异常长、哪些需求卡在关键路径上
- 需要在动工前拿到可解释的排期依据,而不是凭经验拍一个时间点
本服务为计算服务:调用一次,返回一份完整的排期结果。无状态、不留存数据、不产生副作用(不写文件、不改配置、不触发外部动作)。
⚠️ 调用前必做:入口确认(四步闸门)
本服务不会替你做工艺判断。 在发起调用前,你必须先与用户完成以下四步确认。
跳过任何一步都会导致排期结果失真,且服务端不会自动纠正。
第 1 步:识别流程类型
先向用户确认这是哪一类流程:
| 流程类型 | config.template_id |
说明 |
|---|---|---|
| 游戏研发 | game_dev_standard |
含 UX / 白模 / 视觉 / 客户端 / 服务端 / 还原 / 联调 + 测试段 |
| 其他 | 按服务商公布的模板名 | 若无对应模板,需在 config 中显式描述工序衔接 |
> 识别不出类型时必须停下来问用户。不要用默认值硬排。
第 2 步:核对职能名称
把用户口中的岗位名,逐一映射到本服务的 func 取值(见下方取值表)。
名称不一致时必须列给用户确认,不要自行猜测映射关系。
第 3 步:确认依赖关系
默认工艺顺序是服务端的缺省假设,不是用户团队的实际工艺。
必须把关键衔接点(谁等谁)列给用户确认。用户说"不一样"时,用 pred 显式声明。
第 4 步:确认测试段
测试段是每个需求的固定工序(qa_case → qa_func → qa_integr),默认为链式前置。
必须询问用户:测试段是否纳入本次排期?小需求如何压缩(建议 qa_case 用 0 工时 + is_milestone)?
> 硬红线:以上四步中任何一步拿不到用户的明确回答,都不得发起调用。
> 宁可停下来问,也不要交付一份基于错误假设的排期结果。
调用方法
向下列地址发起 HTTP POST 请求,请求体为 JSON:
POST https://flyingfish.cloud/sched/schedule
Content-Type: application/json
> 服务地址:https://flyingfish.cloud/sched/schedule(以商品详情页公布为准)。
> 数据传输说明(最小必要原则):调用时发送的项目名称、需求清单、职能与人员标识(如 UX1 / C1)、工时与可用性配置,均为完成排期计算所必需——排期算法必须在本地数据上求解资源冲突。除此之外不再传输任何信息。
>
> 建议调用方在提交前对人员标识做符号化处理(使用岗位代号而非真实姓名),并避免在需求名称中携带未公开的商业信息。本服务为无状态计算服务:不留存、不落库、不用于训练,响应返回后即释放。
请求格式
请求体分为 action 与 payload 两层:
{
"action": "schedule",
"payload": {
"meta": { ... },
"people": [ ... ],
"requirements": [ ... ],
"config": { ... }
}
}
返回格式
{
"ok": true,
"data": { ... }
}
失败时:
{
"ok": false,
"error": { "code": "ERROR_CODE", "message": "可读的错误说明" }
}
按量付费(Payment-Needed / 402)
本服务按次计费。首次调用(未携带付费凭证)会收到:
HTTP/1.1 402 Payment Required
Payment-Needed: <报价凭证,Base64URL>
响应体内含本次报价,含 out_trade_no(订单号)、amount(金额)、currency、goods_name,以及商家签名。按 Payment-Needed 凭证完成支付后,携带 Payment-Proof 请求头重放同一请求即可得到结果:
POST https://flyingfish.cloud/sched/schedule
Content-Type: application/json
Payment-Proof: <支付完成后获得的凭证>
Payment-Proof 通过校验后,响应返回 200 并附带 Payment-Validation 头,响应体为:
{
"resource_id": "/schedule",
"content": { "ok": true, "data": { ... } },
"trade_no": "…",
"out_trade_no": "…",
"already_fulfilled": false,
"fulfillment_confirmed": true
}
> 同一 Payment-Proof 重复提交不会重复扣费(服务端按 out_trade_no 幂等处理,already_fulfilled 会置为 true)。
> ⚠️ 资金安全护栏(调用方必须遵守)
>
> 本服务的付费流程必须经用户显式确认后方可执行。调用方 Agent 在收到 402 报价后,不得自行完成支付,须先向用户展示:
>
> - 扣费金额 amount 与币种 currency
> - 收款方(商品名 goods_name)
> - 本次调用用途(一次排期计算)
>
> 用户明确同意后,方可按 A2M(Agent-to-Merchant)协议获取支付凭证并重放请求;用户不同意则终止调用。
>
> 额度上限:本服务为按次计费,每次调用金额固定为商品详情页公示单价(当前 ¥0.01),服务端不提供可变报价、不含阶梯与累计扣费。单次授权仅对应当前这一次调用,不可跨次复用;调用方应自行对累计支出设置上限。
>
> 未获用户授权的支付行为,由调用方 Agent 及其部署方承担全部责任。
输入字段说明
meta — 项目基本信息
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
project |
string | 是 | 项目名称,用于输出标题 |
wall_days |
number | 是 | 交付墙(硬节点,单位:天)。服务据此判断排期是否可行 |
start_date |
string | 否 | ISO 日期(如 2026-10-01),用于把天数映射为真实日期;不填则输出相对天数 |
time_unit |
string | 否 | day(默认)或 half_day |
title |
string | 否 | 覆盖默认输出标题 |
people[] — 人力池
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 人员唯一标识,被 segments[].person 引用 |
name |
string | 否 | 显示名,不填则用 id |
role |
string | 否 | 职能标签 |
availability |
array | 否 | 不可用区间,如 {"from": 5, "to": 8, "reason": "休假"} 表示第 5 天到第 8 天不可排 |
> ⚠️ 强烈建议填写 availability。不填资源日历的排期结果在真实项目中往往不可执行。
availability 使用半开区间 [from, to):{"from": 5, "to": 8} 表示第 5、6、7 天不可用。
requirements[] — 需求清单
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 需求唯一标识 |
name |
string | 是 | 需求名称 |
priority |
string | 是 | high / medium / low,作为排期主排序依据 |
segments |
array | 是 | 该需求的职能段列表。空数组表示纯里程碑需求(0 工时) |
deadline |
number | 否 | 该需求单独的交付节点(天) |
segments[] — 职能段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
func |
string | 是 | 职能类型,见下方取值表 |
person |
string | 是 | 引用 people[].id |
duration |
number | 是 | 工时(单位与 meta.time_unit 一致)。> 0 才会被排入 |
pred |
array | 否 | 显式前置:同需求内其他 func 名数组。不填则按默认工艺顺序处理 |
is_milestone |
bool | 否 | true 表示 0 工时闸门(如评审节点),只作为依赖锚点,不占用人力 |
func 标准取值:
| 取值 | 中文 | 说明 |
|---|---|---|
ux |
UX / 交互 | 制作的公共入口 |
whitemodel |
白模 | |
visual |
视觉 | |
client |
客户端 | |
server |
服务端 | 与客户端并行推进 |
restore |
还原 | |
integrate |
联调 |
细分职能(需指定 L2 模板):
以下职能属于「测试段」,必须同时在 config.template_id 指定 game_dev_standard 才可用;
不指定模板时服务端只识别上表 7 个基础职能,传细分名会被拒绝(这是为避免"排了个假流程"而设的硬校验)。
| 取值 | 中文 | 说明 |
|---|---|---|
qa_case |
测试用例 | 用例编写,通常在开发结束前完成 |
qa_func |
功能测试 | 依赖用例完成 |
qa_integr |
集成回归 | 依赖功能测试完成 |
> 测试段是每个需求的固定工序:qa_case → qa_func → qa_integr 依次串接(默认依赖为链式前置)。
> 小型需求可通过「qa_case 的 duration 填 0 + is_milestone: true」压缩测试前置,而非删除测试段。
>
> 其他自定义职能名:需在 config 中描述其衔接关系,并确保团队工序可被显式表达。
config — 工艺与约束参数
| 参数 | 默认 | 说明 |
|---|---|---|
template_id |
无 | 工艺模板。指定后启用该行业模板的职能集与依赖规则。游戏研发用 game_dev_standard(启用测试段细分职能)。不指定则只用 7 个基础职能 |
phantom_duration.restore |
0.5 |
还原段的标准工时 |
phantom_duration.integrate |
1.0 |
联调段的标准工时 |
ux_gate |
true |
有 UX 段时,是否要求其完成后再开始后续制作 |
whitemodel_gate_client |
true |
客户端是否需等待白模完成 |
restore_gate_visual |
true |
还原是否需等待视觉完成 |
integrate_gate_client_server |
true |
联调是否需等待前后端均完成 |
idle_gap_threshold |
2 |
人力连续空闲告警阈值(天) |
> 以上开关按团队实际工艺设置。若你的团队工序衔接与默认不同,调整这些开关即可适配。
输出字段说明
meta — 排期概要
| 字段 | 说明 |
|---|---|
project |
项目名 |
makespan |
实际排期总时长 |
wall_days |
输入的交付墙 |
feasible |
是否能在交付墙内完成(true / false) |
generated_at |
生成时间戳 |
schedule — 排期明细
按人视角 schedule.people[]:
| 字段 | 说明 |
|---|---|
id / name / role |
人员标识 |
tasks[] |
该人的任务列表,每项含 req / func / start / end / priority |
utilization |
该人利用率(0–1) |
按需求视角 schedule.requirements[]:
| 字段 | 说明 |
|---|---|
id / name / priority |
需求标识 |
segments[] |
各职能段的 start / end |
finish |
该需求完成时间 |
critical_path — 关键路径(CPM 浮时)
基于实际排程结果计算的活动总浮时。total_float ≈ 0 的活动构成关键链,其延误将直接推后整体交付。
| 字段 | 说明 |
|---|---|
method |
计算方法说明 |
makespan |
项目总工期 |
critical_count |
关键活动数量 |
chain[] |
关键链上的活动序列,每项含 op_id / req_id / func / person / start / finish / dur |
total_float |
对象映射:op_id → 总浮时(天),覆盖全部已排入活动 |
> 浮时 = 该活动在不影响总工期的前提下可延后的天数。浮时为 0 ⇒ 一天都不能拖。
self_check — 自检结果
| 字段 | 说明 |
|---|---|
passed |
排期是否通过自检 |
violations[] |
违反约束的项 |
idle_gaps[] |
人力连续空闲片段 |
overload[] |
人力过载项 |
dependency_reverse[] |
依赖倒置项 |
warnings[] |
提示性告警 |
decisions — 决策依据
| 字段 | 说明 |
|---|---|
makespan |
总工期 |
unplaced[] |
未能排入的需求(资源不足) |
resource_queue |
按人汇总的任务排队情况 |
sacrifice[] |
牺牲事件流水:低优需求被高优插队/截断的记录 |
cycles[] |
依赖环检测结果 |
wall_breach |
交期越界核算,见下 |
bottlenecks[] |
瓶颈资源排行,见下 |
decisions.wall_breach — 交期越界
| 字段 | 说明 |
|---|---|
project |
项目级:deadline / makespan / breach_days / breached |
requirement_breaches[] |
需求级:每项 req_id / finish / deadline / breach_days / breached / unplaced |
breached_count / total_requirements |
越界需求数 / 总需求数 |
decisions.bottlenecks[] — 瓶颈资源排行
| 字段 | 说明 |
|---|---|
rank |
瓶颈排名 |
person / funcs[] |
资源标识与其承担职能 |
op_count / busy_days / span_days |
任务数 / 占用天数 / 跨度天数 |
utilization |
利用率(占用 / 跨度) |
critical_ops / req_count |
压关键链的任务数 / 涉及需求数 |
> 排序规则:优先看是否压着关键链,其次看占用总时长与利用率。
完整调用示例
{
"action": "schedule",
"payload": {
"meta": {
"project": "示例版本",
"wall_days": 30,
"start_date": "2026-10-01"
},
"people": [
{ "id": "U1", "name": "交互-小李", "role": "ux" },
{ "id": "Q1", "name": "白模-小王", "role": "whitemodel" },
{ "id": "W1", "name": "视觉-小张", "role": "visual",
"availability": [{"from": 10, "to": 12, "reason": "休假"}] },
{ "id": "C1", "name": "客户端-小赵", "role": "client" },
{ "id": "S1", "name": "服务端-小钱", "role": "server" }
],
"requirements": [
{
"id": "R001",
"name": "登录流程优化",
"priority": "high",
"segments": [
{ "func": "ux", "person": "U1", "duration": 2 },
{ "func": "whitemodel","person": "Q1", "duration": 3 },
{ "func": "visual", "person": "W1", "duration": 2 },
{ "func": "client", "person": "C1", "duration": 5 },
{ "func": "server", "person": "S1", "duration": 4 },
{ "func": "restore", "person": "Q1", "duration": 0.5 },
{ "func": "integrate", "person": "C1", "duration": 1.0 }
]
},
{
"id": "R002",
"name": "背包整理功能",
"priority": "medium",
"segments": [
{ "func": "ux", "person": "U1", "duration": 1 },
{ "func": "client", "person": "C1", "duration": 3 },
{ "func": "server", "person": "S1", "duration": 2 },
{ "func": "integrate", "person": "C1", "duration": 1.0 }
]
}
],
"config": {
"ux_gate": true,
"whitemodel_gate_client": true,
"idle_gap_threshold": 2
}
}
}
使用建议
关于输入准备
- 工时单位请全表统一(都用「天」或都用「半天」),避免混用导致结果偏差
priority会显著影响排期顺序,建议按真实业务价值排序,不要全填high- 尽量填写
availability,这是让排期结果接近真实执行的关键输入
关于结果解读
- 先看
meta.feasible:为false时说明交付墙内做不完,看decisions.wall_breach了解超出多少 - 看
decisions.bottlenecks:这是最需要补人或调整工序的岗位 - 看
self_check.idle_gaps:某岗位大片空闲,通常意味着上游没供上或人力配置不均 - 看
critical_path.activities中total_float = 0的活动:这些一旦延误,交付直接受损
关于适用边界
本服务输出的是基于给定输入的排期方案与冲突识别结果,是决策支持而非决策本身。真实项目中的工艺顺序、人员技能差异、外部依赖等,请结合团队实际情况判断。
常见问题
Q:支持多少条需求?
取决于复杂度,常规团队版本量级(数十条需求、十余人)可在数秒内返回。
Q:可以处理自定义职能吗?
可以。func 支持自定义名称,配套在 config 中描述其衔接关系即可。
Q:会保存我的输入数据吗?
不会。服务为无状态计算,调用返回后不保留输入内容。
Q:输入有误时怎么排查?
返回体的 error.code 与 error.message 会指明问题字段。常见错误:缺少必填字段、person 引用了不存在的人员 id。
Q:收到 402 是报错吗?
不是。402 是本服务的正常计费响应,表示需要先完成本次调用付费。按 Payment-Needed 凭证支付后,带上 Payment-Proof 重放请求即可拿到结果。
Q:需要在我这边配置密钥吗?
不需要。服务不要求在本地存放任何密钥;计费与授权全部通过按次付费凭证完成。