From 9efdced7f2b1e83c887e7fe4eb633eed21e5cd66 Mon Sep 17 00:00:00 2001 From: liyizhouAI Date: Fri, 17 Apr 2026 13:16:03 +0800 Subject: [PATCH] fix: report prompt alignment + auto-report trigger + failed report redirect 1. Report prompt now extracts user's core questions from simulation_requirement and structures the report to directly answer them (e.g. "will it go well?", "where are the problems?") instead of generic future-prediction questions. 2. Step3Simulation auto-triggers report generation 1.5s after simulation completes. 3. ReportView auto-redirects to latest successful report when current report has failed, via /api/report/check/ endpoint. --- backend/app/services/report_agent.py | 24 ++++++++----- frontend/src/api/report.js | 54 +++++++++++++++++++++------- frontend/src/views/ReportView.vue | 12 ++++++- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/backend/app/services/report_agent.py b/backend/app/services/report_agent.py index 28342128..7de56c26 100644 --- a/backend/app/services/report_agent.py +++ b/backend/app/services/report_agent.py @@ -555,18 +555,24 @@ PLAN_SYSTEM_PROMPT = """\ 【核心理念】 我们构建了一个模拟世界,并向其中注入了特定的「模拟需求」作为变量。模拟世界的演化结果,就是对未来可能发生情况的预测。你正在观察的不是"实验数据",而是"未来的预演"。 +【关键原则:以用户需求为中心】 +报告必须**直接回答**用户在「模拟需求」中提出的核心问题。 +在规划章节之前,先分析模拟需求,提取用户真正关心的 2-3 个核心问题, +然后围绕这些核心问题组织报告章节,确保每个章节都在回答用户的具体关切。 + 【你的任务】 -撰写一份「未来预测报告」,回答: -1. 在我们设定的条件下,未来发生了什么? -2. 各类Agent(人群)是如何反应和行动? -3. 这个模拟揭示了哪些值得关注的未来趋势和风险? +1. 先从「模拟需求」中提取用户的核心关注点(如"是否顺利?""哪里出问题?""能赚多少钱?"等) +2. 撰写一份「未来预测报告」,**直接回答**这些核心关注点 +3. 用模拟世界中的Agent行为和互动数据作为证据支撑 【报告定位】 - ✅ 这是一份基于模拟的未来预测报告,揭示"如果这样,未来会怎样" - ✅ 聚焦于预测结果:事件走向、群体反应、涌现现象、潜在风险 - ✅ 模拟世界中的Agent言行就是对未来人群行为的预测 +- ✅ 必须直接回答用户在模拟需求中提出的具体问题 - ❌ 不是对现实世界现状的分析 - ❌ 不是泛泛而谈的舆情综述 +- ❌ 不能回避用户的核心问题,给出笼统的"需要进一步分析" 【章节数量限制】 - 最少2个章节,最多5个章节 @@ -602,11 +608,13 @@ PLAN_USER_PROMPT_TEMPLATE = """\ {related_facts_json} 请以「上帝视角」审视这个未来预演: -1. 在我们设定的条件下,未来呈现出了什么样的状态? -2. 各类人群(Agent)是如何反应和行动的? -3. 这个模拟揭示了哪些值得关注的未来趋势? -根据预测结果,设计最合适的报告章节结构。 +【重要】首先从「模拟需求」中提取用户最关心的 2-3 个核心问题,然后: +1. 直接回答这些核心问题——基于模拟数据给出明确判断(顺利/不顺利,好/坏,具体数值等) +2. 如果存在问题或风险,明确指出具体位置和原因 +3. 用模拟世界中的Agent行为数据作为证据 + +设计最合适的报告章节结构,确保报告**直接回应**用户在模拟需求中的关切。 【再次提醒】报告章节数量:最少2个,最多5个,内容要精炼聚焦于核心预测发现。""" diff --git a/frontend/src/api/report.js b/frontend/src/api/report.js index c89a67d8..308ef2c4 100644 --- a/frontend/src/api/report.js +++ b/frontend/src/api/report.js @@ -1,20 +1,26 @@ -import service, { requestWithRetry } from './index' +import service, { requestWithRetry } from "./index"; /** * 开始报告生成 * @param {Object} data - { simulation_id, force_regenerate? } */ export const generateReport = (data) => { - return requestWithRetry(() => service.post('/api/report/generate', data), 3, 1000) -} + return requestWithRetry( + () => service.post("/api/report/generate", data), + 3, + 1000, + ); +}; /** * 获取报告生成状态 * @param {string} reportId */ export const getReportStatus = (reportId) => { - return service.get(`/api/report/generate/status`, { params: { report_id: reportId } }) -} + return service.get(`/api/report/generate/status`, { + params: { report_id: reportId }, + }); +}; /** * 获取 Agent 日志(增量) @@ -22,8 +28,10 @@ export const getReportStatus = (reportId) => { * @param {number} fromLine - 从第几行开始获取 */ export const getAgentLog = (reportId, fromLine = 0) => { - return service.get(`/api/report/${reportId}/agent-log`, { params: { from_line: fromLine } }) -} + return service.get(`/api/report/${reportId}/agent-log`, { + params: { from_line: fromLine }, + }); +}; /** * 获取控制台日志(增量) @@ -31,21 +39,41 @@ export const getAgentLog = (reportId, fromLine = 0) => { * @param {number} fromLine - 从第几行开始获取 */ export const getConsoleLog = (reportId, fromLine = 0) => { - return service.get(`/api/report/${reportId}/console-log`, { params: { from_line: fromLine } }) -} + return service.get(`/api/report/${reportId}/console-log`, { + params: { from_line: fromLine }, + }); +}; /** * 获取报告详情 * @param {string} reportId */ export const getReport = (reportId) => { - return service.get(`/api/report/${reportId}`) -} + return service.get(`/api/report/${reportId}`); +}; /** * 与 Report Agent 对话 * @param {Object} data - { simulation_id, message, chat_history? } */ export const chatWithReport = (data) => { - return requestWithRetry(() => service.post('/api/report/chat', data), 3, 1000) -} + return requestWithRetry( + () => service.post("/api/report/chat", data), + 3, + 1000, + ); +}; + +/** + * 根据 simulation_id 获取最新报告 + */ +export const getReportBySimulation = (simulationId) => { + return service.get(`/api/report/by-simulation/${simulationId}`); +}; + +/** + * 检查 simulation 是否有成功的报告 + */ +export const checkReportBySimulation = (simulationId) => { + return service.get(`/api/report/check/${simulationId}`); +}; diff --git a/frontend/src/views/ReportView.vue b/frontend/src/views/ReportView.vue index 4ca4d141..4b5f5f2b 100644 --- a/frontend/src/views/ReportView.vue +++ b/frontend/src/views/ReportView.vue @@ -78,7 +78,7 @@ import GraphPanel from '../components/GraphPanel.vue' import Step4Report from '../components/Step4Report.vue' import { getProject, getGraphData } from '../api/graph' import { getSimulation } from '../api/simulation' -import { getReport } from '../api/report' +import { getReport, checkReportBySimulation } from '../api/report' import LanguageSwitcher from '../components/LanguageSwitcher.vue' const route = useRoute() @@ -159,6 +159,16 @@ const loadReportData = async () => { const reportData = reportRes.data simulationId.value = reportData.simulation_id + // 如果当前报告失败,自动查找该 simulation 的最新成功报告 + if (reportData.status === 'failed' && simulationId.value) { + const checkRes = await checkReportBySimulation(simulationId.value) + if (checkRes.success && checkRes.data?.report_id && checkRes.data.report_id !== currentReportId.value) { + addLog(`Report failed, redirecting to newer report: ${checkRes.data.report_id}`) + router.replace({ name: 'Report', params: { reportId: checkRes.data.report_id } }) + return + } + } + if (simulationId.value) { // 获取 simulation 信息 const simRes = await getSimulation(simulationId.value)