news 2026/9/13 14:44:08

用 OpenCode Agent 实现 GitHub 重复 PR 自动检测:duplicate-pr Agent 实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 OpenCode Agent 实现 GitHub 重复 PR 自动检测:duplicate-pr Agent 实战指南

用 OpenCode Agent 实现 GitHub 重复 PR 自动检测:duplicate-pr Agent 实战指南

【免费下载链接】openworkThe open-source alternative to Claude Cowork (powered by opencode)项目地址: https://gitcode.com/GitHub_Trending/ope/openwork

导读

在协作仓库中,多个贡献者常常针对同一个 issue 或 feature 提交相互重叠的 Pull Request,人工排查既耗时又容易遗漏。本篇文章以 .opencode/agents/duplicate-pr.md 为核心骨架,讲解 openwork 仓库中如何用 OpenCode 的自定义 Agent 实现"PR 打开即自动查重"的流水线:包括 Agent 的 YAML frontmatter 声明、检索策略与输出契约、以及配套的 GitHub Actions 工作流如何把检测结果自动回帖到 PR 评论区。读完本文,你将掌握在任意 OpenCode 项目中声明一个"仅暴露单一工具、专职做一件事"的 primary Agent,并用opencode run --agent把它接入 CI 事件流的完整方法。

一、这个 Agent 要解决的问题:PR 去重

重复 PR 是开源协作中的典型噪音:两个贡献者可能基于同一个 issue 各自实现了同一功能,或者在相近时间段提交了修复同一缺陷的 PR。如果不加识别,维护者会把时间浪费在重复审查、重复跑 CI、重复合并甚至冲突回滚上。

仓库为此在 .opencode/agents/ 目录下维护了一组面向 GitHub 工作流的 primary Agent,与duplicate-pr同级的还有 triage.md(issue 分类打标签)、changelog.md(变更日志)、executor.md(执行编码任务)、orchestrator.md(编排规划)等,形成了一个"CI 事件 → OpenCode Agent → GitHub 交互"的自动化闭环。duplicate-pr专职负责其中一环:在 PR 刚被打开时,基于其标题与描述检索是否已有目标相同或高度相关的开放 PR

二、Agent 声明:YAML frontmatter 详解

duplicate-pr.md 的文件主体是给 LLM 的角色指令,而文件顶部的 YAML frontmatter 则定义了 Agent 的运行模式、可见工具与归属模型:

--- mode: primary hidden: true model: openai/gpt-5.6-luna color: "#E67E22" tools: "*": false "github-pr-search": true ---

各字段的作用与注意点:

字段含义与影响
modeprimaryAgent 可以作为独立执行入口被直接调用(配合opencode run --agent),这与仅能由其他 Agent 通过 Task 工具调用的 subagent 不同。同目录下 orchestrator.md 中提到的executor属于被编排方,而duplicate-pr是独立执行方
hiddentrue该 Agent 不会出现在交互式会话的 Agent 列表中,属于"仅供脚本/CI 调用"的隐藏入口,避免污染用户的日常选择
modelopenai/gpt-5.6-luna固定使用该模型执行任务,保证输出质量与成本可控
color"#E67E22"在 OpenCode UI 中展示的 Agent 标识色(橙色),纯展示用途
tools."*"false默认禁用全部工具,这是最小权限原则的体现:Agent 只能调用下方显式开启的工具,无法读写文件、执行任意命令
tools."github-pr-search"true唯一放行的工具:在 GitHub 上按关键字检索 PR

这种"默认全关、显式放行一个工具"的写法是该 Agent 安全性的核心设计:重复检测任务只需要搜索能力,不需要代码编辑或 Shell 执行权限,因此把攻击面和误操作面都收敛到最小。

提示:github-pr-search这类工具由 OpenCode 的插件机制注册(仓库的 .opencode/opencode.json 中声明了插件与 MCP 服务配置),如果你的环境未安装对应插件,工具将不可用,Agent 会无法完成任务。

三、角色指令与检索策略

frontmatter 之下的正文是 Agent 的核心行为规范,原文的关键指令可以拆解为四条:

1. 明确职责边界。原文声明:"You are a duplicate PR detection agent. When a PR is opened, your job is to search for potentially duplicate or related open PRs."——Agent 只做"检测",不做审查、不评价代码质量、不修改任何东西。

2. 使用专用工具而非通用搜索。原文要求使用github-pr-search工具检索"可能针对同一 issue 或 feature 的 PR"。之所以指定专用工具,是因为它面向 GitHub PR 数据做了语义化封装(按标题/描述相关性召回、过滤掉已关闭 PR 等),比让 LLM 直接调用ghCLI 更稳定、更可控。

3. 自排除当前 PR。原文有一条强约束:"The input will contain a lineCURRENT_PR_NUMBER: NNNN. This is the current PR number, you should not mark that the current PR as a duplicate of itself."——输入中会携带当前 PR 编号,Agent绝不允许把自己标记为自己的重复项。这条看似简单的防呆规则,实际是防止 Agent 在检索结果中看到自己、产生"自我重复"误报的关键。

4. 多轮关键词检索。原文要求:"Search using keywords from the PR title and description. Try multiple searches with different relevant terms."——不能只搜标题里的一个词,而要拆出标题与描述中的功能关键词、模块名、技术名词,尝试多组不同组合,以提高召回率。例如一个标题为 "Fix: add retry to den-db transient read" 的 PR,应分别用den-dbtransient readretry等词多次检索。

四、输出契约:让机器可消费的结果格式

该 Agent 对输出有严格的格式约定,这是它能够被 CI 脚本直接捕获、回帖的关键:

  • 发现潜在重复时:列出候选 PR 的标题与 URL,并简要说明它们为什么可能相关。格式类似:

    Potential duplicates found: - #4521 "Fix: retry on den-db transient read failures" (https://github.com/.../pull/4521) — likely related: same den-db transient read path - #4498 "feat: add read retry for den-db" — likely related: same feature scope
  • 未发现重复时只输出No duplicate PRs found,一个多余的字都不要。原文特别强调:"BUT ONLY SAY 'No duplicate PRs found' (don't say anything else if no dups)"。

  • 整体要求:保持回复简洁、可执行("Keep your response concise and actionable")。

这种"有结果给清单、无结果给固定句"的约定,让下游脚本可以无歧义地判断检测结果,无需解析自由文本。类似的"确定性输出"风格也体现在仓库其他 Agent 中,例如 triage.md 对打标签条件做了逐条布尔化限定("Only add if…"、"Do not add for…"),都是为了把 LLM 输出变成可判定的机器行为。

五、CI 集成:从 Agent 到 PR 评论的完整链路

Agent 定义本身只是"大脑",真正让它跑起来的是 .github/workflows/opencode-agents.yml 中的duplicate-prsjob。这条工作流把 GitHub 事件、OpenCode CLI 与 PR 评论串成一条自动化链路,核心步骤如下:

1. 准备环境。检出仓库(fetch-depth: 1),安装 Node 24,然后从 constants.json 中读取仓库锁定的 opencode 版本并安装:

- name: Install opencode run: | version="$(node -e "const fs=require('fs'); const parsed=JSON.parse(fs.readFileSync('constants.json','utf8')); process.stdout.write(String(parsed.opencodeVersion||'').trim().replace(/^v/,''));")" curl -fsSL https://opencode.ai/install | bash -s -- --version "$version" --no-modify-path

constants.json读版本号而非写死,保证 CI 中运行的 opencode 与仓库开发环境锁定的版本一致。

2. 组装 Prompt。gh pr view拉取 PR 的标题与描述,连同CURRENT_PR_NUMBER: $PR_NUMBER一起写入pr_info.txt。这一步精确对应了 Agent 指令中"输入包含CURRENT_PR_NUMBER: NNNN一行"的约定:

{ echo "Check for duplicate PRs related to this new PR:" echo "" echo "CURRENT_PR_NUMBER: $PR_NUMBER" echo "" echo "Title: $(gh pr view \"$PR_NUMBER\" --json title --jq .title)" echo "" echo "Description:" gh pr view "$PR_NUMBER" --json body --jq .body } > pr_info.txt

3. 调用 Agent 并回帖。使用opencode run --agent duplicate-pr以 headless 方式执行 Agent,把输出包装成评论正文(并显式声明"以下评论由 LLM 生成,可能不准确"),再用gh pr comment回帖到 PR 上:

opencode run --agent duplicate-pr "$(cat pr_info.txt)" > /tmp/comment_output.txt { echo "_The following comment was made by an LLM, it may be inaccurate:_" echo "" cat /tmp/comment_output.txt } > /tmp/comment_body.txt gh pr comment "$PR_NUMBER" --body-file /tmp/comment_body.txt

工作流权限声明为pull-requests: write(以及 issue 分支的issues: write),这是回帖所需的最小权限。两个分支共用同一个工作流,通过workflow_dispatchtarget输入(issue/pull_request)和number输入选择执行triage-issue还是duplicate-prsjob。

六、为什么这样设计:从仓库实践看可靠性保障

结合仓库中的其他 Agent 与工作流,可以归纳出这套重复 PR 检测方案背后的几条工程原则,它们正是值得在自建 Agent 时复用的经验:

  • 单工具最小权限tools."*": false+ 只开github-pr-search,让一个 Agent 只拥有一把钥匙。对比 triage.md 只开github-triage,可见该仓库对所有 GitHub 交互类 Agent 都采用了同一安全范式。
  • 确定性输出协议:固定输出格式(候选清单或No duplicate PRs found)保证脚本可解析、结果可断言,这也是 headless/CI 场景下使用 LLM Agent 的前提。
  • 输入自排除:通过CURRENT_PR_NUMBER显式阻止自我误报,属于"提示词层面的防呆"。
  • 人类兜底:CI 在 LLM 输出前加上 "The following comment was made by an LLM, it may be inaccurate:" 的免责声明,提醒维护者把检测结果当线索而非结论。这与仓库对 fork PR 的人工审查清单 review-a-contributor-pr/SKILL.md(逐项核查 DCO、ee/CLA、Warden 检查等)形成互补:自动化负责"先筛一遍",人类负责"最终把关"。

七、本地复现与扩展思路

如果你想在本地亲自验证这条链路(不需要触发 CI),可以按以下步骤复现:

# 1. 确保 opencode 已安装且配置了 OPENAI_API_KEY 与 GITHUB_TOKEN # 2. 手工构造与 CI 相同格式的输入 cat > /tmp/pr_info.txt <<'EOF' Check for duplicate PRs related to this new PR: CURRENT_PR_NUMBER: 9999 Title: Fix den-db transient read retry Description: Adds retry logic for transient read failures in den-db. EOF # 3. 以 headless 方式运行 duplicate-pr Agent opencode run --agent duplicate-pr "$(cat /tmp/pr_info.txt)"

在此基础上可以按需扩展:

  • workflow_dispatch换成pull_request/pull_request_target触发器,实现"PR 打开即自动查重"(注意 fork PR 的 token 权限与密钥暴露问题,仓库在 review-a-contributor-pr/SKILL.md 中对此有专门讨论);
  • 在 Agent 指令中增加"优先报告 open(未合并/未关闭)PR"的过滤规则,进一步提高信噪比;
  • 让 Agent 在发现重复时额外建议"可以关联到哪个 issue",帮助维护者一键关闭重复 PR。

结语

duplicate-pr是一个教科书级的最小化 Agent 示例:用 10 余行 frontmatter + 一段行为指令,加上一条 30 余行的 CI job,就为仓库建立了一道自动化的 PR 去重防线。它的设计思路——单工具权限、确定性输出、输入自排除、人类兜底——可以直接迁移到任何基于 OpenCode 的协作工作流中。如果你想深入了解该仓库 Agent 体系的完整面貌,可以继续阅读 .opencode/agents/ 下的其他 Agent 定义、.opencode/skills/ 下的技能清单,以及 .github/workflows/opencode-agents.yml 的完整工作流实现。

【免费下载链接】openworkThe open-source alternative to Claude Cowork (powered by opencode)项目地址: https://gitcode.com/GitHub_Trending/ope/openwork

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 14:42:01

情感识别模型部署实战:解决CUDA、ONNX与推理引擎兼容性问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 14:40:18

MATLAB泽尼克多项式波前分析与像差拟合实现

简介&#xff1a;这是一份基于泽尼克多项式的光学波前相差模拟数据包&#xff0c;面向从事光学设计、像差分析的研究者&#xff0c;以及需要借助MATLAB进行光学仿真的学生。包内提供前32项泽尼克多项式&#xff0c;覆盖从理想零像差到复杂高阶像差的完整序列。每个多项式通过(m…

作者头像 李华
网站建设 2026/9/13 14:39:15

石蒜科生物碱合成中P450酶的作用与机制研究

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 14:37:27

iOS设备指纹SDK稳定性唯一性测评实战:从采集维度到卸载重装验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 14:36:49

SpringBoot+Vue网上书店管理系统:从搭建到答辩的完整实战指南

简介&#xff1a;这是一个基于SpringBoot和Vue实现的网上在线书店管理系统源码与数据库项目&#xff0c;主要面向Java期末大作业、课程设计以及需要完整前后端分离项目的学习者。系统覆盖图书展示、购物车、订单管理等核心业务模块&#xff0c;后端由SpringBoot提供接口&#x…

作者头像 李华
网站建设 2026/9/13 14:35:12

Qt打包工具对比与依赖部署实战:从windeployqt到Inno Setup

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华