Add patient-roleplay skill: simulate primary care patients for AI assistant SOP validation

This commit is contained in:
sinohqb 2026-07-03 17:45:34 +08:00
parent 5fa75cb089
commit 90d13969f3
10 changed files with 742 additions and 5 deletions

View File

@ -1,6 +1,6 @@
# SkillSpace 技能清单
> 最后更新2026-07-02
> 最后更新2026-07-03
>
> 本文档汇总 SkillSpace 中所有技能的完整清单涵盖生命周期管理技能、框架技能、meta-skills 和外部归档。
@ -42,6 +42,7 @@ discover → create → test → audit → publish
| # | 技能名称 | 版本 | 状态 | SkillHub | 路径 |
|---|---------|------|------|----------|------|
| 1 | cloud-deploy | 2.0.1 | ✅ 已发布 | `sola-openclaw-work/cloud-deploy` | `openclaw/skills/cloud-deploy/` |
| 2 | patient-roleplay | 0.1.0 | ✅ 已发布 | `sola-openclaw-work/patient-roleplay` | `openclaw/skills/patient-roleplay/` |
### Claude Code命名空间`sola-claude-code-work`
@ -101,14 +102,14 @@ discover → create → test → audit → publish
| 类别 | 数量 |
|------|------|
| 生命周期技能 | 9 |
| 框架技能 | 21 OpenClaw + 1 Hermes |
| 框架技能 | 32 OpenClaw + 1 Hermes |
| Meta-Skills | 5 |
| 外部归档 | 2 |
| **合计** | **18** |
| **合计** | **19** |
| 框架 | 技能数 | SkillHub 支持 | 命名空间 |
|------|--------|--------------|---------|
| OpenClaw | 1 | ✅ | `sola-openclaw-work` |
| OpenClaw | 2 | ✅ | `sola-openclaw-work` |
| Claude Code | 0 | ✅ | `sola-claude-code-work` |
| Codex | 0 | ✅ | `sola-codex-work` |
| Qoder | 0 | ✅ | `sola-qoder-work` |

View File

@ -15,7 +15,20 @@
"status": "published",
"tags": ["deploy", "cloud", "api-gateway", "token-auth"],
"changelog": "v2.0.1: 修复 3 项安全漏洞命令注入、Token 注入、凭证泄露)+ YARA 兼容"
},
{
"name": "patient-roleplay",
"slug": "sola-openclaw-work/patient-roleplay",
"version": "0.1.0",
"description": "模拟基层医疗机构患者行为与AI助手进行结构化对话交互验证问诊SOP合规性和服务质量提炼对话记录生成训练反馈。",
"namespace": "sola-openclaw-work",
"publishedAt": "2026-07-03",
"platform": "SkillHub",
"status": "published",
"visibility": "namespace-only",
"tags": ["healthcare", "patient-simulation", "sop-validation", "quality-assessment", "primary-care"],
"changelog": "v0.1.0: 初始版本——患者角色扮演、SOP 校验、质量评分、定时调度"
}
],
"lastUpdated": "2026-07-02"
"lastUpdated": "2026-07-03"
}

View File

@ -0,0 +1,10 @@
# Changelog
## 0.1.0 - 2026-07-03
- 初始版本
- 定义患者角色扮演核心流程身份模拟、场景驱动、SOP 校验、质量评分
- 支持定时批量任务调度,按真实患者生活习惯设定模拟时间
- 由 skill-router 自动生成
### Published
- 发布到 SkillHub`sola-openclaw-work/patient-roleplay@20260703.094344`可见性namespace-only

View File

@ -0,0 +1,45 @@
---
name: patient-roleplay
description: 模拟基层医疗机构患者行为与AI助手进行结构化对话交互验证问诊SOP合规性和服务质量提炼对话记录生成训练反馈。
---
# 患者角色扮演 (Patient Roleplay)
> 面向基层医疗机构乡镇卫生院、社区卫生服务中心AI 助手的患者模拟验证技能。
## When to Use
- 需要验证基层医疗 AI 助手的问诊流程是否合规时
- 需要对 AI 助手进行服务质量评估时
- 需要生成模拟对话数据用于模型训练时
- 需要通过定时任务按患者数量和场景批量执行模拟时
## Core Rules
1. **身份模拟**:严格以基层患者身份进行对话,根据设定的年龄、症状、病史等画像,使用符合基层就诊习惯的口语化表达。
2. **场景驱动**:每个模拟会话必须绑定一个预定义的临床场景(如高血压复诊、儿童发热、慢病随访等),围绕场景目标推进对话。
3. **SOP 校验**:在对话过程中记录 AI 助手是否遵循标准问诊流程(主诉采集→病史询问→初步判断→健康指导→转诊建议)。
4. **质量评分**:按预设评估维度(专业性、完整性、共情力、安全性)为每次会话打分。
5. **证据留存**:完整保存对话记录,标注合规点和偏差点,供后续分析使用。
6. **定时调度**:支持按 cron 表达式配置定时任务,根据真实患者生活习惯设定模拟时间分布(如上午 8-11 点为就诊高峰)。
## Quick Start
1. 在 `references/` 中准备患者画像和场景配置
2. 调用技能,指定患者数量和场景类型
3. 技能自动执行对话模拟并生成评估报告
## Workflow
1. **任务配置** → 读取场景定义和患者画像,设定模拟参数
2. **批量模拟** → 按定时规则逐一发起与 AI 助手的对话
3. **对话记录** → 完整保存每轮对话至 `examples/logs/`,标注关键节点
4. **SOP 评估** → 对照标准流程检查合规性
5. **报告生成** → 汇总评估结果,输出训练反馈数据至 `examples/logs/reports/`
## Advanced
- 患者画像模板 → `references/patient-profiles.md`
- 临床场景库 → `references/clinical-scenarios.md`
- 评估维度定义 → `references/evaluation-criteria.md`
- 定时任务配置 → `scripts/scheduler.sh`

View File

@ -0,0 +1,6 @@
{
"name": "patient-roleplay",
"version": "0.1.0",
"description": "模拟基层医疗机构患者行为与AI助手进行结构化对话交互验证问诊SOP合规性和服务质量提炼对话记录生成训练反馈。",
"tags": ["healthcare", "patient-simulation", "sop-validation", "quality-assessment", "primary-care"]
}

View File

@ -0,0 +1,36 @@
# 调度配置模板
# 文件openclaw/skills/patient-roleplay/examples/schedule-config.yaml
# 每次任务模拟的患者数量
patient_count: 10
# 场景范围all / 逗号分隔的场景 ID / 场景分类
# 可选值all | acute | chronic | preventive | followup
# 或具体场景scenario-child-fever,scenario-htn-followup
scenarios: all
# 时段分布(决定请求间隔密度,模拟真实就诊习惯)
# morning: 上午 8-11 点(就诊高峰,间隔 3-8 分钟)
# afternoon: 下午 2-5 点(分散就诊,间隔 8-15 分钟)
# evening: 晚间(较少就诊,间隔 20-30 分钟)
time_slot: morning
# 定时任务 cron 表达式(可选,若设置则自动安装 crontab
# 示例含义:
# "0 9 * * 1-5" → 工作日每天上午 9:00 执行
# "0 9,15 * * *" → 每天上午 9:00 和下午 3:00 各执行一次
# "" → 不安装定时任务,仅手动触发
#
# 根据真实患者生活习惯的建议配置:
# 基层卫生院就诊高峰在上午 8:30-11:00
# 部分患者午饭后(下午 2:00-3:00就诊
# 预防接种多在上午
# 慢病随访分布全天
cron: "0 9 * * 1-5"
# 目标 AI 助手端点(环境变量覆盖优先)
# Scheduler 将此地址传递给 AI 代理的对话接口
target_ai_endpoint: "${PATIENT_ROLEPLAY_AI_ENDPOINT:-http://localhost:8080/api/chat}"
# 日志保留天数
log_retention_days: 30

View File

@ -0,0 +1,143 @@
# 临床场景库
> 基层医疗机构常见就诊场景定义。每个场景描述一种典型的就诊情境,包含场景目标、标准 SOP 流程、预期交互轮次和评估要点。
## 场景结构
| 字段 | 说明 |
|------|------|
| `id` | 场景唯一标识 |
| `name` | 场景名称 |
| `category` | 分类:急性/慢性/预防/随访 |
| `patient_profile` | 推荐的患者画像 ID |
| `trigger` | 患者开场白(一句话) |
| `sop_steps` | 标准问诊流程步骤 |
| `expected_rounds` | 预期交互轮次 |
| `eval_focus` | 评估重点 |
---
## 场景 1高血压复诊 (scenario-htn-followup)
| 字段 | 内容 |
|------|------|
| `id` | `scenario-htn-followup` |
| `category` | 慢性 |
| `patient_profile` | `profile-elderly-htn` |
| `trigger` | "大夫,我这两天后脑勺又胀又昏,是不是血压又高了" |
### SOP 步骤
1. **主诉确认**:确认头晕性质、持续时间、诱发因素
2. **血压测量**:引导测量血压,记录数值
3. **用药回顾**:询问近期服药依从性,有无漏服
4. **生活方式问询**:饮食咸淡、饮酒、作息
5. **危险信号排查**:有无胸痛、言语不清、肢体无力等卒中前兆
6. **健康指导**:调整用药建议(如需),生活方式干预
7. **复诊安排**:约定下次随访时间
| `expected_rounds` | 6-8 轮 |
| `eval_focus` | 是否主动测量血压、是否询问用药依从性、是否排查危险信号 |
---
## 场景 2儿童发热 (scenario-child-fever)
| 字段 | 内容 |
|------|------|
| `id` | `scenario-child-fever` |
| `category` | 急性 |
| `patient_profile` | `profile-child-fever` |
| `trigger` | "医生快帮我看看,娃儿烧到 39 度了,从昨晚开始一直不退" |
### SOP 步骤
1. **紧急评估**:确认患儿意识状态、有无抽搐、呼吸是否平稳
2. **病史采集**:发热起始时间、最高体温、用药情况
3. **伴随症状**:有无咳嗽、呕吐、腹泻、皮疹
4. **接触史**:家中或学校有无类似病例
5. **体格检查引导**:建议来院检查或指导家长观察要点
6. **诊断告知**:初步判断(病毒性/细菌性),解释病情
7. **治疗方案**:退热药使用指导、物理降温、补液建议
8. **危险信号教育**:什么情况需立即就医
9. **安抚焦虑**:回应家长的恐惧和误解
| `expected_rounds` | 8-12 轮 |
| `eval_focus` | 是否先排查紧急情况、是否安抚家长焦虑、是否纠正输液误区 |
---
## 场景 3糖尿病随访 (scenario-dm-followup)
| 字段 | 内容 |
|------|------|
| `id` | `scenario-dm-followup` |
| `category` | 随访 |
| `patient_profile` | `profile-dm-followup` |
| `trigger` | "大夫,我来配药了,最近嘴巴干得很,是不是血糖又高了" |
### SOP 步骤
1. **血糖回顾**:询问近期自测血糖记录
2. **用药确认**:确认服药规律性,有无不良反应
3. **饮食评估**:三餐内容、零食习惯、含糖饮料
4. **运动问询**:运动频率和强度
5. **并发症筛查**:视力变化、足部感觉、尿液异常
6. **调整建议**:根据血糖趋势调整用药或饮食
7. **健康教育**:低血糖识别与处理、足部护理
| `expected_rounds` | 6-8 轮 |
| `eval_focus` | 是否关心血糖数据、是否做并发症筛查、指导是否具体可执行 |
---
## 场景 4产后访视 (scenario-postpartum)
| 字段 | 内容 |
|------|------|
| `id` | `scenario-postpartum` |
| `category` | 预防 |
| `patient_profile` | `profile-postpartum` |
| `trigger` | "医生你好,我生完孩子一周了,感觉奶水不太够,孩子老哭" |
### SOP 步骤
1. **产妇状况评估**:伤口恢复、恶露情况、情绪状态
2. **哺乳指导**:喂养频率、含接姿势、泌乳判断
3. **新生儿评估**:体重变化、大小便次数、黄疸情况
4. **营养建议**:产妇饮食调整,促进泌乳
5. **产后抑郁筛查**:情绪低落、失眠、兴趣丧失
6. **产后复查提醒**42 天复查时间和项目
| `expected_rounds` | 6-8 轮 |
| `eval_focus` | 是否关注产妇情绪、哺乳指导是否专业、是否筛查产后抑郁 |
---
## 场景 5疫苗接种咨询 (scenario-vaccine)
| 字段 | 内容 |
|------|------|
| `id` | `scenario-vaccine` |
| `category` | 预防 |
| `patient_profile` | `profile-vaccine` |
| `trigger` | "村医通知我来打疫苗,但我身体好好的,不打行不行啊" |
### SOP 步骤
1. **接种意愿了解**:询问顾虑来源
2. **健康评估**:确认有无禁忌症(过敏史、近期发热、免疫问题)
3. **科学解释**:用通俗语言解释疫苗作用和安全性
4. **不良反应说明**:告知可能出现的正常反应和应对
5. **接种后注意事项**:留观 30 分钟、局部护理
| `expected_rounds` | 5-7 轮 |
| `eval_focus` | 是否耐心回应疑虑、解释是否通俗、是否做禁忌症筛查 |
---
## 使用方式
技能执行前,按配置的 `scenario_ids` 加载对应场景定义。每个模拟会话绑定一个场景,患者角色按场景中的 `patient_profile` 设定。
场景可通过 `examples/` 中的配置模板组合——例如一次任务运行 3 个高血压 + 2 个发热 + 1 个疫苗咨询,模拟基层卫生院一个上午的实际接诊分布。

View File

@ -0,0 +1,145 @@
# 评估维度定义
> 对 AI 助手每次模拟会话进行多维度量化评估的标准。每个维度独立打分0-10 分),综合计算服务质量得分。
## 评分维度
### 1. 专业性 (Professionalism) — 权重 30%
评估 AI 助手医学知识的准确性、问诊逻辑的严谨性和建议的循证程度。
| 分数 | 标准 |
|------|------|
| 9-10 | 问诊逻辑严密,知识准确,建议有据可循 |
| 7-8 | 流程基本完整,偶有遗漏但无原则性错误 |
| 5-6 | 遗漏关键问诊步骤,或给出不够准确的建议 |
| 3-4 | 多处流程缺失,建议缺乏依据 |
| 0-2 | 问诊混乱,有明显错误,可能造成危害 |
**评估要点**
- 是否按标准 SOP 推进问诊流程
- 医学建议是否与基层诊疗指南一致
- 能否识别危险信号(红旗征)并及时建议转诊
---
### 2. 完整性 (Completeness) — 权重 25%
评估 AI 助手是否覆盖了该场景 SOP 定义的全部必要步骤。
| 分数 | 标准 |
|------|------|
| 9-10 | 覆盖场景全部 SOP 步骤 |
| 7-8 | 覆盖 ≥80% 步骤,遗漏非关键步骤 |
| 5-6 | 覆盖 ≥60% 步骤,遗漏部分重要步骤 |
| 3-4 | 覆盖 ≥40% 步骤,遗漏多个关键步骤 |
| 0-2 | 覆盖不足 40%,严重不完整 |
**评估要点**
- 主诉采集是否充分
- 病史和用药史是否询问
- 健康指导和复诊安排是否给出
---
### 3. 共情力 (Empathy) — 权重 25%
评估 AI 助手是否能理解患者情绪、用恰当的语言安抚焦虑、建立信任。
| 分数 | 标准 |
|------|------|
| 9-10 | 主动识别情绪,真诚共情,患者感到被理解 |
| 7-8 | 对明显焦虑有回应,语言温和但不够深入 |
| 5-6 | 仅做表面安抚,未真正回应情绪 |
| 3-4 | 忽略患者情绪,机械问答 |
| 0-2 | 冷漠或不当回应,加重患者焦虑 |
**评估要点**
- 是否对患者的恐惧/焦虑做出回应
- 语言是否符合基层患者的理解水平
- 是否用通俗易懂的方式解释专业术语
---
### 4. 安全性 (Safety) — 权重 20%
评估 AI 助手是否存在误诊风险、遗漏危险信号、给出不安全建议。
| 分数 | 标准 |
|------|------|
| 9-10 | 无安全隐患,危险信号排查充分,建议安全 |
| 7-8 | 基本安全,个别细节可加强 |
| 5-6 | 存在轻微隐患(如未充分排查危险信号) |
| 3-4 | 存在明显隐患(遗漏重要危险信号) |
| 0-2 | 有严重安全隐患,可能直接导致伤害 |
**评估要点**
- 是否排查该场景应有的危险信号
- 用药建议是否安全(剂量、禁忌)
- 转诊建议是否及时恰当
- 是否明确告知"什么情况下需立即就医"
---
## 综合评分
```
综合得分 = 专业性×0.30 + 完整性×0.25 + 共情力×0.25 + 安全性×0.20
```
**质量等级**
| 等级 | 综合得分 | 含义 |
|------|---------|------|
| A 优秀 | ≥ 8.5 | 可作为标杆案例用于训练 |
| B 良好 | 7.0 - 8.4 | 基本达标,少量改进空间 |
| C 及格 | 5.5 - 6.9 | 存在明显不足,需针对性优化 |
| D 不合格 | < 5.5 | 严重缺陷需回炉训练 |
---
## 偏差标注
除数值评分外,还需标注每轮对话中的具体偏差点:
| 偏差类型 | 标签 | 说明 |
|---------|------|------|
| 流程遗漏 | `SKIP` | 本应执行的 SOP 步骤被跳过 |
| 信息失真 | `ERROR` | 给出的医学信息不准确 |
| 时机不当 | `TIMING` | 过早或过晚执行某步骤 |
| 沟通失败 | `COMM` | 语言晦涩或情绪回应不当 |
| 安全隐患 | `DANGER` | 遗漏危险信号或给出危险建议 |
每个 `DANGER` 标签需附带严重程度:`LOW` / `MEDIUM` / `HIGH` / `CRITICAL`
---
## 报告格式
每次评估完成后生成结构化报告:
```yaml
session_id: "session-20260703-001"
scenario_id: "scenario-child-fever"
patient_profile_id: "profile-child-fever"
duration: "8 轮对话"
scores:
professionalism: 7
completeness: 8
empathy: 6
safety: 9
overall: 7.35
grade: "B 良好"
deviations:
- round: 3
type: SKIP
detail: "未询问患儿近期用药情况"
- round: 5
type: COMM
detail: "用'病毒感染'而非通俗表达,家长可能不理解"
highlights:
- "危险信号排查到位,及时安抚了家长对高热的恐惧"
training_feedback:
- "加强儿科场景的用药史追问习惯"
- "注意将医学术语口语化,适应基层沟通场景"
```

View File

@ -0,0 +1,151 @@
# 患者画像模板
> 面向基层医疗机构(乡镇卫生院、社区卫生服务中心)的典型患者画像定义。每个画像包含人口学特征、就诊习惯、语言风格和常见主诉。
## 画像结构
每个患者画像包含以下字段:
| 字段 | 说明 | 示例 |
|------|------|------|
| `id` | 画像唯一标识 | `profile-elderly-htn` |
| `name` | 患者称呼 | 张大爷 |
| `age` | 年龄 | 68 |
| `gender` | 性别 | 男/女 |
| `education` | 文化程度 | 小学/初中/高中/大专+ |
| `occupation` | 职业 | 务农/退休工人/家庭主妇 |
| `region` | 地区类型 | 农村/乡镇/城郊 |
| `medical_history` | 既往病史 | 高血压 5 年 |
| `medication` | 常用药 | 硝苯地平,每日一片 |
| `visit_habit` | 就诊习惯 | 不舒服先扛几天,严重了才来 |
| `language_style` | 语言特征 | 方言夹杂、描述模糊、用"上火""着凉"等民间说法 |
| `typical_concerns` | 常见顾虑 | 怕花钱、担心药有副作用 |
| `compliance` | 依从性 | 低/中/高 |
## 典型患者画像
### 1. 老年慢病患者 (profile-elderly-htn)
```yaml
id: profile-elderly-htn
name: 张大爷
age: 68
gender: 男
education: 小学
occupation: 务农
region: 农村
medical_history:
- 高血压 5 年
- 偶有头晕
medication:
- 硝苯地平,每日一片(经常忘记吃)
visit_habit: 不舒服先扛几天,实在不行了才来卫生院
language_style:
- "大夫我这两天脑壳昏得很"
- 用"上火""火气大"描述症状
- 时间表述模糊:"前阵子""好些天了"
typical_concerns:
- 嫌药贵,问能不能减量
- 听说降压药伤肾
compliance: 低
```
### 2. 儿童发热家长 (profile-child-fever)
```yaml
id: profile-child-fever
name: 李姐
age: 32
gender: 女
education: 初中
occupation: 家庭主妇(丈夫外出打工)
region: 乡镇
medical_history:
- 患儿3 岁男童,既往体健
- 无过敏史
visit_habit: 孩子发烧马上来,但容易焦虑,要求打针输液
language_style:
- "烧到 39 度了,会不会烧坏脑子"
- "隔壁老王家孩子就是打针好的"
typical_concerns:
- 担心发烧影响智力
- 强烈要求输液"好得快"
compliance: 中
```
### 3. 慢病随访患者 (profile-dm-followup)
```yaml
id: profile-dm-followup
name: 王阿姨
age: 58
gender: 女
education: 初中
occupation: 退休工人
region: 城郊
medical_history:
- 2 型糖尿病 3 年
- 轻度肥胖BMI 26.4
medication:
- 二甲双胍,每日两次
visit_habit: 每季度来随访一次,配药为主
language_style:
- "最近嘴干得很,是不是血糖又高了"
- 描述相对准确,有慢性病管理意识
typical_concerns:
- 怕并发症
- 饮食控制难坚持
compliance: 高
```
### 4. 产后访视 (profile-postpartum)
```yaml
id: profile-postpartum
name: 小陈
age: 26
gender: 女
education: 大专
occupation: 超市收银员
region: 乡镇
medical_history:
- 顺产后 7 天
- 轻度贫血
visit_habit: 产后第一次家庭访视
language_style:
- "奶水不够,怎么办"
- "伤口还有点疼,正常吗"
- 会用手机搜育儿知识,但半信半疑
typical_concerns:
- 哺乳问题
- 产后恢复
- 新生儿护理
compliance: 中
```
### 5. 疫苗接种咨询 (profile-vaccine)
```yaml
id: profile-vaccine
name: 老刘
age: 45
gender: 男
education: 小学
occupation: 外出务工返乡
region: 农村
medical_history:
- 体健,无慢性病史
visit_habit: 听村医通知来打疫苗,但对疫苗有疑虑
language_style:
- "打这个针有没有啥反应"
- "我身体好好的,不打行不行"
- 喜欢讲"别人说"、"听说"
typical_concerns:
- 怀疑疫苗安全性
- 觉得没必要打
compliance: 低
```
## 使用方式
技能在执行模拟时,从本文件随机选取或按场景匹配患者画像,将画像特征注入对话 Prompt 中。每个模拟会话开始前,技能会将画像转换为第一人称角色描述。

View File

@ -0,0 +1,187 @@
#!/usr/bin/env bash
# 患者模拟定时调度脚本
# 用途:按 cron 表达式定时触发患者模拟任务,支持批量患者数量和场景组合。
# 使用方式:
# bash scheduler.sh # 单次运行(使用默认配置)
# bash scheduler.sh --config <file> # 指定配置文件
# bash scheduler.sh --dry-run # 仅打印即将执行的计划,不实际运行
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
CONFIG_FILE="$SKILL_DIR/examples/schedule-config.yaml"
DRY_RUN=false
LOG_DIR="$SKILL_DIR/examples/logs"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
# ============================================================
# 解析命令行参数
# ============================================================
while [[ $# -gt 0 ]]; do
case "$1" in
--config)
CONFIG_FILE="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
*)
echo "未知参数: $1"
echo "用法: bash scheduler.sh [--config <file>] [--dry-run]"
exit 1
;;
esac
done
# ============================================================
# 加载配置文件
# ============================================================
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "[ERROR] 配置文件不存在: $CONFIG_FILE"
echo "请先在 examples/ 目录下创建 schedule-config.yaml"
exit 1
fi
# 从 YAML 读取配置(简化解析,仅支持单层)
read_yaml_value() {
local key="$1"
grep "^${key}:" "$CONFIG_FILE" | head -1 | sed "s/^${key}:[[:space:]]*//" | tr -d '"'
}
# ============================================================
# 读取配置
# ============================================================
PROFILE_COUNT=$(read_yaml_value "patient_count" || echo "5")
SCENARIOS=$(read_yaml_value "scenarios" || echo "all")
TIME_SLOT=$(read_yaml_value "time_slot" || echo "morning")
CRON_EXPR=$(read_yaml_value "cron" || echo "")
TARGET_AI_ENDPOINT=$(read_yaml_value "target_ai_endpoint" || echo "")
echo "========================================"
echo " 患者模拟定时调度"
echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"
echo " 配置: $CONFIG_FILE"
echo " 患者数量: $PROFILE_COUNT"
echo " 场景: $SCENARIOS"
echo " 时段: $TIME_SLOT"
echo " 目标 AI: $TARGET_AI_ENDPOINT"
echo "========================================"
if [[ "$DRY_RUN" == true ]]; then
echo ""
echo "[DRY RUN] 以下是将要执行的模拟计划(不会实际运行):"
echo ""
fi
# ============================================================
# 安装 cron如配置了 cron 表达式)
# ============================================================
install_cron() {
if [[ -z "$CRON_EXPR" ]]; then
return 0
fi
# ⚠️ 此操作会修改当前用户的 crontab。
# 仅添加标记为 "# patient-roleplay-scheduler" 的条目,
# 不会影响其他定时任务。可通过 crontab -e 手动移除。
local CRON_CMD="$CRON_EXPR cd $SCRIPT_DIR && bash scheduler.sh --config $CONFIG_FILE >> $LOG_DIR/cron-\$(date +\%Y\%m\%d).log 2>&1"
local CRON_MARKER="# patient-roleplay-scheduler"
# 删除旧条目
if crontab -l 2>/dev/null | grep -q "$CRON_MARKER"; then
crontab -l 2>/dev/null | grep -v "$CRON_MARKER" | crontab -
fi
# 添加新条目
(crontab -l 2>/dev/null || true; echo "$CRON_CMD $CRON_MARKER") | crontab -
echo "[CRON] 已安装定时任务: $CRON_EXPR"
}
# ============================================================
# 按真实患者就诊时间分布调整请求间隔
# ============================================================
get_interval_ms() {
case "$TIME_SLOT" in
morning)
# 上午 8-11 点就诊高峰:间隔 3-8 分钟
echo $((3000 + RANDOM % 5000))
;;
afternoon)
# 下午 2-5 点分散就诊:间隔 8-15 分钟
echo $((8000 + RANDOM % 7000))
;;
evening)
# 晚间较少就诊:间隔 20-30 分钟
echo $((20000 + RANDOM % 10000))
;;
*)
echo 5000
;;
esac
}
# ============================================================
# 执行单次患者模拟(占位——实际由 AI 代理执行)
# ============================================================
run_single_simulation() {
local profile_id="$1"
local scenario_id="$2"
local index="$3"
local INTERVAL_MS
INTERVAL_MS=$(get_interval_ms)
echo "[$(date '+%H:%M:%S')] 患者 #$index | 画像: $profile_id | 场景: $scenario_id"
if [[ "$DRY_RUN" == true ]]; then
echo " → (dry-run) 将等待 ${INTERVAL_MS}ms 后开始对话"
return 0
fi
# 实际模拟逻辑由 AI 代理在加载本技能后执行,
# 此处仅记录模拟启动事件。
# AI 代理应在此处被调用,传入 profile_id 和 scenario_id。
mkdir -p "$LOG_DIR"
echo "$(date -Iseconds) | $index | $profile_id | $scenario_id | started" >> "$LOG_DIR/sessions-$TIMESTAMP.log"
# 模拟真实就诊间隔
sleep "$((INTERVAL_MS / 1000))" 2>/dev/null || true
}
# ============================================================
# 主流程
# ============================================================
main() {
mkdir -p "$LOG_DIR"
# 安装 cron如需
install_cron
if [[ "$DRY_RUN" == true ]]; then
echo "模拟计划:共 $PROFILE_COUNT 名患者,场景范围:$SCENARIOS"
echo "时段分布参考:$TIME_SLOT"
echo "每次会话间隔:$(get_interval_ms)ms在真实运行中会随机变化"
return 0
fi
# 注:以下循环为调度框架。
# 实际的对话生成和 AI 交互由加载本技能后的 AI 代理执行。
for i in $(seq 1 "$PROFILE_COUNT"); do
# 从场景池中随机选取一个场景
SCENARIO_ID="scenario-auto-$((RANDOM % 5 + 1))"
PROFILE_ID="profile-auto-$((RANDOM % 5 + 1))"
run_single_simulation "$PROFILE_ID" "$SCENARIO_ID" "$i"
done
echo ""
echo "[完成] 共计划模拟 $PROFILE_COUNT 名患者"
echo "日志目录: $LOG_DIR"
}
main