
办公Agent在2024年之后已经从技术圈热词变成企业数字化项目的真实预算项。但在实际推进中很多团队会陷入“看大厂演示很兴奋回到自己业务里无从下手”的状态。大厂忙于构建Agent平台生态从模型访问、提示词模板、工具调度、记忆存储到发布渠道都做成闭环这确实降低了做演示的门槛企业真正缺的不是又一个聊天窗口而是能跟自己的OA、IM、审批流、知识库和业务数据库对接能稳定完成“提取待办、填写工单、整理纪要、跟进提醒”这类具体事务的工兵型Agent。这篇文章从办公Agent的定位、技术架构、最小可运行案例、部署验证、故障排查到安全治理给出了一套可以在企业里逐步落地的方法。1. 先看懂大厂筑墙Agent平台生态和企业需要的东西不是同一层1.1 “筑墙”到底筑在哪里目前常见的Agent平台通常会提供一整套完整的链路模型服务、Agent编排、工具市场、知识库、记忆存储、监控告警、发布渠道。对快速验证一个想法来说这套链路很方便开发者甚至不需要了解Agent内部是怎么工作的就能做出一个看起来能对话、能调用工具的Demo。问题在于当企业想把Agent真正接进生产系统时“方便”会变成“约束”。Agent的流程定义会保存在平台侧工具调用记录和业务数据会经过平台侧模型的升级节奏、限流策略、计费方式也由平台控制。更关键的是如果平台没有提供完整的导出和迁移能力企业花费大量精力调好的Agent流程、技能包、提示词和工具配置都无法平滑迁回自建环境。这就是“大厂忙筑墙”的本质平台化产品追求把用户留在生态内所以会做闭环而企业办公软件追求的是控制权、数据主权和长期可维护性。两者诉求不同导致“看平台演示很满意落地时很被动”的情况非常普遍。1.2 企业真正缺的是“办公工兵”“办公工兵”和“通用智能助手”是两种不同的东西。通用助手以对话为中心用户问一句它答一句边界模糊很难衡量价值办公工兵则是围绕明确岗位和明确职责能自主完成一条办公事务链路的Agent。举几个常见场景会议纪要Agent接收录音转写文本提取决议、待办、负责人、截止日期保存到项目管理系统并自动发送跟踪提醒。客服工单Agent识别用户意图检索知识库生成答复草稿将高复杂度问题升级给人工客服。审批辅助Agent读取审批表单匹配审批规则生成初审意见在指定时间提醒审批人。这些场景的共同点是范围小、结果可验证、出错可回滚、需要和已有办公系统打通。它们不追求“像人一样思考”只追求“把一件具体事务稳定完成”。企业需要的不是更多Agent技术概念而是能把一个岗位上一件重复性事务自动化的“工兵”。1.3 选型结论先定义业务边界再选Agent底座办公Agent选型时需要先回答一个问题这个Agent的流程定义、工具调用和业务数据将来放在哪个环境里运行。只要这个答案不清晰选哪个平台都可能出现返工。平台化Agent与自建/混合方案的主要差异可以用一张表看清楚分层平台化Agent自建或混合方案模型层使用平台内置模型切换成本高通过统一模型网关接入可随时替换模型供应商编排层使用平台编排器流程固化在平台侧使用开源框架或自研Agent Loop流程代码自有工具层使用平台工具市场扩展受平台审核限制将企业内部API统一封装为工具开放标准协议接入数据层记忆和知识库存储在平台侧记忆与业务数据存储在企业自己的数据库与对象存储中发布渠道依赖平台内置的IM和渠道通过Webhook、企业内部IM机器人、OA接口对接我的判断是办公Agent的最终形态不是“用一个大厂平台做一切”而是“模型服务能力 自建Agent Loop 企业系统API”。平台可以用作模型来源和实验环境但核心流程、工具连接和业务数据必须掌握在企业自己手里。2. 自建办公Agent的核心概念循环、工具、记忆和技能2.1 Agent Loop为什么是办公Agent的地基Agent并不是一个静态模型而是一个不断循环的执行过程。以一次会议纪要整理任务为例完整链路是接收任务构造系统提示词和用户输入调用模型得到中间结果根据结果判断是否需要调用工具执行工具后把工具结果写回上下文再继续调用模型直到任务完成或达到终止条件。这个循环通常叫Agent Loop它是办公Agent的地基。没有这个循环模型只能做单轮问答无法完成“读取文本、提取待办、保存数据、返回总结”这样的多步操作。实现Agent Loop时有两个关键参数参数作用建议值max_iterations限制最大循环次数防止Agent反复调用工具导致死循环5到10视任务复杂度调整max_tool_calls_per_step单轮允许执行的最大工具调用数3到5防止一次返回过多工具调用撑爆上下文在实际实现中循环必须有退出条件。比较好的退出条件是“模型返回的结果中没有tool_calls”这意味着模型认为任务已经完成可以直接返回最终答案。2.2 工具调用让Agent从“能说”变成“能做”模型本身不能直接读写企业的OA系统、数据库或者IM。Agent要连接外部系统必须通过工具。工具定义通常包含四个部分名称、描述、输入参数Schema、执行函数。工具描述质量直接影响模型是否选择正确的工具。一个典型的工具Schema如下{ type: function, function: { name: save_todo_item, description: 保存一条待办事项返回待办ID, parameters: { type: object, properties: { content: { type: string, description: 待办内容 }, assignee: { type: string, description: 负责人 }, due_date: { type: string, description: 截止日期格式YYYY-MM-DD } }, required: [content] } } }模型会返回结构化的工具调用请求例如{ tool_calls: [ { id: call_1, type: function, function: { name: save_todo_item, arguments: {\content\: \完成门户首页框架\, \assignee\: \张伟\} } } ] }Agent主循环要负责解析这个请求执行对应的函数再把函数返回值以tool消息的形式追加到上下文中继续交给模型。工具返回值如果过大需要截断或摘要后再回传否则会快速消耗上下文窗口。2.3 记忆和技能办公Agent需要长期状态办公场景和纯聊天场景最大的区别是它需要跨轮次、跨任务地保留业务状态。昨天创建的待办今天要能查询上周的项目结论下周要能引用。这要求Agent具备记忆能力。记忆可以分为三个层次短期上下文当前任务轮次内的对话记录和工具结果保存在请求消息列表中。长期业务记忆从历史任务中抽取的结论、偏好、关键实体存入数据库或向量库。结构化业务数据待办、审批单、工单这类强结构化数据必须有确定的数据表或文件存储不能只依赖向量检索。技能是另一个容易被忽略的组件。所谓Skill本质是“任务方法包”包含一段针对特定任务的系统提示词、一组工具选择规则和若干示例。比如“会议纪要整理技能”会规定输出格式、待办字段和提取规则。技能的意义在于把一次调好的方法沉淀下来避免每次执行都靠模型临场发挥。2.4 MCP与Skill的区别很多人在学习Agent时会把MCP和Skill混在一起。它们在办公Agent中负责的层次不同。对比项MCPSkill定位一种协议解决Agent如何连接外部工具和数据源一种任务级能力包解决特定任务怎么做粒度按工具、资源、提示词暴露能力按任务组织提示词、工具和示例解决的核心问题工具接入方式标准化任务执行方法复用关系Skill内部可以调用MCP暴露的工具MCP负责打通底层连接Skill负责上层编排可以这样类比MCP像网络协议解决不同系统之间能不能通信Skill像内置的方法流程解决拿到数据之后按什么步骤处理。企业做办公Agent时两者不是二选一而是叠加使用用MCP统一连接企业内部系统用Skill沉淀各岗位的办事方法。3. 用最小代码实现一个会议纪要Agent3.1 需求拆解三个职能为了把概念落到代码上这里实现一个最小可运行的办公Agent会议纪要待办整理Agent。它只做三件事接收一段会议记录文本。识别其中的决议和待办事项。把待办事项保存到本地存储并返回整理结果。这个案例不接入真实OA系统但保留了办公Agent最核心的骨架Agent Loop、工具定义、工具执行、结构化结果存储。理解了这段骨架就能迁移到工单、审批、知识库等更复杂的场景。3.2 环境准备与项目结构本示例使用Python 3.10及以上版本依赖requests、fastapi、uvicorn。模型接口采用OpenAI兼容的Chat Completions接口具体模型供应商和模型名称由环境变量配置。安装命令如下mkdir office-agent cd office-agent python -m venv .venv source .venv/bin/activate pip install requests fastapi uvicorn项目结构如下office-agent/ ├── agent_core.py # Agent主循环 ├── tools.py # 工具Schema与工具执行函数 ├── server.py # FastAPI接口 ├── requirements.txt └── todos.json # 待办数据文件首次运行自动生成3.3 实现Agent主循环先写tools.py定义工具和执行函数。这里用JSON文件作为存储降低环境依赖方便读者直接运行验证。import json import os import datetime TODO_FILE os.path.join(os.path.dirname(__file__), todos.json) def load_todos(): if not os.path.exists(TODO_FILE): return [] with open(TODO_FILE, r, encodingutf-8) as f: return json.load(f) def save_todo_item(content, assignee, due_date): todos load_todos() todo { id: len(todos) 1, content: content, assignee: assignee, due_date: due_date, status: open, created_at: datetime.datetime.now().isoformat() } todos.append(todo) with open(TODO_FILE, w, encodingutf-8) as f: json.dump(todos, f, ensure_asciiFalse, indent2) return {ok: True, id: todo[id]} def list_todos(statusopen): todos load_todos() return [t for t in todos if t[status] status] TOOL_SCHEMAS [ { type: function, function: { name: save_todo_item, description: 保存一条待办事项返回待办ID, parameters: { type: object, properties: { content: {type: string, description: 待办内容}, assignee: {type: string, description: 负责人}, due_date: {type: string, description: 截止日期格式YYYY-MM-DD} }, required: [content] } } }, { type: function, function: { name: list_todos, description: 按状态查询待办列表, parameters: { type: object, properties: { status: {type: string, enum: [open, done]} } } } } ] def execute_tool(name, arguments): if name save_todo_item: return save_todo_item( arguments.get(content, ), arguments.get(assignee, ), arguments.get(due_date, ) ) if name list_todos: return list_todos(arguments.get(status, open)) return {error: unknown tool: name}然后写agent_core.py实现Agent主循环。这里的关键是把工具调用结果作为tool消息回传给模型直到模型不再请求工具调用。import json import os import requests from tools import TOOL_SCHEMAS, execute_tool LLM_API_BASE os.getenv(LLM_API_BASE, https://api.example.com/v1) LLM_API_KEY os.getenv(LLM_API_KEY, ) LLM_MODEL os.getenv(LLM_MODEL, gpt-4o-mini) MAX_ITERATIONS 5 SYSTEM_PROMPT 你是一个办公助手负责整理会议纪要中的决议和待办事项。 当遇到需要保存的待办时调用 save_todo_item 工具。 当需要查询已有待办时调用 list_todos 工具。 最后用简洁的中文总结已完成的操作。 def chat_completion(messages): resp requests.post( f{LLM_API_BASE}/chat/completions, headers{ Authorization: fBearer {LLM_API_KEY}, Content-Type: application/json }, json{ model: LLM_MODEL, messages: messages, tools: TOOL_SCHEMAS }, timeout60 ) resp.raise_for_status() return resp.json()[choices][0][message] def run_agent(user_text): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_text} ] for step in range(MAX_ITERATIONS): message chat_completion(messages) messages.append(message) tool_calls message.get(tool_calls) or [] if not tool_calls: return message.get(content) or 模型没有生成有效结果。 for call in tool_calls: fn call[function] name fn[name] try: arguments json.loads(fn.get(arguments) or {}) except json.JSONDecodeError: arguments {} result execute_tool(name, arguments) messages.append({ role: tool, tool_call_id: call[id], content: json.dumps(result, ensure_asciiFalse) }) raise RuntimeError(fAgent执行超过最大迭代次数{MAX_ITERATIONS}请检查是否出现死循环。) if __name__ __main__: meeting_text 今天评审了门户改版方案。确认分三周完成 第一周完成首页框架负责人张伟 第二周接入统一登录负责人李婷 第三周联调测试负责人王强。 result run_agent(请整理以下会议记录中的待办事项并保存到待办列表。\n meeting_text) print(result)这段代码的循环逻辑是办公Agent最核心的骨架。需要注意timeout60是一个基础值长文本或复杂工具链要单独调整。MAX_ITERATIONS设置得过小容易导致复杂任务被提前终止过大会增加单次请求耗时和费用。3.4 运行验证与预期结果配置好环境变量后运行export LLM_API_BASEhttps://你的模型接口地址/v1 export LLM_API_KEY你的密钥 export LLM_MODEL你的模型名称 python agent_core.py如果模型支持工具调用运行过程中会先完成三次save_todo_item调用再生成最终总结。控制台输出大致如下[step 1] 模型请求工具调用: save_todo_item, save_todo_item, save_todo_item [step 2] 模型返回总结文本 已整理会议记录中的3条待办事项 1. 完成首页框架负责人张伟 2. 接入统一登录负责人李婷 3. 联调测试负责人王强查看todos.json会看到已经落盘的结构化数据。这一步验证的意义在于模型进行了多步思考和工具调用最终结果被持久化到文件而不仅仅是输出了一段文本。这证明Agent已经具备执行办公事务的基本能力而不是停留在对话层面。4. 把Agent发布成内部服务部署与验证4.1 用FastAPI暴露一个轻量接口本地命令行运行只能验证核心逻辑。要接入企业OA、IM或内部系统需要把Agent包装成HTTP服务。这里用FastAPI实现一个最小接口。# server.py from fastapi import FastAPI from pydantic import BaseModel from agent_core import run_agent app FastAPI() class TaskRequest(BaseModel): instruction: str context: str app.post(/agent/run) def agent_run(req: TaskRequest): try: result run_agent(req.instruction \n req.context) return {ok: True, result: result} except Exception as e: return {ok: False, error: str(e)}启动服务uvicorn server:app --host 0.0.0.0 --port 8000用curl验证接口curl -X POST http://127.0.0.1:8000/agent/run \ -H Content-Type: application/json \ -d {instruction:提取待办,context:下周完成接口评审负责人刘洋}正常返回{ ok: true, result: 已保存1条待办完成接口评审负责人刘洋 }4.2 接口返回与错误处理接口层不能只做转发还要处理两类错误一类是业务错误比如工具参数校验失败、待办内容为空。这类错误应该返回明确的业务提示而不是抛出500。另一类是系统错误比如模型接口超时、模型返回格式不合法。这类错误需要记录完整异常堆栈并给调用方一个可重试或可降级的信号。当前示例中agent_run把所有异常统一捕获并返回给了调用方。生产环境应该区分错误码例如ERR_TIMEOUT、ERR_INVALID_TOOL_ARGUMENT、ERR_MAX_ITERATIONS方便上游系统做重试或转人工。4.3 生产部署还要补哪些能力本地原型和生产服务之间的差距不是代码量的差距而是工程保障的差距。下面是主要关注点维度本地原型生产环境模型访问使用临时API Key独立模型账号设置预算和配额配置管理环境变量直接读取配置中心支持动态调整模型名和参数日志print输出结构化日志关联请求ID和工具调用ID认证鉴权无内部服务调用认证限制调用方范围存储本地JSON文件数据库或对象存储支持容量扩展和备份部署方式uvicorn直接启动Docker镜像K8s或企业应用平台灰度回滚手动改代码版本化发布支持快速回滚监控告警无监控延迟、token消耗、工具调用失败率办公Agent晚一秒响应通常可以接受但工具调用错误导致数据写错性质就严重得多。生产环境上线前至少要保证存储、日志和权限三项具备。5. 办公Agent最常见的五类故障排查5.1 Agent不调用工具或一直调用错误工具现象模型直接返回一段文字没有产生工具调用或者反复调用list_todos而不是save_todo_item。排查顺序确认模型接口是否真的支持工具调用参数。部分模型或接口网关会忽略tools字段。检查工具描述是否足够清晰。工具描述中要写清楚“什么时候用”“输入是什么”“会产生什么副作用”。检查工具Schema中的必填参数。如果required过严模型会倾向于不调用工具。在系统提示词中增加工具选择规则和示例减少模型临场猜测。工具调用错误的常见原因和处理方式现象常见原因处理建议模型从不调用工具接口不支持工具调用或提示词未说明确认接口能力在提示词中明确要求总调用同一个工具工具描述不区分边界在描述里增加“当……时使用”参数传错Schema定义与真实业务字段不一致精简参数提供枚举值和默认值工具执行报错入参缺失或类型错误执行函数内做参数兜底和校验5.2 任务循环无法终止现象Agent一直在调用工具比如不断查询待办列表、不断重新保存同一条数据直到达到最大迭代次数。原因通常是三类工具结果中没有给出明确的“完成信号”模型被中间结果不断触发新动作或者Agent Loop缺少重复调用去重。解决方式设置max_iterations并抛出明确的终止异常。在系统提示词中要求“完成任务后不要继续调用工具”。对重复工具调用做检查相同参数在短时间内重复调用时直接返回缓存结果。在工具结果中提供足够的完成信息例如“已保存待办ID1”避免模型认为还需要再保存一次。5.3 模型响应超时或执行器终止现象任务在中间某一步突然报错错误信息类似“the agent execution provider did not respond in time”或“agent execution terminated due to error”。这类提示通常来自模型供应商网关或Agent执行环境表示请求超时或执行被外部中断。排查顺序先判断是模型响应超时还是工具执行卡死。查看模型请求的耗时如果单次请求超过30秒就要考虑缩短输入上下文或换更快的模型。查看工具函数中是否有外部HTTP调用或数据库长事务给工具调用单独设置超时。如果错误发生在模型侧可以提示模型重试或让Agent重新进入下一个循环。现象可能原因处理建议单次模型请求超时上下文过长或模型负载高压缩历史消息拆分任务设置更长超时工具调用后无响应工具函数阻塞给工具执行加超时和异步化改造执行器终止任务受限重试次数或策略限制加入重试机制减小单次任务粒度5.4 上下文被撑爆现象前几轮正常越到后面模型响应越慢或者出现上下文超长错误。原因是Agent Loop每轮都会把历史消息、工具结果不断追加到messages里。如果工具返回大量数据上下文会快速膨胀。处理建议工具结果只保留关键字段不要全量回传。历史消息做摘要超过一定轮数后用一段总结代替完整对话。对长文本任务先让模型抽取结构化信息再基于结构化信息继续处理。根据模型的上下文窗口限制设置消息长度阈值。5.5 权限和数据访问失控现象Agent能够访问它本不该访问的数据或者执行了破坏性操作。办公Agent接入OA、数据库和IM后工具权限就是数据安全边界。排查时重点检查工具是否做了调用者身份透传还是所有Agent共享一个超管权限账号。工具的白名单是否最小化删除、批量修改、转账、审批这类高危工具是否默认关闭。是否对发送给模型的文本做了脱敏。是否有工具调用审计日志。权限问题不是模型能解决的必须在工具层和平台层强制约束。6. 安全与治理办公Agent能接触业务系统时的底线6.1 最小权限与工具白名单Agent能调用什么工具必须单独配置不能把企业内部所有API都暴露给模型。推荐使用类似下面的策略文件agent_policy: max_iterations: 5 tools_whitelist: - name: list_todos action: read - name: save_todo_item action: write - name: delete_todo_item action: write enabled: false sensitive_fields: - phone - id_card - salary human_confirm_tools: - delete_todo_item - send_message audit_log: ./logs/agent-audit.jsonl这个配置表达的原则是可以读的默认放开可以写的默认收紧有破坏性的操作默认禁用。human_confirm_tools中的工具在Agent请求执行时必须进入待确认状态由人工批准后才真正执行。6.2 敏感数据脱敏用户发送给模型的内容可能包含手机号、身份证号、薪资等敏感信息。在把数据写入messages之前要做一次脱敏。一个最简单的脱敏函数示例import re MASK_RULES [ (r1[3-9]\d{9}, PHONE_MASK), (r\d{17}[\dXx], ID_CARD_MASK), ] def mask_sensitive_text(text: str) - str: for pattern, placeholder in MASK_RULES: text re.sub(pattern, placeholder, text) return text脱敏要放在数据进入Agent系统的入口层而不是模型返回之后。因为敏感数据一旦进入模型服务可能被记录在模型供应商日志或训练体系中风险已经发生。6.3 关键操作加人工确认办公Agent不是所有操作都可以全自动执行。涉及发送消息、删除数据、审批、支付、对外承诺等关键操作应该设计成两阶段执行Agent生成待执行动作进入待确认队列。用户确认后系统才调用真正的外部接口。实现时可以把工具执行分为dry_run和confirm_run两种模式。Agent默认做预演确认后才真正执行。这个设计会增加一个交互环节但能大幅降低Agent出错时的损失。6.4 审计与可回滚每次Agent执行都应该记录审计日志至少包含{ request_id: req_20250101_001, user_id: zhangsan, timestamp: 2025-01-01T10:00:0008:00, instruction: 整理待办, steps: [ { step: 1, tool: save_todo_item, arguments: {content: 完成首页框架, assignee: 张伟}, result: {ok: true, id: 1} } ], final_answer: 已保存1条待办 }审计日志不能只记录用户输入和最终结果必须记录模型请求的完整工具参数和工具返回值。否则出问题时无法判断是哪一步写错了数据。7. 从“可以演示”到“能上班”办公Agent落地建议7.1 落地前检查清单在把一个办公Agent从演示推向业务之前至少要核对以下项目业务边界是否明确能做什么、不能做什么有没有写进系统提示词和工具白名单。失败后果能否承受如果Agent写错一条待办影响多大如果是删除审批影响多大。工具权限是否最小化Agent账号是否只拥有完成当前任务所需的最小权限。日志能否追踪每一次工具调用是否都有请求ID、时间、参数和结果。模型成本和延迟是否可控单次任务平均调用模型几次token消耗多大。是否可以在平台外自建核心流程是否被绑定在特定Agent平台上能否迁移。是否有人工确认环节写操作、删除操作、外发操作是否都有确认机制。7.2 学习环境与生产环境的差异学习阶段最重要的是把Agent Loop跑通理解模型为什么要调用工具、工具结果如何回传、循环如何终止。此时可以用本地JSON文件、测试API Key和少量示例数据。生产阶段要做的是减法而不是加法不要一开始就做多Agent协作、不要把所有系统都接入、不要追求全自动化。建议先从“一个角色、一件事务、有限工具”开始跑通之后再加第二个工具、第二个场景。7.3 扩展方向多Agent协作与流程编排当单Agent能力稳定后可以按岗位拆分多个Agent例如会议纪要Agent、工单处理Agent、审批辅助Agent。多Agent协作不等于让所有Agent都参与同一个对话更常见的是通过任务队列传递结果会议纪要Agent生成待办列表。任务队列把待办分发给对应负责人。跟进Agent定时检查待办状态并提醒。多Agent只有在任务边界清晰、数据流明确时才值得引入。如果只是希望多个模型角色对话往往会让系统更复杂且难以验证结果质量。7.4 防止被平台锁定最后回到“大厂筑墙”这个背景。企业在自建办公Agent时应该在架构上预留四个可替换出口模型层可替换通过模型网关统一管理模型API不把模型供应商写死在业务代码里。工具层用标准协议优先使用MCP等开放协议暴露工具能力避免工具接口与平台强绑定。数据层自主可控Agent记忆、技能包、审计日志都存储在自建存储中定期导出备份。编排层可迁移Agent Loop和提示词是普通代码与配置不用私有格式保存。如果只保留一个判断我会建议团队把办公Agent看成一段需要长期维护的业务代码而不是一个一次性Demo。技术选型时先想清楚“如果平台切换了我的Agent还能不能跑”再决定要不要把核心流程放进别人的墙里。