
如何用 AI 构建可投入生产的工单系统做后台系统的朋友这两年应该都有同感工单系统这种“老古董”业务突然被 AI 架到了风口浪尖上。老板的需求从“能记录、能流转”变成了“能不能自动分类、自动回复、自动把工单转给对的人”。市面上讲 AI 工单的教程不少但大部分停留在“调用一个 API 跑个 demo”的程度真要说扛住生产环境的流量、权限、数据一致性和审计要求很多方案根本站不住脚。我最近刚好把一个传统工单系统的核心流程用 AI 重构了一遍从需求拆解到上线踩坑都过了一遍。这篇博文就把我的完整思路、技术选型、实操细节和生产化改造过程记录下来。内容偏工程实践适合已经做过工单系统、想要引入 AI 能力的后端开发也适合准备从零搭建 AI 工单系统的技术负责人参考。这里不堆理论只讲怎么把 AI 真正“嵌”进工单系统里而不是做个花瓶功能。1. 内容整体设计与思路拆解1.1 需求澄清你想要的到底是哪一种 AI 工单系统动手写代码之前先要分清“AI 工单”到底解决什么问题。我见过很多项目失败不是技术不行而是需求本身没想清楚。根据实际使用场景AI 在工单系统里基本能落在这四类能力上智能分类与打标根据工单标题和描述自动判断工单类型、优先级、所属部门甚至自动关联知识库里的标准解决方案。智能回复与摘要对常见问题生成拟稿回复对长工单生成摘要辅助客服或运维人员快速理解问题背景。智能路由与分派根据工单内容、坐席负载、技能匹配度把工单自动分配给合适的处理人。智能问答与检索增强基于内部知识库、历史工单让 AI 在答复时引用真实文档而不是凭“幻觉”编答案。这四类能力可以单独用也可以组合。但它们的实现难度和成本差异非常大。比如智能分类用传统机器学习模型甚至规则就能做到七八十分而智能回复如果涉及对接生产系统、要带权限控制复杂度会指数级上升。所以第一步不是选模型而是和业务方对齐一个关键问题AI 辅助人还是 AI 替代人我的建议是第一版一定要做成“辅助人”AI 给出建议人来确认。这既是技术风险的缓冲也是业务方接受度的保障。1.2 技术选型为什么我选择了大模型 Agent 的架构明确了需求后接着就是选型。传统工单系统基于规则引擎或固定流程缺点是维护成本高、灵活性差。比如新增一种工单类型可能要改代码、改数据库、改界面一整套流程下来小半天就没了。而基于大模型的方案可以用自然语言描述规则让模型来匹配和分发改动成本大幅降低。我最终的架构选择了“大模型 Agent”组合而不是纯粹的“对话机器人”。区别在于大模型负责理解语言、生成内容它本身不感知业务状态也不具备调用外部系统的能力。Agent作为大脑和手脚的连接器负责感知上下文、调用工具、执行动作比如查询工单状态、修改数据库、发送通知。这种拆分的好处是职责清晰。模型可以随时替换比如从开源模型换到闭源模型而 Agent 层保持稳定反过来业务流程变更时只需要调整 Agent 的工具和策略不用动模型逻辑。语言层面我用 Java 作为主服务语言因为工单系统通常要和企业内部系统集成Java 的生态最成熟。AI 编排层单独拆了一个 Python 服务负责调用模型、管理上下文、执行 Agent 逻辑。两个服务通过 REST API 和消息队列通信避免了语言之间的强耦合。这套组合在团队协作上也更顺Java 工程师专注业务系统AI 工程师专注提示词和模型调用。1.3 适用边界哪些场景不适合用 AI 硬做好的架构师不光要知道能做什么还要知道不能做什么。有些场景我建议不要上 AI或者至少不要只靠 AI涉及强审批流的工单比如财务报销、权限申请这类工单需要多人逐级审批每一步都有明确的状态机。AI 可以在前置环节做信息提取但审批决策必须由人来完成否则出问题责任说不清。数据极其稀疏的冷门业务如果某类工单一年就几单AI 几乎学不到规律分类和回复的建议会非常随意。这时候用固定模板和人工经验更靠谱。对响应延迟极其敏感的场景大模型单次推理少则几百毫秒多则几秒。如果工单系统要求“提交后 50ms 内返回自动处理结果”纯大模型方案肯定不满足需要加缓存或预先计算。我的原则是AI 适合做“辅助决策”和“信息整理”不适合做“最终裁决者”。生产环境的稳定性要优先于所谓的智能体验。2. 核心细节解析与实操要点2.1 工单数据模型设计AI 依赖的“上下文工程”很多做 AI 应用的人容易忽略数据模型觉得只要把文本丢给大模型就行。但工单系统要生产可用数据模型的合理程度直接决定 AI 能力的天花板。我设计核心表的时候额外考虑了下面几个字段CREATE TABLE ticket ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, description TEXT NOT NULL, category VARCHAR(50), priority TINYINT, status VARCHAR(20) DEFAULT OPEN, assignee_id BIGINT, creator_id BIGINT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, ai_summary TEXT, ai_suggested_category VARCHAR(50), ai_suggested_assignee VARCHAR(100), ai_confidence DECIMAL(5,4), raw_context JSON );注意raw_context这个字段它的设计来自一次惨痛教训。早期版本没有存原始请求的上下文导致后续 AI 分析时缺失了关键信息比如用户是从哪个页面提交的、操作系统是什么、用的哪个客户端版本。这些看似无关紧要的信息对故障类工单的分类和路由非常关键。所以我在工单创建时把当时的上下文快照存成 JSONAI 分析时可以直接读取。另外AI 生成的中间结果比如建议的分类、建议的处理人、置信度和最终人工确认的结果要分开存储。我的表里同时有category和ai_suggested_category目的是做对比评估。上线初期需要持续检查 AI 建议的准确率如果准确率低于阈值就要调整提示词或补充训练数据。没有这个对照字段后续的优化就是盲人摸象。2.2 提示词设计少喊口号多给示例提示词是 AI 工单系统的灵魂也是最容易出现“看着对、实际烂”的部分。初次写提示词的人容易犯一个错误把所有要求用抽象描述堆进去比如“请准确分类”“请保持专业语气”。实际效果往往不稳定。我的做法是用少样本示例few-shot代替抽象规则。以智能分类为例我在系统提示词system prompt里内置了三到五组真实工单的示例你是工单分类助手。请根据工单的标题和描述从以下分类中选择最合适的一项 分类列表网络故障、账号权限、硬件报修、软件使用、数据变更、其他 示例1 标题无法访问内网OA系统 描述从办公室有线网络登录OA一直转圈其他人正常重启电脑无效。 分类网络故障 示例2 标题申请开测试数据库只读账号 描述数据分析组需要访问测试库库名test_db需要只读权限有效期两周。 分类账号权限 请分析以下工单 标题{title} 描述{description} 只输出分类名称不要输出解释。这里的关键细节是“只输出分类名称不要输出解释”。很多模型默认会给你来一段“根据您的描述我认为这个问题属于……”的废话解析起来很麻烦。严格要求限定输出格式可以大幅降低下游解析的复杂度。我再强调一个容易踩的坑示例的选择要有代表性而且要覆盖最容易混淆的边界情况。比如“网络故障”和“软件使用”有什么区别示例里最好同时出现一个“端口不通”和一个“软件设置不会操作”的样例。模型是从示例中学习边界的示例越接近真实分布效果越好。2.3 上下文管理工单是一段持续对话不是一次性提问工单处理往往不是一次性提问用户会在原有工单上补充信息处理人也会在内部备注中沟通。为了让 AI 理解完整背景我们需要把工单的所有历史记录拼接成上下文。但这里有两个问题令牌token有限制工单描述、用户追加留言、内部备注、操作日志全放进去很容易超出上下文窗口。信息权重不同内部备注包含敏感信息和处理思路不能直接用来生成对用户的回复操作日志对分类有价值但对生成回复没价值。我的方案是设计一个上下文管理器按角色和用途动态组装提示词上下文来源是否用于分类是否用于生成回复说明工单标题和描述是是核心信息用户追加留言是是问题演化过程内部备注是否包含内部信息不可外泄操作日志是部分使用仅用于状态判断历史处理记录是是参考相似案例对于超出窗口的长工单我会做滑动窗口截取保留最早的问题描述和最近的三条交互记录中间内容视情况摘要压缩。这个策略在实测中效果最好既保住了核心背景又不会让模型被冗余信息干扰。2.4 Agent 工具设计让 AI 可以“动手”的边界Agent 的价值在于能调用工具。我设计的 Agent 核心工具包括get_ticket_detail(ticket_id)获取工单详情。query_knowledge_base(keyword)检索知识库相关文章。search_similar_tickets(keyword)搜索相似历史工单。notify_user(ticket_id, message)给用户发送通知。update_ticket_category(ticket_id, category)修改工单分类。每个工具都定义了明确的入参和出参Agent 根据用户指令自动决定调用哪些工具。这里要注意工具不是越多越好。我的切身体会是每增加一个工具模型选错工具的几率就高一截。第一版控制在五个工具以内等运行稳定后再逐步扩展。工具权限方面要特别谨慎。update_ticket_category在设计中只能更新 AI 建议字段不能直接改最终分类必须由人工确认后写入。这种“只建议、不决定”的权限隔离可以避免 AI Agent 出现不可控的连锁修改。我在代码里用两个不同的接口把这部分隔开了。3. 实操过程与核心环节实现3.1 环境准备模型、框架与项目初始化我的生产环境选择了私有化部署的大模型主要考虑数据合规。开发阶段用的是 OpenAI 兼容接口的云端模型通过环境变量切换。推荐的基础环境如下主服务Java 17 Spring Boot 3.2AI 服务Python 3.11 FastAPI大模型接口兼容 OpenAI 格式的 local API也可换成云端 API向量数据库Milvus用于知识库检索消息队列RabbitMQ用于异步处理 AI 分析任务关系数据库MySQL 8.0主业务数据Spring Boot 的 Java 服务主要管业务Python 服务管 AI 推理。这两个服务我是分开部署的这样 AI 服务的负载波动不会影响主业务的稳定性。Java 服务调用 Python 服务时经过了一层简单的签名校验同时设置超时时间三秒避免模型推理卡死导致工单接口不可用。核心依赖在pom.xml里加下面几个dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-amqp/artifactId /dependency dependency groupIdcom.squareup.okhttp3/groupId artifactIdokhttp/artifactId version4.12.0/version /dependency dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId /dependencyPython 侧使用 FastAPI 相对轻量核心部分只有两个接口一个用于工单分类一个用于生成回复。两个接口内部都会调用同一个 Agent 编排模块。3.2 工单创建异步 AI 分析的主流程实现用户提交工单后主流程要做到“快速保存异步分析”。不能等大模型返回结果后才告诉用户“提交成功”那样用户等待时间会很长而且模型一旦超时工单就创建不出来了。我的实现逻辑是用户 POST /api/tickets服务端先校验必填字段将工单状态置为OPEN立即返回工单 ID。同时将工单 ID、标题、描述、上下文快照发送到 RabbitMQ 的消息队列。Python AI 服务监听队列消费消息后调用大模型进行分析。AI 分析完成后将建议的分类、优先级、处理人等通过回调接口写回主数据库。如果 AI 分析失败超时、模型报错等工单依然正常存在只是没有 AI 建议字段。不会阻塞整个流程。关键代码如下Java 侧创建工单并发送消息PostMapping(/api/tickets) public ResponseEntityTicket createTicket(RequestBody TicketCreateRequest request) { Ticket ticket new Ticket(); ticket.setTitle(request.getTitle()); ticket.setDescription(request.getDescription()); ticket.setCreatorId(request.getCreatorId()); ticket.setStatus(OPEN); ticket.setCreatedAt(LocalDateTime.now()); ticketMapper.insert(ticket); // 异步发送 AI 分析任务 MapString, Object context new HashMap(); context.put(ticketId, ticket.getId()); context.put(title, request.getTitle()); context.put(description, request.getDescription()); context.put(source, request.getSource()); context.put(userAgent, request.getUserAgent()); rabbitTemplate.convertAndSend(ai.analysis.queue, context); return ResponseEntity.ok(ticket); }Python 侧消费队列并调用模型的代码简化如下import json import openai OPENAI_API_KEY os.environ[OPENAI_API_KEY] OPENAI_BASE_URL os.environ[OPENAI_BASE_URL] MODEL_NAME os.environ.get(MODEL_NAME, qwen2.5-14b-instruct) def analyze_ticket(message): ticket_id message[ticketId] title message[title] description message[description] category classify_ticket(title, description) callback(ticket_id, {suggested_category: category, confidence: 0.92})这段代码里的classify_ticket会把我们设计的提示词和用户内容拼装好调用模型接口然后解析返回的分类名称。3.3 智能回复与知识库检索为 Agent 加上 RAG光有分类还不够生产环境真正吃性能的是“智能生成回答”。为了减少幻觉、提高回答的可信度我引入了检索增强生成RAG。具体流程是把内部知识库文档比如操作手册、常见问题指南拆分成片段用 embedding 模型向量化后存入 Milvus。用户在线提问时先根据工单标题和描述检索 Top K 相关片段。把检索到的片段拼接到提示词里要求模型基于片段内容回答并标注引用来源。这里有一个坑必须提醒知识库文档的拆分粒度直接影响检索效果。我一开始按段落拆分结果一个段落经常包含两个不同主题检索出来的内容不够聚焦。后来改成按语义切分每个片段控制在 200~400 字并且保留标题信息作为元数据。效果提升非常明显检索相关性提升了大约三成。Agent 调用知识库的提示词片段你是一名企业 IT 支持助手。请根据以下参考资料回答用户问题。 如果参考资料无法回答请直接回答“资料库中没有相关信息”不要编造。 参考资料 {retrieved_chunks} 用户问题 {question} 请用简洁的语言回答并在结尾注明引用的资料编号如 [1]。生成回复后系统不会直接发送给用户而是先由客服人员在界面点“确认发送”或者修改后再发送。这个人工确认流程非常有效既保留了 AI 的提效作用又防止了错误信息直接触达用户。3.4 路由与分派从“人肉派单”到“人机协同派单”工单分配在生产场景中是个敏感操作分配错了轻则重派重则影响服务时效。传统方式是根据“工单类型”直接绑定到固定处理组这样做的毛病是负载不均——热门组天天爆单冷门组闲得长草。我的方案是AI 建议候选人列表人在最终策略层决定。Agent 根据工单内容、处理人的技能标签以及当前待处理工单数生成一个排序后的候选人列表。排序的权重大致是综合得分 技能匹配度 × 0.5 当前负载逆序 × 0.3 历史解决率 × 0.2为了让 Agent 可以动态获取这些数据我开发了一个get_assignee_candidates工具输入工单 ID 和分类输出候选人 JSON 数组。Agent 拿到数据后在提示词里通过“分析原因、列出候选人、给出建议”三步生成最终建议。需要注意的是这个建议仅仅是写入ai_suggested_assignee字段真正的assignee_id仍然由团队小组长确认后修改或者由系统根据预设策略自动确认前提是 AI 置信度高于 0.9 且历史准确率稳定。这里我踩过一个印象很深的坑曾有段时间模拟测试时 AI 总能选出合理的人但上了生产之后突然出现大量建议派给同一个人的情况。排查后发现是因为该处理人解决过很多历史工单知识库和路由模型都把他标记为高匹配度导致所有工单都往他身上堆。后来我在负载权重里加入了“近七日待处理数”的实时计算并设定了单人最大建议比例阈值才把这个问题压下去。3.5 异步任务稳定性重试、降级与消息可靠消费生产环境里最怕的不是 AI 不聪明而是 AI 服务挂了之后把主链路拖死。我在做异步任务时给 AI 服务加了三层保护消息确认机制消费者消费消息后必须显式 ACK如果处理过程中抛出异常则消息会重新入队。重试与死信队列每条消息最多重试三次超过三次进入死信队列人工介入查看。降级开关通过配置中心动态开关 AI 功能。如果线上发生大规模模型回调超时可以一键关闭 AI 分析让工单系统退化为纯人工模式。降级开关的代码简化如下Value(${ai.enabled:true}) private boolean aiEnabled; public void handleTicketCreated(TicketCreatedEvent event) { if (!aiEnabled) { log.warn(AI 功能已降级工单 {} 跳过自动分析, event.getTicketId()); return; } // 正常发送到 AI 分析队列 }这种降级设计在真实故障中帮了大忙。有一次我们调用的模型服务端升级连续两个小时处于不稳定状态工单创建量本身就大如果每个工单创建都阻塞等待模型返回整个系统就瘫痪了。因为有异步队列和降级开关运维同事直接把ai.enabled设为false系统立刻恢复到传统流程业务毫发无伤。这给我一个深刻的教训AI 功能永远不能成为核心业务的单点。3.6 测试与灰度发布AI 功能不能凭感觉上线AI 和传统代码最大的不同是它的输出是概率性的没法用“断言等于”的思路来测试。我采用的测试策略是分层分级单元测试验证提示词模板拼接正确、工具函数入参出参正确、数据库读写正常。这部分用 pytest 和 JUnit 常规解决。离线评测集准备 200 条带标准答案的历史工单跑一遍分类准确率。低于 85% 不出门。评测集要覆盖各类场景比例和真实生产分布保持一致。影子模式AI 建议只记录、不展示跑一周后和人工结果做对比计算准确率和可用率。灰度发布从 5% 的工单量开始启用 AI 建议展示确认无问题后逐步放大到 100%。这个流程明确排除了直接让 AI 参与生产的可能。任何提示词的改动都要先过一遍离线评测集防止“改了这头、砸了那头”。我见过一个团队调了一下语气描述结果分类准确率从 88% 掉到 70%就是因为没有评测集纯粹靠感觉调参。4. 常见问题与排查技巧实录4.1 模型响应格式不稳定把口头的“只输出分类”当耳旁风最常遇到的问题就是模型不严格遵守输出格式。明明写了“只输出分类名称”它偏偏输出“分类网络故障置信度90%”。这种脏数据解析起来非常烦人。我的解决办法有两层。第一层是提示词层面明确使用 JSON 格式约束请以如下 JSON 格式输出 {category: 网络故障, confidence: 0.92}第二层是代码层兜底用正则提取出 JSON 片段解析失败则标记为“无法解析”由人工处理。不要因为 AI 输出格式不对就让整个流程崩溃。这个兜底逻辑很笨但生产环境的鲁棒性恰恰来自这些笨逻辑。4.2 检索不到知识库内容先查文本拆分再查 embedding线上反馈“AI 说知识库没有相关信息”但明明知识库里就有。这个问题排查时先不要怀疑模型而是检查检索链路。我的排查顺序是检查查询文本预处理是否正常是否去掉了无意义的语气词是否进行了分词。检查知识库切片是否按语义拆分如果切得太碎关键词被切散检索就找不到了。检查 embedding 模型和检索查询是否一致不同模型生成的向量不能混用。检查召回的 Top K 数量K3 可能太少可以调到 K5同时配合重排模型。有一次我遇到某类工单一直检索不到内容最后发现是这段知识库里包含大量表格文本提取后表格结构全乱了切成的一堆散字根本没法匹配。后来专门针对表格内容做了 OCR 和结构化提取问题才彻底解决。4.3 工单接口响应变慢优先排查同步调用链有段时间我们的工单创建接口从 100ms 涨到 2000ms一开始怀疑是数据库慢查询后来发现是负责 AI 服务的 Python 进程发生 GC 暂停导致 Java 侧同步等待响应超时。改造方案很简单把所有 AI 调用都丢进消息队列异步处理接口响应时间立刻回到 80ms 左右。生产环境务必记住一条原则外部 AI 服务的任何不稳定都不应该直接影响核心业务的写路径。宁可用户暂时看不到 AI 建议也不能让工单创建本身变慢。4.4 常见问题速查表问题现象可能原因排查与解决AI 分类结果不稳定提示词示例不足或示例偏少增加 5~8 组典型示例覆盖边界场景模型输出包含多余文字提示词约束不够强硬改用 JSON 格式约束并做正则解析兜底知识库检索不到内容文本拆分粒度不合理按语义拆分保留标题元数据适当调大 K 值工单接口变慢AI 调用阻塞了主流程统一改为异步消费消息超时熔断Agent 反复调用错误工具工具描述不够清晰重写工具的描述字段写明输入输出和使用时机AI 建议处理人全是同一个人历史数据偏差导致负载失衡加入实时负载权重设置单人建议上限模型上下文过长历史记录拼接无限制实现滑动窗口摘要截取核心部分4.5 经验技巧小结最后分享几个在实际项目中证明有效的经验线上效果不好先不要换模型。先检查提示词里的示例是不是和真实工单分布一致。很多问题不是模型不行而是喂给模型的“教材”不对。给 AI 所有“建议类”字段都加一个置信度。置信度低的建议自动隐藏只在高置信度时才弹出给客服参考。这样既保留智能又不打扰人。AI 分析结果要留存原始请求和响应方便事后复盘和建立评测集。没有数据积累AI 永远只能停留在“碰运气”阶段。上线后每天跑一个定时任务统计 AI 建议的人工采纳率。采纳率低于 60% 的分类说明建议质量有问题需要优先优化。根据我个人实际操作中的体会最值钱的部分不是模型调用代码本身而是围绕 AI 建立的一套“人能监督、事能回滚、数据能评估”的工程体系。把工单系统理解为 AI 的容器AI 再好也离不开发布、监控、灰度、降级这些基本功。好在我这次从第一天就把这些基础设施搭上了后期迭代时才没有手忙脚乱。如果你正在规划自己的 AI 工单系统我建议你按这个顺序推进先梳理业务场景再定 AI 边界然后设计数据模型和提示词最后再铺开代码。只要你把“生产可维护”放在“功能花哨”前面这套系统就能走得很远。