mcpField
C
council

council

github.com/rheinmirAgent 工作流10233 次安装2 周前更新
代码仓库

关于 council

council 是通过 orca orchestration 运行分阶段 LLM 评议的 Agent 技能,适合需要多方回答和审计记录的复杂问题。它结合匿名互评、主席综合、确定性转录与版本化 HTML 报告。

主要功能

  1. 01三阶段评议流程
  2. 02匿名互评排序
  3. 03确定性汇总与异议呈现
  4. 04JSON 和 Markdown 转录
  5. 05离线版本化 HTML 报告

适用场景

  1. 01用多个模型审视高风险问题
  2. 02隐藏作者身份比较回答
  3. 03留存可审计的排序记录
  4. 04将评议结果发布为 HTML 报告

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rheinmir/setup --skill council

安装后在 Claude Code 中输入/council确认已加载。

详细介绍

Skill: council

🧭 为每个席位选择后端(廉价模型 vs Claude),并行运行多个席位(每个席位一个 worktree——不要在一个文件夹中运行多个 opencode)→ 请参阅 orca-dispatch-reference(唯一事实来源)。

围绕 Andrej Karpathy 的 llm-council (https://github.com/karpathy/llm-council) 三阶段构建的确定性运行框架——Stage 1「First Opinions」、Stage 2「Review」(匿名同行排名)、Stage 3「Final Response」(主席)——接入 orca 编排。

内容

目的与背景
  • 目的: 在 orca 编排上运行 Karpathy 风格的三阶段 LLM 理事会——N 个席位独立作答、匿名交叉评分、主席汇总——并提供确定性 transcript 和强制 HTML report(Stage 4)。
  • 触发条件(何时使用): 面对棘手问题时,如果单个模型的答案风险较高,且你希望由评审团提供答案,并留下“谁给什么排名”的审计记录,同时通过匿名处理消除偏袒自己的倾向。若只需要一个快速答案,直接询问一个模型即可。调用方式:「run a council」、「llm-council」、「panel of models」、「blind peer-rank these answers」、「ensemble + chairman」或 /council。
  • 非目标: 不用于只需一个答案的快速问题;council.py 不调用模型;不负责为席位选择模型(由适配器 harness/council.config.yaml 负责);report 不会在 transcript 之外添加新的评判。
心智模型

分工如下:

  • harness/scripts/council.py 负责确定性协议,绝不调用模型:匿名处理(移除作者信息 → 按稳定的 sha256 顺序映射为 A/B/C)、均值排名聚合、呈现异议、锚点保护(由 seed 驱动,按评审者调整展示顺序——不使用 Math.random),以及 json+md transcript。
  • orca 编排 负责模型生成:每个席位的答案、每位评审者的排名、主席的综合结果。它会像处理其他多 Agent 批次一样进行调度(参见 orca-workflow、orchestration)。
  • harness/council.config.yaml 是唯一适配器(verified: false):指定每个席位使用的模型、评审模型和主席。每个值都是 # ASSUMPTION (not verified)。引擎不会基于这些值分支处理,只会将它们写入 transcript。编辑此文件即可完成理事会配置。

question → Stage 1 answers.json → Stage 2a blind packet(A/B/C + 展示顺序)→ Stage 2b judges.json → Stage 2c transcript(均值排名、异议、chairman_brief)→ Stage 3 chairman_synthesis → Stage 4 版本化 HTML report。

输入和输出约定
字段必需?含义
输入问题是所有席位使用相同的问题;--question 用于在 report 中显示问题
输入harness/council.config.yaml是席位 / 评审者 / 主席(verified: false)
输入roster persona(--case / --profile / --personas)否为 Stage-1 提示词添加额外的视角
输入--seed N否锚点保护的 seed,覆盖 anchor_seed
输出answers.json · judges.json是[{"id","author","text"}] · [{"judge","ranking":[...]}]
输出scratchpad/council-<slug>/council.packet.{json,md} + council.transcript.{json,md}是匿名数据包;共识、获胜者、异议、chairman_brief、chairman_synthesis
输出llmwiki/html/council/council-report-NNN-seed<seed>.html是(必需)版本化 report,不覆盖旧文件;latest.html 指向最新版本
规则与能力
  • RULE-01 (MUST):语言(强制):所有 seat/judge/chairman 都必须使用完整带变音符号的越南语作答;将此句加入每个 Stage-1/Stage-2/Stage-3 提示词。
  • RULE-02 (MUST):运行输出始终位于 scratchpad/council-<slug>/ 下——绝不能直接放在 run/ 或仓库根目录文件夹中。
  • RULE-03 (MUST):采用盲测而非排除机制作为保护措施——评审只能看到 A/B/C 标签,且标签顺序按各自的展示顺序排列。
  • RULE-04 (MUST):名单始终包含至少 1 对立场相反的成员;使用奇数规模(3/5),避免平均排名出现平局。
  • RULE-05 (MUST):始终渲染 Stage-4 HTML;渲染器出错时只发出 WARN,绝不能因此终止 rank 命令或 transcript.{json,md}。
  • RULE-06 (MUST):council.py 绝不调用模型;引擎绝不根据配置值进行分支判断——只将其写入 transcript。
  • 能力:通过编排层(seat/judge/chairman)分发模型生成任务;在本地确定性地计算协议;写入 transcript + HTML 文件;报告不使用网络/CDN。
失败边界
  • council.py selftest 未以 0 退出,或 orca status --json 未显示运行中的 runtime → 阻塞,不运行 council。
  • Seat 的回答未使用变音符号 → 报告也会缺少变音符号(如实渲染)→ 重申 RULE-01 并重新运行该 seat。
  • Judges 缺失 → rank 只会生成盲测数据包,然后停止(部分完成,等待 Stage 2b)。
  • HTML 渲染器出错 → 发出 WARN,transcript 仍会生成(Stage 4 部分完成,重新运行 render)。
  • 名单缺少立场相反的成员 → 在 stderr 发出警告;大小写或 persona 拼写错误 → 提供最接近的建议,不会直接失败。

操作方式

主要工作流
步骤类型输入操作输出/退出状态失败/后续操作
W01确定性repo、runtime前置条件:council.py selftest、orca status --json、配置中包含 seats/judges/chairman满足条件缺失 → 阻塞
W02有副作用问题(+ lens)Stage 1——为每个 seat 分发一个 worker,汇总为 answers.jsonanswers.jsonseat 出错/未使用变音符号 → 重新运行该 seat
W03确定性answers.jsonStage 2a——council.py prepare盲测数据包—
W04有副作用数据包Stage 2b——按展示顺序向 judge 分发盲测回答,汇总为 judges.jsonjudges.json—
W05确定性answers + judgesStage 2c——council.py rank(自动写入 Stage-4 HTML)transcript + 报告渲染出错 → WARN,B02
W06有副作用chairman_briefStage 3——分发给 chairman,将 chairman_synthesis 粘贴到 transcript 中完整 transcript—
W07确定性transcriptStage 4——运行 council.py render <transcript.json>,生成包含 synthesis 的报告新的版本化报告出错 → WARN,transcript 保持不变

各步骤的详细说明(W01–W07 的事实依据):

前置条件
  • python3 harness/scripts/council.py selftest 以 0 退出(引擎运行正常)。
  • orca status --json 显示有 runtime 正在运行;已启用编排。
  • 在 harness/council.config.yaml 中设置了 Seats/judges/chairman。
协议(将各阶段映射到 orca 分发任务)
Stage 1——首轮意见(由编排生成)

在 council.config.yaml 中为每个 seat 分发一个 worker,向所有 worker 提出相同的问题。

语言(强制):所有 seat/judge/chairman 都必须使用完整带变音符号的越南语 作答(拼写正确,包含全部声调符号和抑扬符号)。绝对不要使用不带变音符号的越南语 (ASCII)。council.py 会如实渲染输入文本 (ensure_ascii=False,不进行规范化)——如果 seat 的回答缺少变音符号,报告 也会缺少变音符号。将此句加入每个 Stage-1/Stage-2/Stage-3 提示词。

orca orchestration task-create --spec "Answer: <question>" --json
orca orchestration dispatch --task <task_id> --to <seat_handle> --inject --json
orca orchestration check --wait --types worker_done --timeout-ms 300000 --json

将回复汇总到 answers.json 中,格式为 [{"id","author","text"}, ...],其中 author 是 seat ID(真实身份;下一步会将其移除)。

阶段 2a — 盲评数据包(council.py 是确定性的)
python3 harness/scripts/council.py prepare answers.json --config harness/council.config.yaml --out scratchpad/council-<slug>/

<slug> = 本次运行的简短名称(例如 release-gate)。始终放在 scratchpad/ 下(按每个仓库的约定加入 gitignore)——绝不要直接放在 run/ 或仓库根目录的文件夹中;这些 位置会留下无人清理的未跟踪杂项(经验教训 170726:过去的会话照搬此示例, 导致仓库根目录出现 6 个多余的 run-council*/ 目录)。写入 scratchpad/council-<slug>/council.packet.{json,md}:将答案重新标记为 A/B/C 并 移除作者信息,同时记录每位评委在锚点防护机制中的展示顺序。 按每位评委对应行的顺序向其展示答案,以消除位置偏差。

阶段 2b — 评审(由编排生成)

按 council.config.yaml,以每位评委的展示顺序向其分发盲评答案。请每位评委 按标签返回排名(最佳在前)。 汇总至 judges.json — [{"judge","ranking":["B","A","C"]}, ...]。

防护机制依靠的是盲评,而非排除:评委可以是席位成员,但它无法 识别自己的答案,因此不能偏袒自己。

阶段 2c — 汇总(council.py 是确定性的)
python3 harness/scripts/council.py rank answers.json --judges judges.json --config harness/council.config.yaml --out scratchpad/council-<slug>/

写入 scratchpad/council-<slug>/council.transcript.{json,md}:平均排名共识、获胜者、 异议表(争议最大的答案)和 chairman_brief。

阶段 3 — 最终回复(由编排生成)

向主席分发 transcript 中的 chairman_brief(共识顺序 + 必须解决的异议要点)。主席的综合意见即为最终答案;将其 粘贴回 transcript 的 chairman_synthesis 字段以供记录,然后运行 council.py render <transcript.json>,重新生成显示综合意见的阶段 4 HTML (rank 自动写入的报告中综合意见为空,因为 rank 只会根据答案和评委重新构建)。

阶段 4 — HTML 报告(必需,由 council.py 自行渲染,离线)

始终渲染——无需标志,不依赖外部技能。 每次 rank 成功后, render_report_html(t, personas)(就在 council.py 中)会写入一个带版本号的 .html 文件 — llmwiki/html/council/council-report-NNN-seed<seed>.html (NNN 递增,不覆盖 → 每次运行留下一份不可变记录)+ latest.html 作为便捷 指针(加入 gitignore,避免 diff 频繁变动)。不使用 CDN(系统字体 + 内联 SVG favicon/grain)→ 离线可用;不耦合 docs-site-macos。数据仅 来自刚构建的 transcript(t)→ 不会编造新内容,所有席位文本都在本地通过 html.escape 转义(防止 HTML 注入)。整个渲染块由 try/except 包裹: 渲染器出错只会发出 WARN,绝不会导致 rank 命令或 transcript.{json,md} 失败 (Taleb 爆炸半径防护)。委员姓名和视角取自 council.personas.yaml;传入 --question 时显示问题(留空 → 报告会隐藏问题行,而不是打印占位文本)。

页面严格包含以下三个 section,顺序如下:

  1. 理事会意见。 每个席位一张卡片(边框颜色 = sha256(author),按 共识排名 + 奖牌排序),答案会将 (1)(2)(3) 自动格式化为列表。 来源: t["answers"] + t["aggregate"]。
  2. 无记名投票(盲评投票)。 投票表使用匿名标签 A/B/C:每位评委 占一行,显示按标签排列的排名 + 锚点防护机制的展示顺序。仅在本 section 末尾揭示 A/B/C → 作者的映射。 来源: t["judge_rankings"] + t["anchor_guard"]。
  3. 最终仪表板。 KPI(获胜者 / 争议最大项 / 共识度)+ 平均排名 共识表;若 chairman_synthesis 已粘贴到 transcript 中,则醒目显示。 (rank 只根据答案和评委重新构建,因此主席填写之前此字段为空—— 此时综合意见区块会自动隐藏。) 来源: t["winner"] / t["most_contested"] / t["aggregate"]。

由于所有指标都来自已确定的 transcript,报告只是展示层—— 不会添加新的评判。同一份 transcript → 相同的 HTML。

分支
ID类型守卫条件行为跳过 / 失败汇合点
B01user_optional想要多样化视角(provider 较少)抽取 persona roster(见下方 Persona lenses),将 lens 插入 Stage-1 提示词(动态方式),或填入配置中的 persona: 字段(固定方式);roster 和理由写入 transcript未抽取 → seat = 纯模型W02
B02recoveryHTML 报告出错,或需要显示 chairman_synthesis重新运行 council.py render <transcript.json> → 新的版本化文件renderer 仍然出错 → WARN,transcript 是事实来源结束
B03conditional_required运行 rank 时没有 --judges仅生成 blind packet,然后停止—W04
验证与停止条件

确定项:selftest(12 项检查)证明相同的 answers.json + judges.json + seed → transcript 字节完全一致;报告只是 transcript 的展示层。需要审核:chairman synthesis 的质量。在 W07 之后停止,此时报告已包含 synthesis。

示例
  • 正向: 使用 roster --case decision 配置 3 个 seat,运行“召开 council:是否应该拆分 monorepo” → 3 个 seat 用带越南语变音符号的越南语作答 → prepare 生成 A/B/C → 3 个 judge 进行排名 → rank --out scratchpad/council-monorepo/ 输出 winner + dissent → chairman 汇总 → render 写入包含 synthesis 的 council-report-NNN-seed<seed>.html。
  • 边界/失败: council.py selftest 退出码非 0 → 在 W01 停止,不 dispatch 任何 seat。rank 中 renderer 出错 → 仅 WARN,仍会写入 council.transcript.json,之后重新运行 render。
参考 — Persona lenses — “伟人”视角(可选,增量式)

默认情况下,每个 seat = 一个 MODEL 作答。Persona 层增加多样化视角:每个 seat 戴上一个 lens(Feynman / Munger / Taleb / Rams 等)——当模型多样性受限(provider 较少)时尤为重要。Engine council.py 不变:persona 只是塞入 Stage-1 提示词的文字。

忘了名字 / 语法? council.py roster --list(或不带参数的 roster)会打印全部 case(按用途)· profile · 18 个 persona——按用途选择 --case,不必记住名字。 记错了也能准确调用: 名称和 id 均可匹配,且不区分大小写(--personas Feynman,Taleb 可用);输入错误 → 提供最接近的建议(--case risks → “你是不是想输入 'risk'?”),不会直接失败。

按 case 抽取 3-5 人(纯代码,可记录日志):

python3 harness/scripts/council.py roster --list                 # catalog: case/profile/persona
python3 harness/scripts/council.py roster --case risk            # 3 ghế, có ≥1 cặp đối-trọng
python3 harness/scripts/council.py roster --case ml-ai --size 5  # 5 ghế
python3 harness/scripts/council.py roster --profile lean         # 5 người execution-lean
python3 harness/scripts/council.py roster --personas feynman,taleb,rams --json
  • Case 标签:design · strategy · debug · risk · product · decision · simplify · ml-ai(见 harness/council.personas.yaml 中的表格)。
  • 规则: roster 始终会配置 至少一对对立观点(避免回音室);若缺少 → 在 stderr 发出警告。使用奇数数量(3/5),让 mean-rank 不会出现平局。
  • 库:18 个 persona + 13 对对立观点(来源:github.com/0xNyk/council-of-high-intelligence)。

在 protocol 中使用: 抽取 roster 后,将每个 persona 分配给一个 seat——有两种方式:

  1. 动态(推荐): orchestrator 获取 roster --json 的输出,为每个 seat 将 lens 插入 Stage-1 提示词:“通过 <name> 的视角回答:<lens>。<sig>。”
  2. 固定: 在 harness/council.config.yaml 中为每个 seat 填写 persona: 字段。

Roster 和抽取理由(case、tension 对)会写入 transcript,以便审计(支柱 5)。“哪个 model 填入 seat”仍是已隔离的未知项,记录在 council.config.yaml(verified)中——persona-lens 与此无关。

参考 — council.py 命令
命令功能
rank <answers.json> --judges <judges.json>完整聚合 → transcript.json + .md
rank <answers.json> --judges <j>+ 自动写入带版本号的 llmwiki/html/council/council-report-NNN-seed<seed>.html(Stage-4,必需)
rank <answers.json>(不带 judges)输出盲测数据包,然后停止
prepare <answers.json>仅生成盲测数据包(Stage 2a)
render <transcript.json>从已有 transcript 重新渲染 Stage-4 HTML(例如粘贴 chairman_synthesis 后)→ 新的带版本号文件
roster --case <tag> / --profile <p> / --personas a,b,c抽取 3-5 个 persona-lens(纯查找,至少 1 对立场相反);--size 3|5、--json
selftest一致性测试向量;断言确定性 + 正确性

标志:--seed N(锚点防护种子;覆盖配置中的 anchor_seed), --out DIR(transcript json/md)、--config harness/council.config.yaml、 --question "..."(报告中显示的实际问题;留空 → 隐藏 question 行)。 Stage-4 HTML 始终带版本号并写入 llmwiki/html/council/ — 无需标志。

参考 — 适配器边界(现在构建,之后适配)
  • 契约(现在已构建并测试): json schemas(answers.json、 judges.json、transcript)以及 council.py 中所有确定性操作。
  • 隔离区(verified: false): harness/council.config.yaml 中的模型身份。数学运算与它们无关。
  • 之后适配(一个文件): 编辑配置中的席位/评委/主席,运行一次真实 council,然后将 verified: true。无需更改引擎。
参考 — 确定性保证

相同的 answers.json + judges.json + 种子 → 每次运行都会生成逐字节相同的 transcript。匿名化取决于 sha256(id),而非输入顺序或作者,因此位置和作者身份都不会泄露。锚点防护使用参数为每位评委单独设定种子,不使用全局 RNG。selftest 可验证以上所有保证(12 项检查)。

评论

支持 Markdown