输出通道
AICR 把 agent 的职责(代码推理)与自身的职责(报告格式、校验、路由和渲染)分离。 所有正式评审结果都通过 AICR 工具产出,绝不通过 agent 的自由文本 stdout。同一个 problem 可以干净地渲染为 VCS 行内评论、issue 条目或 IM 摘要卡片。
自动批次恢复
Section titled “自动批次恢复”自动提交批次保存分析产物和逐渠道回执。恢复跳过分析与已确认发送,每次远端报告写入都在 发送前持久化稳定操作 ID。GitHub/Gitea 的 issue、review 发布器及 GitLab MR 发布器查询 正文中的隐藏标记,确认响应丢失的写入;managed issue 状态更新和删除查询原资源。
飞书应用在首次尝试后最多 59 分钟内复用稳定 UUID。飞书/企业微信 webhook 无法查询不确定 发送,不会自动重发。标记缺失或歧义、查询被拒、UUID 过期均保留未知状态。查询最多 20 页、 每页 100 项,截止时间 30 秒。远端发布与本地持久化不在同一事务,不保证 exactly-once。
沿用既有重试预算和一次终态失败恢复。管理端批次 API 的 publications、
publicationOperations 提供写入和对账次数。人工 Retry 保留远端日志,修改配置不能清空
不确定发送。日志导致检查点超过 1 MiB 时停止发布并保留最后持久状态。重启恢复需使用
SQLite 或 Redis。旧检查点无法还原从未保存的操作 ID;升级前应停止旧写入进程。
进程内工具注册表向评审执行器暴露以下 AICR 工具:
| 工具 | 用途 | 必填字段 |
|---|---|---|
aicr.report_problem |
报告一个锚定到变更行的可操作 problem | file、line、severity、category、message |
aicr.publish_summary |
发布结构化 Markdown 评审摘要 | markdown |
aicr.skip |
标记评审被有意跳过 | reason |
aicr.fetch_more_context |
请求变更文件或窄范围相关文件的源码上下文 | path、reason |
aicr.try_blame |
请求 VCS 校验的、尽力而为的行归属(不含文件内容) | path、reason |
aicr.fetch_more_context 和 aicr.try_blame 是只读上下文工具。编排器会通过配置的
VCS 适配器回放它们,并用获取到的内容/归属跑一次最终 follow-up。
自由文本 stdout 不是报告
Agent 适配器运行绝不能把自然语言 stdout 当作 IM 摘要发布。如果 agent 无法产出
结构化输出,AICR 触发结构化修复 pass;若仍失败,回退到直接 LLM 调用。说明“没有可操作
问题”或“没有可评审代码”的散文会被归一化为 aicr.skip,而不是作为兜底消息发布。
Problem schema
Section titled “Problem schema”IM 报告保留完整问题正文、建议和代码引用,仅在发送消息超过平台字节上限时裁剪并注明, 原生提醒和报告链接保留。详见 IM 消息限制。
aicr.report_problem 接受最小化、通道无关的形状:
| 字段 | 必填 | 含义 |
|---|---|---|
file |
是 | 受影响文件的仓库相对路径 |
line |
是 | 主锚点的新文件行号(必须是变更行或可评论的 diff 行) |
end_line |
否 | 范围 problem 的结束行(渲染为 file:start-end) |
severity |
是 | info、low、medium、high 或 critical |
category |
是 | 简短 problem 家族,如 correctness、security、api-contract |
message |
是 | 问题分析:哪里错、触发场景、影响 |
suggestion |
否 | 最小可行的修复方向;可包含 fenced diff 补丁 |
fingerprint |
否 | 稳定的去重 key(在支持的通道中以隐藏评论保留) |
aicr.report_problem 不接受 agent 提供的归属信息。需要作者或修订上下文时,agent
调用 aicr.try_blame;AICR 校验请求并把归属回填到 follow-up pass。
Channel 类型
Section titled “Channel 类型”Channel 的 kind 是由输出实现注册表约束的自由字符串(Zod 校验形状;dispatcher
解析 kind)。
| Kind | Problem 输出 | Summary 输出 | 说明 |
|---|---|---|---|
gitea_pr_review |
一条合并的 PR review/评论正文 | PR review / 配置的 summary 发布器 | problem 先缓冲,再作为一条 Markdown 正文 flush;403/422 时退化为一条 issue 评论 |
github_pr_review |
一条合并的 PR review/评论正文 | PR review / 配置的 summary 发布器 | 与 gitea_pr_review 相同的缓冲+flush;403/422 时退化为 issue 评论 |
gitlab_mr_review |
当 baseSha/headSha 可用时发 MR discussion |
MR note / 配置的 summary 发布器 | 行锚点不可用时退化为通用 MR note |
gitea_problem_issue / github_problem_issue / gitlab_problem_issue |
收集后对账 | 创建 / 更新 / 解决托管 problem issue | 这里 fingerprint 稳定性最重要;github_problem_issue 用字符串标签名,resolved_action 支持 none、close 和 mark_resolved(GitHub 无 issue 删除 API);GitLab 上 assignee 必须是项目成员,CE 实际只支持单个 assignee |
gitea_issue / github_issue |
收集后渲染为 issue 评论 | 聚合 issue 评论 | 适用于 push 事件或基于 issue 的分诊 |
feishu_bot |
收集后聚合 | 交互卡片(JSON 2.0 schema) | 见 IM 机器人 |
feishu_app |
收集后聚合 | 通过应用消息 API 发送共享飞书卡片 | 可选来源群目录匹配作者并 @;见 IM 机器人 |
wecom_bot |
收集后聚合 | Markdown 消息 | 见 IM 机器人 |
托管 problem issue 生命周期
Section titled “托管 problem issue 生命周期”gitea_problem_issue、github_problem_issue 和 gitlab_problem_issue 跨评审对账过期的托管 issue。关键行为:
- Fingerprint 稳定性。 每个 problem 带一个
fingerprint。AICR 在每个托管 issue 内的 隐藏aicr:problems标记里跟踪打开的 fingerprint。当之前打开的 fingerprint 消失,该 issue 被移到 Resolved 段(可选关闭)。 - 文件范围解决守卫。 只有当生命周期模型对照当前源码确认修复后,problem 才会被标记为“已解决”。
这通常要求当前评审确实重新分析了包含该 problem 的文件;但一次真正的空评审(例如
lgtm运行)在生命周期分析启用时,会改为验证该 issue 所有仍打开的 fingerprint。未经模型确认时, 由触及无关文件的提交触发的评审——或什么都没发现的评审——不会 把之前报告的每个 problem 都标记为已解决。每个托管 issue 正文嵌入aicr:file=<path>,以便恢复文件归属。 - 最近 issue 上限。 对账只列出仍处于 open 状态的 issue(
state=open),上限由review.problem_issue.max_recent_issues控制(默认 30,范围 1–200,可按 workspace 覆盖)。 最近窗口之外的 fingerprint 不会在该 run 去重或关闭。 - GitHub
resolved_action。 支持none、close和mark_resolved(GitHub 无 issue 删除 API)。Gitea 和 GitLab 额外支持delete(GitLab 上 token 用户必须是项目 owner 或 admin)。 - GitLab assignee。 非项目成员的 assignee 会被静默丢弃,且 CE 忽略复数
assignee_ids字段,因此 AICR 通过assignee_id发送单个 assignee。新增成员要等 GitLab 异步成员授权 传播完成后才可被指派。
issue_mode、resolved_action、assign_committer、owners_file 和严重性标签字段见
输出通道配置。
未指定 trigger 的 channel 使用接收事件的兼容 profile;channel 显式指定的
trigger 优先。GitHub App installation token 按输出 channel 的 trigger 和目标仓库获取。
GitLab MR channel 保留包含子群组的完整项目路径,并使用项目内的 MR iid。
Note Hook 从顶层 merge_request 读取该标识,不能用 note ID 或全局 MR ID 替代。
参见 GitLab discussion API。
某次评审的 line_comments 和 summary 发往哪些 channel 按事件解析,适用哪套路由世代
取决于配置:
- v2
routing.rules[](配置携带路由规则时):规则按triggers、target_kinds和source.repo_ref匹配,带显式priority。channel 选择按事件依次解析为:命中规则的outputs、workspaces.instances.<id>.outputs、workspaces.defaults.outputs、outputs.routes.default。显式[]关闭该输出类型;只有未设置的字段才继承。同一 trigger 不得由两套路由世代同时控制。 - 遗留
outputs.routes(未配置路由规则时):一个default块加上按trigger和target_kind匹配的可选rules。数组顺序中第一个匹配且列表非空的规则生效;空列表回落到 workspace 实例,再到 default;仅line_comments最后回落到第一个*_pr_reviewchannel。
outputs: routes: default: line_comments: [gitea-pr-review] summary: [gitea-pr-review] rules: - match: { trigger: p4-main, target_kind: commit } summary: [feishu-code-review]no_problems.action 决定一次成功但无可操作问题的评审是否通知各 channel
(publish、suppress 或 publish_if_summary)。channel 可以按 channel 或按
workspace 覆盖全局策略。如果所有选中的 summary channel 都抑制零问题结果,run 会被
记为跳过,skipReason="no_problems_suppressed"。该策略只控制可见的通知:
托管 problem issue channel 仍会在每次真正的零问题评审后对账已有指纹,
让经模型确认已修复的 issue 得以关闭(resolved_action: none 可关闭该行为)。