在西湖大学 NLP 实验室(张岳教授组)实习期间,我负责 DeepScientist 平台的 AI Copilot 模块开发,包括多轮对话链路、工具调用、SSE 流式输出等核心功能。平台用户 5000+,这篇文章整理面试中关于这个项目的常见问题和回答思路。
如何介绍这个项目
背景说明
DeepScientist 是一个面向科研人员的 AI 辅助平台,核心是帮助研究者完成文献检索、论文分析、实验设计等科研任务。我在其中负责 AI Copilot 模块,也就是平台的智能对话核心。
科研场景和普通问答有本质区别:用户的问题往往需要跨多个步骤才能回答,比如”帮我找最近三年关于 diffusion model 加速的论文,总结一下主流方法”——这不是一次检索能搞定的,需要 Agent 拆解任务、调用工具、整合结果。
内容介绍
整个 AI Copilot 模块分三层:
- 对话管理层:多轮上下文维护、会话隔离、历史摘要压缩
- Agent 执行层:基于 ReAct 模式的工具调用链路,支持文献检索、论文解析、代码执行等工具
- 输出层:SSE 流式输出,前端实时渲染,支持 Markdown、代码块、引用卡片
要点
三个核心技术点:ReAct 工具调用、SSE 流式输出、多轮对话上下文管理。
价值
- 用户从”手动检索+人工整理”变成”一句话描述需求,Agent 自动完成”
- 平台 DAU 提升,用户平均会话时长从 3 分钟增加到 12 分钟
- 复杂科研任务的完成率从 40% 提升到 75%
热门面试题
简单介绍一下这个项目
DeepScientist 是西湖大学 NLP 实验室开发的科研 AI 平台,我负责其中 AI Copilot 模块的核心链路开发。
科研场景的特点是任务复杂、需要多步推理。比如用户问”帮我分析这篇论文的方法论并和最新工作对比”,这需要先解析 PDF、再检索相关论文、再做对比分析,三步缺一不可。
我基于 ReAct 模式设计了工具调用链路,让 Agent 能够拆解任务、按步骤调用工具(文献检索、PDF 解析、代码执行等),最终整合结果输出。输出层用 SSE 实现流式推送,用户能实时看到 Agent 的思考和输出过程,体验接近 ChatGPT。
平台目前用户 5000+,复杂任务完成率从 40% 提升到 75%。
你在项目里是什么角色
AI Copilot 模块从 0 到 1 由我负责,包括:
- 后端:FastAPI + 异步架构,对话管理、工具注册、Agent 执行循环
- 流式输出:SSE 链路设计,前后端协议定义
- 工具开发:文献检索工具、PDF 解析工具、代码执行沙箱接口
- Prompt 工程:系统 Prompt 设计、工具描述优化、输出格式约束
你提到了 ReAct,详细说说
ReAct 是 Reasoning + Acting 的结合,核心是让大模型像人一样”先想再做”。
传统问答模式:用户问 → 模型直接答。遇到需要外部信息的问题就只能靠训练数据,容易幻觉。
ReAct 模式:用户问 → 模型思考(需要什么信息)→ 调用工具 → 观察结果 → 继续思考 → 最终回答。
举个 DeepScientist 里的例子:
1 | 用户:帮我找 2024 年关于 LoRA 微调效率的论文,总结主要贡献 |
ReAct 的关键优势是动态决策——Agent 不是按固定流程走,而是根据每步的结果决定下一步做什么。这对科研场景非常重要,因为用户的问题往往没有固定的解法路径。
SSE 是什么,为什么用 SSE 而不是 WebSocket
SSE(Server-Sent Events)是一种服务器向客户端单向推送数据的协议,基于 HTTP 长连接。
为什么选 SSE 而不是 WebSocket:
| 维度 | SSE | WebSocket |
|---|---|---|
| 方向 | 单向(服务器→客户端) | 双向 |
| 协议 | HTTP | WS |
| 断线重连 | 浏览器原生支持 | 需要手动实现 |
| 实现复杂度 | 低 | 高 |
| 适用场景 | 流式输出、通知推送 | 实时聊天、游戏 |
AI 对话的输出是单向的——服务器流式推送 token,客户端只需要接收渲染。SSE 完全够用,而且实现更简单,不需要维护 WebSocket 连接状态。
FastAPI 里的实现:
1 | from fastapi import FastAPI |
前端用 EventSource 接收:
1 | const es = new EventSource('/chat/stream'); |
踩过的坑: Nginx 默认会缓冲响应,导致流式输出变成”一次性输出”。需要在响应头加 X-Accel-Buffering: no 或在 Nginx 配置里关闭 proxy_buffering。
多轮对话的上下文是怎么管理的
多轮对话有两个核心问题:上下文窗口有限和会话隔离。
会话隔离:
每个用户会话有独立的 session_id,对应独立的消息历史。用 Redis 存储,key 是 session:{session_id}:messages,TTL 24 小时。
上下文窗口管理(三层策略):
1 | 第1层:滑动窗口 |
token 预算控制:
1 | def build_context(session_id: str, new_message: str) -> list[dict]: |
工具调用怎么设计的,如何保证大模型不调用错误的工具
工具注册:
每个工具是一个 Python 函数 + 描述 schema,注册到工具注册表:
1 |
|
三层保障防止错误调用:
- 精确的工具描述:每个工具的
description写清楚”什么时候用”、”不适合什么场景”,参数写清楚格式约束和枚举值 - 参数校验:工具执行前用 Pydantic 校验参数,不合法直接返回错误信息给模型,让它重新调用
- 重试机制:调用失败时,把错误信息加入上下文,让 Agent 自动修正参数重试,最多 3 次
项目的难点是什么
最难的是流式输出和工具调用的结合。
普通流式输出很简单,但 ReAct 模式下,Agent 在输出最终答案之前要先调用工具——而工具调用是同步的(需要等结果),这期间前端没有任何输出,用户会以为卡住了。
解决方案是分阶段流式:
1 | 阶段1:流式输出 Agent 的"思考过程"(Thought) |
SSE 事件类型区分:
1 | # 思考过程 |
前端根据事件类型渲染不同 UI,用户全程有反馈,不会感觉卡顿。
如何避免大模型幻觉
科研场景对准确性要求很高,幻觉是最大的风险。
四层防护:
- Prompt 约束:系统 Prompt 明确要求”只基于工具返回的信息回答,不允许使用训练数据中的论文细节”
- 来源标注:要求模型在回答中标注每个论点的来源(哪篇论文、哪个工具返回的)
- 相似度阈值:RAG 召回时设置 0.75 的相似度阈值,低于阈值直接告知用户”未找到相关文献”
- 用户反馈:界面有 👎 按钮,点击后记录 session_id 和消息 id,我会人工 trace 日志分析原因
如果重新设计,你会改什么
- 引入评测基准:目前靠用户反馈,不够系统化。应该建立一套科研问答的 benchmark,定期跑评测
- 工具结果缓存:同一个检索请求在短时间内可能被多次调用,加 Redis 缓存能显著降低延迟和 API 成本
- Agent 可观测性:每次工具调用的耗时、token 消耗、召回相似度都应该有 trace,方便性能分析
- 多模态支持:科研场景经常需要分析图表,接入多模态模型让 Agent 能理解论文里的图
面试节奏建议
介绍项目时按这个顺序:背景痛点 → 解决方案 → 技术亮点 → 业务价值,每段控制在 30 秒左右,主动在技术亮点处停顿,给面试官提问的机会。
面试官最感兴趣的点通常是:SSE 流式实现细节、ReAct 工具调用链路、多轮对话上下文管理。这三个准备好,基本能应对 80% 的追问。