从零搭建个人科研Agent:混合模型策略与LangGraph核心闭环实战(二):搜索系统升级与报告质量优化
项目名称:ScholarCraft
定位:一个本地与远端混合模型驱动的科研调研Agent,能自主规划、调用工具、阅读论文并生成结构化报告。
技术栈:LangGraph + Ollama (Qwen3-4B) + 小米 MiMo API
进度:搜索系统全面升级、智能评估机制完善、工具能力增强、本地论文库扩充至26篇、报告质量显著提升
前言
在第一篇文章中,我记录了 ScholarCraft 从零到一实现核心闭环的全过程——环境搭建、模型选型、工具系统和状态机设计。当时 Agent 能跑通"搜索→读取→生成报告"的完整流程,但论文库只有 3 篇种子论文,搜索词靠本地 Qwen3-4B 生成,质量不稳定,也没有重试和评估机制。
"能跑通"只是第一步。真正让 Agent 变得好用,需要解决三个核心问题:搜索结果的质量如何保证?搜不到相关论文时怎么办?报告能不能每次都保持同样的深度和诚实度?
这篇文章记录的就是这个打磨过程。所有代码改动都经过了实际测试验证,每一步的决策逻辑我也会写清楚。
一、搜索系统全面升级
1.1 多角度搜索策略
初始版本的搜索只用 LLM 生成一个关键词,命中率完全取决于这个词有多精准。面对不熟悉的领域,本地 Qwen3-4B 往往只能给出泛泛的短语组合,搜索结果波动很大。
改进后的做法是要求 LLM 从四个维度生成查询变体:
| 搜索角度 | 目标 | 示例 |
|---|---|---|
| 综述角度 | 获取全景视角 | diffusion model molecular generation survey review |
| 经典方法角度 | 命中这个领域公认的方法名 | DiffSBDD EDM GeoDiff molecular generation |
| 最新进展角度 | 获取前沿预印本 | diffusion model molecule generation 2024 recent advances |
| Benchmark 角度 | 获取标准化评测数据 | QM9 ZINC GEOM diffusion model benchmark evaluation |
四个角度的查询并行执行,结果合并去重。这个设计参考了学术文献调研的规范做法——综述提供全貌,经典方法提供锚点,最新进展提供前沿,Benchmark 提供对比基准。
在 tool_select_node 的 Prompt 中加入多角度指令后,搜索词质量变化明显。以前面对"扩散模型在分子生成中的应用",本地模型只能生成 diffusion model molecular generation survey 这种宽泛词;现在切换到 MiMo 驱动后,能给出 DiffSBDD EDM GeoDiff molecular generation 这种具体的方法名组合。
1.2 搜索词生成改用 MiMo
这是搜索质量提升最关键的一步。
本地 Qwen3-4B 在大多数工具选择任务上够用,但生成搜索词需要更强的领域知识——知道这个领域有哪些经典方法、哪些公认数据集、哪些常见评测基准。这些知识本地小模型不具备。
远端 MiMo-V2.5-Pro 的推理能力和知识储备远超本地模型。同一句"搜一下扩散模型在分子生成中的应用",MiMo 能生成:
text
"DiffSBDD EDM GeoDiff molecular generation"
"diffusion model QM9 ZINC MOSES benchmark molecular generation"
这就是为什么在 tool_select_node 中,搜索步骤和补充搜索步骤全部走 MiMo,而非搜索步骤(read_paper、compare)继续用本地 Qwen3-4B。这个分层的架构设计是项目面试叙事中很重要的一环。
1.3 强制先搜本地库
在多次运行中观察到 MiMo 在规划步骤时有时会直接跳到 search_arxiv,跳过本地搜索,导致本地已有的 26 篇论文被闲置。
修复方式是在 plan_task 的 system_prompt 中加了一条硬约束:
text
规划规则:第一步必须使用 search_local 优先检索本地论文库,
第二步使用 search_arxiv 补充最新预印本。
改动只有一行,但效果立竿见影——本地库再也不会被跳过。
1.4 新增 Semantic Scholar 工具
arXiv 是预印本平台,有两个固有缺陷:论文未经同行评审,质量参差不齐;没有引用统计,无法区分"奠基性论文"和"刚发上去的草稿"。
Semantic Scholar API 完美弥补了这两个缺陷。它免费、不需要 Key、支持按引用次数排序、返回发表在正式会议/期刊上的论文信息。
工具已经写好并注册到了 MCP Server。虽然当前 WSL 网络环境下 Semantic Scholar 的连接不稳定,暂时注释掉了自动调用,但架构上已经就绪。将来网络恢复只需取消注释即可启用三数据源(本地 + arXiv + Semantic Scholar)协同检索。
二、智能评估与流程控制
2.1 迭代式检索:搜不到就换个姿势再搜
最初的 Agent 搜一次就认了。如果搜索结果太少(比如只返回 1 篇),或者全都不相关,它照样继续往下走,最后生成的报告自然没什么内容。
现在在 evaluate_node 中增加了搜索质量检查。核心逻辑很简单:
-
搜索完成后,统计有效论文数量
-
如果少于 3 篇,且重试次数未满上限,就回到
tool_select_node,让 LLM 根据上轮搜索结果生成新的搜索词,再搜一轮 -
如果数量够了,进行相关性评估
日志中可以清晰看到这个过程:
text
[EVAL] 只找到 1 篇有效论文,触发补充搜索(第1次重试)
[SELECT] 补充搜索模式,生成新查询词...
[CALL] 使用 arXiv 联网检索: 'equivariant diffusion model 3D molecular generation drug design'
[EVAL] 找到 4 篇有效论文,搜索完成,继续下一步
2.2 LLM 相关性评估
只检查数量是不够的。arXiv 有时会返回一堆完全不相关的论文——比如搜"分子生成扩散模型",能给你返回"星际分子云形成"的论文。如果只看数量,5 篇不相关的论文会被当作"够了"。
现在搜索完成后,让本地 Qwen3-4B 对搜索结果与用户需求的相关性打分(0-10 分),并给出简短理由。
在实际测试中,这条机制直接捕捉到了一次低相关性搜索结果:
text
[EVAL] 相关性评估: 2/10 (大多数论文与分子生成中的扩散模型应用无关,
仅有一篇标题提及扩散模型在分子生成中的调研,但其余内容涉及星际带、
硫分子、水冰和分子云形成,与用户需求匹配度低。)
[EVAL] 相关性不足(2/10),触发补充搜索
2.3 极低相关性提前终止
如果反复搜了几次还是搜不到,继续硬搜只是在浪费 API 额度。增加了提前终止逻辑:
-
相关性已经低于 3 分
-
且已经重试过一次
满足这两个条件时,直接停止搜索,把现有信息诚实输出。
2.4 模型分层调用的修正
在开发迭代中我犯过一个错误:把相关性评估、read_paper 等任务也交给 MiMo 处理。结果偶尔出现 JSON 解析失败,还浪费了不少额度。
修正后重新明确了分工:
| 任务 | 模型 | 原因 |
|---|---|---|
| 搜索词生成 + 补充搜索 | MiMo API | 需要广博领域知识,调用频次低 |
| 任务规划(初始拆解) | MiMo API | 强推理能力 |
| 相关性评估 | 本地 Qwen3-4B | 评分任务,小模型足够用 |
| read_paper | 本地 Qwen3-4B | 从已有列表里选 ID |
| 报告生成 | 本地 Qwen3-4B | 离线可用,格式稳定 |
这个分层设计是面试中讨论"混合模型策略"时的核心论据。
三、工具能力增强
3.1 read_paper 双路径修复
这是一个困扰了很久的问题:LLM 在 read_paper 步骤传入 arxiv_2604.27636v1 这类 ID,但 read_paper_detail 工具只能读本地库中的 paper_001 格式,导致频繁报错"未找到论文"。
修复方式是在 tool_call_node 中新增一个分支:如果 paper_id 以 arxiv_ 开头,就从前面搜索步骤的结果中直接提取对应论文的摘要,而不是去本地数据库查找。同时,如果 ID 是 paper_ 开头的本地 ID,正常走 MCP 调用路径。
text
[CALL] arXiv 论文,从搜索结果中提取: arxiv_2604.27636v1
[CALL] 提取成功: Generative structure search for efficient and diverse discov...
3.2 read_paper 上下文注入
之前的 LLM 在 read_paper 步骤不知道有哪些论文可选,经常生成空参数导致报错。现在在 tool_select_node 中,当步骤是 read_paper 时,会把前面搜索步骤返回的论文 ID 和标题列表注入 Prompt。
LLM 能看到类似这样的信息:
text
前面搜索步骤找到的论文列表(请从中选择 paper_id):
- ID: paper_001
标题: Diffusion Models for Molecular Generation: A Survey
- ID: paper_013
标题: Equivariant diffusion for molecule generation in 3D
有了这个上下文,LLM 终于能正确生成 {"paper_id": "paper_001"} 而不是瞎猜搜索词了。
3.3 compare 步骤激活
之前的 compare 步骤在 MiMo 规划时会被规划出来,但执行时被标记为 deferred(跳过)。原因很简单——不知道在对比步骤里能干什么。
现在新增了 _execute_compare 函数:收集前面所有搜索结果和已读论文的详细信息,调用本地 LLM 生成结构化的横向对比表格。
这意味着 MiMo 规划出来的每一个步骤都有实际执行,不会再有"规划了但跳过"的空白环节。
四、报告质量与论文库建设
4.1 结构化深度报告 Prompt
之前的 report_node Prompt 过于开放,只要求"包含摘要、方法对比、关键指标、总结",没有具体深度要求。结果是有时摘要只有两行,有时洋洋洒洒,质量波动很大。
现在通过 Prompt 明确要求:
-
摘要 ≥150 字,必须包含研究背景、核心方法数量、关键发现和主要局限
-
方法概览表格固定六列:方法名称/年份/来源/核心贡献/数据集/局限性,缺失信息填写"未提供"
-
关键指标必须标注数据集名称和测试条件
-
跨数据集指标不得直接对比
-
检索策略声明必须包含数据源、关键词、筛选条件和最终纳入论文数量
这些规则让报告格式不再依赖 LLM 的临时发挥,每次输出的质量和深度保持一致。
4.2 空结果检测
在一次测试中,MiMo API 调用超时导致所有搜索结果为空,但 report_node 仍然被触发,LLM 编造了不存在的论文来填充报告。这是严重的数据可信度问题。
修复方式是在报告生成前增加空结果检测:如果 tool_results 中没有任何实质性论文数据,直接生成诚实声明,说明本次检索未找到相关论文及可能的原因。这彻底杜绝了"因空结果而编造"的情况。
4.3 本地论文库扩充:从 3 篇到 26 篇
这是整个阶段最耗时但也最有价值的一项工作。具体步骤如下:
用 Zotero(BetterBibTeX JSON 格式)导出文献元数据 → 写转换脚本 convert_zotero.py 将 Zotero 格式转为 ScholarCraft 的 JSON 格式 → 写 enrich_papers.py 脚本用 MiMo 自动填充 method、dataset、key_metric 等字段 → 手工审核并补全核心方法论文的指标数据。
最终论文库覆盖了以下方向:
| 方向 | 论文数 | 代表工作 |
|---|---|---|
| 扩散模型方法 | 8篇 | EDM、DiGress、FreeGress、UniGuide |
| VAE 方法 | 4篇 | JT-VAE、Grammar VAE、Chemical VAE |
| GAN 方法 | 2篇 | MolGAN、ORGAN |
| 评测基准 | 2篇 | GuacaMol、MOSES |
| 综述 | 7篇 | 覆盖扩散模型、3D分子生成、药物设计 |
| 经典基础方法 | 3篇 | Transformer、LoRA、JiT |
本地搜索的返回量从以前的 2-3 篇提升到 9-12 篇,相关性评分首次出现 10/10。
五、端到端测试
运行 python app.py "帮我调研扩散模型在分子生成中的应用方法",Agent 完整执行了五个步骤:
text
[PLAN] 生成 5 个步骤
[SELECT] 步骤 1: search_local → 多角度搜索完成,合并去重后共 9 篇论文
[EVAL] 相关性评估: 10/10 → 搜索完成
[SELECT] 步骤 2: search_arxiv → 补充搜索后找到 5 篇论文
[EVAL] 相关性评估: 9/10 → 搜索完成
[SELECT] 步骤 3: read_paper → 从搜索结果中提取 arxiv 论文详情
[SELECT] 步骤 4: compare → 执行对比分析
[SELECT] 步骤 5: summarize → 生成结构化报告
[SAVE] 报告保存成功
零错误,五个步骤全部完成。最终报告中的方法对比表格列出了 EDM、FreeGress、UniGuide 等核心方法及其数据集和局限性,关键指标部分出现了 FreeGress 的 79% MAE 提升等具体数值。
六、总结与下一步
本文记录了 ScholarCraft 从第一篇博客时的"初始版本"到现在的完整升级过程:
| 改进维度 | 改进前 | 改进后 |
|---|---|---|
| 搜索策略 | 单关键词 | 多角度并行 + MiMo 驱动 |
| 评估机制 | 无 | 迭代重试 + 相关性打分 + 提前终止 |
| 报告质量 | 自由发挥 | 结构化深度 Prompt + 空结果检测 |
| 论文库 | 3篇 | 26篇多方向覆盖 |
| compare 步骤 | 跳过 | 真实对比分析 |
| read_paper | 频繁报错 | 双路径 + 上下文注入 |
这些改进让 ScholarCraft 从一个"能跑通"的 Demo 升级成了一个"跑得好"的可靠系统。但还有一个关键能力缺失——记忆系统。当前 Agent 的每一次调研都是独立的,关闭终端再打开,它完全不记得之前做过什么调研、用户偏好什么方向。
在下一篇文章中,我将开始为 ScholarCraft 构建三层记忆系统:短期记忆(LangGraph Checkpointer 实现会话级上下文共享)、上下文管理(Token 预检与主动压缩机制)、长期记忆(SQLite + ChromaDB 实现跨会话偏好记录)。
完整的项目代码会同步更新到 GitHub,欢迎关注和交流。
本文是 ScholarCraft 系列的第二篇,后续文章将陆续更新。如果有任何工程落地上的问题或建议,欢迎在评论区讨论。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)