跳转到内容

AI 任务系统

AI 任务系统是 OpenPR 将工作分配给 AI 编码代理的机制。它弥合了人类在项目跟踪器中创建 Issue 与 AI 代理自主编写代码解决问题之间的差距。

该系统有四个组件:

  1. API — 创建任务、管理状态、接收代理的回调
  2. Worker — 后台进程,轮询待处理任务并通过 Webhook 派发
  3. Webhook — 向代理端点发送带任务详情的 HTTP POST
  4. 代理 — 执行任务并回报结果的 AI 编码工具(Codex、Claude Code、OpenCode)
Issue 分配给机器人
|
v
API 创建 ai_task(状态:pending)
|
v
Worker 领取任务(状态:processing)
|
v
Worker 通过 Webhook POST 派发
|
v
代理执行(编写代码、运行测试)
|
v
代理调用 API 回调
|
v
任务标记为 completed 或 failed
pending --> processing --> completed
^ |
| v
+------- failed(如有剩余重试次数,回到 pending)
状态含义
pending任务已入队,等待 Worker 领取
processingWorker 已认领任务并派发给代理
completed代理报告成功完成
failed代理报告失败或所有重试次数已用完
cancelled任务被手动取消

每个任务有可配置的 max_attempts(默认:3)。当派发失败或代理报告失败时:

  1. 如果 attempts < max_attempts,任务回到 pending 状态并设置 next_retry_at 时间戳
  2. 重试退避为线性:attempts * 30 秒,上限 600 秒(10 分钟)
  3. 如果所有尝试都已用完,任务转为 failed 并触发 ai.task_failed Webhook 事件

每次状态转换都记录在 ai_task_events 表中,包含带时间戳的事件类型和载荷:

事件类型触发时机
created任务初始创建
picked_upWorker 认领任务进行处理
progress代理报告中间进度
completed代理报告成功完成
retried任务在失败后回到 pending
failed任务用完所有重试次数

系统支持四种任务类型:

类型说明引用类型
issue_assignedIssue 已分配给机器人进行实现work_item
review_requested请求代码审查或提案审查proposal
comment_requested请求机器人对 Issue 或提案发表评论comment
vote_requested请求机器人对治理提案投票proposal

AI 代理在系统中表示为 entity_type = 'bot' 的用户。它们像其他用户一样注册在 users 表中,但认证方式不同。

机器人令牌使用 opr_ 前缀,具有工作区范围。以 SHA-256 哈希形式存储在 workspace_bots 表中。

Authorization: Bearer opr_0a5bc81ea108dad8077decc880abced0d923aa873b9ff774575ec152aecf15d5

机器人令牌包含:

字段说明
workspace_id令牌所属的工作区
permissions权限字符串数组(readwriteadmin
is_active令牌当前是否有效
expires_at可选的过期时间戳
last_used_at每次 API 调用时自动更新

机器人用户通过 ai_participants 表注册为特定项目的 AI 参与者。每个参与者有:

字段说明
name显示名称(如 “Claude Agent”)
model模型标识(如 “claude-opus-4”)
provider供应商名称(如 “anthropic”)
capabilities描述代理能力的 JSON 对象
max_domain_level自治级别:observeradvisorvotervetoerautonomous
can_veto_human_consensus代理是否可以推翻人类投票
reason_min_length投票理由的最小长度
is_active参与者是否启用

Worker 是一个独立的 Rust 二进制程序,作为后台服务运行。它每 5 秒轮询 ai_tasks 表查找待处理任务。

Worker 使用 PostgreSQL FOR UPDATE SKIP LOCKED 在并发环境中安全地认领任务:

  1. 查询 next_retry_at 为空或已过期的 pending 任务
  2. 原子地将状态更新为 processing 并递增 attempts
  3. 记录 picked_up 事件

任务按 priority DESC, created_at ASC 排序——高优先级任务优先处理,同优先级按创建时间先后顺序。

对于每个认领的任务,Worker:

  1. 查找任务项目中该机器人用户的活跃 Webhook
  2. 构建包含任务详情的派发载荷
  3. 向 Webhook URL 发送 HTTP POST
  4. 如果 POST 失败,记录失败并进行重试或将任务标记为失败

发送给代理的 Webhook POST 请求体包含:

{
"task_id": "uuid",
"project_id": "uuid",
"ai_participant_id": "uuid",
"task_type": "issue_assigned",
"reference_type": "work_item",
"reference_id": "uuid",
"payload": {
"issue_title": "Fix authentication flow",
"issue_description": "The login endpoint returns 500..."
},
"attempts": 1,
"max_attempts": 3
}

Worker 接受 --concurrency 参数(默认:4),控制每个轮询周期领取多少任务。实际批次大小为 concurrency * 10

执行任务后,代理通过 REST API 向 OpenPR 回报结果。

POST /api/projects/:project_id/ai-tasks/:task_id/complete
Authorization: Bearer opr_...
Content-Type: application/json
{
"summary": "Fixed the authentication flow by...",
"files_changed": ["src/auth.rs", "src/middleware.rs"],
"commit_sha": "abc123"
}

请求体存储为任务的 result 字段。任务转为 completed 状态,并触发 ai.task_completed Webhook 事件。

POST /api/projects/:project_id/ai-tasks/:task_id/fail
Authorization: Bearer opr_...
Content-Type: application/json
{
"error_message": "Test suite failed with 3 errors",
"payload": {
"test_output": "..."
}
}

如果任务还有剩余重试次数,它将带退避延迟回到 pending。否则转为 failed 并触发 ai.task_failed Webhook 事件。

POST /api/projects/:project_id/ai-tasks/:task_id/progress
Authorization: Bearer opr_...
Content-Type: application/json
{
"step": "running tests",
"progress_pct": 75
}

进度报告记录为 ai_task_events 中的 progress 事件,但不会改变任务状态。

当 Issue 分配给机器人用户且存在匹配的 bot_user_id Webhook 时,Issue 分配会触发创建 issue_assigned AI 任务。

当提案进入投票阶段时,会自动为项目中所有活跃的 AI 参与者创建 vote_requested 任务。这由 queue_vote_requested_tasks_for_project 处理,遍历活跃的机器人用户并创建幂等任务。

POST /api/projects/:project_id/ai-tasks
Authorization: Bearer <jwt_or_bot_token>
Content-Type: application/json
{
"ai_participant_id": "bot-user-uuid",
"task_type": "issue_assigned",
"reference_type": "work_item",
"reference_id": "issue-uuid",
"priority": 5,
"payload": { "instructions": "..." },
"max_attempts": 3,
"idempotency_key": "unique-key-to-prevent-duplicates"
}

idempotency_key 防止重复创建任务。如果已存在相同键的任务,API 返回 409 Conflict。

操作谁可以执行
创建任务项目管理员/所有者或系统管理员
完成/失败任务被分配的 AI 参与者或系统管理员
报告进度被分配的 AI 参与者或系统管理员
列出任务任何项目成员