feat: 将成长档案调整为近期实修回顾
This commit is contained in:
@@ -37,7 +37,15 @@ def test_agent_debug_can_simulate_user_growth_profile_context():
|
||||
status=1,
|
||||
)
|
||||
)
|
||||
db.add(UserGrowthProfile(user_id=1, profile_text="用户在表达障碍主题上反复出现身体紧绷。"))
|
||||
db.add(
|
||||
UserGrowthProfile(
|
||||
user_id=1,
|
||||
schema_version=2,
|
||||
recent_review="最近谈到表达时不知道怎么回到当下。",
|
||||
current_focus="表达时先看见当下",
|
||||
profile_text="旧版画像不得注入",
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
|
||||
result = asyncio.run(
|
||||
@@ -53,10 +61,11 @@ def test_agent_debug_can_simulate_user_growth_profile_context():
|
||||
)
|
||||
|
||||
rendered = "\n".join(item["content"] for item in result.messages)
|
||||
assert "[长期成长档案]" in rendered
|
||||
assert "表达障碍" in rendered
|
||||
assert "[近期实修回顾]" in rendered
|
||||
assert "表达时先看见当下" in rendered
|
||||
assert "旧版画像不得注入" not in rendered
|
||||
assert result.tool_trace[0]["tool"] == "load_debug_user_context"
|
||||
assert result.tool_trace[0]["response"]["growthProfileUsed"] is True
|
||||
assert result.tool_trace[0]["response"]["recentPracticeReviewUsed"] is True
|
||||
assert "[当前产品权益]" in rendered
|
||||
|
||||
|
||||
@@ -88,7 +97,13 @@ def test_agent_debug_loads_selected_topic_history_summary_and_permissions():
|
||||
allow_share_draft=0,
|
||||
status=1,
|
||||
),
|
||||
UserGrowthProfile(user_id=1, profile_text="用户在表达时容易身体紧绷。"),
|
||||
UserGrowthProfile(
|
||||
user_id=1,
|
||||
schema_version=2,
|
||||
recent_review="最近谈到面对领导时不敢表达。",
|
||||
current_focus="面对领导时的当下表达",
|
||||
profile_text="",
|
||||
),
|
||||
ChatMessage(
|
||||
id=100,
|
||||
session_id=20,
|
||||
@@ -109,6 +124,7 @@ def test_agent_debug_loads_selected_topic_history_summary_and_permissions():
|
||||
topic_session_id=30,
|
||||
user_id=1,
|
||||
summary="学员正在观察面对权威时的紧绷。",
|
||||
main_events="面对领导时如何表达",
|
||||
emotions="害怕",
|
||||
body_feelings="心口紧",
|
||||
status="success",
|
||||
@@ -134,6 +150,9 @@ def test_agent_debug_loads_selected_topic_history_summary_and_permissions():
|
||||
rendered = "\n".join(item["content"] for item in result.messages)
|
||||
assert "[当前对话主题]" in rendered
|
||||
assert "[所选主题摘要]" in rendered
|
||||
assert "本次关注:面对领导时如何表达" in rendered
|
||||
assert "情绪:害怕" not in rendered
|
||||
assert "身体感受:心口紧" not in rendered
|
||||
assert "我又不敢说话了" in rendered
|
||||
assert "我想继续刚才的主题" in rendered
|
||||
assert "老师求助卡:可由学员主动生成" in rendered
|
||||
|
||||
@@ -72,7 +72,15 @@ def test_finish_topic_enqueues_summary_and_worker_updates_growth_profile_for_ena
|
||||
assert completed.status == "success"
|
||||
assert completed.summary
|
||||
profile = db.query(UserGrowthProfile).filter_by(user_id=1).one()
|
||||
assert "最近主题" in profile.profile_text
|
||||
assert profile.schema_version == 2
|
||||
assert "本次主要谈到" in (profile.recent_review or "")
|
||||
assert profile.current_focus == "我做阴影人格会抗拒,身体发紧"
|
||||
assert profile.profile_text == ""
|
||||
assert profile.common_emotions is None
|
||||
assert profile.body_patterns is None
|
||||
assert profile.homework_done is None
|
||||
assert profile.effective_homework is None
|
||||
assert profile.recent_progress is None
|
||||
assert db.query(UserGrowthProfile).filter_by(user_id=1).count() == 1
|
||||
assert db.query(GrowthProfileRevision).filter_by(user_id=1).count() == 1
|
||||
|
||||
@@ -167,11 +175,21 @@ def test_stale_topic_settlement_is_recovered_after_restart():
|
||||
assert "自动恢复" in (summary.error_message or "")
|
||||
|
||||
|
||||
def test_prompt_can_include_growth_profile_context_without_replacing_knowledge_context():
|
||||
def test_prompt_includes_only_v2_recent_review_without_replacing_knowledge_context():
|
||||
with _db() as db:
|
||||
user = User(id=1, phone="13800000001", name="学员", daily_chat_limit=100, daily_chat_used=0)
|
||||
db.add(user)
|
||||
db.add(UserGrowthProfile(user_id=1, profile_text="用户最近反复在表达障碍和身体紧绷之间观察。"))
|
||||
db.add(
|
||||
UserGrowthProfile(
|
||||
user_id=1,
|
||||
schema_version=2,
|
||||
recent_review="最近谈到面对领导时不敢表达。",
|
||||
current_focus="面对领导时如何回到当下",
|
||||
profile_text="旧画像不应进入提示词",
|
||||
common_emotions="紧张",
|
||||
body_patterns="身体紧绷",
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
|
||||
growth_context = GrowthProfileService.prompt_context(db, user)
|
||||
@@ -183,24 +201,45 @@ def test_prompt_can_include_growth_profile_context_without_replacing_knowledge_c
|
||||
)
|
||||
|
||||
content = "\n".join(item["content"] for item in messages)
|
||||
assert "[长期成长档案]" in content
|
||||
assert "表达障碍" in content
|
||||
assert "[近期实修回顾]" in content
|
||||
assert "面对领导时如何回到当下" in content
|
||||
assert "旧画像不应进入提示词" not in content
|
||||
assert "身体紧绷" not in content
|
||||
assert "常见情绪" not in content
|
||||
assert "[本轮可靠知识上下文]" in content
|
||||
|
||||
|
||||
def test_legacy_growth_profile_is_not_injected_before_v2_rebuild():
|
||||
with _db() as db:
|
||||
user = User(id=1, phone="13800000001", name="学员", daily_chat_limit=100, daily_chat_used=0)
|
||||
db.add_all(
|
||||
[
|
||||
user,
|
||||
UserGrowthProfile(
|
||||
user_id=1,
|
||||
schema_version=1,
|
||||
profile_text="旧版长期人格画像",
|
||||
common_emotions="焦虑",
|
||||
),
|
||||
]
|
||||
)
|
||||
db.commit()
|
||||
|
||||
assert GrowthProfileService.prompt_context(db, user) is None
|
||||
|
||||
|
||||
def test_summary_json_parser_ignores_model_reasoning_and_uses_final_json():
|
||||
raw = """
|
||||
<think>
|
||||
先分析一下,并给出一个未完成草稿:
|
||||
```json
|
||||
{"profileText": "不应采用的草稿"}
|
||||
{"reviewText": "不应采用的草稿"}
|
||||
```
|
||||
</think>
|
||||
```json
|
||||
{
|
||||
"profileText": "只保留最终成长档案",
|
||||
"commonEmotions": ["紧张"],
|
||||
"recentProgress": ["开始观察身体感受"]
|
||||
"reviewText": "只保留最终近期回顾",
|
||||
"currentFocus": ["当下正在谈到的问题"]
|
||||
}
|
||||
```
|
||||
"""
|
||||
@@ -208,5 +247,5 @@ def test_summary_json_parser_ignores_model_reasoning_and_uses_final_json():
|
||||
parsed = _parse_summary_json(raw)
|
||||
|
||||
assert parsed is not None
|
||||
assert parsed["profileText"] == "只保留最终成长档案"
|
||||
assert parsed["reviewText"] == "只保留最终近期回顾"
|
||||
assert "think" not in str(parsed).lower()
|
||||
|
||||
@@ -54,6 +54,8 @@ def test_generate_help_card_from_topic_summary_and_mark_copied():
|
||||
assert "给老师的求助卡" in card.content
|
||||
assert "不会自动发送给老师" in card.content
|
||||
assert "阴影人格练习步骤是否正确" in card.content
|
||||
assert "情绪 / 身体感受" not in card.content
|
||||
assert "已经尝试过或被建议的功课" not in card.content
|
||||
assert db.get(TopicSession, 1).help_card_generated == 1
|
||||
assert db.query(TeacherHelpCard).count() == 1
|
||||
|
||||
@@ -61,4 +63,3 @@ def test_generate_help_card_from_topic_summary_and_mark_copied():
|
||||
|
||||
assert copied.copied == 1
|
||||
assert copied.copied_at is not None
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from app.models.growth import PeriodicReport, TopicSummary, UserGrowthProfile
|
||||
from app.models.user import User
|
||||
from app.services.periodic_report_service import PeriodicReportService, periodic_report_dict
|
||||
from app.services.periodic_report_worker import PeriodicReportWorker, scheduled_period
|
||||
from app.services.model_service import ModelCompletion
|
||||
from app.services.tracked_generation_service import TrackedGenerationService
|
||||
|
||||
|
||||
@@ -51,7 +52,11 @@ def test_generate_periodic_report_from_topic_summaries():
|
||||
report = PeriodicReportService.generate_for_user(db, user=user, report_type="weekly", period_start=now - timedelta(days=7), period_end=now)
|
||||
|
||||
assert report.status == "success"
|
||||
assert report.schema_version == 2
|
||||
assert report.content
|
||||
assert "长期成长档案" not in report.content
|
||||
assert "推荐功课:" not in report.content
|
||||
assert "情绪:害怕" not in report.content
|
||||
data = periodic_report_dict(report)
|
||||
assert data["sourceSummaryIds"] == [1]
|
||||
assert data["sourceTopicIds"] == [1]
|
||||
@@ -71,6 +76,68 @@ def test_generate_empty_periodic_report_when_no_summaries():
|
||||
assert periodic_report_dict(report)["sourceSummaryIds"] == []
|
||||
|
||||
|
||||
def test_periodic_report_strips_model_reasoning_before_saving(monkeypatch):
|
||||
with _db() as db:
|
||||
now = _now()
|
||||
user = User(id=1, phone="13800000001", name="学员", daily_chat_limit=100, daily_chat_used=0)
|
||||
session = ChatSession(id=1, user_id=1, title="当下", message_count=1, last_message_at=now, is_deleted=0)
|
||||
topic = TopicSession(id=1, user_id=1, chat_session_id=1, title="当下", core_question="我想先看当下", status="completed")
|
||||
summary = TopicSummary(
|
||||
id=1,
|
||||
user_id=1,
|
||||
topic_session_id=1,
|
||||
summary="最近谈到想先看当下。",
|
||||
generated_at=now - timedelta(days=1),
|
||||
)
|
||||
db.add_all([user, session, topic, summary])
|
||||
db.commit()
|
||||
monkeypatch.setattr(
|
||||
TrackedGenerationService,
|
||||
"generate",
|
||||
staticmethod(
|
||||
lambda *_args, **_kwargs: ModelCompletion(
|
||||
answer="<think>内部分析与旧画像标签</think>\n## 本周期谈到的主题\n\n最近谈到想先看当下。",
|
||||
model_id=1,
|
||||
model_name="test-model",
|
||||
input_token=1,
|
||||
output_token=1,
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
report = PeriodicReportService.generate_for_user(
|
||||
db,
|
||||
user=user,
|
||||
report_type="weekly",
|
||||
period_start=now - timedelta(days=7),
|
||||
period_end=now,
|
||||
)
|
||||
|
||||
assert report.content.startswith("## 本周期谈到的主题")
|
||||
assert "内部分析" not in report.content
|
||||
assert "<think>" not in report.content
|
||||
|
||||
|
||||
def test_legacy_periodic_reports_are_hidden_until_regenerated():
|
||||
with _db() as db:
|
||||
now = _now()
|
||||
user = User(id=1, phone="13800000001", name="学员", daily_chat_limit=100, daily_chat_used=0)
|
||||
legacy = PeriodicReport(
|
||||
user_id=1,
|
||||
schema_version=1,
|
||||
report_type="weekly",
|
||||
period_start=now - timedelta(days=7),
|
||||
period_end=now,
|
||||
title="旧版成长报告",
|
||||
content="常见情绪、身体模式、有效功课和近期变化",
|
||||
status="success",
|
||||
)
|
||||
db.add_all([user, legacy])
|
||||
db.commit()
|
||||
|
||||
assert PeriodicReportService.list_user_reports(db, user_id=1) == []
|
||||
|
||||
|
||||
def test_async_report_job_is_durable_and_idempotent():
|
||||
with _db() as db:
|
||||
now = _now()
|
||||
|
||||
@@ -53,7 +53,10 @@ def test_generate_share_draft_from_topic_summary_and_mark_copied():
|
||||
|
||||
assert "实修分享稿草稿" in draft.content
|
||||
assert "系统不会自动发送到任何群" in draft.content
|
||||
assert "不代表已经彻底解决" in draft.content
|
||||
assert "不代表结论" in draft.content
|
||||
assert "情绪和身体反应" not in draft.content
|
||||
assert "做了什么功课" not in draft.content
|
||||
assert "当下的一点变化" not in draft.content
|
||||
assert "我看见自己不敢表达" in draft.content
|
||||
assert db.get(TopicSession, 1).share_draft_generated == 1
|
||||
assert db.query(ShareDraft).count() == 1
|
||||
|
||||
Reference in New Issue
Block a user