1. 先说说这个智能体到底解决什么问题
做博世设备维修的朋友应该都有体会:最烦的往往不是设备本身难修,而是“修完了还要写一堆工单”。客户要凭证、厂家要记录、自己也要留底。一个熟练工程师修一台设备可能半小时,写一份合格工单却可能要二十分钟,如果遇到一个不常见的故障,还得翻历史记录、查手册、找同行问,时间就更是无底洞。我做了好几年售后维修,一直想把手上的维修经验、历史工单、技术通报整合起来,让AI帮忙写工单、找旧案例。于是就有了这个“博世维修AI智能体”。
这个智能体不是一个简单的聊天机器人,它干两件事:第一,基于维修过程中的结论、检测数据和现场描述,自动生成结构化故障工单;第二,通过语义检索从历史维修记录库里找到相似的故障案例、维修方案和备件信息,供工程师参考。说白了,就是把“写文档”和“查资料”这两件最耗时间的事接给AI干,让工程师把精力集中在“拆、测、修”上。
适合谁看?如果你也是做设备维修、售后服务的,或者你正在搞智能体应用、想用大模型解决行业文档处理问题,这篇内容应该能帮你避开我踩过的不少坑。我不是做理论研究的,下面写的都是实际跑通的流程和代码,没有那种“一键部署”的玄学。
1.1 维修工单编写,为什么值得用AI
维修工单这东西,看着简单,写起来很讲究。一份合格工单至少要包含:客户信息、设备型号、故障现象、检测过程、故障原因、更换备件、维修操作、测试结果、建议事项。缺一项,后面出了问题就说不清。很多老师傅手艺很好,但写工单就像挤牙膏,不是漏这个就是漏那个。
用AI生成工单,关键不是“用自然语言随便编一段”,而是要让AI按照固定模板填内容。这里有个核心思路:把工单的字段结构定义清楚,然后把维修过程中的碎片信息当作“参数”传给大模型,让它帮忙扩充、润色、补全。举个例子,现场工程师记录“CNC主轴异响,检测发现轴承磨损,更换轴承后正常”,AI可以结合设备型号、维修工时、备件编码等结构化字段,生成一段完整的故障分析和处理描述,甚至还能根据历史案例自动补充“建议定期润滑”这类维护提示。
我测试下来的实际效果是:一份原本需要人工写15分钟的工单,用智能体辅助后能在2分钟内生成初稿,人工只需要审核修改。写出来的工单比大部分新人写得更规范,因为AI会严格遵循你喂给它的模板和措辞习惯。不过前提是模板要设计好,提示词不能太随性,这部分我后面会详细讲。
1.2 “旧案例检索”的痛,比你想的更难
很多维修团队都有一个“专家库”,但这个库通常是散布在Excel表格、微信聊天记录、纸质维修单、系统数据库里的。真遇到疑难杂症时,检索靠什么?靠老师傅的记忆。老师傅退休了,知识也跟着走了。
传统的关键词搜索也不顶用。维修记录里同样的故障,今天写“电机不转”,明天写“马达无响应”,后天写“上电后风机没反应”。用精确匹配,一条都查不到。这就是典型的“文档能搜到,但语义查不来”的问题。
所以旧案例检索必须用语义检索。我把历史维修记录统一清洗、切片、向量化,存进向量数据库,再配合BM25关键词召回做混合检索。工程师只要描述现象,比如“博世冰箱启动后频繁停机,显示屏闪烁”,系统就能从几千条旧工单里找到“压缩机启动不良”“主板电压不稳”“显示板接触不良”这些相关案例,不管你用的是不是原词。这一步是整个智能体最核心的价值,也是我花时间最多的部分。
2. 整体架构:一个维修智能体的拆解
先给大家看一个简化版的数据流思路,不涉及具体平台,你完全可以照着搭:
维修现场信息(现象、检测数据、工程师备注)→ 进入工作流 → 先做案例检索(RAG)→ 把检索到的相似案例作为参考 → 大模型结合参考和现场信息生成结构化工单 → 人工审核 → 保存工单 → 新工单再入库,形成闭环。
整个系统可以拆成三个模块:数据层(历史工单库、知识库、设备信息表)、检索层(向量化+召回+排序)、生成层(大模型对话接口+提示词模板+结构化输出校验)。这三层装在一个后台服务里,对外暴露一个简单界面,工程师在手机上填几项信息,就能得到工单草稿和相似案例列表。
2.1 核心模块与数据流向
先说数据层。历史工单必须转成统一的JSON结构。比如字段包括:equipment_model(设备型号)、failure_symptom(故障现象)、fault_reason(故障原因)、repair_action(维修操作)、replacement_parts(更换备件)、test_result(测试结果)、maintenance_suggestion(维护建议)。这些字段直接对应最终工单的各个栏目。
检索层的关键是索引。我把每一条历史工单切成若干段:故障现象单独一段,检测过程单独一段,维修操作单独一段,备件信息单独一段。为什么切成多段而不是整条工单一起向量化?因为相似故障可能只体现在某个字段上。比如旧工单的“故障现象”和新故障很类似,但“维修操作”完全不同,这时整条工单的相似度会被拉低,而分段后能更精准地召回现象匹配的部分。
生成层则是一个典型的Agent动作序列:先接收用户填写的非结构化描述,然后调用检索接口,拿到top5相关案例,再把案例内容和工单模板塞给大模型,让它生成“填充好”的工单。这里有一个很多教程不会提的关键点:大模型一次不要给它太多案例,三到五个就够。给多了它反而不知道重点是什么,经常把不相关的维修操作混进来。
2.2 为什么要用RAG而不是让大模型直接回答
我刚开始做原型的时候偷懒,直接把故障现象发给大模型,让它“凭经验”生成工单。效果呢?工单格式漂亮,但内容经不起推敲,它会一本正经告诉你“请检查电源线是否松动”这种废话。尤其涉及博世设备特有的故障码和备件编号时,模型基本是在编造。
后来我改成RAG架构,让大模型不直接回答,而是先检索再回答。说白了,就是先给模型一份“参考资料”,告诉它“这是本团队处理过的真实案例,请基于这些案例并结合你自身的维修常识来写工单”。这样一来,大模型的输出就有了依据,幻觉少了一大半。尤其是备件编号、故障码、扭矩值这类信息,必须从知识库里拿,不能靠模型“想当然”。这就是RAG最大的意义。别神话大模型,它再大,也记不住你车间里那批老设备的脾性。
2.3 可靠性设计:智能体的“容错控制”
智能体跑在维修场景里,最怕的是它“自作主张”。比如现场明明说了“未更换任何备件”,AI却根据历史案例补了一条“更换轴承”。这种多填的“建议”,一旦被车间新人直接复制到工单里,就是将错就错。所以我特别强调“容错”。
我在工程上是这么做的:所有生成内容都给出“置信来源”标注。具体来说,大模型输出的每一句描述后面,系统自动回查知识库,看这句话的内容能不能在某个旧案例或产品手册里找到对应的原文片段。找不到原文支撑的描述,在工单草稿里用高亮标记“未经历史案例支持”,提醒审核人员注意。这一步实现起来不复杂,就是拿生成文本里的关键短语(比如备件编号、故障码、数值)去检索知识库,检索不到就把整句标出来。有了这层校验,AI胡说八道的影响就被限制住了。
这其实就是热词里常说的“自主容错控制”的工程落地。别小看这些细节,维修行业一个错误的备件编号可能带来几百上千元的损失,可靠性优先级永远高于花哨功能。
3. 故障工单编写的实操细节
3.1 工单结构和字段设计
工单不是作文,是结构化文档。我的建议是先拆字段,再写模板。这里列一套适合“博世设备维修”的工单字段,你可以按自己业务增删:
| 字段名 | 示例 | 必填 |
|---|---|---|
| 工单编号 | BSH-2025-0312 | 是 |
| 设备型号 | Bosch GWS 18-125 V-LI | 是 |
| 设备序列号 | 制造序号或资产码 | 是 |
| 报修时间 | 2025-06-11 14:32 | 是 |
| 故障现象 | 无法正常充电,充电器指示灯闪烁 | 是 |
| 检测过程 | 用万用表测量电池包输出端电压为空 | 是 |
| 故障原因 | 电池包内部保护板烧毁 | 是 |
| 维修操作 | 更换电池包保护板,重新校验 | 是 |
| 更换备件 | 保护板 P/N 1619P12345 | 否 |
| 测试结果 | 充电1小时后指示灯正常,连续运行30分钟无异常 | 是 |
| 维护建议 | 建议每季度检测电池健康度 | 否 |
字段设计对AI生成效果影响很大。如果字段太粗糙,比如只有一个“维修内容”大框,AI生成时容易写成一堆流水账,不好用。拆成字段后,AI的每个输出都有明确的“格子”,你可以针对每个格子写具体的生成指令。比如“维修操作”字段要求写明“拆卸—更换—重装—测试”流程,而“维护建议”字段则要求必须是“预防性、周期性”的建议,禁止写“如果再次出现请联系客服”这种废话。
3.2 生成工单的提示词模板与“固化写法”
我踩过的坑:提示词写得太开放,AI生成的内容又长又泛,很难落到实用。后来我把提示词改成“约束式”,效果立竿见影。下面是我实际在用的一个简化版模板,核心思路是“设定角色—提供信息—给出案例—限定输出规则”。
你是博世设备维修工单撰写助手。请根据以下“现场维修信息”和“相似历史案例”,填写一份结构化维修工单。 现场维修信息: {用户填写的非结构化描述} 相似历史案例(仅作参考,不要照抄): {检索到的3~5个案例JSON} 输出规则: 1. 严格按照工单字段输出,每个字段一行,格式为“字段名:内容”。未提供的信息留空,禁止编造。 2. “检测过程”字段必须包含具体的仪器、测量点或测试步骤,宁缺毋滥。 3. “维修操作”字段按“拆卸—更换/维修—重装—测试”的顺序描述,每步不超过30字。 4. “更换备件”字段必须使用案例如有明确的备件编号,否则留空。 5. 最终输出不允许出现“可能”“大概”等模糊词。这里有两个容易被忽略的细节:一是“未提供的信息留空”这句话极其重要,它能防止AI脑补;二是“维修操作”限定顺序,能保证工单阅读起来条理清晰。注意,提示词末尾不要再说“请一定遵守”之类的废话,规则已经列清楚了,多余的话反而会稀释指令权重。
3.3 输出规范化:结构化输出与校验
大模型输出的是文本,为了让它能直接存入系统,最好让模型输出JSON,而不是“字段名:内容”。用JSON的好处是程序可以自动解析、校验、落库。我给大模型加了一个约束:以JSON格式返回,键名就是工单字段名。为了稳定,我甚至在请求参数里强制设定了response_format={"type": "json_object"}(不同模型接口写法略有差异,但都能做到)。
拿到JSON后,还需要做几步校验:必填字段是否为空(空则报错退回给用户补充)、故障原因是否属于预设的语义类别(比如“机械磨损”“电气故障”“软件异常”)、备件编号是否符合“字母+数字+”的格式。这些校验规则不复杂,但能把AI输出的垃圾挡在外面。我自己的经验是,加校验后工单合格率从78%提升到了95%以上,剩下的5%基本都是模板和案例覆盖不到的新问题。
4. 旧案例检索:让历史维修记录变成可用的知识库
4.1 旧案例数据清洗与入库
历史工单格式五花八门:有老的Excel导出、有扫描的PDF、有维修系统里的数据库记录。清洗工作不能一次性用脚本跑完,得先抽样看数据质量,再定规则。
核心清洗规则:
- 将同义字段合并。比如表格里的“维修结果”“处理结果”“修复情况”统一映射为
repair_action或test_result。 - 删除与维修无关的备注。很多老人喜欢在工单里写“客户态度差”“上门路远”之类的废话。这些内容既干扰向量化,也没有检索价值,直接删。
- 对故障现象字段做轻度“改写归一”。注意,不要做大规模同义词替换,因为会丢失原有表达习惯。我这里只是把英文缩写统一(例如“PCB”→ “线路板”),以及把繁体转简体。
- 数据量少怎么办?几百条也能用。我先跑了不到一年数据的1200条工单,效果已经不错。重点是每条工单的“故障现象”和“维修操作”质量要高,别指望垃圾进垃圾出。
清洗完成后,我会把每条工单拆成多个片段存入文档库。文档结构示例:
{ "case_id": "BSH-2025-0312", "equipment_model": "Bosch GWS 18-125 V-LI", "segments": [ {"field": "symptom", "text": "无法正常充电,充电器指示灯闪烁"}, {"field": "detection", "text": "用万用表测量电池包输出端电压为空"}, {"field": "repair", "text": "更换电池包保护板,重新校验"}, {"field": "part", "text": "保护板 P/N 1619P12345"} ] }每条工单分成四个segment,分别对应四个字段。为什么这样分?因为检索“维修操作”类问题时,命中repair段更合理;检索“故障现象”类问题时,symptom段更直接。如果把字段名也拼进文本里,会稍微影响向量质量,所以我只存入字段的值,靠元数据里的field标签来区分。这是检索效果的一个隐藏优化点。
4.2 向量化与混合检索策略
向量化我用的是一套开源的Embedding模型,维度不算高,但匹配“中文维修口语”足够。Embedding模型选型上有个坑:不能只看榜单分数,要拿你实际的故障现象句子去测相似度。比如“充电器闪红灯”和“充电报错,红灯亮”这两个句子,好的Embedding应该认为高度相似,而有些通用模型反而认为它们不够近,因为“闪红灯”和“红灯亮”字面上差挺多。
我的检索方案不是单一的向量检索,而是“向量检索 + BM25关键词检索”的混合模式。BM25擅长处理故障码、备件编号这种必须精确匹配的场景;向量检索擅长处理同义表达和口语化描述。两者取并集后,再用一个重排模型按相关性打分,取Top5。这个方案在召回率和准确率上都比单纯向量检索好。尤其在维修场景里,故障码“E2262”这类词经常出现,如果只用向量检索,偶尔会把同字母前缀的错误码也拉进来,BM25就能把它们严格区分开。混合检索是旧案例检索环节最值得做的投入。
4.3 排序与重排:怎么让最相关的案例排前面
召回阶段一般拿Top20,然后重排到Top5。重排模型可以用轻量级的交叉编码器(Cross-Encoder),也可以直接用大模型来做。我试过两种:用交叉编码器速度快、成本低,效果稳定;用大模型重排则能结合更多上下文,但延迟太高,没必要。
这里分享一个排序技巧:在重排打分时,除了语义相似度,还额外加入一个“型号匹配加分”。如果候选案例的设备型号与当前故障设备型号完全相同,在原始分基础上加0.2。别小看这个系数,维修案例里不同型号之间虽然有时能互相参考,但备件和操作细节往往差异很大。加了型号权重后,检索结果更贴近真实需求。实现时,在重排脚本里对每个候选案例的equipment_model字段做一次比较,相同则加分,就这么简单。
5. 从零搭建一个可落地的智能体:我的实操记录
5.1 环境与工具选型
我的后端是Python写的,用FastAPI提供HTTP接口。向量数据库用开源的Chrom了,因为对中小规模数据(几千条工单)已经完全够用,不用专门上分布式。Embedding模型直接跑在本地GPU上,6GB显存就够。大模型这一块,因为涉及工单数据内部使用,我没有直接把工单全部喂给云端API,而是在同一个内网部署了一个量化后的开源模型,用来做生成和重排。如果你没有内网部署条件,使用合规的云端大模型API也没问题,但要注意数据脱敏,工单里的客户姓名和联系方式一律不能带出。
整套系统的调度我写成了一个Agent工作流,没有用现成的低代码平台。原因有两个:一是工单校验逻辑要写不少定制的Python函数,低代码平台处理起来很别扭;二是我想把检索、生成、校验完全揉在一个服务里,调优起来更顺手。当然,如果你想快速验证,用Dify或Coze搭一版demo也完全可以,但正式落地我会建议还是走代码。
5.2 关键代码与实现路径
下面这段代码是我实现“根据用户输入先检索再生成工单”的核心骨架,我简化去掉了日志和异常处理,但逻辑是完整的:
from fastapi import FastAPI from pydantic import BaseModel from typing import List import chromadb from sentence_transformers import SentenceTransformer import json # 初始化向量库 client = chromadb.PersistentClient(path="./case_db") collection = client.get_or_create_collection(name="bosch_cases") # 初始化嵌入模型 encoder = SentenceTransformer("./local_embed_model") # 模型调用函数(伪代码) def call_llm(system_prompt, user_prompt): # 此处替换为你实际使用的大模型接口 return llm_response class WorkOrderRequest(BaseModel): symptom: str # 现场故障现象描述 detection: str = "" # 现场检测信息 equipment_model: str = "" def bm25_search(query: str, top_k: int): # 用jieba分词 + BM25分数计算,返回候选ID列表 # 实际工程中我使用rank_bm25库实现 return ["case_001", "case_002", ...] def vector_search(query: str, top_k: int): q_emb = encoder.encode(query).tolist() res = collection.query(query_embeddings=[q_emb], n_results=top_k) return res["ids"][0] def rerank(query: str, candidates: List[str], model: str) -> List[str]: # 用交叉编码器或LLM对candidates重新排序 return reranked_ids def build_context(case_ids: List[str]): context_parts = [] for cid in case_ids: doc = collection.get(ids=[cid]) case = json.loads(doc["metadatas"][0]["json"]) context_parts.append(json.dumps({"case_id": cid, **case}, ensure_ascii=False)) return "\n".join(context_parts) @app.post("/generate_work_order") def generate_work_order(req: WorkOrderRequest): query_text = f"{req.equipment_model} {req.symptom} {req.detection}" ids_bm25 = bm25_search(query_text, 10) ids_vec = vector_search(query_text, 10) merged = list(dict.fromkeys(ids_bm25 + ids_vec)) top_cases = rerank(query_text, merged)[:5] context = build_context(top_cases) prompt_template = f"""你是博世设备维修工单撰写助手。...(此处省略提示词模板,参见上文)... 现场维修信息: 设备型号:{req.equipment_model} 故障现象:{req.symptom} 检测信息:{req.detection} 相似历史案例: {context}""" result = call_llm(system_prompt="你是严谨的维修工单生成器,禁止编造。", user_prompt=prompt_template) # 解析JSON + 校验 work_order = json.loads(result) validate_work_order(work_order) return {"work_order": work_order, "references": top_cases}实际跑起来时,有几个点要注意:一是collection.get每次调用都去拿元数据,如果候选多了会慢,建议启动时把案例元数据缓存到内存;二是BM25搜索要对案例segments的文本做分词索引,我用了jieba,并加了设备型号、备件编码等自定义词典,才能让“GWS18-125”这种词被正确分词。
5.3 调优指标与效果对比
我把这套系统在一个维修小组里试跑了两个月,用了一个比较笨但有效的评估方法:把历史上的人工工单当作标准答案,让AI对同一故障描述生成工单,让老师傅盲评。
调优前后对比:
- 仅直接让大模型生成,不检索:工单字段缺失率25%,备件编号错误率30%,老师傅认为可用率仅40%。
- 加RAG检索,但未加重排:字段缺失率降到8%,备件错误率降到7%,可用率到75%。
- 加混合检索、重排、字段校验后:字段缺失率1.5%,备件错误率1%,可用率到93%。
关键调优点在两道:一是重排加入设备型号加分,直接把“跨型号误导”问题压下去;二是校验规则阻止了空字段被AI自行脑补。这两点是收益最高的,建议你优先做。
6. 常见问题与避坑指南
6.1 检索召回不准,怎么办
症状:检索出来的案例跟当前故障明显不搭边,比如“充电故障”给召回“外壳清洁”的案例。排查思路:
第一,看查询文本的组成是否合理。我发现很多人构建查询时只用了“故障现象”几个字,比如“不充电”,这样向量检索容易偏向泛化的“充电”概念。我一般会把“设备型号+现象+检测信息”拼成一个完整查询,让向量包含更多上下文。第二,检查分段是否过粗或过细。如果整条工单作为一段,检索到的内容容易主题混杂;如果切得太碎,又可能丢失关联。我用“字段级分段”,故障现象和维修操作分开索引,效果最好。第三,调整BM25和向量召回的比重。如果你发现精确匹配的故障码经常被漏掉,可以调高BM25的候选数量,同时保证向量召回也预留同样数量。重排模型的选择也很关键,如果资源允许,用效果更好的重排模型能直接提升几个点。
6.2 大模型生成工单出现幻觉,怎么约束
幻觉是硬伤。我的经验是双管齐下:提示词里明确“未提供的信息留空,禁止编造”,并在输出后做字段校验。但只靠提示词和校验还不够,因为你拦不住它把“可能”写成“肯定”。我最后用的一个很实用的技巧是:把“更换备件”字段从生成式改为“选择式”。也就是说,AI不再负责生成备件字段,而是由系统从检索到的旧案例里提取备件编号列表,让AI在列表中选择最匹配的一个,选不了就留空。这样备件字段的幻觉率几乎降为0。
类似地,故障码、扭矩值、标准间隙等关键参数,也应该优先走“检索—选择”而不是“生成—编造”。
6.3 部署与性能方面的几个坑
第一个坑是把Embedding模型和大模型都放在同一台没显存的机器上,导致推理排队。我后来给它们分开部署:嵌入模型占一个轻量GPU,大模型占另一个服务,日常使用互不影响。
第二个坑是向量库的持久化路径。Chrom在Docker容器里默认用临时目录,重启后库就没了。一定要把PersistentClient的路径挂载到宿主机磁盘,这个坑我丢过一次数据,教训深刻。
第三个坑是并发。如果有多个工程师同时访问,大模型推理接口会成为瓶颈。我在FastAPI层加了简单的请求队列,不使用异步无节制地并发,宁可让前面的人等一两秒,也别把显存打爆导致OOM。毕竟维修现场用系统的人不多,并发真的不高,没必要为极端场景牺牲稳定性。
第四个坑是检索结果的“引用标注”。工单上如果不写“参考了哪个历史案例”,后面回溯时根本说不清AI为什么建议这个操作。所以我在最终输出的工单里加了一行“参考案例编号”,点击后能跳到原工单。这一步对质量审计和老师傅复核都特别重要。
最后再多说一句
这套智能体谈不上完美,但已经实打实帮我节省了大量工单处理时间,也让新人维修工不再事事问师父。我个人体会最深的是:AI落地到维修行业,门槛不在算法,而在“领域数据治理”。把历史工单整理成干净的、可检索的结构化文档,比调大模型参数重要十倍。如果你也想做类似的东西,我建议从今天起就把手头维修记录里的故障现象和维修操作单独整理成表格,攒上两三百条,你会发现检索和生成的效果远超预期。
再分享一个小技巧:每次AI生成工单后,哪怕人工改动只有一句话,也值得把改完的版本存回案例库。智能体的价值是滚雪球式的,案例库越积累,检索越准,生成越靠谱。这个正循环,是任何现成AI产品都替代不了的。