PaperMind · 端到端运行流程详解
从用户提交 PDF 文件夹,到生成结构化研究提案(含创新点 + 实验方案)的完整代码执行路径、每次 LLM 调用与工具调用的输入输出全记录。
0总览:七步漏斗流水线
整个系统由 WorkflowOrchestrator 编排,分三大阶段:预处理(步骤 1-3,带缓存)→ Plan(LLM 动态规划步骤 4-7)→ Execute(步骤 4-7,每步后插入 Reflexion 自校验)。
1启动阶段(进程级)
用户运行 python run_backend.py 启动 FastAPI 服务,前端 npm run dev 启动 Vite。
启动命令
python run_backend.py # 等价于:uvicorn backend.api.main:app --host 0.0.0.0 --port 8000
启动钩子(on_startup)
应用启动时预加载重型依赖,避免首次请求时才触发 import(torch 单独 import 100+ 秒):
# 顺序预加载 import torch # ~5s from transformers import AutoModel, AutoTokenizer # ~3s import chromadb # ~2s # 预热 Embedder 单例:加载 BGE-m3 模型 + 首次 forward(初始化 CUDA 上下文) _embedder = get_default_embedder() _embedder.embed_texts(["预加载测试文本"])
0.0.0.0:8000,BGE 模型已 warmup,前端可访问 localhost:51732用户提交分析任务
前端发 HTTP 请求,后端创建任务并后台异步启动,立即返回 task_id。
HTTP 请求
# POST /api/analyze { "folder_path": "D:/papers", "research_direction": "多模态学习" }
路由处理 routes.py:157
task_manager.create_task()→ 生成task_id(uuid),状态pendingasyncio.create_task(run_analysis(...))→ 后台异步启动,不阻塞响应- 立即返回
{"task_id": "..."}
后台主流程 routes.py:51
# 初始化组件 client = DeepSeekClient() # LLM 客户端 registry = build_default_registry() # 工具注册表 memory = MemoryManager() # 双层记忆 orchestrator = WorkflowOrchestrator(client, registry, memory) # 执行流水线 pipeline_output = await orchestrator.run_pipeline(...) # 生成报告 + 评估 report = await ReportAgent(client).generate_report(final_results) evaluation = await Evaluator(client).evaluate(...) # 存结果 task_manager.update_task(task_id, status="completed", result={...})
progress_callback 实时推送 {stage, status, message, progress, payload} 到 GET /api/progress/{task_id},前端可流式渲染进度条。
3Phase 1:预处理(步骤 1-3,带缓存)
由 Controller._preprocess_papers() 编排,对每篇论文检查 PaperLibrary 缓存状态:已完成的步骤直接从磁盘加载(标记 cached),未完成的执行后写盘。
处理流程
- PyMuPDF 提取每页文本 + 字号/字体信息
- 启发式识别章节标题(字号 > 正文×1.15 或加粗 + 关键词匹配
abstract|introduction|method...) - 去页眉页脚(短行 < 80 字符且重复出现)
- 提取图表标题(
Figure X/表 X正则) - 合并跨页段落,修复断句
{
"file_path": "D:/papers/xxx.pdf"
}
{
"path": "D:/papers/xxx.pdf",
"title": "Attention Is All You Need",
"sections": [
{
"heading": "Abstract",
"content": "...",
"figure_captions": ["Figure 1: ..."]
}
]
}
data/cache/parsed/{paper_id}.json,PaperLibrary 标记 parse_status=done。下次同一论文直接 load_parsed() 加载,跳过解析。
处理流程
- 长度判断:总字符 > 20000 → 按章节分块抽取后合并;否则一次性抽取
- 调用 LLM(
_call_extract):强制tool_choice={"type":"function","function":{"name":"extract_paper_fields"}} - 字段完整性校验:缺失字段 → 针对性补抽(
focus_fields只补缺失的,不重跑整篇) - 长论文合并:多块记录按置信度取最高 value,
source_sections去重合并
LLM Prompt · 抽取(核心)
[System] 你是论文结构化抽取助手。严格通过函数调用输出 JSON, 每个字段含 value/source_sections/confidence。 limitations 必须真实可溯源,严禁臆造。 [User] 请从以下论文中抽取结构化字段。 论文标题:{title} 论文正文: ## Abstract {...} ## Introduction {...} 抽取要求: 1. 必须抽取以下字段:title、task_problem、method、key_contributions、 datasets、metrics、results、limitations、future_work 2. 每个字段必须是 FieldSource 结构: { "value": "字段值(字符串,尽量简洁完整)", "source_sections": ["原文出处章节标题列表"], "confidence": 0.0-1.0 } 3. source_sections 必须标注字段信息来源于上面哪个章节(用章节标题原文),便于回溯核查 4. limitations 字段特别要求:必须是论文明确承认的局限,或可从实验结果直接推断的局限, 严禁臆造或泛泛而谈。若论文未明确提及局限,value 填写"论文未明确陈述局限",confidence 设为较低值(如 0.3) 5. confidence 反映可信度: - 信息明确且原文直述 → 0.9-1.0 - 需要从原文推断 → 0.6-0.8 - 信息不足或模糊 → 低于 0.6 6. 严格输出 JSON,不要添加任何额外说明文字或 markdown 代码块标记
LLM Prompt · 针对性补抽(缺失字段)
[User] 前一次抽取缺失了以下字段:{", ".join(focus_fields)}。 请重点从原文中补抽这些字段,其他字段可留空。 {...同上 prompt...}
Function Calling Schema · extract_paper_fields
{
"type": "function",
"function": {
"name": "extract_paper_fields",
"description": "从论文中抽取结构化字段,每个字段含 value/source_sections/confidence",
"parameters": {
"type": "object",
"properties": {
"title": { "type": "object", "properties": {
"value": {"type":"string"},
"source_sections": {"type":"array","items":{"type":"string"}},
"confidence": {"type":"number"}
}},
"task_problem": { ... 同上 ... },
"method": { ... },
"key_contributions": { ... },
"datasets": { ... },
"metrics": { ... },
"results": { ... },
"limitations": { ... },
"future_work": { ... }
},
"required": ["title","task_problem","method","key_contributions",
"datasets","metrics","results","limitations","future_work"]
}
}
}
{
"paper_path": "D:/papers/xxx.pdf",
"parsed_paper": {ParsedPaper dict}
}
{
"path": "...",
"title": {
"value": "Attention Is All You Need",
"source_sections": ["Title"],
"confidence": 1.0
},
"task_problem": {
"value": "序列建模任务...",
"source_sections": ["Introduction"],
"confidence": 0.9
},
"method": {
"value": "Transformer 架构...",
"source_sections": ["3 Method","3.1"],
"confidence": 0.95
},
"limitations": {
"value": "位置编码外推性差...",
"source_sections": ["6 Conclusion"],
"confidence": 0.7
},
...
}
source_sections 回溯到具体章节,limitations 严禁臆造。这是后续创新点论证可追溯性的基石。
处理流程
- 分块:按段落累积到 ~500 字符落块,每块携带
section标题 - 向量化:BGE-m3 本地 Embedding(无 API 成本),块内容 =
section_heading + text - 写入 Chroma:
paper_chunkscollection,metadata 含paper_path/title/section - 同步构建 BM25:倒排索引供关键词检索
{
"papers_json": [{ParsedPaper}, ...]
}
{
"indexed_count": 12,
"status": "done"
}
4Phase 2:Plan(LLM 动态规划)
让 LLM 根据任务自主规划步骤顺序/增减,体现动态编排。失败时回退默认七步计划。实际执行时过滤掉步骤 1-3(已由预处理完成),只执行步骤 4-7。
调用位置 controller.py:126
LLM Prompt · 动态规划
[System] 你是 Agent 编排器,负责生成可执行的动态计划。只输出 JSON。 [User] 你是论文创新 Agent 的 Controller。请为以下任务生成动态执行计划。 任务:分析文件夹 {folder_path} 中的 PDF 论文, 识别研究空白,生成 2-3 个创新点并设计实验方案。 可用 Agent: - PaperParser:扫描文件夹并解析 PDF - Extractor:单篇论文结构化抽取 - Indexer:向量索引构建 - GapAnalyzer:跨论文 Gap 识别 - InnovationGenerator:创新点生成与筛选 - ExperimentDesigner:实验方案设计 - Integration:整合输出研究提案 请生成执行计划,输出 JSON 数组,每个元素含: - step: 步骤序号(整数) - agent: Agent 名称(上述之一) - action: 该步骤具体任务描述 - depends_on: 依赖的步骤序号列表 你可以根据任务自主调整顺序或增减步骤。 默认链路:解析→抽取→索引→Gap分析→创新生成→实验设计→整合。 严格只输出 JSON 数组,不要其他文本。
"D:/papers" 或 "已上传的 12 篇论文"
[
{"step":4,"agent":"GapAnalyzer",
"action":"跨论文综合分析识别研究空白",
"depends_on":[2]},
{"step":5,"agent":"InnovationGenerator",
"action":"针对 Gap 生成创新点并筛选",
"depends_on":[4]},
...
]
5Phase 3:Execute(步骤 4-7 + Reflexion)
逐步执行计划,每步完成后插入 Reflexion 自校验钩子(仅对 Extractor / GapAnalyzer / InnovationGenerator 启用)。每步还根据结果动态调整剩余计划。
处理流程
- 聚合对比矩阵:把 N 篇论文的 8 个字段聚合成文本(关键:让模型在全局视野下识别 Gap)
- 调用 LLM 做跨论文综合推理,识别四类 Gap
- RAG 增强:对每个 Gap 调用
hybrid_search检索原文细节,补充 evidence
LLM Prompt · Gap 识别
[System] 你是一位严谨的学术研究分析专家,擅长跨论文综合推理与 Gap 识别。 只输出严格 JSON,不要输出任何其他内容。 [User] 你是一位资深学术研究者,需要从以下多篇论文的结构化对比中识别研究空白(Gap)。 ## 论文对比矩阵 ===== 论文 1: Attention Is All You Need ===== [研究任务/问题] 序列建模任务... [核心方法] Transformer 架构... [局限性] 位置编码外推性差... [未来工作] 扩展到多模态... ===== 论文 2: BERT ===== [研究任务/问题] ... [核心方法] ... [局限性] ... ## 任务 请综合分析上述论文,识别以下四类 Gap 信号: 1. repeated_limitation(重复局限):多篇论文提到同一局限性,但无人解决 2. method_gap(方法空白):某类问题只有少数方法尝试且效果不佳 3. contradictory(矛盾结论):不同论文对同一问题给出冲突结论 4. unfulfilled_future(未兑现的未来工作):多篇论文指向同一未来方向但无人完成 对于单篇论文场景,重点关注该论文自身的 limitations 与 future_work 字段。 ## 输出要求 严格输出 JSON: { "gaps": [ { "description": "Gap 的清晰描述", "gap_type": "repeated_limitation|method_gap|contradictory|unfulfilled_future", "source_papers": ["来源论文标题1"], "evidence": "论证依据,引用具体论文的具体字段", "confidence": 0.0到1.0之间的置信度 } ] } 只输出真正有证据支撑的 Gap,不要编造。每个 Gap 的 source_papers 至少包含 2 篇论文。
{
"papers_records": [
{PaperRecord 1},
{PaperRecord 2},
...
]
}
{
"gaps": [
{
"description": "位置编码外推性普遍较差",
"gap_type": "repeated_limitation",
"source_papers": ["Attention...","BERT..."],
"evidence": "两篇均提及... [原文佐证]\n - 《Attention》6 Conclusion: ...",
"confidence": 0.85
}
]
}
触发条件
仅对 Extractor / GapAnalyzer / InnovationGenerator 启用。步骤完成后,让 LLM 对照上下文检查结果质量。
LLM Prompt · 自校验
[System] 你是质量审核员,负责对照上下文检查 Agent 输出质量。只输出 JSON。 [User] 请对照上下文检查以下步骤的结果质量。 步骤:{step_name} 上下文: 步骤 2 结果:{抽取记录摘要...} 结果: {result_str} 检查要求: 1. 评估结果是否准确、完整、无臆造; 2. 输出 0-1 的置信度(confidence); 3. 列出发现的问题(issues); 4. 置信度低于 {CONFIDENCE_THRESHOLD=0.7} 时 needs_retry=true; 5. 指出需重试的字段或方面(retry_fields)。 严格以 JSON 输出: {"confidence": 0.85, "issues": ["问题1"], "needs_retry": false, "retry_fields": []}
重试逻辑
confidence < 0.7→needs_retry = true- 调用
retry_func()重新执行该步骤(针对性补抽,非整篇重跑) - 最多重试
MAX_RETRIES=2次 - 仍不达标 → 标记
needs_human_review,流程继续不阻塞
{
"step_name": "GapAnalyzer",
"result": {步骤结果},
"context": {依赖步骤结果}
}
{
"confidence": 0.85,
"issues": ["..."],
"needs_retry": false,
"retry_fields": []
}
处理流程
- 调用 LLM:针对每个 Gap 从四类来源生成候选创新方向
- 规范化 + 排序:按三维评分之和降序
- 取 Top 2-3
- 联网新颖性去重:对每个创新点用 DuckDuckGo 搜索近 1-2 年 arXiv/Google Scholar,验证是否已有相同工作
LLM Prompt · 创新生成
[System] 你是一位学术创新生成专家,擅长从研究空白中挖掘可执行的创新方向。 只输出严格 JSON,不要输出任何其他内容。 [User] 你是一位富有创造力的学术研究者,需要基于以下研究空白(Gap)生成候选创新方向。 ## 用户研究方向约束 用户的研究方向为:{research_direction} 生成的创新点应尽量与该方向相关,并在 supporting_evidence 中说明创新点与该方向的关联。 ## 研究空白列表 - [repeated_limitation] 位置编码外推性普遍较差(来源: Attention..., BERT...) - [method_gap] ... ## 任务 针对每个 Gap,从以下四类来源生成候选创新方向: 1. method_combination(方法组合):把 A 论文方法迁移到 B 论文问题 2. limitation_fix(局限改进):直接解决被反复提及的局限 3. cross_domain(跨域迁移):引入其他领域方法 4. new_scenario(新场景应用):把现有方法用到未被覆盖的数据/场景 对每个候选创新方向,用三维评分(0-10 分): - novelty(新颖性) - feasibility(可行性) - significance(显著性) ## 输出要求 严格输出 JSON: { "innovations": [ { "title": "创新点标题", "idea": "创新思路详细描述", "source": "method_combination|limitation_fix|cross_domain|new_scenario", "gap_origin": "对应的 Gap 描述", "score": {"novelty": 8.0, "feasibility": 7.5, "significance": 8.0}, "supporting_evidence": "论据支撑" } ] } 生成多个候选(每个 Gap 至少 1-2 个),按综合得分(三项之和)从高到低排序。
{
"gaps": [{Gap}, ...],
"research_direction": "多模态学习"
}
{
"innovations": [
{
"title": "基于 RoPE 的多模态位置编码",
"idea": "...",
"source": "limitation_fix",
"gap_origin": "位置编码外推性差",
"score": {"novelty":8.0,"feasibility":7.5,"significance":8.5},
"novelty_check": "近 1-2 年无相同工作",
"supporting_evidence": "..."
}
]
}
LLM Prompt · 实验设计
[System] 你是一位学术实验设计专家,擅长设计严谨可执行的研究方案。 只输出严格 JSON,不要输出任何其他内容。 [User] 你是一位资深学术研究者,需要为以下创新点设计可执行的研究方案。 ## 创新点列表 - 基于 RoPE 的多模态位置编码: ...(来源: limitation_fix,Gap: 位置编码外推性差) ## 任务 为每个创新点设计完整、可执行的研究方案,包含: - hypothesis(研究假设):清晰可验证的假设 - datasets(数据集列表):适合该研究的公开数据集 - baselines(基线方法列表):需要对比的现有方法 - metrics(评估指标列表):量化评估指标 - ablation(消融实验设计列表):验证各组件贡献 - steps(实验步骤列表):可复现的实验流程 - expected_results(预期结果):预期达到的性能或发现 - risks(风险):可能的失败点与应对 ## 输出要求 严格输出 JSON: { "experiment_plans": [ { "innovation_title": "对应的创新点标题", "hypothesis": "研究假设", "datasets": ["数据集1","数据集2"], "baselines": ["基线方法1","基线方法2"], "metrics": ["指标1","指标2"], "ablation": ["消融实验1"], "steps": ["步骤1","步骤2","步骤3"], "expected_results": "预期结果描述", "risks": "风险与应对描述" } ] } 每个创新点对应一条方案,方案须具体可执行。
{
"innovations": [{Innovation}, ...]
}
{
"experiment_plans": [
{
"innovation_title": "基于 RoPE 的多模态位置编码",
"hypothesis": "RoPE 能提升多模态任务外推性",
"datasets": ["COCO","VQA"],
"baselines": ["ALiBi"," vanilla PE"],
"metrics": ["BLEU","Accuracy"],
"ablation": ["移除旋转矩阵"],
"steps": ["..."],
"expected_results": "...",
"risks": "..."
}
]
}
输入聚合 workflow.py:127
_build_final_results() 从各步骤的 tool_calls 里聚合 4 字段:
{
"papers_records": [...], # 步骤②所有抽取记录
"gaps": [...], # 步骤④所有 Gap
"innovations": [...], # 步骤⑤所有创新点
"experiment_plans": [...] # 步骤⑥所有实验方案
}
LLM Prompt · 整合报告
[System] 你是学术研究提案撰写专家,擅长把多篇论文的 Gap 分析、创新点与实验方案 整合为结构清晰、可追溯的研究提案。严格输出 JSON,不要输出任何额外说明文本。 [User] 请基于以下前序步骤产物,整合为一份结构化研究提案。 ## 研究主题 {topic} ## 一、论文结构化记录(含 source_sections,可追溯) ----- 论文 1: Attention Is All You Need (path=...) ----- [研究任务/问题] 序列建模... (出处章节: Introduction) [核心方法] Transformer... (出处章节: 3 Method; 3.1) [局限性] 位置编码外推性差 (出处章节: 6 Conclusion) ... ## 二、识别到的 Gap 列表 Gap 1 [repeated_limitation] (置信度=0.85): 位置编码外推性普遍较差 来源论文: Attention...; BERT... 论证: 两篇均提及... ## 三、创新点列表(含三维评分) 创新点 1: 基于 RoPE 的多模态位置编码 (来源=limitation_fix) 创新思路: ... 三维评分: 新颖性 8 / 可行性 7 / 显著性 9 新颖性验证: 近 1-2 年无相同工作 论据支撑: ... ## 四、实验方案列表 方案 1 (对应: 基于 RoPE 的多模态位置编码) 研究假设: ... 数据集: COCO, VQA ... ## 整合任务 1. 背景综述:基于 Gap 分析梳理领域现状与脉络 2. 创新点论证:对每个创新点补充 Gap 来源 + 创新思路 + 三维评分 + 论据支撑 3. 实验方案:保留每个创新点的完整实验方案要素 4. 参考文献溯源:所有引用论文的来源标注,可追溯至具体章节(source_sections) 5. Markdown 报告:按指定结构生成完整 Markdown 文本 ## Markdown 报告结构要求 # 研究提案:[主题] ## 一、背景综述 ## 二、创新点论证 ### 创新点 1:[标题] - Gap 来源:... - 创新思路:... - 三维评分:新颖性 X / 可行性 X / 显著性 X - 论据支撑:... ## 三、实验方案 ## 四、参考文献溯源 ## 输出要求 严格输出 JSON: { "background_review": "背景综述文本", "innovations": [...], "experiment_plans": [...], "references": [{"title":"...","path":"...","sections":[...]}], "markdown": "完整 Markdown 报告字符串" } 注意: - references 必须可追溯至具体章节(source_sections) - 不得编造论文或证据,所有引用须来自上述论文记录 - 若某字段在输入中缺失,对应位置写"暂无"而非编造
{
"papers_records": [...],
"gaps": [...],
"innovations": [...],
"experiment_plans": [...]
}
{
"background_review": "...",
"innovations": [...],
"experiment_plans": [...],
"references": [
{"title":"...","path":"...",
"sections":["3 Method","6 Conclusion"]}
],
"markdown": "# 研究提案:...\n## 一、背景综述\n..."
}
6评估阶段
流水线完成后,Evaluator 汇总工具调用追踪 + 输出质量评估,产出统一评估结果。
调用位置 evaluator.py:28
ToolCallTracker汇总工具调用成功率 / 总数 / 失败数 / 耗时QualityEvaluator对每个创新点调 LLM 做三维评分校验
LLM Prompt · 质量评估
[System] 你是一位学术评审专家,擅长对创新点进行多维评分。只输出严格 JSON。 [User] 你是一位严谨的学术评审专家,请对以下创新点进行三维评分(0-10 分,保留一位小数)。 ## 创新点信息 - 标题:{title} - 思路:{idea} - 论据支撑:{supporting_evidence} - 新颖性检查:{novelty_check} ## 评分维度 - novelty(新颖性):与现有工作的差异程度 - feasibility(可行性):技术实现与资源获取的难度 - significance(显著性):学术或应用价值 ## 输出要求 严格输出 JSON: { "innovation_title": "...", "score": {"novelty": 8.0, "feasibility": 7.5, "significance": 8.0}, "reasoning": "评分理由,简明扼要" }
输出
{
"innovations_scores": [...],
"tool_call_success_rate": 0.89,
"total_tool_calls": 47,
"failed_tool_calls": 5,
"avg_confidence": 0.78,
"tool_calls": [...],
"quality_assessment": {...}
}
7完整 LLM 调用清单
单次完整运行共触发 11 次 LLM 调用(不含工具内部重试)。
| # | 阶段 | 调用位置 | Prompt 设计要点 | 输出格式 |
|---|---|---|---|---|
| 1 | Plan | controller.py:151 | Agent 编排器,生成动态计划 | JSON 数组 |
| 2 | 步骤② | extract_schema.py:102 | 强制 Function Calling,source_sections 防编造,limitations 严禁臆造 | FieldSource JSON |
| 3 | 步骤②补抽 | extract_paper_structure.py:161 | 只补缺失字段,不重跑整篇 | FieldSource JSON |
| 4 | 步骤②自校验 | extract_paper_structure.py:306 | 对照原文逐字段检查置信度 | JSON |
| 5 | 步骤④ | analyze_gaps.py:113 | 四类 Gap 信号识别,对比矩阵输入 | JSON gaps 列表 |
| 6 | 步骤④ Reflexion | reflexion.py:67 | 质量审核员,对照上下文检查 | JSON confidence |
| 7 | 步骤⑤ | generate_innovations.py:81 | 四类创新方向 + 三维评分 + 方向约束 | JSON innovations |
| 8 | 步骤⑤ Reflexion | reflexion.py:67 | 同上 | JSON confidence |
| 9 | 步骤⑥ | design_experiments.py:51 | 8 要素实验方案 | JSON plans |
| 10 | 步骤⑦ | report_agent.py:197 | 整合 4 字段为 Markdown 研究提案 | JSON + markdown |
| 11 | 评估 | quality.py:73 | 学术评审专家三维评分校验 | JSON score |
工具调用清单
| 工具 | 步骤 | 输入 | 输出 | 特性 |
|---|---|---|---|---|
scan_folder | ① | folder_path | pdf_files 列表 | 本地 |
parse_pdf | ① | file_path | ParsedPaper | 本地 · 并发 · 缓存 |
extract_paper_structure | ② | paper_path, parsed_paper | PaperRecord | LLM · 并发 · 缓存 |
build_vector_index | ③ | papers_json | indexed_count | 本地 · 持久化 |
analyze_gaps | ④ | papers_records | gaps 列表 | LLM · 内部调 RAG |
hybrid_search | ④⑤ | query | 检索片段 + 分数 | Chroma + BM25 |
generate_innovations | ⑤ | gaps, research_direction | innovations 列表 | LLM · 内部调 web_search |
web_search | ⑤ | query | 搜索结果摘要 | DuckDuckGo |
design_experiments | ⑥ | innovations | experiment_plans | LLM |
load_memory / save_memory | ⑤ | type, query | 历史 Gap/创新点 | Chroma 长期记忆 |
8Prompt 设计的 5 个核心原则
贯穿所有 prompt 的设计哲学。
① System 角色锚定
每个 prompt 都用 system 消息锁定角色("你是 XX 专家"),并在末尾强调"只输出严格 JSON",避免自由文本。
② 结构化输出强制
全部用 Function Calling 或显式 JSON Schema,避免 LLM 自由发挥导致解析失败。步骤② 用 tool_choice={"type":"function",...} 强制调用。
③ 防编造机制
source_sections 强制溯源 + "严禁臆造" + "缺失填暂无"。步骤② limitations 字段特别约束:论文未明确承认时填"论文未明确陈述局限"而非编造。
④ 上下文注入
把前序步骤的结构化产物作为"证据"喂给模型,而非让模型凭空推理。步骤④ 喂对比矩阵、步骤⑦ 喂 4 字段聚合。
⑤ 降级兜底
每个 LLM 调用都有 try/except,失败时回退到本地格式化或默认值。步骤⑦ LLM 失败 → _format_markdown() 本地组装。
9降级与容错策略
每个步骤都有失败兜底,局部失败不阻塞全局。
| 失败点 | 降级路径 | 影响 |
|---|---|---|
| 单篇论文解析失败 | 隔离跳过,独立缓存可单独重跑 | 不影响其他论文 |
| LLM 输出非 JSON | Function Calling 强制 schema + parse_json_safe 程序层兜底 | 该字段降级为空 |
| 工具调用超时/失败 | 3 次重试 + 降级路径 | 记录 degraded_steps |
| 论文超长截断 | 按章节分块抽取后合并去重 | 无影响 |
| Controller 规划失败 | 异常捕获 + 回退默认七步 | 无影响 |
| 向量索引构建失败 | 跳过 RAG,仅用结构化字段做 Gap 分析 | Gap evidence 无原文佐证 |
| 联网搜索失败 | 跳过新颖性去重,标记"未验证" | novelty_check 为空 |
| Reflexion 重试 2 次仍不达标 | 标记 needs_human_review,流程继续 | 评估报告标注 |
| 步骤⑦ LLM 整合失败 | 本地 _format_markdown() 格式化组装 | 报告样式简化 |
| LLM 编造内容 | 所有字段强制 source_sections 字段级回溯 | 可人工核查 |