feat: 儿童心理陪伴筛查插件初始版本

- 核心 PsychoScreener 模块,支持 MiniMax API 调用
- 8 种心理问题类别检测(霸凌、抑郁、焦虑、家庭矛盾等)
- ScreeningResult 数据模型,含类别/严重程度/建议
- 单元测试 12 个(含参数化测试,覆盖 7 个虚构场景)
- build_response_prefix() 支持检测后注入前缀标记
- pyproject.toml + .gitignore 完整项目脚手架
main
Sileya 2026-04-04 17:04:04 +08:00
commit d5e64f40c4
8 changed files with 863 additions and 0 deletions

15
.env.example Normal file
View File

@ -0,0 +1,15 @@
# 儿童心理陪伴玩偶 - 环境变量配置
# 复制此文件为 .env 并填入实际值
# MiniMax API Key必填
# 获取地址https://platform.minimaxi.com/
MINIMAX_API_KEY=your-api-key-here
# MiniMax 模型(可选,默认 MiniMax-M2.5
MINIMAX_MODEL=MiniMax-M2.5
# MiniMax API 地址(可选,默认使用官方接口)
MINIMAX_BASE_URL=https://api.minimaxi.com/v1/text/chatcompletion_v2
# 日志级别
LOG_LEVEL=INFO

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
# Python
__pycache__/
*.py[cod]
*.so
.venv/
venv/
.env
# Test
.pytest_cache/
.coverage
htmlcov/
# IDE
.idea/
.vscode/
*.swp
# Build
*.egg-info/
dist/
build/
# OS
.DS_Store

107
README.md Normal file
View File

@ -0,0 +1,107 @@
# 儿童心理陪伴玩偶
基于小智AI生态的儿童心理筛查插件通过分析儿童与玩偶的对话内容
识别潜在的心理问题(如霸凌、抑郁情绪、焦虑、家庭矛盾等),
为家长提供早期预警。
## 项目结构
```
child-psycho-companion/
├── src/
│ └── psycho_screener/ # 核心筛查模块
│ ├── __init__.py
│ └── screener.py # 筛查器实现
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ └── test_screener.py # 单元测试
├── .env.example # 环境变量模板
├── pyproject.toml
└── README.md
```
## 快速开始
### 1. 安装
```bash
cd child-psycho-companion
pip install -e .
```
### 2. 配置 API Key
```bash
export MINIMAX_API_KEY=your-api-key-here
```
### 3. 使用示例
```python
from psycho_screener import PsychoScreener
screener = PsychoScreener(api_key="your-api-key")
# 对儿童对话进行筛查
context = """
孩子:今天在学校,小明又打我了,我好害怕。
孩子:他说如果我告诉老师就会打我。
"""
result = screener.screen(context)
if result.detected:
print(f"检测到问题:{result.summary}")
prefix = screener.build_response_prefix(result)
print(f"响应前缀:{prefix}")
```
### 4. 运行测试
```bash
# 安装测试依赖
pip install -e ".[dev]"
# 运行单元测试Mock 模式,不调用真实 API
pytest tests/test_screener.py -v -m unit
# 运行集成测试(需要真实 API key
export MINIMAX_API_KEY=your-key
pytest tests/test_screener.py -v -m integration
```
## 核心流程
```
儿童语音 → 小智AI (STT) → 对话上下文
心理筛查器 (MiniMax API)
ScreeningResult {detected, category, severity}
┌───────────┴───────────┐
detected=True detected=False
↓ ↓
注入前缀标记 原样返回
"已发现特定心理问题:..."
```
## 检测类别
| 类别 | 描述 | 严重程度 |
|------|------|---------|
| bullying | 霸凌/同伴冲突 | low-high |
| depression | 抑郁情绪 | medium-high |
| anxiety | 焦虑/恐惧 | low-medium |
| family_conflict | 家庭矛盾 | medium-high |
| self_esteem | 自卑/自我否定 | low-medium |
| trauma | 创伤事件 | medium-high |
| social_isolation | 社交孤立 | medium-high |
| other | 其他心理需求 | - |
## 下一步
- [ ] 接入 xinnan-tech/xiaozhi-esp32-server MCP 接入点
- [ ] 构建案例库系统
- [ ] 开发咨询师终端
- [ ] 家长端报告界面

31
pyproject.toml Normal file
View File

@ -0,0 +1,31 @@
[project]
name = "child-psycho-companion"
version = "0.1.0"
description = "儿童心理陪伴玩偶 - 对话心理筛查插件"
requires-python = ">=3.10"
dependencies = [
"requests>=2.31.0",
"pydantic>=2.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"pytest-mock>=3.14",
"requests-mock>=1.12",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = [
"unit: Unit tests with mocked API calls",
"integration: Integration tests requiring real API calls",
]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.pytest.ini_options]
testpaths = ["tests"]

View File

@ -0,0 +1,9 @@
"""
儿童心理陪伴 - 核心筛查模块
功能对儿童对话上下文进行心理问题筛查检测潜在心理需求或问题
目标年龄段3-8
"""
from .screener import PsychoScreener, ScreeningResult
__all__ = ["PsychoScreener", "ScreeningResult"]

View File

@ -0,0 +1,219 @@
"""
儿童心理陪伴 - 筛查器
基于 MiniMax API对儿童对话进行心理问题筛查
"""
from __future__ import annotations
import os
import json
import requests
from typing import Literal
from pydantic import BaseModel, Field
# ============================================================================
# 数据模型
# ============================================================================
class ConcernCategory(str):
"""心理问题类别"""
NONE = "none"
BULLYING = "bullying" # 校园霸凌/同伴冲突
DEPRESSION = "depression" # 抑郁情绪
ANXIETY = "anxiety" # 焦虑/恐惧
FAMILY_CONFLICT = "family_conflict" # 家庭矛盾
SELF_ESTEEM = "self_esteem" # 自卑/自我否定
TRAUMA = "trauma" # 创伤事件
SOCIAL_ISOLATION = "social_isolation" # 社交孤立
OTHER = "other" # 其他
class ScreeningResult(BaseModel):
"""筛查结果"""
detected: bool = Field(description="是否检测到心理问题")
category: str = Field(default=ConcernCategory.NONE, description="问题类别")
severity: Literal["none", "low", "medium", "high"] = Field(
default="none", description="严重程度"
)
summary: str = Field(default="", description="简要描述检测到的问题")
suggestion: str = Field(default="", description="建议行动")
raw_response: str = Field(default="", description="模型原始响应(调试用)")
# ============================================================================
# 筛查系统提示词
# ============================================================================
SYSTEM_PROMPT = """你是一个专业的儿童心理咨询师助手专注于分析3-8岁儿童的对话内容识别潜在的心理需求或问题。
## 你的任务
分析给定的儿童对话上下文判断是否存在以下心理问题类别
1. **bullying** - 霸凌/同伴冲突孩子表达被欺负被嘲笑被孤立被人威胁等
2. **depression** - 抑郁情绪孩子表达悲伤绝望无助对事物失去兴趣提到"不想活了"
3. **anxiety** - 焦虑/恐惧孩子表达担心害怕做噩梦回避某些情境等
4. **family_conflict** - 家庭矛盾孩子表达父母争吵离婚担心被忽视被严厉惩罚等
5. **self_esteem** - 自卑/自我否定孩子表达"我不行""没人喜欢我""我太笨了"
6. **trauma** - 创伤事件孩子描述意外事故暴力事件亲人离世等创伤性经历
7. **social_isolation** - 社交孤立孩子表达没有朋友被排斥孤独感等
8. **other** - 其他值得关注的心理需求
## 输出格式
请严格按以下JSON格式返回不要添加任何额外内容
{
"detected": true/false,
"category": "具体类别",
"severity": "none/low/medium/high",
"summary": "一句话描述检测到的问题",
"suggestion": "建议的应对方式简短1-2句话"
}
## 判断标准
- **low**: 轻微迹象需要关注但无需立即介入
- **medium**: 中度迹象建议与家长沟通
- **high**: 严重迹象需要专业干预
如果对话内容完全正常没有任何心理问题迹象返回
{
"detected": false,
"category": "none",
"severity": "none",
"summary": "未检测到心理问题",
"suggestion": ""
}
注意
- 只关注确实存在问题的迹象不要过度解读
- 儿童的语言表达可能不精确需要结合上下文判断
- 正常的情绪表达偶尔哭发脾气不构成问题"""
# ============================================================================
# 筛查器
# ============================================================================
class PsychoScreener:
"""
儿童心理问题筛查器
使用方法
screener = PsychoScreener(api_key="your-api-key")
result = screener.screen("今天小明打我了,我很伤心")
if result.detected:
print(f"检测到问题:{result.summary}")
"""
def __init__(
self,
api_key: str | None = None,
model: str = "MiniMax-M2.5",
base_url: str = "https://api.minimaxi.com/v1/text/chatcompletion_v2",
):
self.api_key = api_key or os.environ.get("MINIMAX_API_KEY", "")
self.model = model
self.base_url = base_url
if not self.api_key:
raise ValueError(
"MiniMax API key is required. "
"Set MINIMAX_API_KEY env var or pass api_key parameter."
)
def _call_minimax(self, messages: list[dict]) -> str:
"""调用 MiniMax API"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
}
payload = {
"model": self.model,
"messages": messages,
}
response = requests.post(
self.base_url,
headers=headers,
json=payload,
timeout=30,
)
response.raise_for_status()
data = response.json()
# 兼容不同返回格式
if "choices" in data:
return data["choices"][0]["message"]["content"]
elif "output" in data:
return data["output"]
return str(data)
def screen(self, context: str) -> ScreeningResult:
"""
对给定的对话上下文进行心理问题筛查
Args:
context: 儿童的对话上下文可以是多轮对话的汇总文本
Returns:
ScreeningResult: 包含检测结果的数据模型
"""
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"请分析以下儿童对话内容:\n\n{context}"},
]
try:
raw_response = self._call_minimax(messages)
except Exception as e:
return ScreeningResult(
detected=False,
category=ConcernCategory.OTHER,
severity="none",
summary=f"API调用失败: {str(e)}",
suggestion="",
raw_response=str(e),
)
# 尝试解析 JSON
try:
# 提取 JSON可能模型返回带有 markdown 代码块)
content = raw_response.strip()
if content.startswith("```"):
lines = content.split("\n")
content = "\n".join(lines[1:-1]) # 去掉 ```json 和 ```
parsed = json.loads(content)
return ScreeningResult(
detected=parsed.get("detected", False),
category=parsed.get("category", ConcernCategory.NONE),
severity=parsed.get("severity", "none"),
summary=parsed.get("summary", ""),
suggestion=parsed.get("suggestion", ""),
raw_response=raw_response,
)
except json.JSONDecodeError:
# 无法解析 JSON返回原始内容
return ScreeningResult(
detected=False,
category=ConcernCategory.OTHER,
severity="none",
summary="无法解析模型响应",
suggestion="",
raw_response=raw_response,
)
def build_response_prefix(self, result: ScreeningResult) -> str:
"""
根据筛查结果构建响应前缀
Args:
result: 筛查结果
Returns:
str: 如果检测到问题返回前缀字符串否则返回空字符串
"""
if not result.detected:
return ""
return f"【已发现特定心理问题】类别:{result.category},严重程度:{result.severity},描述:{result.summary}"

1
tests/conftest.py Normal file
View File

@ -0,0 +1 @@
# Test configuration for pytest

456
tests/test_screener.py Normal file
View File

@ -0,0 +1,456 @@
"""
单元测试 - 儿童心理筛查器
测试场景使用虚构的儿童对话上下文验证筛查函数能否正确识别并标注心理问题
运行方式
pytest tests/test_screener.py -v
"""
import pytest
import json
from unittest.mock import patch, MagicMock
from psycho_screener.screener import (
PsychoScreener,
ScreeningResult,
ConcernCategory,
)
# ============================================================================
# Mock API 响应(用于测试)
# ============================================================================
MOCK_RESPONSES = {
# 场景1霸凌/同伴冲突
"bullying": json.dumps({
"detected": True,
"category": "bullying",
"severity": "medium",
"summary": "孩子描述被同学欺负、被嘲笑,感到伤心和无助",
"suggestion": "建议家长与孩子耐心沟通,了解具体情况,并与学校老师联系"
}),
# 场景2抑郁情绪
"depression": json.dumps({
"detected": True,
"category": "depression",
"severity": "high",
"summary": "孩子表达对生活失去兴趣、经常哭泣、觉得自己没有价值",
"suggestion": "高度建议寻求专业儿童心理咨询师帮助,密切关注孩子的安全"
}),
# 场景3焦虑/恐惧
"anxiety": json.dumps({
"detected": True,
"category": "anxiety",
"severity": "low",
"summary": "孩子表达对即将到来的考试感到紧张,有些担心",
"suggestion": "可以通过游戏和放松训练帮助孩子缓解焦虑情绪"
}),
# 场景4正常对话无问题
"normal": json.dumps({
"detected": False,
"category": "none",
"severity": "none",
"summary": "未检测到心理问题",
"suggestion": ""
}),
# 场景5家庭矛盾
"family_conflict": json.dumps({
"detected": True,
"category": "family_conflict",
"severity": "high",
"summary": "孩子描述父母经常争吵、提到害怕父母离婚",
"suggestion": "建议家长注意家庭氛围对孩子的影响,考虑家庭咨询"
}),
# 场景6自卑/自我否定
"self_esteem": json.dumps({
"detected": True,
"category": "self_esteem",
"severity": "medium",
"summary": "孩子反复说自己很笨、什么都不如别人、不值得被喜欢",
"suggestion": "建议多给予孩子正面鼓励和肯定,避免过度批评"
}),
# 场景7社交孤立
"social_isolation": json.dumps({
"detected": True,
"category": "social_isolation",
"severity": "medium",
"summary": "孩子表达在学校没有朋友、午餐时间独自一人、感到孤独",
"suggestion": "建议帮助孩子学习社交技巧,与学校合作创造更多交友机会"
}),
}
# ============================================================================
# 测试用例:虚构儿童对话上下文
# ============================================================================
TEST_CASES = [
# ---- 霸凌/同伴冲突 ----
{
"case_id": "bullying_01",
"scenario": "同伴冲突",
"context": (
"孩子:今天在学校,小明又打我了,他抢了我的玩具还不让我告诉老师,"
"他说如果我告诉老师就会打我。我很害怕,我现在不想去学校了。\n"
"孩子:每次下课我都躲起来,因为我怕再被他欺负。\n"
),
"expected_detected": True,
"expected_category": "bullying",
"expected_severity_min": "medium", # minimum: at least medium
},
# ---- 抑郁情绪 ----
{
"case_id": "depression_01",
"scenario": "抑郁情绪",
"context": (
"孩子:最近我总是觉得很累,什么都不想做,连我最喜欢的动画片都不想看了。\n"
"孩子:我觉得我是一个很糟糕的人,没有人喜欢我。\n"
"孩子:有时候我想,要是我不在了就好了。\n"
),
"expected_detected": True,
"expected_category": "depression",
"expected_severity_min": "high",
},
# ---- 焦虑/恐惧 ----
{
"case_id": "anxiety_01",
"scenario": "分离焦虑",
"context": (
"孩子:明天妈妈要送我上幼儿园,我好害怕,我不想和妈妈分开。\n"
"孩子:我担心在幼儿园里会做噩梦,害怕一个人睡觉。\n"
),
"expected_detected": True,
"expected_category": "anxiety",
"expected_severity_min": "low",
},
# ---- 正常对话 ----
{
"case_id": "normal_01",
"scenario": "正常对话",
"context": (
"孩子:今天我画了一幅画,是一只大恐龙!\n"
"孩子:晚上吃的是我最喜欢的红烧肉,好开心呀!\n"
"孩子:明天我想和好朋友一起去公园玩。\n"
),
"expected_detected": False,
"expected_category": "none",
"expected_severity_min": "none",
},
# ---- 家庭矛盾 ----
{
"case_id": "family_conflict_01",
"scenario": "家庭矛盾",
"context": (
"孩子:昨天晚上爸爸妈妈又吵架了,吵得很凶,妈妈哭了。\n"
"孩子:我很害怕,怕他们会离婚。\n"
"孩子:我觉得是我的错,是因为我表现不好他们才吵架的。\n"
),
"expected_detected": True,
"expected_category": "family_conflict",
"expected_severity_min": "high",
},
# ---- 自卑/自我否定 ----
{
"case_id": "self_esteem_01",
"scenario": "自卑/自我否定",
"context": (
"孩子:今天老师表扬了小红但是没有表扬我,我就是个笨蛋,什么都做不好。\n"
"孩子:班上的同学都不喜欢我,没有人想和我坐同桌。\n"
"孩子:我什么都学不会,我好笨啊。\n"
),
"expected_detected": True,
"expected_category": "self_esteem",
"expected_severity_min": "medium",
},
# ---- 社交孤立 ----
{
"case_id": "social_isolation_01",
"scenario": "社交孤立",
"context": (
"孩子:今天课间的时候我一个人蹲在角落,没有人来和我玩。\n"
"孩子:同学们都有自己的朋友,只有我是一个人。\n"
"孩子:我不想去学校了,那里好孤单。\n"
),
"expected_detected": True,
"expected_category": "social_isolation",
"expected_severity_min": "medium",
},
]
# ============================================================================
# Fixtures
# ============================================================================
@pytest.fixture
def api_key():
"""测试用 API key不会被真实调用"""
return "test-minimax-api-key-12345"
@pytest.fixture
def screener(api_key):
"""创建筛查器实例"""
return PsychoScreener(api_key=api_key)
# ============================================================================
# 测试:真实调用 MiniMax API需要有效的 API key
# ============================================================================
@pytest.mark.integration
class TestPsychoScreenerIntegration:
"""集成测试:真实调用 MiniMax API需设置 MINIMAX_API_KEY"""
@pytest.fixture(autouse=True)
def check_api_key(self):
api_key = os.environ.get("MINIMAX_API_KEY", "")
if not api_key:
pytest.skip("MINIMAX_API_KEY not set, skipping integration test")
def test_screen_bullying(self):
api_key = os.environ.get("MINIMAX_API_KEY")
screener = PsychoScreener(api_key=api_key)
context = TEST_CASES[0]["context"]
result = screener.screen(context)
print(f"\n[integration] bullying result: {result.model_dump_json(indent=2)}")
assert result.detected is True
assert result.category == "bullying"
def test_screen_normal(self):
api_key = os.environ.get("MINIMAX_API_KEY")
screener = PsychoScreener(api_key=api_key)
context = TEST_CASES[3]["context"]
result = screener.screen(context)
print(f"\n[integration] normal result: {result.model_dump_json(indent=2)}")
assert result.detected is False
# ============================================================================
# 测试Mock 测试(不真实调用 API
# ============================================================================
@pytest.mark.unit
class TestPsychoScreenerUnit:
"""单元测试:使用 Mock API 响应"""
def _mock_api_call(self, case_id: str) -> MagicMock:
"""根据 case_id 返回对应的 mock 响应"""
# 从 case_id 提取场景 key
scenario_map = {
"bullying": "bullying",
"depression": "depression",
"anxiety": "anxiety",
"normal": "normal",
"family_conflict": "family_conflict",
"self_esteem": "self_esteem",
"social_isolation": "social_isolation",
}
for key, scenario in scenario_map.items():
if key in case_id:
mock_resp = MagicMock()
mock_resp.raise_for_status = MagicMock()
mock_resp.json.return_value = {
"choices": [{"message": {"content": MOCK_RESPONSES[scenario]}}]
}
return mock_resp
# 默认返回 normal
mock_resp = MagicMock()
mock_resp.raise_for_status = MagicMock()
mock_resp.json.return_value = {
"choices": [{"message": {"content": MOCK_RESPONSES["normal"]}}]
}
return mock_resp
@pytest.mark.parametrize("test_case", TEST_CASES, ids=lambda tc: tc["case_id"])
def test_screen_cases(self, api_key, test_case, requests_mock):
"""参数化测试所有场景"""
case_id = test_case["case_id"]
# Mock HTTP POST
requests_mock.post(
"https://api.minimaxi.com/v1/text/chatcompletion_v2",
json=self._mock_api_call(case_id).json(),
)
screener = PsychoScreener(api_key=api_key)
result = screener.screen(test_case["context"])
# 打印测试结果(方便调试)
print(f"\n[test] {case_id} ({test_case['scenario']})")
print(f" detected={result.detected}, category={result.category}, severity={result.severity}")
print(f" summary={result.summary}")
# 验证检测结果
assert result.detected == test_case["expected_detected"], \
f"[{case_id}] 检测结果不符expected {test_case['expected_detected']}, got {result.detected}"
if test_case["expected_detected"]:
assert result.category == test_case["expected_category"], \
f"[{case_id}] 类别不符expected {test_case['expected_category']}, got {result.category}"
# 验证严重程度(使用顺序比较)
severity_order = ["none", "low", "medium", "high"]
min_idx = severity_order.index(test_case["expected_severity_min"])
result_idx = severity_order.index(result.severity)
assert result_idx >= min_idx, \
f"[{case_id}] 严重程度不足expected >= {test_case['expected_severity_min']}, got {result.severity}"
def test_build_response_prefix_detected(self, api_key):
"""测试:检测到问题时生成前缀"""
screener = PsychoScreener(api_key=api_key)
result = ScreeningResult(
detected=True,
category="bullying",
severity="medium",
summary="孩子描述被同学欺负",
suggestion="建议与家长沟通",
raw_response="",
)
prefix = screener.build_response_prefix(result)
print(f"\nprefix: {prefix}")
assert "已发现特定心理问题" in prefix
assert "bullying" in prefix
assert "medium" in prefix
def test_build_response_prefix_not_detected(self, api_key):
"""测试:未检测到问题时返回空前缀"""
screener = PsychoScreener(api_key=api_key)
result = ScreeningResult(
detected=False,
category="none",
severity="none",
summary="未检测到心理问题",
suggestion="",
raw_response="",
)
prefix = screener.build_response_prefix(result)
assert prefix == ""
def test_json_parse_error_handling(self, api_key, requests_mock):
"""测试:模型返回非 JSON 时优雅处理"""
requests_mock.post(
"https://api.minimaxi.com/v1/text/chatcompletion_v2",
text="This is not JSON response",
)
screener = PsychoScreener(api_key=api_key)
result = screener.screen("some context")
# 应该优雅降级,不抛出异常
assert result.detected is False
assert "API调用失败" in result.summary
# ============================================================================
# 测试:数据结构验证
# ============================================================================
@pytest.mark.unit
class TestScreeningResultModel:
"""测试 ScreeningResult 数据模型"""
def test_screening_result_valid(self):
"""测试有效数据"""
result = ScreeningResult(
detected=True,
category="bullying",
severity="high",
summary="test",
suggestion="test",
raw_response="test",
)
assert result.detected is True
assert result.category == "bullying"
def test_screening_result_defaults(self):
"""测试默认值"""
result = ScreeningResult(detected=False)
assert result.detected is False
assert result.category == "none"
assert result.severity == "none"
assert result.summary == ""
# ============================================================================
# 测试集成小智AI流程
# ============================================================================
@pytest.mark.integration
class TestXiaozhiIntegration:
"""
测试与小智AI的集成流程
假设 xiaozhi-esp32-server 返回的对话上下文经过本筛查器
验证端到端的处理流程
"""
def test_full_flow_with_bullying(self):
"""
模拟完整流程
1. 孩子说了一段可能被霸凌的话
2. 筛查器识别出问题
3. 原有回复被加上前缀
"""
# 模拟 xiaozhi 返回的原始回复
original_response = "不要难过的小朋友,每个人都值得被友好对待哦。"
# 这里需要真实 API key
api_key = os.environ.get("MINIMAX_API_KEY", "")
if not api_key:
pytest.skip("MINIMAX_API_KEY not set")
screener = PsychoScreener(api_key=api_key)
context = (
"孩子:今天小朋友又欺负我了,把我推倒在地上,还骂我。\n"
"孩子:我觉得好委屈,为什么他们要这样对我?"
)
# 步骤1筛查
screening_result = screener.screen(context)
print(f"\n[flow] screening result: {screening_result.model_dump_json(indent=2)}")
# 步骤2构建前缀
prefix = screener.build_response_prefix(screening_result)
# 步骤3覆盖原有回复
if prefix:
final_response = f"{prefix}\n\n{original_response}"
else:
final_response = original_response
print(f"\n[flow] final response:\n{final_response}")
# 验证前缀存在
if screening_result.detected:
assert "已发现特定心理问题" in final_response
else:
assert "已发现特定心理问题" not in final_response
import os # for integration tests