mcpField
E
elicit

elicit

github.com/juxt开发5242.7k 次安装4 周前更新
代码仓库

关于 elicit

elicit 是通过对话编写 Allium 规格的技能,帮助利益相关者界定范围、梳理工作流并澄清行为和边界情况,不规定具体实现方式。

主要功能

  1. 01通过对话起草规格
  2. 02定义范围与边界
  3. 03梳理流程和参与者
  4. 04引导探索主流程与失败路径

适用场景

  1. 01将模糊的产品构想整理为规格
  2. 02记录系统或功能的范围边界
  3. 03梳理参与者与生命周期转换
  4. 04识别边界情况和失败处理

安装

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

$npx skills add https://github.com/juxt/allium --skill elicit

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
assumption-checking.md
detail-elicitation.md
library-spec-signals.md
obstacle-elicitation.md
process-discovery.md

详细介绍

需求引导

本技能将通过对话引导你构建 Allium 规范。目标是揭示歧义,并生成一份描述软件功能、但不规定实现方式的规范。

确定规范范围

在深入细节之前,先明确要规范的内容。并非所有内容都需要放在同一份规范中。

首先要问的问题

“这份规范的边界是什么?” 是一个完整的系统?一个独立的功能领域?更大系统中的一项服务?请明确说明哪些内容属于范围,哪些不属于。

“有没有我们应该有意排除的领域?” 第三方集成可能应归入库规范。旧版功能可能不值得规范。有些功能可能应放在单独的规范中。

“这是一个新系统,还是已经有现成代码?” 如果代码已经存在,你要做的是结合需求引导进行提炼。现有代码会限制规范中哪些内容切实可行。

记录范围决策

在每份规范的开头记录范围:

-- allium: 3
-- interview-scheduling.allium

-- Scope: Interview scheduling for the hiring pipeline
-- Includes: Candidacy, Interview, Slot management, Invitations, Feedback
-- Excludes:
--   - Authentication (use oauth library spec)
--   - Payments (not applicable)
--   - Reporting dashboards (separate spec)
-- Dependencies: User entity defined in core.allium

版本标记(-- allium: N)必须是每个 .allium 文件的第一行。请使用当前的语言版本号。

找到合适的抽象层级

过于具体,就会变成在规范实现方式;过于抽象,就会变得毫无用处。

“为什么”测试

对于每个细节,都要问:“利益相关者为什么在意这一点?”

细节为什么?是否纳入?
“用户使用 Google OAuth 登录”他们需要进行身份验证也许不需要,“用户进行身份验证”可能就足够了
“我们支持 Google 和 Microsoft OAuth”用户可以选择自己的提供方是,这是领域层面的选择
“会话在 24 小时后过期”安全性/用户体验决策是,会影响用户体验
“会话存储在 Redis 中”性能否,这是实现细节
“密码必须至少包含 12 个字符”安全策略是,会影响用户
“密码使用 bcrypt 进行哈希处理”安全实现方式否,这是如何实现的问题,而非实现什么
“可以换一种方式实现吗?”测试

问:“即使采用不同的实现方式,这仍然会是同一个系统吗?”

  • 如果是,那它很可能是实现细节。将其抽象掉。
  • 如果不是,那它很可能属于领域层面。将其纳入规范。

示例:

  • “通过 Slack 发送通知”。也可以用电子邮件、短信等方式。将其抽象为 Notification.created(channel: ...)。
  • “面试官必须在 3 小时内确认”。这个具体时限在领域层面很重要。请纳入时长。
  • “我们使用 PostgreSQL”。也可以使用任何数据库。不要纳入。
  • “出于合规要求,数据保留 7 年”。这是监管要求。请纳入。
“模板与实例”测试

这是一个事物类别,还是一个具体实例?

实例(实现方式)模板(领域层面)
Google OAuth身份验证提供方
Slack通知渠道
15 分钟链接过期时长(可配置)
Greenhouse ATS外部候选人来源

有时,实例本身就是领域关注点。“我们专门集成 Salesforce”可能是一项竞争优势。“我们恰好支持这三个 OAuth 提供方”可能属于设计范围。

如有疑问,可以询问利益相关者:“如果我们改变这一点,系统会变成另一个系统,还是只是换了一种实现方式?”

抽象层级
Too abstract:          "Users can do things"
                              |
Product level:         "Candidates can accept or decline interview invitations"
                              |
Too concrete:          "Candidates click a button that POST to /api/invitations/:id/accept"

抽象得过头的迹象。 这份规范几乎可以描述任何系统。没有可测试的断言。产品负责人会说:“但这并没有体现……”

过于具体的迹象。 你提到了技术、框架或 API。你描述了 UI 元素(按钮、页面、表单)。实现团队会说:“为什么要规定我们该怎么构建?”

配置与硬编码

遇到特定值(3 小时、7 天等)时,请思考:

  1. 这是设计决策吗? 将其纳入规范。
  2. 它可能因部署或客户而异吗? 将其设为可配置项。
  3. 它是随意设定的吗? 考虑是否应该纳入。
-- Hardcoded design decision
rule InvitationExpires {
    when: invitation: Invitation.created_at + 7.days <= now
    ...
}

-- Configurable
config {
    invitation_expiry: Duration = 7.days
}

rule InvitationExpires {
    when: invitation: Invitation.created_at + config.invitation_expiry <= now
    ...
}
黑盒

有些逻辑很重要,但属于不同的层级:

-- Black box: we know it exists and what it considers, but not how
ensures: Suggestion.created(
    interviewers: InterviewerMatching.suggest(
        considering: {
            role.required_skills,
            Interviewer.skills,
            Interviewer.availability,
            Interviewer.recent_load
        }
    )
)

规范说明存在一种匹配算法,会考虑这些输入,并生成面试官建议。规范没有说明匹配如何运作、使用哪些权重或采用哪种具体算法。

当算法复杂且不断演进、产品负责人关注输入和输出而非内部细节时,这就是合适的抽象层级;如有需要,也可以另行编写详细规范来说明。

阅读初始提示词

在选择方法之前,先评估用户带来了什么。初始提示词会告诉你从哪里着手。

用户描述了一个流程。“我们有一个招聘流程:候选人申请、经过筛选、参加面试,然后我们做出决定。”他们从流程层面思考。先进行流程探索——让他们描述流程,然后帮助他们将其整理为规范构造。请参阅流程探索。

用户提到了实体。“我需要为一个包含状态和转换的 Order 实体编写规范。”他们已经在构造层面思考。跳过流程探索,转到范围定义,然后补充细节。在梳理规则和表面时,请参阅细节 elicitation。

用户只有一个模糊的想法。“我们需要构建一个用于管理客户支持的东西。”在编写规范之前,他们需要帮助来理清想法。先通过开放式问题进行流程探索:“请告诉我客户寻求帮助时会发生什么。”请参阅流程探索。

用户已有代码。“我们有一个支付服务,我想记录它的功能。”这是提炼结合引导式访谈。引导他们使用 distill 技能,或结合两者:从代码中提炼结构,从利益相关者处引导出意图。

**用户已有规范。**先阅读规范。使用评估规范确定每个实体的开发阶段。跳过规范已经涵盖的阶段——对于已经包含范围注释的规范,不要重复询问范围问题;对于已经包含转换图的规范,不要重新探索流程。从每个实体所需的层级开始:对于有生命周期但没有规则的实体,进行细节引导;对于有规则但没有失败路径的实体,进行障碍引导。

引导方法

阶段 0:流程探索

目标: 在识别构造之前,了解系统支持的流程。

并非每次会话都需要此阶段。如果用户已经考虑好实体和生命周期,请跳到阶段 1。如果用户描述了一个流程或只有一个模糊的想法,请从这里开始。

在套用 Allium 结构之前,先让用户用自己的话描述系统。记录流程、参与者和结果,然后整理成构造。具体技巧请参阅流程探索。

输出: 流程名称和结果。大致的步骤顺序。已识别的参与者。足以编写粗略规范的信息(包含转换图和开放问题的实体)。

注意: 不要过早跳到实体定义。保持在流程层面,直到流程清晰为止。

阶段 1:范围定义

目标: 了解我们要规范什么,以及边界在哪里。

要问的问题:

  1. “这个系统本质上是做什么的?用一句话概括。”
  2. “这个系统从哪里开始,到哪里结束?哪些内容属于范围,哪些不属于?”
  3. “用户是谁?是否有不同的角色?”
  4. “它会与哪些现有系统集成?这些系统负责什么?”

如果跳过了阶段 0,还要询问:“这个系统支持哪些关键流程?每个流程怎样才算成功?”这能让实体识别以流程为依据,而不是孤立地罗列名词。此处也适用流程发现中的技巧——如果用户难以描述流程,可使用过去时回忆和以结果为先的提问方式。

输出: 参与者和角色列表。核心实体列表(如果执行了阶段 0,则根据流程推导)。边界决策(哪些内容属于外部)。一句话描述。

注意: 范围蔓延(“它还会做 X、Y、Z”,温和地引导回主题)。默认的假设知识(“它显然会处理身份验证”,要明确写出)。描述可能指向库规范,而非特定于应用的逻辑(例如 OAuth、支付处理、电子邮件发送)。

阶段 2:正常流程

目标: 从头到尾梳理主要流程。

如果阶段 0 产出了一个行走骨架(见流程发现),就以此为起点。否则,询问:“如果我们只能为这个流程构建一条路径,那会是什么?”将骨架写成粗略规范,并用领域术语向用户复述(见评估规范)。

然后进一步展开:“每个步骤由什么触发?涉及哪些人?会发生什么变化?”沿着一个实体的生命周期进行梳理,记录状态转换、参与者和触发条件。

Candidacy:
  applied -> screening -> interviewing -> deciding -> hired | rejected

输出: 关键实体的转换图。主要触发条件及其结果。每个步骤的参与者分配。

注意: 过早转向边缘情况(“但如果……”,先记下来,继续关注正常流程)。实现细节开始渗入(“API 端点……”,引导讨论回到结果)。

编写完规范构造后,如果 CLI 可用,请运行 allium check。继续之前先修复结构问题——不要等到阶段 4 才验证。

建立骨架后,请参阅细节引导,了解补充规则、界面、字段和数据依赖关系的技巧。

阶段 3:边缘情况和失败路径

目标: 找出可能出错的情况,以及系统会如何处理。

请参阅障碍引导了解相关技巧。主要方法包括:

  • 使用事前验尸法:“假设这个系统已经建成,但运行失败了。出了什么问题?”
  • 对每个步骤询问:“如果这里没人采取行动会怎样?过一天呢?一周呢?”
  • 对每次交接询问:“谁来接手?他们怎么知道轮到自己了?需要看到什么?”
  • 对每次转换询问:“如果不满足前置条件会怎样?能否撤销?”
  • 对于外部依赖,询问:“这些信息如何进入系统?如果外部服务不可用会怎样?”

输出: 异常转换。带有 requires 守卫条件的时间触发器。升级路径。终止错误状态。不变量。

注意: 无限循环(“然后重试,再重试……”,需要终止状态)。缺少升级机制,因为最终需要让某个人知情。

当利益相关者陈述系统范围的属性(“余额永远不会为负数”“同一候选人的两场面试不会重叠”)时,这些属性可能适合作为顶层不变量。请将其记录为 invariant Name { expression } 声明。

编写完规则和异常转换后,如果 CLI 可用,请运行 allium check。进入细化阶段之前先修复问题。

阶段 4:完善

目标: 验证并补全规范。

请参考假设检查中的技巧。用领域术语描述规范的内容,并根据用户的心智模型进行验证。沿着规范推演具体场景。检验顺序方面的假设。核实参与者的分配。

如果 Allium CLI 可用,请运行 allium check,并利用诊断结果找出结构性缺口。如果 allium analyse 可用,且规范包含规则和界面,请运行该命令,并利用结果找出流程层面的缺口。请参考处理分析结果,了解如何将分析结果转化为领域问题。

需要提出的问题:

  1. “看看[实体],这些状态完整吗?它还可能处于其他状态吗?”
  2. “还有什么内容尚未涵盖吗?”
  3. “这条规则引用了[X],我们需要对它进行定义,还是它属于外部内容?”
  4. “这个细节在这里必不可少吗,还是应该放在详细规范中?”

技巧: 选取一个具体场景,沿着规范进行推演。“假设 Alice 申请 Senior Engineer 职位。请带我逐步了解她的候选状态会发生什么变化。”

产出: 完整的实体定义。记录未解决的问题。确定延期编写的规范。确认外部边界。

当同一种义务模式(例如序列化约定、确定性评估要求)出现在多个界面时,建议将其提取为 contract 声明以供复用。

像明确逻辑一样明确结果

结果的形式是最容易丢失的决策——可能被删除、只记录一部分,甚至被排除在范围之外。应像深入探讨核心方法一样,深入确定结果形式。

  • 逐字段直接询问结果的形式。“这必须准确返回或报告什么?每个字段分别是什么?”获取完整列表,而不是有代表性的示例。
  • **任何派生、披露或报告依据与计算依据不同的数值,都应按核心方法的标准处理:**明确其精确定义、依据、精度以及在退化情况下的行为,并持续追问,直到没有任何歧义。此处一句话的回答往往藏着细微的要求——例如,按不同于计息日数的日计数方式披露的利率,或客户看到的数值与系统保存的数值不同。
  • **默认将结果形式纳入范围。**切勿将系统必须返回或披露的内容排除在范围之外;排除某项输出是需要与操作人员确认的决策,而不是可以悄然省略的内容。

结束前:完整性检查

访谈通常会让人觉得早就结束了——只要主流程说得通,就会产生这种感觉,但这还远远不够。不要凭这种感觉结束访谈。在将对话视为完整之前,请根据以下决策类别逐项检查操作人员说过的所有内容。对于与本系统相关的每个类别,确认对方确实已经回答;如果还没有,就现在提出一个具体、可回答的问题,并继续追问,直到每个相关类别都已经问到并得到回答(或被明确排除在范围之外)。从未问过的类别不能算作“已假定”——它只是尚未问到;需求说明中的沉默意味着应该提问,而不是可以自行猜测。

  • 核心方法或规则。 计算、推导或判定结果时,如果存在不止一种公认的方法或惯例,这个组织采用哪一种?不要默认采用最常见的做法。
  • 单位和精度。 数量的计量单位、精度,以及如何处理更细粒度的数值。
  • 舍入或截断。 将数值调整到其单位精度时,采用哪种方向,以及余数如何处理。
  • 顺序和优先级。 应用或处理多项内容时,采用什么顺序,以及优先级相同时如何打破平局。
  • 阈值和限额。 最小值、最大值、上限,以及低于这些值时会被豁免、忽略或视为零的容差。
  • 时间和生效日期。 某事项何时生效、何时记录、是否允许追溯日期、是否按较早时间点重新计算,以及截止时间。
  • 并发和顺序安排。 两件事同时或短时间内接连发生时,如何确定顺序,以及如何打破平局。
  • 边界输入。 对于零值、负值、空值、缺失值、重复值、超出范围的值,分别是拒绝、忽略还是处理,以及是否仍保留记录。
  • 盈余和短缺。 对任何多余或缺少的部分如何处理——留存、退回、结转、升级处理——以及接下来用于抵扣什么。
  • 范围边界。 本系统负责什么,上游系统或外部系统提供什么。确认排除某项内容也是一项决策,不能悄然省略。
  • 输出和报告形式。 结果必须包含的所有内容,逐字段列明;以及任何采用不同于计算或存储口径的方式报告或披露的数值。
  • 完整生命周期,而不只是创建。 该对象在整个生命周期中会经历的所有事件,而不只是创建和正常运行——提前终止或取消、生命周期中的更改或更正、暂停或挂起、续订或延期、撤销、转移、到期,以及关闭或逐步停用——并且对每种事件,都要明确会重新计算什么,以及剩余部分如何处理。这是最容易被漏掉的类别;针对当前实体,逐项列出这些事件,并询问每一项是否适用。

只要上述任何相关类别仍是未提问的假设,就还没有结束。

需求收集原则

一次只问一个问题

不好的问法:“你有哪些实体,它们可以处于哪些状态,谁可以修改它们?”

好的问法:“这个系统主要管理哪些内容?” 接着问:“我们来看看 [候选资格]。它可以处于哪些状态?” 然后问:“谁可以更改候选资格的状态?”

深入探讨影响

出现选项时,不要只接受第一个答案。要探究其后果。

“你说邀请会在 48 小时后过期。之后会发生什么?” “如果重试后候选人仍未回复呢?” “如果他们一直不回复,这个候选资格会永远卡在那儿吗?”

这样可以发现他们尚未作出的决策。

区分产品与实现

听到实现层面的表述时,引导对方换个角度:

对方说你可以这样引导
“API 返回 404”“所以用户会收到未找到的提示?”
“我们把它存储在 Postgres 中”“会记录哪些信息?”
“前端显示一个模态框”“系统会提示用户确认?”
“我们使用 cron 作业”“这是定期执行的,频率是多少?”
明确指出模糊之处

记录一个待解决问题,总比自行假设更好。

“我不确定拒绝后应该让候选人回到候选池,还是将其彻底移除。我先把这记为一个待解决问题。”

open question "When candidate declines, do they return to pool or exit?"
乐于迭代

修订先前的决定很正常。

“之前我们说所有管理员都能看到所有通知。但你现在提到了按角色划分的仪表盘。我们要重新讨论一下吗?”

深入优先于覆盖面

先完整梳理最重要的实体。其他实体先粗略处理,并留下待解决问题。用户可以在后续会话中继续完善。试图在一次对话中把所有实体都梳理到相同的细致程度,可能会耗尽上下文,却什么也没完成。

知道何时停止

并非所有内容都需要现在明确。

“这已经涉及匹配算法的工作方式了。我们要把它留到详细规格说明中吗?”

“我们已经讨论了主要流程。报告仪表盘听起来像是一个独立的规格说明。”

常见的需求引导陷阱

“显而易见”陷阱

当有人说“显而易见”或“当然”时,深入追问。“你说管理员显然会批准。有没有他们不需要批准的情况?以后能否将这一步自动化?”

“边缘情况螺旋”陷阱

有些人想立刻涵盖所有边缘情况。“我们先把它记为一个待解决问题,暂时聚焦主要流程。之后再回过头讨论边缘情况。”

“模糊同意”陷阱

不要接受没有具体细节的“是”。“你说是,候选人可以重新安排时间。可以改几次?有限制吗?之后会发生什么?”

“缺少执行者”陷阱

留意没有明确执行者的操作。“你说‘时段会被释放’。由谁或什么来释放?这是自动进行的,还是需要有人触发?”

“同义术语”陷阱

如果你听到不同利益相关者、现有代码或相关规格说明中,用不同术语表示同一概念,请停下来解决术语问题后再继续。

“你说的是‘购买’,但之前我们称它为‘订单’。应该使用哪个术语?”

仅仅备注两个术语含义相同,并不算解决问题。这只会确保两个术语都会出现在实现中。选定一个术语,交叉引用相关规格说明,并更新所有引用。不要在任何地方保留旧术语,连“另请参阅”备注中也不行。

需求引导会话结构

这些时间安排适用于由人工主持的会话。在 LLM 对话中,应根据各阶段的输出决定何时推进,而不是盯着时钟。

开场。 简要说明 Allium:“我们要记录的是软件做什么,而不是它如何构建。”商定本次会话的范围。

定义范围。 确定参与者、实体和边界。写出一句话描述。

主流程。 从头到尾梳理主要流程。记录状态、触发条件和结果。

边缘情况。 超时和截止时间、失败模式、升级路径。

总结。 回顾关键决定,列出待解决问题。指出哪些实体仍较粗略,以及下一步需要补充什么。必要时确定下次会话的范围。

需求引导后

对于已明确目标的定向修改,请使用 tend skill。对于需要结构化梳理的大型新增内容(新功能领域、复杂实体关系、需求不明确),即使已经存在规格说明,elicit 仍是合适的工具。检查规格说明与实现是否一致,属于 weed skill 的工作。

参考资料

评论

支持 Markdown