Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

学术导师 Agent (Academic Mentor Agent)

基于 DeepSeek V4 + LangChain 的学术写作辅助 Agent,带 Gradio 对话界面。集成 长期记忆 与 复杂任务分步规划,可检索真实论文并导出 Word 文档。

项目背景与动机

为什么做这个

写综述时,最耗神的往往不是想出观点,而是一堆「琐碎但必须做」的事:跨多个数据库反复检索同一批文献、几十篇引用的格式(APA / IEEE / MLA / GB-T 7714)调了三遍还没统一、长文写到后半程忘了前面定过什么框架。这些事不复杂,但极其耗时——真正需要思考的研究问题反而被挤没了。

所以我想做一个「学术导师」:像导师一样记得你的研究方向、帮你找到真实可引用的文献、按你偏好的格式整理引用、陪你把一篇长文从确认需求到分步写完。它不取代写作,而是把检索、格式、结构这些可自动化的环节接走,让你专注在论证本身。

演进历程:从聊天助手到学术导师,六代迭代

这个项目不是一次性生成,而是经过六代迭代,每一代都解决上一代暴露的问题:

版本 形态 解决的问题 暴露的问题
V1 直接包装 DeepSeek API 的聊天助手(一个 prompt + 一个 chat 函数) 能用上 DeepSeek 对话 只会聊天:不会查文献、不会记忆、不会写长文
V2 接入 Semantic Scholar 检索,从「聊天」到「能查文献」 用户需要搜到真实可引用的论文 检索结果用一次就丢:记不住用户偏好,也没有质量把关
V3 首次加入用户画像记忆 记住研究方向、引用格式偏好 开发者自留备注:「V3 时的记忆模块需要与时俱进」——规则式关键词匹配太死板,换个说法就记不住
V4 手写 ReAct Agent:自实现工具调用循环、自我审校(reviewer 二次校验)、记忆、Semantic Scholar + arXiv 双源检索兜底 真正「能干活」:自己搜论文、回复前自我检查 工具循环、审校、记忆全部手写,逻辑交错,维护成本高;长文写作仍是一次性输出
V5 迁移到 LangChain(@tool + create_agent);重做记忆(规则式兜底 + LLM 提取双通道、防回显、文件锁) 框架化可维护;记忆从「规则死板」变成「规则 + LLM」双保险 复杂写作任务仍一步到位:模型拿到指令就倾向一次写完,无视「先确认需求」
V6 复杂任务状态机 + 两级意图路由 长文分步推进(确认→大纲→逐节→整合);意图识别成本可控 —

说明:当前实现对应 V6;代码文件沿用了早期版本命名 agent_v5_langchain.py。V1、V4 的原始源码已归档至 Other version/ 目录;V2、V3 为阶段总结、无逐版可运行代码。

始终围绕 Agent 的核心公式演进

从 V4 到 V6,这个项目始终在打磨同一个公式:

Agent = LLM(推理) + 记忆(状态) + 工具(行动) + 提示词(策略) + 规划循环(控制)

  • V4(手写):公式里的五个组件——LLM 调用、记忆、工具、提示词、规划循环——全部手写实现,每个都亲手做过一遍。
  • V5(LangChain 标准化封装):用框架把 LLM + 工具封装成标准组件,省掉重复造轮子。
  • V6(强化规划循环与提示词策略):重点强化公式中的两块——规划循环升级为状态机,提示词策略升级为两级意图路由。

每一代都不是「换个框架」,而是围绕公式里某个组件做一次针对性强化。

开发中的三个关键判断

每个决策背后都有一次真实的踩坑或取舍,写出来比结论本身更有说服力:

1. 先手写 ReAct,再迁移到 LangChain(V4 → V5)

手写完整个 ReAct 循环后,我才真正理解 Agent 的本质不是模型调用,而是状态维护——每轮推理之后,系统要把工具结果、对话历史、当前进度当作状态管理起来,否则 agent 就是一次性的。所以 V5 迁到 LangChain 时,我判断它省掉的是重复造轮子;但状态管理、记忆持久化、意图路由这些核心逻辑,我选择自己掌控,而不是把决策权交给框架。

2. 意图识别用两级路由,而非直接交给 LLM(V6)

普通对话占请求的绝大多数。如果我让模型每轮都判断一次「这是不是复杂任务」,等于为 90% 的简单问答也付一次推理成本。所以我把明确句式收进规则层(零成本),只有拿不准的边界句才动用轻量 LLM——判断失败时默认降级为普通对话,最坏情况与不做路由一致。

3. 记忆持久化用多线程 + 文件锁(V5)

记忆更新放在后台线程,是为了不阻塞用户看到回答;但多线程一旦各自持有旧快照,就会互相覆盖——这个坑我踩过才记住。解法是让「读-改-写」整体进入全局锁,worker 永远基于最新文件状态。

技术实现细节见下方「设计要点」;意图路由的 20 条边界用例见 tests/test_intent_routing.py。

功能特性

功能 说明
🔍 论文检索 调用 Semantic Scholar Graph API 搜索真实学术文献
📝 文档生成 用 python-docx 一键导出 Word 文档(支持 Markdown 标题转换)
🧠 长期记忆 用户画像(user_profile.json)跨会话记住研究方向、引用格式、论文进度、关注关键词
📋 任务规划 复杂写作任务自动分步推进:确认需求 → 大纲 → 逐节 → 整合导出
✅ 学术质量自检 输出前强制检查:引用真实性 / 格式一致性 / 逻辑连贯 / 空洞表述
🔎 引用审计 回答中的引用与本次检索白名单比对,无法核实的标注 [需核实]
💬 多轮对话 完整历史回传,保持会话上下文

技术栈

  • 模型:DeepSeek V4(OpenAI 兼容接口,思考模式)
  • Agent 框架:LangChain 1.x create_agent + @tool 工具装饰器
  • 前端:Gradio ChatInterface + gr.State(跨轮状态)
  • 文档:python-docx
  • 检索:Semantic Scholar Graph API

设计要点

以下设计决策是本项目保持可维护、可验证的关键,也是代码实现的直接依据。

1. 复杂任务用「状态机」而非纯 Prompt 控制

实测发现:create_agent 的模型在单个 invoke 内可自由决定执行多少步,即使系统提示词写明「必须先确认需求、禁止一次写完」,模型仍倾向一步到位生成全文。因此改用代码级状态机(idle → outline → writing → done),每一轮只向模型注入当前步骤的单一指令,配合 gr.State 保存跨轮进度,从根上杜绝「一步写完」。

入口用「两级意图路由」:状态机的触发不靠穷举关键词,而是「强信号直接判定 → 弱信号(边界句)才调用轻量 LLM 精判 → 无关直接放行」。普通对话零额外成本与延迟;LLM 只处理拿不准的句子(复用 DeepSeek flash 且禁用思考模式,单次约 0.6-1 秒);识别失败默认降级为普通对话,最坏情况与不做路由一致。

量化对比(52 条边界句实测,python tests/benchmark_intent_routing.py 可复现):

方案 准确率 平均延迟 LLM 调用率 估算成本
纯关键词 86.5% 0.0ms 0% ¥0
纯 LLM 90.4% 503ms 92% ¥0.010
两级路由 96.2% 83ms 13% ¥0.0015

两级路由在准确率上反超纯 LLM(强信号规则层是确定性兜底,纯 LLM 反而在明确句上会波动),同时延迟降约 6 倍、成本省约 7 倍——用数据验证"规则层归规则、拿不准才归 LLM"的取舍。

⚠️ 基准说明:52 条为自建边界句样例(强信号段即规则词表本身),单次运行;LLM 层有随机性,数值会随运行波动、重跑可能不同。想得到稳定结论,建议混入真实用户对话样本、多次运行取均值±方差。

2. 长期记忆:规则式兜底 + LLM 提取,两道防线

  • 规则式:确定性更新核心字段(研究方向 / 引用格式 / 语言偏好),零成本、可预期。
  • LLM 提取:负责开放字段(关键词、论文进度、重要发现),后台线程异步执行,不阻塞响应。
  • 排除了两个坑:① LLM 会把 prompt 里的旧画像值「回显」覆盖新值 → 提取 prompt 不再包含当前画像、规则已处理的字段 LLM 不得覆盖;② 多线程各自持旧快照互相覆盖 → 读-改-写放进全局锁,worker 始终基于最新文件状态。

3. 工具层健壮性

  • Semantic Scholar 限流(429)时指数退避重试 + 友好降级,不让网络抖动打断整个 agent。
  • Word 生成工具兼容 Markdown 标题语法。

快速开始

# 1. 安装依赖(Python 3.11+)
pip install -r requirements.txt

# 2. 配置密钥
cp .env.example .env
#    编辑 .env,填入 DEEPSEEK_KEY 和 SEMANTIC_SCHOLAR_KEY

# 3. 运行
python agent_v5_langchain.py

打开 http://127.0.0.1:7860 即可对话。

密钥获取

变量 获取地址
DEEPSEEK_KEY https://platform.deepseek.com
SEMANTIC_SCHOLAR_KEY https://www.semanticscholar.org/product/api

用法示例

你输入 Agent 行为
什么是城市热岛效应? 直接解释概念(不走复杂流程)
帮我找 2 篇图神经网络的论文 调用 search_papers 检索并整理
帮我写一篇关于城市热岛效应遥感监测的完整综述 触发分步流程:确认需求 → 大纲 → 逐节 → 导出 Word
我的研究方向是城市热岛效应的遥感监测,引用格式用 APA 写入长期记忆,后续回答自动个性化

项目结构

├── agent_v5_langchain.py    # 启动入口(薄壳,核心在 academic_mentor/)
├── academic_mentor/         # 核心包(依赖单向: config → tools/memory → citation_audit/router/state_machine → agent → ui)
│   ├── config.py            # 环境变量 / 常量 / LLM 连接(含意图判断轻量实例)
│   ├── memory.py            # 长期记忆:用户画像读写 / 规则+LLM 提取 / 文件锁
│   ├── tools.py             # 论文检索 / Word 文档生成 / 检索白名单池
│   ├── citation_audit.py    # 引用审计:正则提取引用 + 白名单校验
│   ├── router.py            # 两级意图路由
│   ├── state_machine.py     # 复杂任务状态机 + 各阶段提示词
│   ├── agent.py             # 系统提示词 + create_agent
│   └── ui.py                # Gradio 前端 + 对话回调
├── tests/
│   ├── test_intent_routing.py       # 20 条路由边界用例(每条例标注路由层)
│   └── benchmark_intent_routing.py  # 路由量化对比(52 条,准确率/延迟/成本)
├── Other version/           # 历史版本源码(V1 手写封装 / V4 手写 ReAct)
├── requirements.txt         # 依赖清单
├── .env.example             # 密钥模板(不含真实值)
└── README.md

局限与已知问题

  • 单用户演示:长期记忆按单用户设计,未做多用户隔离,不适合直接多人使用。
  • 引用审计覆盖面有限:只比对本次检索白名单,白名单外的引用无法自动核实。
  • 无 CI:测试与基准需手动运行,未接入持续集成。
  • 基准样本自建:52 条边界句为自建样例,未混入真实用户对话,指标为参考值(见上文基准说明)。

致谢

项目由本人与 Claude Code(Anthropic 的 AI 编码助手)协作开发:核心架构、状态机与两级路由设计由本人主导,Claude Code 协助实现、边界测试与文档迭代。

许可证

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages