如果你的 AI 产品可能被未成年人使用,儿童保护不是"nice-to-have"而是法律要求。COPPA、中国未成年人保护法、EU GDPR 儿童条款都对 AI 产品提出了严格要求。
## COPPA 核心要求
1. 隐私政策
- 清晰说明收集哪些儿童数据
- 说明数据如何使用和共享
- 必须使用儿童能理解的语言
2. 可验证的父母同意
- 收集 13 岁以下儿童数据前必须获得父母同意
- 同意方式必须可验证(不仅是点击"我同意")
3. 数据最小化
- 只收集提供服务所必需的数据
- 不得将儿童数据用于行为广告
4. 数据安全
- 合理的安全措施保护儿童数据
- 保留时间不超过必要期限
5. 儿童权利
- 父母可以查看儿童数据
- 父母可以要求删除儿童数据
- 父母可以撤回同意
from enum import Enum
from dataclasses import dataclass
from datetime import date
class AgeVerificationMethod(Enum):
SELF_DECLARATION = "self_declaration" # 自报年龄
PHONE_VERIFICATION = "phone" # 手机号验证
ID_VERIFICATION = "id_card" # 身份证验证
PARENT_CONFIRMATION = "parent" # 家长确认
AI_ESTIMATION = "ai_estimation" # AI 估计(辅助)
@dataclass
class AgeVerificationResult:
is_minor: bool
age: int | None
confidence: float
method: AgeVerificationMethod
requires_parent_consent: bool
class AgeVerificationService:
"""年龄验证服务"""
# 各地区年龄阈值
AGE_THRESHOLDS = {
'US': 13, # COPPA
'EU': 16, # GDPR(部分成员国为13)
'CN': 14, # 中国未成年人保护法
'UK': 13, # UK Age Appropriate Design Code
}
def __init__(self, region: str = 'CN'):
self.region = region
self.age_threshold = self.AGE_THRESHOLDS.get(region, 14)
async def verify_age(self, user_input: dict) -> AgeVerificationResult:
"""执行年龄验证
Args:
user_input: 包含验证信息的字典
"""
method = AgeVerificationMethod(user_input.get('method', 'self_declaration'))
if method == AgeVerificationMethod.SELF_DECLARATION:
return self._verify_self_declaration(user_input)
elif method == AgeVerificationMethod.PHONE_VERIFICATION:
return await self._verify_phone(user_input)
elif method == AgeVerificationMethod.ID_VERIFICATION:
return await self._verify_id(user_input)
else:
return AgeVerificationResult(
is_minor=True, # 保守策略:未知年龄视为未成年人
age=None,
confidence=0.0,
method=method,
requires_parent_consent=True
)
def _verify_self_declaration(self, data: dict) -> AgeVerificationResult:
"""自报年龄验证(最弱但最常见的起点)"""
declared_age = data.get('age')
if declared_age is None:
# 未提供年龄,保守处理
return AgeVerificationResult(
is_minor=True,
age=None,
confidence=0.1,
method=AgeVerificationMethod.SELF_DECLARATION,
requires_parent_consent=True
)
is_minor = declared_age < self.age_threshold
return AgeVerificationResult(
is_minor=is_minor,
age=declared_age,
confidence=0.3, # 自报年龄置信度低
method=AgeVerificationMethod.SELF_DECLARATION,
requires_parent_consent=is_minor
)
# 中间件:在 API 调用前检查年龄
"""
@app.middleware("http")
async def age_gate(request, call_next):
if request.url.path.startswith("/api/chat"):
user = get_current_user(request)
age_result = await age_service.verify_age({
'method': user.verification_method,
'age': user.declared_age
})
if age_result.is_minor:
if not age_result.requires_parent_consent or user.has_parent_consent:
# 未成年人模式:限制功能
request.state.minor_mode = True
request.state.content_level = 'child_safe'
else:
return JSONResponse(
status_code=403,
content={"error": "需要家长同意才能使用此功能"}
)
return await call_next(request)
"""
from enum import IntEnum
class ContentLevel(IntEnum):
"""内容安全级别"""
CHILD_SAFE = 0 # 适合所有年龄
GENERAL = 1 # 适合一般受众(含轻微复杂话题)
TEEN = 2 # 适合 13+(可能含复杂话题)
MATURE = 3 # 适合 18+(可能含成人话题)
RESTRICTED = 4 # 受限内容
class ContentGrader:
"""内容分级器"""
# 各级别对应的系统提示词
SYSTEM_PROMPTS = {
ContentLevel.CHILD_SAFE: """你是一个面向儿童的友好助手。规则:
1. 使用简单易懂的语言
2. 不讨论暴力、恐怖、成人话题
3. 不提供具体的健康/医疗建议(建议询问家长或医生)
4. 遇到不适合儿童的话题时,引导他们与家长讨论
5. 保持积极、鼓励的态度
6. 不提供任何可执行的危险操作指导""",
ContentLevel.TEEN: """你是一个面向青少年的助手。规则:
1. 可以讨论更复杂的话题(科学、社会、文化)
2. 不提供详细的暴力或自残内容
3. 对敏感话题提供平衡、客观的信息
4. 鼓励批判性思维
5. 不鼓励危险行为""",
ContentLevel.GENERAL: """你是一个通用助手,提供有帮助的信息。""",
ContentLevel.MATURE: """你是一个成人助手。""",
}
# 各级别允许的话题
ALLOWED_TOPICS = {
ContentLevel.CHILD_SAFE: [
'学习辅导', '科学知识', '故事创作', '游戏',
'日常生活', '运动', '艺术', '音乐'
],
ContentLevel.TEEN: [
'*CHILD_SAFE 内容', '社会问题', '心理健康(基础)',
'职业规划', '科技趋势', '文化讨论'
],
}
# 各级别禁止的话题
FORBIDDEN_TOPICS = {
ContentLevel.CHILD_SAFE: [
'暴力/武器', '色情', '毒品', '自杀/自残',
'政治争议', '宗教冲突', '犯罪指导', '酒精/烟草'
],
ContentLevel.TEEN: [
'色情', '犯罪指导', '详细的暴力描述', '毒品使用指导'
],
}
def get_system_prompt(self, level: ContentLevel) -> str:
"""根据内容级别返回系统提示词"""
return self.SYSTEM_PROMPTS.get(level, self.SYSTEM_PROMPTS[ContentLevel.GENERAL])
def check_content_allowed(self, level: ContentLevel, topic: str) -> bool:
"""检查话题是否允许"""
forbidden = self.FORBIDDEN_TOPICS.get(level, [])
return not any(f in topic for f in forbidden)
from dataclasses import dataclass, field
from typing import Optional
from datetime import time
@dataclass
class ParentalControls:
"""家长控制设置"""
user_id: str
parent_id: str
# 时间控制
allowed_hours_start: time = time(8, 0) # 允许使用开始时间
allowed_hours_end: time = time(21, 0) # 允许使用结束时间
max_daily_minutes: int = 60 # 每日最大使用时间
# 内容控制
content_level: ContentLevel = ContentLevel.CHILD_SAFE
blocked_topics: list[str] = field(default_factory=list)
allowed_topics: list[str] = field(default_factory=list)
# 功能控制
allow_web_search: bool = False
allow_image_generation: bool = False
allow_code_execution: bool = False
# 通知
notify_on_sensitive_topic: bool = True
weekly_usage_report: bool = True
class ParentalControlService:
"""家长控制服务"""
def __init__(self, db):
self.db = db
async def set_controls(self, parent_id: str, child_id: str,
settings: dict) -> ParentalControls:
"""设置家长控制"""
controls = ParentalControls(
user_id=child_id,
parent_id=parent_id,
**settings
)
# 保存到数据库
self.db.save_controls(controls)
return controls
async def check_usage_allowed(self, child_id: str) -> tuple[bool, str]:
"""检查是否允许当前使用"""
controls = self.db.get_controls(child_id)
if not controls:
return True, "No parental controls set"
# 检查时间限制
now = datetime.now().time()
if not (controls.allowed_hours_start <= now <= controls.allowed_hours_end):
return False, f"当前不在允许使用时间内({controls.allowed_hours_start}-{controls.allowed_hours_end})"
# 检查每日使用时间
today_usage = self.db.get_daily_usage(child_id)
if today_usage >= controls.max_daily_minutes:
return False, f"今日使用时间已达上限({controls.max_daily_minutes}分钟)"
return True, "Allowed"
async def get_usage_report(self, parent_id: str, child_id: str) -> dict:
"""生成使用报告(家长可查看)"""
controls = self.db.get_controls(child_id)
usage = self.db.get_usage_stats(child_id, days=7)
topics = self.db.get_topic_stats(child_id, days=7)
sensitive = self.db.get_sensitive_interactions(child_id, days=7)
return {
'child_id': child_id,
'period': '7 days',
'total_minutes': usage['total_minutes'],
'daily_breakdown': usage['daily'],
'top_topics': topics[:10],
'sensitive_interactions': sensitive,
'controls': {
'time_limit': controls.max_daily_minutes,
'content_level': controls.content_level.name,
'blocked_features': [
k for k, v in {
'web_search': controls.allow_web_search,
'image_generation': controls.allow_image_generation,
'code_execution': controls.allow_code_execution
}.items() if not v
]
}
}
async def notify_parent(self, parent_id: str, child_id: str,
event_type: str, details: dict):
"""通知家长"""
controls = self.db.get_controls(child_id)
if event_type == 'sensitive_topic' and controls.notify_on_sensitive_topic:
await self._send_notification(
parent_id,
title="⚠️ 您的孩子尝试了敏感话题",
body=f"话题: {details.get('topic', '未知')}\n"
f"时间: {details.get('time', '刚刚')}\n"
f"已自动过滤,建议与孩子沟通。"
)
# API 端点
"""
@app.post("/api/parent/controls")
async def set_parental_controls(request: Request):
parent_id = request.state.user_id
child_id = request.json()['child_id']
settings = request.json()['settings']
# 验证亲子关系
if not verify_parent_child(parent_id, child_id):
raise HTTPException(403, "Not authorized")
service = ParentalControlService(db)
controls = await service.set_controls(parent_id, child_id, settings)
return controls
@app.get("/api/parent/report/{child_id}")
async def get_usage_report(child_id: str, request: Request):
parent_id = request.state.user_id
service = ParentalControlService(db)
return await service.get_usage_report(parent_id, child_id)
"""
| 法规 | 地区 | 年龄阈值 | 关键要求 |
|---|---|---|---|
| COPPA | 🇺🇸 美国 | 13岁 | 可验证的父母同意、数据最小化、无行为广告 |
| GDPR (儿童条款) | 🇪🇺 欧盟 | 16岁(部分13) | 父母同意、隐私设计、数据保护影响评估 |
| UK Age Code | 🇬🇧 英国 | 18岁以下 | 年龄适当设计、默认最高隐私设置、透明度 |
| 未成年人保护法 | 🇨🇳 中国 | 18岁(14岁以下特殊保护) | 青少年模式、时间限制、内容过滤、充值限制 |
| 韩国个人信息法 | 🇰🇷 韩国 | 14岁 | 法定代理人同意、数据保护 |
## 儿童保护检查清单
### 年龄验证
[ ] 实现年龄验证机制(至少自报年龄)
[ ] 对疑似未成年用户升级验证
[ ] 未验证年龄的用户默认按未成年人处理
[ ] 定期验证年龄信息
### 内容安全
[ ] 针对不同年龄级别的内容过滤
[ ] 儿童安全的系统提示词
[ ] 禁止话题列表
[ ] 输出内容额外审核
### 家长控制
[ ] 家长控制面板
[ ] 使用时间限制
[ ] 功能访问限制
[ ] 使用报告
[ ] 敏感话题通知
### 数据保护
[ ] 儿童数据最小化
[ ] 儿童数据加密存储
[ ] 不将儿童数据用于广告
[ ] 不将儿童数据用于模型训练
[ ] 短数据保留期限
[ ] 父母可查看/删除儿童数据
### 交互安全
[ ] 禁止与未成年人的不当对话
[ ] 检测和阻止诱导性行为
[ ] 自残内容检测 + 热线提示
[ ] 不鼓励危险行为
### 合规文档
[ ] 儿童隐私政策(易懂语言)
[ ] 家长同意获取和记录
[ ] COPPA/本地法规合规声明
[ ] 定期合规审计