feat: align agent preview with learner topics
This commit is contained in:
@@ -6,9 +6,10 @@ from types import SimpleNamespace
|
||||
|
||||
from app.api.admin_agent_records import attention_list, retrieval_logs
|
||||
from app.api.admin_records import ai_logs, chat_detail, chat_messages, question_insights, refresh_question_insights
|
||||
from app.api.admin_users import list_users
|
||||
from app.api.admin_users import list_users, user_operation_detail, user_topic_options
|
||||
from app.models import Base
|
||||
from app.models.chat import ChatMessage, ChatSession
|
||||
from app.models.chat import ChatMessage, ChatSession, TopicSession
|
||||
from app.models.growth import TopicSummary
|
||||
from app.models.insight import QuestionInsightCleanedQuestion
|
||||
from app.models.knowledge import HumanAttentionRecord, KnowledgeRetrievalLog
|
||||
from app.models.logs import AiRequestLog
|
||||
@@ -34,6 +35,44 @@ def test_user_list_uses_database_pagination():
|
||||
assert len(response["data"]["items"]) == 10
|
||||
|
||||
|
||||
def test_agent_preview_topic_options_are_lightweight_and_paginated():
|
||||
with _database() as db:
|
||||
user = User(id=1, phone="13800000000", name="学员", daily_chat_limit=10)
|
||||
db.add(user)
|
||||
topics = [
|
||||
TopicSession(
|
||||
id=index + 1,
|
||||
user_id=1,
|
||||
chat_session_id=100 + index,
|
||||
title=f"主题{index + 1}",
|
||||
core_question=f"核心问题{index + 1}",
|
||||
message_count=index,
|
||||
)
|
||||
for index in range(12)
|
||||
]
|
||||
db.add_all(topics)
|
||||
db.flush()
|
||||
db.add(TopicSummary(topic_session_id=topics[-1].id, user_id=1, summary="只用于判断有无摘要", status="success"))
|
||||
db.commit()
|
||||
|
||||
response = user_topic_options(1, keyword="", page=2, pageSize=10, db=db, current_admin=object())
|
||||
|
||||
data = response["data"]
|
||||
assert data["total"] == 12
|
||||
assert data["page"] == 2
|
||||
assert len(data["items"]) == 2
|
||||
assert all("summary" not in item for item in data["items"])
|
||||
assert all("summaryAvailable" in item for item in data["items"])
|
||||
|
||||
detail = user_operation_detail(1, db=db, current_admin=object())["data"]
|
||||
assert detail["user"]["id"] == 1
|
||||
assert detail["metrics"]["totalTopics"] == 12
|
||||
|
||||
searched = user_topic_options(1, keyword="核心问题12", page=1, pageSize=10, db=db, current_admin=object())["data"]
|
||||
assert searched["total"] == 1
|
||||
assert searched["items"][0]["title"] == "主题12"
|
||||
|
||||
|
||||
def test_ai_log_page_does_not_load_large_detail_fields():
|
||||
with _database() as db:
|
||||
db.add_all([
|
||||
|
||||
@@ -2,13 +2,16 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from app.models import Base
|
||||
from app.models.chat import ChatMessage, ChatSession, TopicSession
|
||||
from app.models.entitlement import EntitlementPlan
|
||||
from app.models.growth import UserGrowthProfile
|
||||
from app.models.growth import TopicSummary, UserGrowthProfile
|
||||
from app.models.user import User
|
||||
from app.schemas.admin import AgentDebugRequest
|
||||
from app.services.agent_debug_service import AgentDebugService
|
||||
@@ -54,4 +57,118 @@ def test_agent_debug_can_simulate_user_growth_profile_context():
|
||||
assert "表达障碍" in rendered
|
||||
assert result.tool_trace[0]["tool"] == "load_debug_user_context"
|
||||
assert result.tool_trace[0]["response"]["growthProfileUsed"] is True
|
||||
assert "[当前产品权益]" in rendered
|
||||
|
||||
|
||||
def test_agent_debug_loads_selected_topic_history_summary_and_permissions():
|
||||
with _db() as db:
|
||||
user = User(id=1, phone="13800000001", name="测试学员", daily_chat_limit=100, daily_chat_used=0)
|
||||
session = ChatSession(id=20, user_id=1, title="表达障碍", message_count=2, is_deleted=0)
|
||||
topic = TopicSession(
|
||||
id=30,
|
||||
user_id=1,
|
||||
chat_session_id=20,
|
||||
title="表达障碍练习",
|
||||
core_question="我在面对领导时不敢表达",
|
||||
status="completed",
|
||||
message_count=2,
|
||||
)
|
||||
db.add_all(
|
||||
[
|
||||
user,
|
||||
session,
|
||||
topic,
|
||||
EntitlementPlan(
|
||||
id=10,
|
||||
name="深度陪伴版",
|
||||
plan_type="deep",
|
||||
monthly_topic_limit=90,
|
||||
enable_growth_profile=1,
|
||||
allow_help_card=1,
|
||||
allow_share_draft=0,
|
||||
status=1,
|
||||
),
|
||||
UserGrowthProfile(user_id=1, profile_text="用户在表达时容易身体紧绷。"),
|
||||
ChatMessage(
|
||||
id=100,
|
||||
session_id=20,
|
||||
topic_session_id=30,
|
||||
user_id=1,
|
||||
role="user",
|
||||
content="我又不敢说话了",
|
||||
),
|
||||
ChatMessage(
|
||||
id=101,
|
||||
session_id=20,
|
||||
topic_session_id=30,
|
||||
user_id=1,
|
||||
role="assistant",
|
||||
content="先观察当下的身体感受。",
|
||||
),
|
||||
TopicSummary(
|
||||
topic_session_id=30,
|
||||
user_id=1,
|
||||
summary="学员正在观察面对权威时的紧绷。",
|
||||
emotions="害怕",
|
||||
body_feelings="心口紧",
|
||||
status="success",
|
||||
),
|
||||
]
|
||||
)
|
||||
db.commit()
|
||||
|
||||
result = asyncio.run(
|
||||
AgentDebugService.build_result(
|
||||
db,
|
||||
AgentDebugRequest(
|
||||
promptContent="你是测试 Agent",
|
||||
modelId=1,
|
||||
userId=1,
|
||||
topicSessionId=30,
|
||||
question="那我现在怎么继续?",
|
||||
history=[{"role": "user", "content": "我想继续刚才的主题"}],
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
rendered = "\n".join(item["content"] for item in result.messages)
|
||||
assert "[当前对话主题]" in rendered
|
||||
assert "[所选主题摘要]" in rendered
|
||||
assert "我又不敢说话了" in rendered
|
||||
assert "我想继续刚才的主题" in rendered
|
||||
assert "老师求助卡:可由学员主动生成" in rendered
|
||||
assert "班级分享稿:当前权益不可生成" in rendered
|
||||
context_response = result.tool_trace[0]["response"]
|
||||
assert context_response["topic"]["id"] == 30
|
||||
assert context_response["topic"]["loadedHistoryCount"] == 2
|
||||
assert context_response["topic"]["summaryUsed"] is True
|
||||
|
||||
|
||||
def test_agent_debug_rejects_topic_from_another_user():
|
||||
with _db() as db:
|
||||
db.add_all(
|
||||
[
|
||||
User(id=1, phone="13800000001", name="学员A", daily_chat_limit=100, daily_chat_used=0),
|
||||
User(id=2, phone="13800000002", name="学员B", daily_chat_limit=100, daily_chat_used=0),
|
||||
ChatSession(id=20, user_id=2, title="B的会话", message_count=0, is_deleted=0),
|
||||
TopicSession(id=30, user_id=2, chat_session_id=20, title="B的主题", core_question="B的问题"),
|
||||
]
|
||||
)
|
||||
db.commit()
|
||||
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
asyncio.run(
|
||||
AgentDebugService.build_result(
|
||||
db,
|
||||
AgentDebugRequest(
|
||||
promptContent="你是测试 Agent",
|
||||
modelId=1,
|
||||
userId=1,
|
||||
topicSessionId=30,
|
||||
question="继续这个主题",
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
assert exc.value.status_code == 400
|
||||
assert exc.value.detail == "所选主题不属于当前模拟学员"
|
||||
|
||||
@@ -4,16 +4,17 @@ from datetime import UTC, datetime
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy import create_engine, event
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from app.models import Base
|
||||
from app.models.chat import ChatSession, TopicSession
|
||||
from app.models.chat import ChatMessage, ChatSession, TopicSession
|
||||
from app.models.entitlement import EntitlementPlan
|
||||
from app.models.user import User
|
||||
from app.services.chat_service import ChatService
|
||||
from app.services.entitlement_service import EntitlementService
|
||||
from app.services.rag_service import RagResult, RagService
|
||||
from app.services.topic_session_service import TopicSessionService
|
||||
|
||||
|
||||
@@ -142,3 +143,79 @@ def test_monthly_topic_quota_blocks_new_topic_but_allows_existing_topic():
|
||||
db.flush()
|
||||
|
||||
ChatService._ensure_topic_quota(db, user, session, entitlement)
|
||||
|
||||
|
||||
def test_formal_chat_passes_topic_and_product_context_to_rag(monkeypatch):
|
||||
with _db() as db:
|
||||
message_sequence = iter(range(1000, 1010))
|
||||
|
||||
def assign_sqlite_message_id(_session, _flush_context, _instances):
|
||||
for instance in _session.new:
|
||||
if isinstance(instance, ChatMessage) and instance.id is None:
|
||||
instance.id = next(message_sequence)
|
||||
|
||||
event.listen(db, "before_flush", assign_sqlite_message_id)
|
||||
user, session = _seed_user_session(db)
|
||||
db.add(
|
||||
EntitlementPlan(
|
||||
id=10,
|
||||
name="基础陪伴版",
|
||||
plan_type="basic",
|
||||
monthly_topic_limit=30,
|
||||
allow_help_card=1,
|
||||
allow_share_draft=0,
|
||||
status=1,
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
captured = {}
|
||||
|
||||
def fake_build_result(_db, _user, question, **kwargs):
|
||||
captured.update(kwargs)
|
||||
return RagResult(
|
||||
question=question,
|
||||
knowledge_scopes=[],
|
||||
chunks=[],
|
||||
prompt="测试 prompt",
|
||||
allow_general_knowledge=True,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(RagService, "build_result", fake_build_result)
|
||||
|
||||
ChatService.create_answer(db, user, session.id, "我想继续这个问题")
|
||||
|
||||
assert "[当前对话主题]" in captured["topic_context"]
|
||||
assert "我想继续这个问题" in captured["topic_context"]
|
||||
assert "[当前产品权益]" in captured["product_context"]
|
||||
assert "班级分享稿:当前权益不可生成" in captured["product_context"]
|
||||
|
||||
|
||||
def test_new_topic_resets_previous_topic_rolling_summary():
|
||||
with _db() as db:
|
||||
user, session = _seed_user_session(db)
|
||||
session.summary = "上一个主题的滚动摘要"
|
||||
session.summary_up_to_message_id = 88
|
||||
db.add(
|
||||
TopicSession(
|
||||
id=90,
|
||||
user_id=user.id,
|
||||
chat_session_id=session.id,
|
||||
title="已完成主题",
|
||||
core_question="上一个问题",
|
||||
status="completed",
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
|
||||
topic = TopicSessionService.get_or_create_active(
|
||||
db,
|
||||
user=user,
|
||||
session=session,
|
||||
question="这是一个新主题",
|
||||
deduct_quota=True,
|
||||
)
|
||||
|
||||
assert topic.id != 90
|
||||
assert topic.status == "active"
|
||||
assert session.summary is None
|
||||
assert session.summary_up_to_message_id is None
|
||||
|
||||
Reference in New Issue
Block a user