Skip to content

用户管理

用 user_config 访问名单、URL 直接登录、RBAC 角色与权限、按标注者设定的工作量配额和培训关卡,管理 Potato 里的标注者。

Potato 对一个人分别决定三件事:能不能注册、进来之后可以做什么、以及分给他多少工作。这三件事各是一个配置块,把它们弄混,通常就是"标注者能登录却始终拿不到项目"的原因。

访问模式

开放访问

Potato 默认允许自助注册,新标注者可以从登录页自己创建账号:

yaml
user_config:
  allow_all_users: true

受限访问

把 allow_all_users 设为 false,并列出允许注册的地址。名单之外的人无法创建账号:

yaml
user_config:
  allow_all_users: false
  users:
    - alice@example.com
    - bob@example.com
    - researcher@university.edu

这两个键都在 user_config 之下。写在顶层会被静默忽略,看上去就是一份什么也不管的访问名单。

认证

密码登录

默认方式。标注者用邮箱和密码注册,Potato 把密码存成按用户加盐的 PBKDF2 哈希。

yaml
login:
  type: password

用 URL 参数直接登录

url_direct 直接从 URL 参数里取用户名,不要求密码,众包平台过来的人就是这么处理的:

yaml
login:
  type: url_direct
  url_argument: PROLIFIC_PID

标注者随后访问 http://your-server:8000/?PROLIFIC_PID=abc123,就以 abc123 的身份登录了。

url_argument 也接受一个列表,这时标注者的输出目录名由这些值拼接而成:

yaml
login:
  type: url_direct
  url_argument:
    - PROLIFIC_PID
    - STUDY_ID
    - SESSION_ID

登录类型一共三种:password、url_direct 和 prolific,最后一种是在 URL 直接登录之上再加了 Prolific API 集成。平台那一侧见众包集成。

关闭密码或登录表单

Potato 把每位标注者的标签存在 output_annotation_dir 下以其用户名命名的文件夹里,所以每位标注者都要用用户名登录。没有哪个设置能去掉这一步。有两个设置可以去掉其中的密码,第二个还会连表单一起去掉。

在配置的顶层写 require_password: false 后,登录表单只要求填写用户名。Potato 会当场注册一个没见过的名字,而见过的名字会直接回到该标注者的工作中:

yaml
require_password: false

因此,任何人输入一个已有的用户名,都会接着那位标注者的会话继续。只有在标注者彼此信任或任务 URL 不公开时,才应关闭密码。名单在这种模式下依然有效:设置 user_config.allow_all_users: false 时,不在 users 中的名字会被拒绝。要连表单也去掉,就使用 url_direct 登录,并给每位标注者发送一个带有其用户名的链接。不需要密码就能运行的认证后端见免密登录。

角色与权限

共享管理员密钥

admin_api_key 是一个通过 X-API-Key 请求头发送的共享密钥,它会绕过所有权限检查。不设置时,Potato 会生成一个并写入 {task_dir}/admin_api_key.txt。

yaml
admin_api_key: "your-shared-key"

基于角色的访问控制

配上 rbac 块之后,指定的人正常登录就能进入管理面板,不必持有那个共享密钥:

yaml
rbac:
  enabled: true
 
  # Custom roles, merged over the built-in ones
  roles:
    lead: [view_admin_dashboard, export_data, annotate]
 
  # Assign roles to specific users
  user_role_assignments:
    carol@example.com: admin
    dave@example.com: lead
 
  # Map an SSO claim to a role
  sso_role_mapping:
    "org:my-github-org": adjudicator

权限有 view_admin_dashboard、manage_assignment、adjudicate、export_data 和 annotate 五项。内置的 admin 角色拥有全部五项,adjudicator 拥有 adjudicate、export_data 和 annotate,annotator 拥有 annotate。

一个用户的权限是他所有角色的并集。完全不写 rbac 块时,只有共享密钥和 adjudication.adjudicator_users 名单能带来更高权限,RBAC 出现之前写的项目就是这样继续工作的。

工作量

每名标注者的上限

max_annotations_per_user 给所有人定同一个数:

yaml
max_annotations_per_user: 100

per_annotator_quota 给不同的人定不同的数。它接受 default、by_user 和 by_user_role,其他子键在加载时会被拒绝,而不是被忽略:

yaml
per_annotator_quota:
  default: 50
  by_user:
    alice@example.com: 200
  by_user_role:
    expert: 150
    novice: 40

上限的解析顺序是先看 by_user,再看 by_user_role,最后看 default。角色标签来自 user_roles:

yaml
user_roles:
  alice@example.com: expert
  bob@example.com: novice

这里的标签只是工作量标签。只有当它同时在 rbac.roles 里也是一个角色名时才带来权限,所以 expert 和 novice 就只是配额标签而已。

每个项目的标注者数

num_annotators_per_item 决定每个项目由多少人看到,而这决定了你最后能不能报告一致性:

yaml
num_annotators_per_item: 3
min_annotators_per_instance: 2

max_annotations_per_item 是同一个上限的已弃用别名。两者设成不同的值会在加载时被拒绝,而不是静默取其一。

分配策略

yaml
assignment_strategy: random
random_seed: 1234

可选的策略有 random、fixed_order、least_annotated、max_diversity、diversity_clustering、category_based、batch、priority、model_review、llm_confidence、psychometric 和 active_learning。random_seed 默认是 1234,所以需要复现某次运行时把它固定下来。每种策略的作用见任务分配。

甄选标注者

培训阶段在正式任务之前先给标注者一批有已知答案的练习项目,由 passing_criteria 决定谁可以继续:

yaml
training:
  enabled: true
  data_file: data/training.json
  passing_criteria:
    min_correct: 8
    max_mistakes: 2
    max_mistakes_per_question: 1
  allow_retry: true
  failure_action: block

项目格式和反馈选项见培训阶段。

任务进行中的注意力检查

培训在一开始筛人。注意力检查则在真正开工之后继续测量:

yaml
attention_checks:
  enabled: true
  items_file: data/attention_checks.json
  frequency: 10
  min_response_time: 3.0
  failure_handling:
    warn_threshold: 2
    warn_message: "Please read items carefully before answering."
    block_threshold: 5
    block_message: "You have been blocked due to too many incorrect responses."

黄金标准和一致性报告见质量控制。

会话

yaml
secret_key: "a-long-random-string"
session_timeout_minutes: 60
persist_sessions: true
session_lifetime_days: 7

secret_key 用来给会话 cookie 签名,它也可以改由 POTATO_SECRET_KEY 环境变量提供。一个都没有时,Potato 每次启动都会生成新密钥,于是每次重启所有人都会被登出。

session_timeout_minutes 会清除空闲达到这么长时间的会话,每次请求都会让计时重新开始。Potato 2.11 是第一个真正执行这项设置的版本,默认值为 480 分钟。像这个示例一样设为 60 时,离开一小时的标注者回来后需要重新登录。

示例:科研团队配置

yaml
annotation_task_name: "Sentiment Annotation"
task_dir: .
 
user_config:
  allow_all_users: false
  users:
    - researcher1@university.edu
    - researcher2@university.edu
    - student1@university.edu
    - student2@university.edu
 
rbac:
  enabled: true
  user_role_assignments:
    researcher1@university.edu: admin
 
user_roles:
  researcher1@university.edu: expert
  student1@university.edu: novice
 
per_annotator_quota:
  default: 200
  by_user_role:
    expert: 300
    novice: 120
 
num_annotators_per_item: 2
assignment_strategy: least_annotated
 
data_files:
  - data/main.json
 
item_properties:
  id_key: id
  text_key: text
 
annotation_schemes:
  - annotation_type: radio
    name: sentiment
    description: "What is the sentiment of this text?"
    labels:
      - Positive
      - Negative
      - Neutral
    sequential_key_binding: true
 
output_annotation_dir: annotation_output/

示例:众包配置

yaml
annotation_task_name: "Sentiment Annotation Study"
task_dir: .
 
login:
  type: url_direct
  url_argument: PROLIFIC_PID
 
completion_code: "POTATO2024"
 
user_config:
  allow_all_users: true
 
max_annotations_per_user: 50
num_annotators_per_item: 3
assignment_strategy: random
 
hide_navbar: true
jumping_to_id_disabled: true
 
attention_checks:
  enabled: true
  items_file: data/attention_checks.json
  frequency: 10
  failure_handling:
    warn_threshold: 2
    block_threshold: 5
 
data_files:
  - data/main.json
 
item_properties:
  id_key: id
  text_key: text
 
output_annotation_dir: annotation_output/

延伸阅读

实现细节见源文档和角色与权限参考。