办公软件里的那些重复劳动,大概是所有打工人共同的痛点。写周报、调格式、做PPT、从表格里抠数据,每一项单看不难,叠在一起却能吞掉大把时间。我这次做的毕业设计,就是把AI智能体塞进一个自研的Office套件里,让大模型不只停留在“聊天框里回答问题”,而是真正能调用工具、操作文档、生成内容,像一个坐在旁边的实习生一样把杂活接走。
简单说,这个项目包含三个部分:一套支持文字、表格、演示文稿的Web端Office套件,一个承接大模型调用的后端服务,以及中间那层最关键、也最花心思的AI智能体工作流引擎。整套系统跑通之后,用户可以用自然语言下发指令,比如“把这份文档改成会议纪要格式”“根据这组销售数据生成季度PPT”,智能体会自动拆解任务、调用编辑器的API、生成内容并落回文档里。
这篇文章会按我实际的开发顺序来拆:选题和需求怎么定、整体架构怎么搭、智能体的工具调用机制怎么设计、几个核心功能模块怎么实现、性能怎么调、踩过哪些坑。如果你是计算机科学与技术专业的应届生,正在纠结毕设选题,或者想在简历里放一个“AI+生产力工具”方向的完整项目,这套复盘应该能给你不少可以直接抄的作业。
1. 选题动机与需求拆解
1.1 为什么选“AI智能体+Office套件”
毕设选题我纠结了挺久。纯算法方向没把握,纯Web系统又显得不够新,最后决定做一个“应用层AI”的项目,既要有实质的系统工程,又要把智能体落地到真实场景里。选Office套件是因为它离用户最近,需求最明确,不像一些ToB系统那样需要大量领域知识才能说清楚价值。
另一个重要原因是,Office套件的功能边界足够清晰,方便做成能被智能体调用的工具集。文字处理、表格计算、演示文稿,这三类编辑器天然就有稳定的操作接口——插入段落、修改样式、读取单元格、添加幻灯片。把编辑器能力封装成工具函数,大模型通过函数调用(Function Calling)来操纵这些工具,就能组成一条“感知-决策-执行”的闭环。
这个方向的技术栈也很有代表性:前端要解决编辑器内核和复杂UI,后端要处理大模型接入与流式输出,中间还夹着一层Prompt编排和工具协议。做完这一套,等于把一个全栈AI应用的关键环节都过了一遍。
1.2 目标用户与核心需求
我把目标用户设定为两类人。第一类是每天要写材料、做汇报的职场人,他们的核心痛点是“产出结构化内容”太慢,写一页PPT大纲可能就要半小时;第二类是学生会和教师群体,经常手握一堆资料却不知道怎么编排成册。对这两类人来说,AI的价值不是替代思考,而是先把骨架搭好、把格式理清,让人把精力留在判断和修改上。
围绕这两类用户,我梳理出三个核心场景:
- 长文档辅助写作:给定零散材料,自动生成结构化初稿,支持续写、扩写、改写和全文摘要。
- 演示文稿快速生成:用户提供主题或文档,自动规划大纲,逐页生成标题、正文和配图建议,最终导出可编辑的PPTX。
- 表格洞察与公式辅助:读取表格数据,自动生成统计摘要,用自然语言描述数据趋势,还能把自然语言翻译成Excel公式。
这三个场景分别对应套件里的三个编辑器,也让智能体有了“干实事”的抓手,而不是悬在空中的玩具。
1.3 功能范围划线
毕设周期有限,我给自己划了明确的边界。核心必做:文档编辑器的基础编辑能力(富文本操作)、三个AI功能模块、智能体的工具调用主线、用户文档的上传与存储。明确不做:多人协同编辑、复杂的样式系统(如页面分页排版)、移动端适配。
这样划线的逻辑是:把工程重点放在AI链路的完整性和稳定性上,而不是铺开做一堆浅尝辄止的编辑器功能。概念验证阶段最怕的就是“看起来哪里都能点,实际上哪里都跑不通”。
2. 系统总体架构设计
2.1 编辑器内核与前端方案
编辑器这块我调研了三条路:自己用Contenteditable实现、基于Quill二次开发、直接用成熟文档框架改造。第一个方案工作量大且坑极多,第二个方案自定义能力强但表格支持偏弱,最终我选择了基于开源的文档编辑器内核做二次开发,在保障基础编辑体验的同时,通过插件机制注册智能体需要的外部接口。
前端的整体框架用了React加TypeScript,状态管理选了Zustand——够轻,配合编辑器这种局部状态非常频繁的场景,比Redux少写很多样板代码。界面风格参考了主流办公软件的三栏布局:左侧文件列表、中间编辑区、右侧智能体对话面板。对话面板是AI功能的主入口,任何指令都通过这个面板发出,结果以流式方式实时回显。
值得一提的细节是,编辑器内核的事件系统被我单独封装了一层“能力适配层”。比如“插入段落”和“修改文本颜色”这类原子操作,统一暴露成insertParagraph(text, style)和setTextColor(color)形式的命令,这样智能体调用时不用关心底层是基于内容模型还是DOM操作,降低了大模型工具定义的复杂度。
2.2 后端服务与AI接入层
后端用了Python的FastAPI,核心考虑是生态。Python那边有大模型相关的SDK和数据处理库,文件格式转换(比如生成PPT)也有python-pptx这类现成库,能省掉大量胶水代码。服务拆了三个模块:文件服务(上传、解析、转存)、任务服务(读取工具调用队列并驱动执行)、AI网关(统一封装模型请求和流式响应)。
AI网关的设计参考了代理模式,把模型供应商的差异屏蔽在业务之外。前期调试我用一种模型做快速验证,后期切换更强模型只需要改一个配置项。网关内部实现了请求队列和令牌桶限流,避免前端无限制地打爆模型API。
任务服务是智能体执行链路的中枢。它维护任务状态机,状态包括:待拆解、待调用工具、等待模型续写、完成。工具调用的结果会回填到对话上下文里,作为下一次模型请求的参考信息,这个机制是整套智能体“会干活”的关键。
2.3 智能体工作流设计
智能体的工作流我采用了一种极简的ReAct变体:模型根据用户指令,决定下一步动作,动作要么是“调用工具”,要么是“直接回答”。前端把模型返回的JSON解析出来,如果里面有工具调用,就执行并把结果回传给模型;如果只有文本,就直接展示给用户。
这套设计的优点是把“决策逻辑”完全交给模型,系统本身保持无状态,扩展工具时不需要改工作流引擎。我在工具定义里严格要求了参数描述,比如“文档标题级别必须是1到6的整数,默认是2”,这样模型才能准确理解参数取值范围,减少无效调用。
为了让工作流更稳,我还加了“计划先行”策略。对于复杂任务,比如生成一份多页PPT,模型会先输出一个JSON格式的计划列表,系统把计划逐条展示给用户确认,确认后按计划顺序执行。这个机制本质上是把大任务拆成多个可验证的小步骤,避免模型在长链路中“迷失方向”。
3. 智能体核心机制设计与实现
3.1 工具注册与函数调用协议
整个智能体最底层的是工具注册机制。我在后端定义了一个装饰器,任何函数只要标注了名称、描述和参数Schema,就会自动注册进一个全局工具表。模型请求发出的时候,工具表会被序列化成OpenAI Function格式的参数,传给大模型。
工具函数的返回格式我也做了统一规定:必须是一个JSON对象,包含success(布尔值)、data(执行结果)和message(人类可读的描述)三个字段。这个约定很重要,因为模型需要根据返回值判断是否继续调用后续工具,清晰的结果格式能明显提升模型在多轮工具调用中的稳定性。
下面是文档插入工具的一个简化示例:
from app.agent import register_tool, ToolResult @register_tool( name="document.insert_paragraph", description="在文档光标位置插入一个新段落", parameters={ "type": "object", "properties": { "text": {"type": "string", "description": "段落文本内容"}, "style": {"type": "string", "enum": ["normal", "heading1", "heading2", "quote"], "description": "段落样式"} }, "required": ["text"] } ) def insert_paragraph(text: str, style: str = "normal") -> ToolResult: # 内部调用编辑器内核的 API 完成插入 ... return ToolResult(success=True, data={"paragraph_id": 123}, message="段落已插入")这个机制带来的扩展性很好。后期我加了“获取当前文档文字内容”“替换选中文本”等工具,只需要各写一个函数,模型马上就能学会使用。
3.2 多轮上下文管理与记忆
多轮对话里最头疼的问题是上下文爆炸。Office场景下,一轮操作可能往上下文里塞进整篇文档的内容——比如用户要求“总结这篇文章”,系统需要把全文传给模型,如果接着又说“再改成周报格式”,又得再传一次。轮次一多,token数直线飙升,不仅慢,还烧钱。
我的方案是“分级上下文管理”。系统把上下文分为三层:固定系统提示(角色设定和能力说明)、会话消息列表(只保留最近6轮)、动态工具结果(只保留最近3轮的返回数据)。当工具返回的内容特别大时,比如全文摘要,我会让工具返回压缩后的摘要文本而不是原始全文,从源头控制token量。
此外,我给每个会话维护了一个轻量的“记忆文件”,记录用户的操作偏好,比如“用户喜欢首行缩进两个字符”“用户生成的PPT偏好深色模板”。这些信息在对话开始时以精简片段注入系统提示词,让模型在后续操作中更贴合用户习惯。实现起来不复杂,但体验提升非常明显。
3.3 结构化输出解析与错误容忍
大模型的文本输出天生不稳定,一旦输出不是合法JSON,整个工具调用链就会断。我做了三层兜底。第一层,在模型请求的参数里强制设定输出格式为JSON对象,并把相关示例写清楚;第二层,后端接了解析器,能自动修复常见的JSON语法错误,比如多余逗号、未闭合括号;第三层,如果解析仍然失败,系统会直接把原始文本当作“模型回复”展示给用户,而不是报错中断。
实际测试里,这三层兜底把工具调用的成功率从裸模型的82%拉到了96%以上。让我印象最深的是解析器“修复多余逗号”这个能力,看起来只是一个小函数,却在实际运行中避免了很多白屏和转圈。
结构化输出还有一个隐藏的好处:前端可以拿到模型返回的JSON,提前渲染出工具执行的“预览卡片”。比如模型计划生成5页PPT,前端先把5个页面的标题展示在面板上,用户一眼就能看出AI到底打算干嘛,有不满意的地方还能在下一次指令里直接修改。
4. 核心功能模块实战实现
4.1 长文档智能写作与改写
写作模块主要做了三个能力:续写、扩写和改写。续写是在光标位置生成下一段内容,扩写是把一个要点拓展成完整论述,改写则是按目标风格润色原有内容。
这里我踩过最大一个坑是“生成内容与上下文脱节”。最初版本里,模型只能看到当前段落的前几句,生成的内容读起来像漂浮的纸片,接不上前文。后来我让文档工具在生成前先返回一个“浓缩上下文”:当前章节的小标题、最近500字正文、文档总体大纲。把这些信息拼进提示词之后,生成内容的衔接度明显提升。
为了让生成结果可回溯,我把每次AI写入的内容标记成了特殊样式,用户可以在右侧面板一键查看“哪些是AI写的、哪些是人工写的”。这个小设计在答辩演示时加了不少分,也让用户更有安全感——AI改完的东西,随时能还原。
4.2 PPT一键生成与页面编排
PPT生成是三个模块里链路最长、也最考验智能体编排能力的。我的流程分四步:第一步,接收用户提供的主题或文档;第二步,模型生成PPT大纲(含标题、结构、每页要点);第三步,按大纲逐页生成内容;第四步,调用后端脚本把内容渲染成PPTX文件。
第二步和第三步之间的衔接很关键。模型首轮返回的大纲是一个JSON数组,数组中每个元素代表一页幻灯片,包含三级结构:章节标题、页面标题、要点列表。系统把大纲渲染成可视化面板,用户可以增删页面。确认后,系统逐页把“章节标题+页面标题+已有要点”作为上下文传入模型,生成页面内的完整文本和配图建议。
PPT文件落地我用了python-pptx库,纯代码排版虽然不高级但胜在稳定可控。每一页生成后会立即渲染一张缩略图回传前端,整个流程像看直播一样一页页蹦出来,体验感远好于全部生成完再一次性展示。整个链路平均生成一份8页PPT约耗时40秒,大部分时间花在大模型逐页请求上,我在前端加了进度条和取消按钮,避免用户干等。
4.3 表格数据洞察与公式翻译
表格模块相对轻量,更像一个“数据问答”入口。用户上传CSV或直接粘贴数据后,系统先调用工具完成数据采样和基础统计(最大值、最小值、均值、方差、行数列数),再把采样结果传给模型做趋势解读。
公式翻译功能实现起来比预想简单,核心是整理一张“功能动词到Excel函数”的对照表塞进提示词。比如“求平均值”对应AVERAGE,“条件计数”对应COUNTIF,模型理解需求后输出完整公式,我再写一个验证函数,用公式解析库检查语法合法性,不合法就让模型重写,最多重试两次。最终用户点一下就能把公式插入到当前单元格,实用性很强。
这个工具让我意识到一件事:AI在办公场景里最大的价值不是“做大设计”,而是“把已知操作做得更快”。公式翻译这类功能,用户知道Excel里有函数,但记不住参数;AI把这个信息差填上了,用户就愿意用。
5. 性能优化与踩坑实录
5.1 流式输出与前端渲染
最初版本里,AI生成内容是一整段一次性返回的,用户要盯着转圈几秒钟甚至十几秒,体验非常差。后来我改成了基于SSE(Server-Sent Events)的流式输出,前端拿到增量文本后逐块渲染。
流式输出有一个连带问题:工具调用是结构化的,没法像纯文本那样平滑地“流式展示”。我的处理方式是,前端的流式通道里同时传输文本增量和工具状态事件,工具状态事件用特定前缀标识,前端解析到之后渲染成流程卡片。这样用户在等待生成PPT大纲时,能实时看到“正在分析文档结构”“正在生成第3页内容”这些中间状态,焦虑感大幅降低。
一个性能细节是:模型返回的Token被拆成小块后,前端如果每次收到都触发全量Diff,编辑器会卡顿。我在前端加了“合并渲染”机制,把50毫秒内的增量合并成一次DOM操作,实测长文档生成时,编辑器的输入延迟从可见卡顿降到了基本无感。
5.2 长文本分片与模型上下文窗口
文档全文分片是绕不开的问题。模型单次上下文窗口有限,动不动传10万字文档进去,要么超出窗口直接报错,要么超长请求慢到不可用。我的策略是分层处理:上传文档后先全文解析建立索引,对话时根据用户指令类型选择切片。
比如“生成全文摘要”,我会让工具先把章节标题全部提取出来,模型基于标题规划摘要结构;正文部分用滑动窗口分片,每片带500字重叠区,避免切断句意。分片完成后,逐片生成局部摘要,再用一个汇总模型把局部摘要合并成总摘要。
这个方法不是万能钥匙,遇到内容关联性极强的手册类文档时,局部摘要会丢失细节。但胜在稳定,90%以上的场景都能跑通,而且把耗时控制在了可接受范围内。
5.3 工具并发与重试策略
智能体有时候会一口气请求多个工具,比如“帮我把这篇文章转成会议纪要,再统计一下词频”。最初我的实现是串行执行工具,模型要等前一个工具返回才能继续,浪费了不少时间。后来改成并发执行互不依赖的工具,任务服务里维护一张依赖表,只有存在依赖关系的工具才强制等待。
重试策略也有讲究。模型请求偶尔会超时或返回空值,直接失败重发整个请求,不仅浪费之前工具调用的开销,还可能产生重复内容。我的策略是:只对幂等的工具做无脑重试,比如“获取文档字数”这种读操作;对写操作,重试前先让模型明确“上一次执行是否成功”,根据确认结果决定继续还是重做。
这套策略让我想到了一个很有用的原则:AI应用里,“失败恢复”比“避免失败”更重要。因为模型天然存在不确定性,系统必须设计成“允许出错,但错误要能被纠正”,而不是假设每次调用都完美。
6. 测试评估与个人心得
6.1 功能验收与效果对比
开发完成后,我整理了一份验收清单,主要检查各模块的主流程是否闭环。测试用例包括:从零开始生成一篇长文、把已有文档改写成周报格式、上传销售数据并生成可视化摘要、根据一个主题生成8页完整PPT。
整体跑下来,原来预计1小时的办公任务,在套件辅助下基本压缩到10到15分钟。最流畅的是改写场景,模型几乎不需要调用多次工具,一次就能完成;最不稳定的是长文档生成,偶尔会出现后半部分偏题的情况,需要人工干预调整大纲。
为了量化效果,我对比了纯文档生成和“计划先行”模式下的输出质量。用同一份素材跑10次,前者的有效产出率约七成,后者接近九成。原因很清楚:先输出大纲让结构先定了,后续每段生成都有锚点,模型不太容易跑偏。
6.2 遇到的三个典型问题复盘
第一个问题是工具调用循环卡死。早期模型偶尔会反复调用同一个工具而不输出任何文本,像是陷入了死循环。我在任务服务里加了工具调用次数上限,超过5次就强制中断并让模型给出阶段总结。第二个问题是多页PPT出现模板内容泄漏,后面页会带上前面页的文案。排查下来是上下文重复注入导致的,把每页的输入上下文隔离之后解决。
第三个问题比较隐蔽:编辑器状态同步延迟。工具在文档里插入了内容,但前端编辑器DOM没有刷新,出现“AI写了一段话但界面看不到”的诡异现象。这跟编辑器内核的事件监听机制有关,我把数据变更改成显式触发同步事件之后,问题不再出现。
这三个问题的共同点是没有一个靠“看代码”就能发现,全部是在实际使用中被逼出来的。这也是我想说的:AI应用的Bug往往不是逻辑错了,而是状态对了但展示时机错了。
6.3 可以继续扩展的方向
如果继续做下去,我第一个想补的是插件市场。既然工具注册机制已经通用化了,完全可以允许第三方开发者贡献自己的工具函数,像装浏览器插件一样装进套件。第二个方向是本地知识库的深度整合,让智能体可以检索用户的历史文档并在生成时引用,而不是只看当前打开的这一个文件。
再往下想,还可以接OCR能力,用户截图即变成可编辑文字;或者接语音输入,让整个套件变成“动嘴就能办公”的工具。这些扩展在架构上都不会伤筋动骨,因为智能体链路是稳定的一层壳,加能力就是在壳上开新的洞。
最后分享一个我在项目答辩时被问到的、也最能体现这个项目价值的问题:“你这个AI套件和直接用ChatGPT写文档有什么区别?”我的答案是:ChatGPT给的是文字,我这个套件给的是“内容加排版加文件”。用户拿到的是一份现成的、可编辑的文档,而不是一大段需要自己重新排版粘贴的文本。这个区别看似微小,却是办公场景和聊天场景的本质差异——办公要的是成品,聊天要的是答案。
整个项目做下来,我最大的体会是:AI编程的难点已经不在“调用大模型”这个动作上,而在怎么把模型的能力编织进一个真实可用的系统里。工具协议、状态管理、错误恢复、上下文时效,每一层都是课本上碰不到的工程问题。这些东西比某个花哨的功能更容易被低估,但恰恰是它们决定了一个演示项目能不能变成一个真正有人愿意用的产品。