用 build-evidence-map 构建可审计证据图谱:让 GitHub Copilot 的争议性技术决策有据可查
【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot
awesome-copilot 仓库的build-evidence-mapSkill 提供了一套可复用的工程化方法:把一个有争议的技术问题转化为一份机器可验证的"证据图谱"(evidence map)JSON 工件,精确记录支持、反驳、限定与缺失的证据,而不是把分歧揉进一段流畅的散文里。读完本文,你将掌握四类节点与四种边的建模规则、证据分级与源区域判定方法、.doubt.json的完整 schema 与不变量,以及如何使用仓库内置的零依赖验证器对图谱进行失败即关闭(fail-closed)的确定性校验并取得 64 字符收据。
这个 Skill 解决什么问题
在技术评审、研究综合、提案审查或重大决策场景中,最容易出问题的地方不是"我们倾向哪个结论",而是推理链不可见:某条证据到底支撑了什么?哪条证据与结论冲突却被悄悄略过?哪些关键事实我们其实并不知道?
build-evidence-map的核心主张非常明确:不要用一张"图"去装饰一个未经溯源的回答。它要求先把立场(position)、中间命题(claim)、证据(evidence)和未知(unknown)原子化地拆开,再用带注释的有向边表达它们之间的推理关系,最终产出以.doubt.json为后缀的 UTF-8 JSON 文件——一份"可移植的决策工件",任何人都能沿着边追溯每个结论的证据来源。
该 Skill 的定位边界在 SKILL.md 中写得很清楚:对于简单的事实性断言或一般性事实核查,应改用doublecheck之类的验证工作流;只有当证据与中间命题、权衡和缺失事实之间的关系本身才是重点时,才使用本 Skill。也就是说,它的适用对象不是"这个说法对不对",而是"围绕这个决策,哪些证据支持、哪些反对、哪些限定、哪些缺失,以及它们如何影响最终裁决"。
核心模型一:四类节点
整个图谱只允许四种节点类型,这是 map-schema.md 定义并在 contract.mjs 中硬编码的白名单:
| 节点类型 | 语义 | 使用要点 |
|---|---|---|
position | 唯一的当前裁决(verdict) | 全图恰好一个,且必须有至少一条入边支撑 |
claim | 中间命题 | 连接证据与最终裁决的推理步骤 |
evidence | 对某一源区域的忠实陈述 | 必须带sourceId,且必须作为至少一条边的from参与推理 |
unknown | 可能改变裁决的特定缺失事实 | 用于结构化地表达不确定性,而不是"泛泛的还需更多研究" |
从源码结构看,validate.mjs 通过NODE_TYPES集合(position、claim、evidence、unknown)逐节点校验类型,任何图外类型都会被标记为node-type违规;而confidence字段则被明确拒绝(false-precision规则),因为验证器认为"置信度百分比"是虚假的精确性——表达不确定性只能用unknown节点或收窄/限定立场。
核心模型二:四种边
节点之间的推理关系也只有四种,RELATIONS集合同样定义在 contract.mjs。evidence-ladder.md 给出了每类边"何时使用"与"最常见的冒牌货"对照表:
| 关系 | 何时使用 | 常见冒牌货 |
|---|---|---|
supports | 源增强了接受目标的理由 | 主题相似 |
contradicts | 在同一范围与条件下两者不能同时成立 | 日期或人群不同 |
qualifies | 源收窄了目标的范围、强度或适用性 | 隐藏不利证据 |
missing | 某个具体缺失的事实阻碍或可能推翻目标 | 泛泛的"还需更多研究" |
Skill 特别警告两点:主题相似不是支持(topical similarity is not support);范围、日期或人群不同并不自动构成矛盾——这些差异应该用qualifies边表达,而不是粗暴地标成contradicts。每条边还必须附带一句通俗语言注释(plain-language note),说明为什么源节点与目标节点相关。
证据分级:从直接观察到无支撑断言
在动手采集证据之前,evidence-ladder.md 要求优先使用实际可行的最强证据,共六级,由高到低:
- 直接当前观察——可复现的行为、命令输出、检视过的工件或测量结果;
- 权威一手来源——官方规范、数据集、法律、文档、一方仓库或原创研究;
- 独立佐证——底层证据各不相同的可靠来源;
- 显式推断——前提与假设在图谱中可见的结论;
- 弱代理指标——与确切断言不直接吻合的相关指标、基准、轶事或测试;
- 无支撑断言——没有证据支撑的自信、重复或粉饰性语言。
注意一个重要的限定:更高级别的证据仍然可能过时、不相关或相对当前命题过宽——等级只衡量证据强度,不自动等于适用性。
源区域测试:创建证据节点前的五个自问
每条证据都必须锚定到一个有界的具体源区域。创建evidence节点前,evidence-ladder.md 要求回答:
- 我依赖的确切句子、表格、命令输出、页面、章节或行区间是什么?
- 它是否蕴含节点文本,还是仅仅讨论了同一主题?
- 它的日期和版本是否适合该断言?
- 该证据是独立的,还是从另一份被引来源复制而来?
- 什么上下文会反转或收窄当前解释?
如果无法定位到确切区域,规则是:创建unknown节点,而不是证据节点。这一条直接约束了证据质量的下限,也解释了为什么后面会看到验证器对locator与excerpt施加严格的格式约束。
十步工作流
SKILL.md 给出完整工作流,共十步:
第 1 步:框定单一决策。写出一个可证伪的问题和一个暂定立场,不断收窄问题,直到读者能识别图谱在检验哪个行动或信念。
第 2 步:收集有界源区域。优先直接观察与一手来源。为每个源记录:URL 或绝对本地路径、发布者、发布日期、检索日期、章节/页/行/时间戳定位符,以及一小段可核查的摘录。当源质量有争议时,阅读 evidence-ladder.md。
第 3 步:原子化推理。只创建前述四类节点。
第 4 步:为每条边定类型。使用supports、contradicts、qualifies、missing之一,并附通俗语言注释说明源节点为何作用于目标。
第 5 步:保留反证。即使暂定裁决在反证下仍然成立,也不得删除不利证据;范围差异用qualifies边表示。
第 6 步:结构化地表达不确定性。不要编造置信度百分比——添加unknown节点、收窄立场或限定某个命题。
第 7 步:写 UTF-8 JSON。文件使用.doubt.json后缀,遵循 map-schema.md;ID 保持简短、稳定、语义化。
第 8 步:失败即关闭地验证。以本SKILL.md为基准解析scripts/validate.mjs的相对路径,然后用 Node.js 18 或更新版本运行:
node <skill-directory>/scripts/validate.mjs decision.doubt.json验证器只使用 Node.js 内置模块,不需要 npm 或网络访问。修复所有发现项后才能报告成功;只有命令退出码为0且打印出VALID加 64 字符收据时,才能说图谱是有效的。文件哈希、节点计数、JSON 解析成功或人工 schema 检查都不是Doubt 收据。如果确定性验证无法运行,必须报告阻塞而不是虚构成功。
随后,只有在用户已经安装doubt-ai@0.8.0时才能渲染已验证的图谱;不得隐式安装或执行远程包:
doubt map decision.doubt.json --out decision.html第 9 步:仅在明确网络许可下验证源快照。下面的命令会逐一检索记录的 HTTP(S) 源,若摘录无法匹配则失败关闭:
doubt verify decision.doubt.json \ --out decision.verified.doubt.json绝不隐式运行该命令。本地文件验证不走网络。不得手工编写verification对象,也不得掩盖不匹配。
第 10 步:检查交付物。确认问题、裁决、反证、未知项、边注释与精确源区域仍然可读。JSON 是规范的、可编辑的工件;HTML 只是可分享的视图。
.doubt.json规范:完整示例
map-schema.md 给出了规范的 JSON 结构。规范工件是 UTF-8 JSON,实用时使用.doubt.json后缀:
{ "title": "Short artifact title", "question": "One decision-changing question?", "updatedAt": "YYYY-MM-DD", "verdict": "A provisional, evidence-bounded answer.", "nodes": [ { "id": "current-position", "type": "position", "label": "Current position", "text": "The proposition represented by this node." }, { "id": "primary-observation", "type": "evidence", "label": "Observed result", "text": "A faithful statement of the source region.", "sourceId": "source-1" }, { "id": "missing-baseline", "type": "unknown", "label": "Missing baseline", "text": "The exact absent fact and why it matters." } ], "edges": [ { "from": "primary-observation", "to": "current-position", "relation": "supports", "note": "Why the observation increases reason to accept the position." }, { "from": "missing-baseline", "to": "current-position", "relation": "missing", "note": "Why this missing baseline could reverse the position." } ], "sources": [ { "id": "source-1", "title": "Source title", "url": "https://example.com/source", "publisher": "Publisher", "date": "YYYY-MM-DD", "retrievedAt": "YYYY-MM-DD", "locator": "Section: Results, p. 7, § 2.1, L12-L18, or 00:04:31", "excerpt": "A short, checkable excerpt or bounded source-region description." } ] }注意verdict的定位是"暂定的、受证据约束的答案"——图谱的裁决永远不应比证据更宽(见后文质量门禁)。
不变量:验证器强制执行的契约
contract.mjs 中的inspectMapContract实现了完整的契约检查,validate.mjs通过validateMapFile把它包装成命令行工具。逐条对应 schema 的不变量如下:
顶层字段。title、question、verdict、updatedAt必须是非空字符串;updatedAt必须是真实存在的日历日期(YYYY-MM-DD,parseIsoDate会校验月份天数等合法性);nodes必须是非空数组,edges与sources必须是数组(可为空)。
节点约束。每个节点必须有唯一字符串id、合法的type、非空的label与text;confidence字段一旦出现即报false-precision。证据节点必须有sourceId且引用已存在的源;每个证据节点必须至少作为一条边的from参与推理(否则报unused-evidence)。
源约束。每个源必须拥有全部七个非空字段(title、publisher、date、retrievedAt、url、locator、excerpt):
url必须是http(s)://、file://、相对路径或绝对本地路径(sourceLocation正则);locator必须匹配有界定位符模式(contract.mjs),支持如p. 7、§ 2.1、L12-L18、lines 12-18、时间戳00:04:31以及Section: ...形式;excerpt长度必须落在40–500 字符之间,且包含至少 6 个不同的字母数字符号(substantiveExcerpt去重检查),重复填充词会报low-information-excerpt;- 日期链不变量:
source.date不得晚于updatedAt,retrievedAt不得晚于updatedAt,retrievedAt不得早于source.date。
边约束。from/to必须引用已存在的节点,禁止自指;from/to/relation三元组不得重复(duplicate-edge);relation必须属于四类白名单;note必须是非空字符串。
图结构约束。图谱必须恰好一个position节点,且该节点至少有一条入边(unsupported-position);每个非 position 节点必须存在一条有向推理路径通向 position(reaches深度优先遍历,否则报disconnected-node);图中不得存在有向环(三色标记 DFS 检测,报reasoning-cycle);每个源必须被至少一个证据节点引用(unused-source)。
验证器运行原理:收据是怎么算出来的
validate.mjs 的主流程清晰且刻意保持最小化:
validateMapFile(file)读取并JSON.parse文件;解析失败返回带invalid-json发现的失败结果,绝不崩溃后继续;inspectOfflineMap(map)在inspectMapContract基础上,仅当图谱有效时计算收据;receiptFor(map)对每个源取其id、retrievedAt与摘录的 SHA-256,拼进receiptPayload(其契约标记为doubt-evidence-receipt-v1),再对整包做规范序列化(canonicalJson按键排序)后计算整体 SHA-256,得到 64 个十六进制字符的收据。
这就是为什么"JSON 解析成功"不等于"有效图谱":收据覆盖的是源的检索日期与摘录摘要,而不是 URL 当前服务的可变字节——这也是源码里Receipts cover that value and the recorded excerpt, not the mutable bytes currently served by the URL一语的由来。
命令行用法(见 validate.mjs 的帮助文本):
node <skill-dir>/scripts/validate.mjs <map.doubt.json> [--json]- 不带
--json时输出人类可读结果:无效则打印INVALID <n> finding(s)及逐条path [rule] message;有效则打印VALID <receipt>,并附带一行指标:claim 数、evidence 数、source 数、contradiction 数与显式 unknown 数; - 带
--json时输出完整结果对象(含findings、metrics、receipt、valid); - 图谱无效时进程退出码设为
1,便于接入 CI 或脚本门禁。
整个验证器只依赖 Node.js 内置模块(node:crypto、node:fs/promises、node:path、node:url),无需 npm install、无需网络,这正是它适合作为"确定性门禁"嵌入工作流的原因。
可选验证记录:只有命令才能写
verification对象只能由一次成功的显式源验证命令添加,且必须逐字段满足校验(map-schema.md、contract.mjs):
{ "verification": { "status": "verified", "method": "normalized-excerpt-match", "checkedAt": "YYYY-MM-DDTHH:mm:ss.sssZ", "contentSha256": "64 lowercase hexadecimal characters", "excerptSha256": "64 lowercase hexadecimal characters", "finalUrl": "The checked URL or absolute local path", "locatorStatus": "matched" } }约束要点:status必须恰为verified;method必须恰为normalized-excerpt-match;checkedAt必须是带Z的 ISO UTC 时间戳,且其日期部分必须等于该源的retrievedAt;两个 SHA-256 字段必须是 64 位小写十六进制;locatorStatus只能是matched或not-machine-checked;finalUrl必须是合法源位置。
特别提醒:对于页面、章节、时间戳类定位符,locatorStatus允许取not-machine-checked——但这不代表该区域被人工确认过,不要把它当作人工核实完成的证据。
质量门禁:交付前的九项检查
一份完成的图谱必须全部满足 SKILL.md 列出的九条质量门禁:
- 恰好一个
position具有传入推理; - 每个
evidence节点命名一个源并参与某条边; - 每个源都被使用,且具备日期、有界定位符与实质性摘录;
- 每个非 position 节点都有通向 position 的有向路径;
- 推理图无重复边、无有向环;
- 当源集合确实包含反证或限定性证据时,图谱中必须呈现它们;
- 每个可能改变裁决的缺口都是显式的
unknown节点; - 每条边注释都解释了支持、矛盾、限定或缺失;
- 裁决不比证据更宽。
前六条是验证器可机械执行的图结构与溯源约束,后三条是内容质量要求——提醒作者:反证不能因为裁决存活就被删除,不确定性必须落在图谱里,裁决措辞不能超出证据覆盖范围。
交付结果报告
完成验证后,向用户报告 SKILL.md 规定的五项内容:
- 用一句话陈述当前立场;
- 最强的反证或限定是什么;
- 最重要的未解决未知项;
- 规范 JSON 与任何渲染 HTML 的路径;
- 确定性验证与显式源验证是否已经运行。
同时必须遵守一条诚实性红线:绝不把结构上有效的图谱描述为"已被证明为真"。验证只确立了可追溯性与图结构完整性;源质量和推理质量仍然需要人工审查。
在 awesome-copilot 中获取并使用该 Skill
该 Skill 已在仓库的 docs/README.skills.md 中登记,可用 GitHub CLI 安装:
gh skills install github/awesome-copilot build-evidence-map也可以把整个文件夹手动复制到本地 skills 目录。Skill 目录结构如下,全部资源随 Skill 一起分发:
- SKILL.md —— 主指令(工作流、质量门禁、交付要求);
- references/evidence-ladder.md —— 证据分级、源区域测试、边测试;
- references/map-schema.md —— JSON schema 示例与不变量、可选验证记录;
- scripts/contract.mjs —— 契约校验与收据计算的底层实现;
- scripts/validate.mjs —— 零依赖命令行验证器入口。
使用时的最小闭环是:框定问题 → 按 schema 手写(或由 Copilot 辅助生成)decision.doubt.json→ 运行node <skill-dir>/scripts/validate.mjs decision.doubt.json直至输出VALID与收据 → 必要时在明确许可下用doubt verify做源快照核验 → 按五项要求交付报告。整个过程把"结论可信"从依赖模型自信,迁移到了可复核的图结构与源锚点之上。
【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考