开发日志14-【studyAgent】-文件传输
在开发时我发现单纯的文本已经无法满足考研党的需求了。面对复习大纲、知识点总结,如果能让 AI 直接“阅读”用户上传的文档,并结合系统内置的“学习计划规划”能力,可以进一步满足用户的需求。市面上的 Kimi、ChatGPT 都有很棒的文件解析能力。为了在我的项目中复刻这一体验,同时不破坏现有的 Tool Calling(工具调用)逻辑,我摸索出了一套解决方案。本文将复盘这一功能的完整实现过程与踩坑记录。具体实现策略是:
预处理:在用户发送消息前,先通过独立的接口提取文件纯文本。
静默拼接:前端将“提取到的长文本”与“用户的提问”拼装在一起,伪装成一条普通文本发给 Agent 主循环。
数据分离:底层保存完整上下文防失忆,UI 层只展示精致的文件卡片。
一、文档解析与静态存储
为了支持考研党最常用的 .txt, .pdf, .docx 格式,我在后端引入了 PyMuPDF 和 python-docx。
除了提取文字,后端还要负责文件的物理存储,以便前端能渲染出可点击下载的文件卡片。
核心逻辑如下:
接收文件后,根据后缀名调用不同的库提取纯文本,并限制最大 Token 长度(如 8000 字),防止撑爆 LLM 上下文。
返回提取出的文本 extracted_text,以及本地静态映射的 url。
二、解决大模型失忆与用户历史文档查阅需求
- 问题:如果把几万字的文件内容存进数据库,每次切换历史会话时,界面上会渲染出一大坨极其丑陋的文字,因为前端总是通过数据库来查询数据,并将其渲染在页面上的;但如果不存进数据库只发给大模型一次,只把用户query和大模型的回答存下来,那么用户在多轮对话(比如:“帮我把大纲里的第三章延后一天”)时,大模型就会“失忆”,因为它在历史记录里找不到文件内容了。
解决办法:
我在后端存库前,用专属的标识符将巨量文本(提取到的文件内容)包裹起来。大模型能看懂并拥有了长期记忆,在获取历史上下文的时候可以直接从数据库message对象的content中直接获取到具体的提取到的文件内容,而在前端 Vue 渲染历史记录时,只需一行正则将其抹除:
cleanContent = cleanContent.replace(/===FILE_START===[\s\S]*?===FILE_END===\n?/, '').trim()
这样既能保证大模型不失忆,又能保证前端不会渲染出冗长的文本内容。
2. 问题:经过上一步大模型是不会失忆了,但用户查看历史记录会非常疑惑:“根据文件帮我生成学习计划,可是文件在哪?”这是因为我们通过正则把提取的文件内容剔除,同时又没有存储下用户上传的文件,导致这个文件只是一次性,并不能被反复查看到。
解决方法:在上一步提取文件内容时,不仅做extract文件内容这一项工作,同时把文件存在本地项目的静态目录,并同时返回文件的url,该url的路径构造如下:
#将文件存入服务器本地静态目录
file_path = os.path.join(UPLOAD_DIR, filename)
with open(file_path, "wb") as f:
f.write(content_bytes)
base_url = str(request.base_url).rstrip("/")
file_url = f"{base_url}/static/uploads/{filename}"
此时在静态目录中我们可以看到文件会被存储下来:
之后在后端send_message方法中我们会获取到提取的文件content以及文件的url,把url存入message的附件字段,当渲染窗口中历史message时,只要获取到文件的url就能支持查看自己历史发送过的文件。
3. 效果对比
在没有实施上述策略,为了保证大模型不失忆而把文件内容全部存入数据库时,前端渲染如下,它把冗长的文件内容一并打印出来了:
而实施上述策略后,我们不仅可以保证数据库数据的完整,使得大模型获取历史上下文后不会失忆,还把文件的url存了下来,使用户可以任意查看之前发送过的文件:
因为绝大多数现代浏览器(如 Chrome, Edge)原生不支持直接在网页中预览 Word (.docx) 文件。当把 …/computeNet.docx 输入浏览器回车时,它通常会直接触发后台下载,点击预览会自动触发文件下载:
模型也能正确接收文档的内容,根据文档内容制定计划:
至此,我的 408 考研助手正式具备了“阅读理解”能力。用户可以丢一份考纲/需要复习的ppt给它,它能结合现有的 Tool Calling 自动生成思维导图、并精准排布到用户的日程待办中!
更多推荐




所有评论(0)