ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

AI办公助手开发实战:会议纪要转任务与企业知识库RAG

AI办公助手开发实战:会议纪要转任务与企业知识库RAG AI 办公是最近一段非常热的方向。很多产品陆续把会议纪要、文档总结、任务派发、制度问答放进了同一个入口用户不再必须打开多个系统去查找和填写信息。但真正动手开发过这类功能的人会发现难度不在把一段文本发给大模型后获得回复而是如何让模型输出能够被任务系统识别如何让回答引用企业内部资料又如何在自动执行任务时不越过权限边界。从技术开发的视角看现阶段谈“布局 AI 办公”真正拉开差距的往往不是哪家模型参数更大而是谁能把办公场景里的数据权限、文档结构、执行流程提前整理好。模型可以理解为一位能力很强的实习生但不能让这位实习生在没有企业上下文、没有操作边界的情况下直接处理真实任务。这篇内容会从一个高频场景切入会议纪要自动生成、任务结构化、知识库制度问答搭建一个最小可运行的 AI 办公助手并说明从演示项目走向生产环境必须补齐的工程能力。1. 先理解 AI 办公平台的能力分层1.1 不是“加一个聊天框”而是三层结构一个 AI 办公功能如果只做“输入问题输出一段回答”本质上还是通用的对话能力离办公场景的落地还有距离。办公场景的核心特征是数据来自企业文档流程需要落入任务系统操作必须受到组织和权限约束。可以把 AI 办公拆成三层来理解能力层解决的问题对应技术模块典型例子模型层理解、总结、生成大模型接口、提示词管理、结构化输出把会议转写文本压缩成会议要点知识层回答企业内部问题文档解析、切片、向量化、检索召回从员工手册里找到年假计算规则执行层改变业务数据状态函数调用、接口对接、审批流、任务系统在任务管理工具里创建一条待办并分配负责人当用户说“帮我整理上周运营例会的待办事项”三层能力会这样协同模型层理解会议记录并抽取结构化信息执行层调用会议系统的 API 确认会议中提到的负责人和截止时间任务系统再创建待办。整个过程中不是只发生一次模型请求而是发生多次调用和多步状态变化。1.2 提前布局的核心是沉淀办公数据和组织信息有些平台能更早推出完整的 AI 办公能力通常不是因为某一天才接入大模型而是更早把办公软件里的组织架构、审批流、文档权限和文件结构做成了机器可识别的数据。比如一个部门的权限树如果已经维护得足够清楚AI 在回答“这个预算我能看吗”时就能把“能不能看”拆成权限校验和内容检索而不是把所有文件都丢给模型。对应到普通团队如果要现在开始建设 AI 办公能力最应该提前做的工作不是攒一堆提示词而是统一用户身份和组织结构保证任何 AI 操作都能落到具体的人和部门。文档要有稳定 ID、版本、权限和来源信息方便后续做检索和引用。任务系统、审批系统尽量开放 API这样 AI 才能替用户执行操作。对高风险操作先建立“创建草稿、人工确认再执行”的流程。先理解清楚这几层的关系后续写代码时就不会把知识库问答和自动化执行混成一套逻辑。2. 搭建最小 AI 办公助手的环境准备2.1 选一个高频且有代表性的场景会议纪要转任务开发任何系统都最好从一个最小闭环开始。这里选择“会议纪要转任务”作为第一个闭环原因是它真实覆盖了 AI 办公的关键难点输入是非结构化文本可能是语音转写或速记文字。输出需要被业务系统识别不能只是自然语言段落。执行动作必须可确认、可追踪最好还能区分高风险和低风险。假设原始会议记录如下会议讨论新用户增长活动。产品小王说活动页面预计周五上线需要设计先给 Banner 做三版。运营大刘负责渠道排期下周二前确认预算。用户组反馈希望支持邀请奖励后端老张评估要改动邀请关系链排期到下周四。目标输出是一段会议摘要。几条明确决策。若干 action item每条包含负责人、任务内容和原始截止时间描述。可能存在的风险和阻塞点。真实场景中模型并不总能准确算出“下周二”对应的具体日期所以最小版本可以保留截止时间的原始文本“下周二前”后续再通过日历组件或日期解析函数转换。2.2 技术选型与依赖清单学习环境不需要一开始就接入很重的办公系统。建议使用以下组合组件用途说明Python 3.10开发语言类型标注和异步支持都比较成熟FastAPIWeb API方便暴露 HTTP 接口openai SDK模型调用大多数模型服务提供 OpenAI 兼容接口Chroma本地向量库学习阶段方便快速做 RAG 验证JSON 校验工具输出质量检查生产环境可使用 Pydantic 做强校验创建一个项目目录并安装依赖mkdir ai-office-mini cd ai-office-mini python -m venv .venv source .venv/bin/activate pip install openai1.0 fastapi0.110 uvicorn[standard]0.29 chromadb0.4 pydantic2.0如果使用的模型服务不兼容 OpenAI SDK只需要修改客户端构造的那一段代码整体架构不会受影响。2.3 配置文件与本地连接密钥生产中不要把 API Key 写在代码里。这里用环境变量保存# config.py import os from dataclasses import dataclass dataclass class Settings: api_key: str os.getenv(LLM_API_KEY, ) base_url: str os.getenv(LLM_BASE_URL, ) chat_model: str os.getenv(LLM_CHAT_MODEL, your-chat-model) embedding_model: str os.getenv(EMBEDDING_MODEL, your-embedding-model) temperature: float 0.2 settings Settings()注意不同模型服务对模型名称的定义不一样有的叫qwen-plus有的叫gpt-4o-mini也有内部自建服务。真实项目要把模型名和版本作为配置项不能硬编码在业务代码里。下面是环境变量文件示例# .env LLM_API_KEYyour-api-key LLM_BASE_URLhttps://your-model-endpoint.example.com/v1 LLM_CHAT_MODELyour-chat-model EMBEDDING_MODELyour-embedding-model本地开发时可以用export或dotenv加载。生产环境通常放到配置中心或密钥管理服务里。3. 用代码实现“会议文本 - 结构化任务”3.1 先做模型层的结构化输出普通聊天模型会自然输出一段文字但任务系统需要的是字段稳定的 JSON。因此第一步是在提示词中约定输出结构再对模型返回内容做解析。# meeting_extractor.py import json from openai import OpenAI from config import settings SUMMARY_SYSTEM_PROMPT 你是一个会议纪要助手。用户会给一段会议记录或转写文本。 请提取以下字段 - summary: 会议整体摘要 - decisions: 会议中明确做出的决策 - action_items: 待办任务列表每项包含 owner、todo、deadline_text - risks: 风险列表每项包含 level 和 desc 必须返回 JSON不要返回 markdown 代码块。 示例结构 { summary: 会议讨论了新用户增长活动安排, decisions: [活动页面周五上线], action_items: [ {owner: 设计, todo: 输出三版 Banner, deadline_text: 周五前} ], risks: [ {level: high, desc: 后端需要改动邀请关系链排期存在风险} ] } 调用模型时部分模型服务支持response_format{type: json_object}可以开启强约束但不是所有服务都支持因此还需要一层后置解析def extract_json(text: str) - dict: if in text: first text.find() last text.rfind() text text[first 3:last].lstrip(json).strip() return json.loads(text) class MeetingNormalizer: def __init__(self, client: OpenAI): self.client client def to_summary(self, transcript: str) - dict: try: resp self.client.chat.completions.create( modelsettings.chat_model, temperaturesettings.temperature, messages[ {role: system, content: SUMMARY_SYSTEM_PROMPT}, {role: user, content: transcript}, ], response_format{type: json_object}, ) except Exception as exc: # 如果服务不支持 response_format可以去掉该参数后重试 print(JSON mode failed, retry without response_format:, exc) resp self.client.chat.completions.create( modelsettings.chat_model, temperaturesettings.temperature, messages[ {role: system, content: SUMMARY_SYSTEM_PROMPT}, {role: user, content: transcript}, ], ) content resp.choices[0].message.content return extract_json(content)注意一点即使是统一使用 OpenAI 兼容接口不同模型对response_format的命名也可能存在差异。如果提示中不支持直接降级为普通文本输出再依赖后置解析函数提取 JSON。降级后的模型偶尔会在 JSON 前后夹带说明文字所以要先做解包不能直接json.loads。3.2 用执行器创建任务和发送提醒模型层输出 action items 后执行层需要把这些结构化信息转成真实系统的动作。为了安全起见最小 Demo 先用一个内存执行器模拟# task_executor.py class TaskExecutor: def __init__(self): self.created_tasks [] self.notices [] def create_task(self, owner: str, content: str, source: str) - dict: task { owner: owner, content: content, source: source, status: pending, } self.created_tasks.append(task) task_id fT{len(self.created_tasks):04d} return {code: 0, task_id: task_id, task: task} def send_notice(self, owner: str, content: str) - dict: self.notices.append({owner: owner, content: content}) return {code: 0, message: notice sent}这里把“创建任务”和“发送提醒”设计成两个独立方法方便以后替换成真正的业务 API。真实环境对接任务系统时需要补充用户授权 token、任务字段映射、目标项目 ID 等信息不能只用名字和内容。接下来把整个流程串起来# service.py from openai import OpenAI from meeting_extractor import MeetingNormalizer from task_executor import TaskExecutor class MeetingFlowService: def __init__(self): client OpenAI(api_keysettings.api_key, base_urlsettings.base_url) self.normalizer MeetingNormalizer(client) self.executor TaskExecutor() def process(self, meeting_id: str, transcript: str): result self.normalizer.to_summary(transcript) # 对 action_items 生成任务 for item in result.get(action_items, []): task_result self.executor.create_task( owneritem.get(owner, ), contentitem.get(todo, ), sourcefmeeting:{meeting_id}, ) # 低风险提醒可以先发送高风险后续走审批 self.executor.send_notice(item.get(owner, ), task_result[task]) return { meeting_id: meeting_id, summary: result.get(summary, ), decisions: result.get(decisions, []), action_count: len(result.get(action_items, [])), risk_count: len(result.get(risks, [])), }3.3 用 FastAPI 暴露异步接口大模型调用通常需要几秒甚至更久不能要求网页同步等待。前端先收到“任务已接收”后台再慢慢处理。FastAPI 的BackgroundTasks适合学习环境生产环境建议替换为 Celery、Redis Stream 或消息队列。# main.py from fastapi import FastAPI, BackgroundTasks from pydantic import BaseModel from service import MeetingFlowService app FastAPI() service MeetingFlowService() class MeetingProcessRequest(BaseModel): meeting_id: str transcript: str app.post(/api/meetings/process) async def process_meeting( req: MeetingProcessRequest, background_tasks: BackgroundTasks, ): background_tasks.add_task( service.process, req.meeting_id, req.transcript, ) return {status: accepted, meeting_id: req.meeting_id}这个接口先返回 accepted表示请求已经进入后台任务。真正的任务执行结果需要通过数据库持久化再让用户前端轮询或通过 WebSocket 获取。学习环境和生产环境的任务处理差异见下表环境任务处理方式优点局限学习环境FastAPI BackgroundTasks代码量少进程重启会丢任务不适合多实例生产环境Celery Redis分布式、可重试需要额外维护队列生产环境消息队列 独立 Worker解耦明显开发部署成本更高4. 办公场景离不开企业知识库 RAG4.1 为什么不能只靠模型记忆回答问题会议纪要可以靠一次模型调用完成但企业制度问答不能靠编。比如问“新员工年假是几天”模型如果没读过公司的员工手册就会基于通用知识回答结果可能与公司制度不同。RAG 的核心思路是先在企业文档库中检索出相关片段再把片段作为上下文交给大模型让模型基于参考资料作答。这样问题的答案就有来源可查。4.2 最小 RAG 流程实现先准备一个员工制度文本文件例如# 考勤与休假制度 员工入职满一年后可享受每年 10 天年假。 试用期内不享受年假。 年假需要提前 3 个工作日通过系统提交申请。需要把这个文本切分成适合向量检索的片段。固定字符数切分最简单但对标题和章节不够友好。这里给出一个面向学习环境的通用实现# rag_index.py from openai import OpenAI from config import settings import chromadb chroma_client chromadb.PersistentClient(path./data/chroma) collection chroma_client.get_or_create_collection(nameoffice_kb) def embed_texts(client: OpenAI, texts: list[str]): resp client.embeddings.create( modelsettings.embedding_model, inputtexts, ) return [item.embedding for item in resp.data] def split_chunks(text: str, size: int 300, overlap: int 50): chunks [] start 0 while start len(text): end min(start size, len(text)) chunk text[start:end] if len(chunk.strip()) 20: chunks.append(chunk) if end len(text): break start end - overlap return chunks def index_markdown_file(client: OpenAI, file_path: str, doc_id: str): content open(file_path, encodingutf-8).read() chunks split_chunks(content) ids [f{doc_id}:{idx} for idx in range(len(chunks))] embeddings embed_texts(client, chunks) collection.upsert( idsids, embeddingsembeddings, documentschunks, metadatas[ {source: file_path, chunk_id: idx} for idx in range(len(chunks)) ], )索引完成后查询阶段要做三件事给问题生成向量、在向量库中检索、把命中的文本交给模型回答。# rag_query.py from openai import OpenAI from config import settings import chromadb chroma_client chromadb.PersistentClient(path./data/chroma) collection chroma_client.get_or_create_collection(nameoffice_kb) def ask_office_question(client: OpenAI, question: str) - dict: question_embedding client.embeddings.create( modelsettings.embedding_model, input[question], ).data[0].embedding hits collection.query( query_embeddings[question_embedding], n_results3, ) docs hits[documents][0] metadatas hits[metadatas][0] context \n\n.join( f[{i 1}] {doc} for i, doc in enumerate(docs) ) prompt f根据资料回答员工问题。 要求 1. 优先使用资料中的原意不要编造。 2. 如果资料无法回答问题直接说“资料中没有找到”。 3. 每个结论后标注参考编号例如 [1]。 资料 {context} 问题{question} resp client.chat.completions.create( modelsettings.chat_model, temperature0.1, messages[ {role: system, content: 你是企业制度问答助手。}, {role: user, content: prompt}, ], ) return { answer: resp.choices[0].message.content, references: metadatas, }检索结果中的 metadata 保存了来源文件后续前端可以展示“答案来自考勤与休假制度.md”这是 RAG 比普通对话更有价值的一点可回溯、可核对。4.3 检索不到正确答案时先查这几个原因RAG 看起来代码不多真正跑到业务里仍然会遇到“明明文档有答案模型却说没有”的问题。常见原因如下现象可能原因检查方法处理建议相关文档存在但没被召回文档切片把关键句子切碎打印命中文档片段内容改用标题层级切分保留段落完整权限范围没生效所有用户的检索共用同一个 collection对比不同用户返回的 metadata给 metadata 加部门或权限字段查询时用 where 过滤模型回答没有引用原文提示词没有要求标注来源检查最终回答里是否出现 [1] 标记在提示词中强制要求逐条标注检索结果不够准确纯向量检索匹配不到表格或代码手动在文档里搜索问题关键词增加关键词检索做混合检索生产环境不建议只做纯向量检索。表格类、编号类、政策类文档通常还需要 BM25 或全文检索作为补充再通过 RRF 合并排序。5. 运行最小系统并验证结果5.1 启动服务并提交一段会议记录开发阶段使用 Uvicorn 启动export LLM_API_KEYyour-api-key export LLM_BASE_URLhttps://your-model-endpoint.example.com/v1 uvicorn main:app --host 0.0.0.0 --port 8000用 curl 提交会议内容curl -X POST http://127.0.0.1:8000/api/meetings/process \ -H Content-Type: application/json \ -d { meeting_id: m-001, transcript: 会议讨论新用户增长活动。产品小王说活动页面预计周五上线需要设计先给 Banner 做三版。运营大刘负责渠道排期下周二前确认预算。用户组反馈希望支持邀请奖励后端老张评估要改动邀请关系链排期到下周四。 }正常响应{ status: accepted, meeting_id: m-001 }5.2 预期输出示例与结构说明后台处理完后服务日志或执行器会保存类似下面的数据{ summary: 新用户增长活动本周五上线运营需在下周二完成渠道排期和预算确认用户组提出邀请奖励需求后端评估后安排到下周四。, decisions: [ 活动页面本周五上线, 邀请奖励功能接入排期 ], action_items: [ { owner: 设计, todo: 输出三版 Banner, deadline_text: 周五前 }, { owner: 运营, todo: 完成渠道排期并确认预算, deadline_text: 下周二前 }, { owner: 后端, todo: 评估邀请关系链改造, deadline_text: 下周四前 } ], risks: [ { level: high, desc: 邀请奖励涉及邀请关系链改造存在联调不充分风险 } ] }这个 JSON 结构是关键。后续不管要把任务同步到哪个系统只要owner能映射到系统用户todo能作为任务标题source能回溯到会议 ID就可以完成一次真实派发。5.3 验证不能只看“能不能返回文字”很多入门项目在模型返回内容后就直接结束了但一个合格的工程链路至少应该检查下面几项返回内容是否真的是合法 JSON而不是模型编造的多余文字。action_items 的数量是否与会议原文一致观察模型是否漏掉了比较隐蔽的任务。任务是否重复创建重复提交同一个 meeting_id 时是否触发幂等逻辑。负责人是否来自原文是否存在模型随意补充负责人的情况。RAG 回答的每个结论是否都能对应一个 reference。处理任务前不要假设“大模型一定靠谱”。在真实项目里宁可多一个人工确认步骤也不要让模型直接写入业务库。6. AI 办公落地时容易踩到的七个坑6.1 模型输出了格式不稳定的 JSON现象服务端调用json.loads时不断报错有时候能解析有时候不能。原因模型可能输出 markdown 代码块或者在 JSON 前后附加“好的这是整理后的结果”等说明文字。解决方式不要只靠一次调用成功。增加提取函数先剥离代码块标记再尝试json.loads。如果多次失败可以把模型原始输出记录下来用于事后分析。6.2 模型把人名和部门“脑补”出来现象会议原文只提到“产品经理说要做”模型生成任务时把负责人写成了“产品部张三”。原因模型会结合训练数据或对话惯性补齐名称但办公场景不允许猜测。解决方式提示词中明确写出“如果负责人没有明确出现owner 填空字符串不要猜测”。生产环境还需要身份映射表负责人 ID 必须能在组织架构里查到。6.3 所有系统资料全部塞进上下文现象为了让 AI 回答得更准确把公司全部制度文档一次性拼到 Prompt 里。原因大模型上下文窗口有限无关内容会影响回答质量还会造成成本浪费。解决方式用检索器先召回 Top-K再拼接有限上下文。上下文不是越全越好相关内容越集中越好。6.4 输出“下周二前”之后才发现日期没有解析现象模型结构输出里带的是文字但任务系统需要具体截止时间。原因会议中的“下周二”依赖当前日期模型不一定能正确计算尤其跨月、跨年时更容易出错。解决方式不要要求模型生成具体日期先保存deadline_text再交给专门的日历解析模块。让每个模块只做自己擅长的事。6.5 自动执行操作没有人工审批门槛现象AI 根据会议纪要自动给负责人创建了真实任务但会议记录本身不完整或负责人理解错误导致误派。原因把“理解”和“执行”两个过程没有隔离。解决方式把任务分成低风险和高风险。低风险可以自动提醒修改真实数据、发送对外消息、删除内容等高风险动作必须走“草稿 - 人工审批 - 执行”的流程。6.6 RAG 检索没有加权限过滤现象用户搜索“项目预算”结果里出现了没有权限查看的预算附件内容。原因知识库 collection 是全局的没有把文档权限同步到检索层。解决方式建立文档权限同步任务把文档 ID 对应的部门或用户列表存入向量库 metadata。查询前一步拉取当前用户有权限的文档 ID检索时加where过滤。6.7 没有一套评估集就频繁改提示词现象每次调整提示词后发现 A 场景改好了B 场景又坏了。原因提示词改动没有回归测试。解决方式准备几十条典型的会议记录和制度问答问题把期望输出整理成固定 JSON。每次修改提示词后跑一遍回归集用字段命中率评估变化方向。7. 从 Demo 到生产环境还需要补齐的关键环节7.1 用户身份与权限透传演示环境下服务端调用模型和执行器的身份是“系统管理员”但生产环境必须清楚“当前操作人是谁”。要做到权限透传需要在 API 网关解析登录态得到 user_id 和部门信息。模型调用层记录用户 ID方便审计。知识库检索层根据用户权限过滤文档。任务执行层不再使用全局管理员 token而使用该用户对应的应用授权令牌。如果 AI 办公助手能代替用户创建任务、发送消息那么它本质上拥有了该用户的办公系统权限。这类系统必须和杀毒软件类似宁可默认不允许也不要默认放行。7.2 任务队列、重试与幂等大模型调用可能超时办公系统 API 也可能短暂不可用因此任务处理必须支持重试。但重试前要考虑幂等同一个 meeting_id 是否只生成一份纪要同一个 action item 如果创建任务失败重试后会不会生成重复任务通知发送成功但客户端超时再重试会不会发两遍常见做法是在数据库里使用业务幂等键例如source_meeting_id action_hash。每次执行前先查幂等表存在就不重复执行。7.3 日志、审计与人工介入入口AI 办公系统的工作日志不能只输出到控制台。至少要记录字段示例请求 IDreq_8f3a1b用户 IDuser_1023操作类型会议纪要转任务模型输出原始 JSON人工审批状态pending执行结果created记录模型输出非常重要。用户看到一条错误任务时如果只有任务结果没有模型输出根本无法定位是提示词问题、检索问题还是接口映射问题。7.4 用评估集持续迭代AI 办公平台想稳定工作至少需要维护三套评估数据数据集用途组成结构化输出集判断模型是否输出合法 JSON 且字段完整30 条会议记录 标准 JSON知识库问答集判断 RAG 答案是否准确、有引用50 条制度问答操作安全回归集判断高风险操作是否被正确拦截涉及删除、发消息、修改数据等当模型版本升级、提示词调整或文档结构变化时都要跑一遍这些回归集。不要凭一两个截图判断系统“看起来没问题”。8. AI 办公建设清单与下一步方向如果团队准备搭建自己的 AI 办公能力可以用下面这张清单做现状盘点检查项状态落地建议组织架构和用户 ID 统一未开始 / 进行中 / 已完成AI 操作必须能定位到人和角色文档有稳定 ID、来源和权限未开始 / 进行中 / 已完成这是 RAG 可追溯的前提任务/审批系统有可调用接口未开始 / 进行中 / 已完成先确认权限模型是否支持应用 token模型输出有格式校验未开始 / 进行中 / 已完成用 Pydantic 或 JSON Schema 校验高风险操作有人工审批未开始 / 进行中 / 已完成先人工后自动逐步放开处理过程有日志保留未开始 / 进行中 / 已完成记录原始输入、模型输出、执行结果有固定评估集未开始 / 进行中 / 已完成每次改动跑回归在这个基础上下一步可以按三条线扩展第一线是接真实办公系统。把内存版 TaskExecutor 替换成任务系统 API让 action item 真正创建到目标项目里。第二线是增加更多知识库处理能力支持 PDF、表格、扫描件并在检索层加入科室、部门、密级过滤。第三线是完善人与 AI 的协作流程比如会议纪要生成后先进入“待确认”状态会议发起人确认后再发布到项目群建立“AI 做草稿、人做决策”的机制。真正让 AI 办公有价值的不只是模型能生成多好的文字而是企业能不能给模型一个安全、可审计、有边界的操作环境。这个环境建设得越早后续接入更聪明的模型时系统能承接的能力就越大。
返回列表