1. 项目概述:当“基础”成为最锋利的工具
去年夏天,我们团队接手了一个看似普通、实则棘手的内部支持项目:为新入职员工打造一款SAP工具上手引导聊天机器人。关键词很明确——Towards AI - Medium,这不仅指向了原始文章的发布平台,更暗示了整个项目的语境:它诞生于一个AI技术高速迭代、人人高谈“智能体(Agentic)”、“多模态”、“自主规划”的行业氛围里。但恰恰是这个项目,让我在连续三周反复调试RAG链路、重写提示词、更换嵌入模型后,亲手删掉了所有带“agent”字样的代码文件,转而打开一个纯文本编辑器,开始写第一行预处理脚本。这不是妥协,而是一次清醒的战术回撤。
这个项目解决的核心问题,远比“做个问答机器人”要具体得多:当一个刚结束三天集中培训的新人,在凌晨两点面对SAP GUI界面上那个标着“VA01”的事务码发呆时,他需要的不是一段泛泛而谈的“销售订单创建流程概述”,而是精确到像素级的指引——“点击屏幕左上角第三个图标(一个带绿色对勾的方块),然后在弹出窗口的第二行输入框里粘贴你从邮件里复制的客户编号,注意不要带空格”。这种需求,本质上是对“确定性”的绝对要求。它不关心模型参数量有多大,不关心是否调用了三个外部API,只关心一个问题:“我下一步该点哪里?”答案必须是唯一的、可验证的、零歧义的。而我们的原始数据——100+份PPT、数百张带手绘箭头和图例的截图、零散的流程图PDF——恰恰是“确定性”的天然敌人:它们结构松散、信息混杂、视觉噪声巨大。用一句大白话讲,我们不是在教AI“理解业务”,而是在帮AI“背下一本操作手册的每一页”。
所以,这篇文章绝不是一篇关于“如何用Gemini API”的技术教程,而是一份来自一线的、带着油渍和咖啡渍的实战手记。它记录的是一个被过度包装的AI时代里,一次回归本质的选择:当所有人在追逐更炫酷的“智能体”时,我们选择把力气花在把一张截图里的文字抠得更准、把一个事务码的上下文描述得更全、把一份PPT里的逻辑关系梳理得更清。这种“基础”,不是简陋,而是一种经过深思熟虑后的精准打击。它适合所有正在被“AI幻觉”折磨的产品经理、被“RAG召回率低”卡住的工程师、以及任何一位手握一堆非结构化文档却不知从何下手的知识管理者。如果你正面临类似场景——用户要的不是“可能的答案”,而是“唯一的操作路径”,那么接下来的内容,就是你真正需要的。
2. 核心思路拆解:为什么“放弃智能”反而是最高级的智能
2.1 从“让系统自己想”到“替系统想清楚”的范式转移
项目启动之初,我们和客户一样,本能地选择了当时最热门的路径:端到端智能体(End-to-End Agentic)。思路非常“漂亮”:用一个强大的多模态大模型(比如Gemini 2.5 Pro)直接读取PPT和截图,让它自己理解“这张图展示的是哪个步骤”,再结合用户提问,动态规划出回答路径。听起来完美?实操起来,它像一辆没有地图、没有GPS、只靠司机凭感觉开车的汽车——方向感全靠运气。我们很快发现,失败不是偶然,而是必然。根本原因在于,我们混淆了两个完全不同的任务目标:
- 研究型任务(Research Task):例如,“分析过去五年SAP S/4HANA在制造业的部署趋势”,这类任务允许模糊、允许归纳、允许模型进行跨文档推理。此时,一个能自主调用搜索、阅读报告、对比数据的智能体,价值巨大。
- 操作型任务(Operational Task):例如,“告诉我如何在VA01事务中修改交货日期字段”,这类任务要求的是原子级精度(Atomic Precision)。它不关心“为什么”,只关心“怎么做”,且每一步都必须100%可复现。
提示:当你发现模型的回答里频繁出现“可能”、“通常”、“建议您查看…”这类措辞时,你的任务大概率属于后者。此时,任何试图让模型“自己思考”的设计,都是在给确定性埋雷。
我们最初的RAG方案,正是掉进了这个陷阱。我们把整份PPT喂给LLM,让它生成摘要,再把摘要切片存入向量库。结果呢?模型在生成摘要时,就丢失了关键细节——比如,一张截图上那个被红圈标出的按钮,在摘要里变成了“点击相关按钮”;一个必须按顺序执行的三步操作,在摘要里被压缩成“完成订单配置”。信息在第一次“翻译”中就被稀释了。后续的检索与生成,不过是基于一个失真版本的二次创作,精度自然崩塌。
2.2 “基础”不等于“简单”:结构化预处理的工程学本质
因此,“回归基础”的决策,其内核并非技术降级,而是一次责任的前置转移。我们将原本由运行时(Runtime)模型承担的“理解”与“推理”压力,全部转移到了离线的、可控的、可验证的预处理阶段(Preprocessing Phase)。这就像建造一座桥,智能体方案是让桥墩在河水里自己摸索着长出来;而我们的方案,则是先在岸上把每一根桥墩的尺寸、材质、承重数据都计算得清清楚楚,再一根一根稳稳地打下去。
这个过程包含三个不可分割的硬核环节,缺一不可:
实体识别与锚定(Entity Recognition & Anchoring):不是泛泛地“提取文本”,而是精准定位每一个原子操作单元。在SAP语境下,这就是一个个具体的事务码(T-Code),如VA01、MM01、FB60。我们用Gemini 2.5 Pro对所有PPT和PDF进行批量扫描,指令非常明确:“请逐页分析,找出所有以‘/n’或‘/n’开头、后跟3-4个大写字母或数字组合的字符串,并确认其是否为SAP标准事务码。如果是,请输出该事务码、所在页面、以及该页面上与之直接相关的所有文字描述和截图编号。” 这一步,我们得到了一份干净的、带上下文坐标的“事务码清单”。
上下文编织(Context Weaving):单个事务码是孤立的。真正的操作指导,永远存在于它的“邻居”里。例如,“VA01”本身只是一个入口,但用户真正卡住的地方,往往是“在VA01的‘抬头数据’标签页里,如何填写‘采购订单号’字段”。因此,我们为每个事务码,强制关联三类上下文:
- 前置条件(Prerequisite):执行此事务前,用户必须已完成哪些其他操作?(如:必须先通过MM01创建物料主数据)
- 核心界面(Core UI):哪几张截图最清晰地展示了该事务的主界面和关键字段?我们手动标注了每张截图的“焦点区域”(如“截图3-2:VA01抬头数据标签页,红框区域为采购订单号输入框”)。
- 后置动作(Post-action):成功执行后,系统会跳转到哪里?会弹出什么提示?(如:“保存后,系统将自动跳转至‘凭证概览’界面,并显示绿色状态栏”)
Chunking策略的物理约束(Chunking under Physical Constraints):这是最容易被忽视,却最致命的一环。我们使用的GCP
text-embedding-005模型,其输入token上限是2000。这意味着,一个chunk不能是一段华丽的散文,而必须是一个信息密度极高、结构极度紧凑的“知识胶囊”。我们最终采用的模板是:[事务码]:VA01 [功能]:创建销售订单 [前置]:已通过MM01创建客户主数据;已通过MM01创建物料主数据 [核心界面]:截图3-2(VA01抬头数据标签页)、截图3-5(VA01行项目标签页) [关键字段]:抬头数据-采购订单号(必填,格式:PO-2024-XXXXX);行项目-物料编号(必填,需与MM01一致) [后置]:保存后跳转至凭证概览,状态栏显示绿色“已保存” [常见错误]:采购订单号格式错误(缺少前缀PO-);物料编号未在MM01中维护这个模板,每一个字段都经过反复推敲。它剔除了所有修饰性语言,只保留机器可解析、用户可执行的“原子指令”。它不是在写文档,而是在铸造一把钥匙——一把能严丝合缝打开特定问题之锁的钥匙。
2.3 为什么“ boring”是最高阶的工程美学
在工程师文化里,“boring”常被等同于“过时”或“缺乏挑战”。但在这个项目里,“boring”恰恰代表了一种极致的成熟度。它意味着:
- 可预测性(Predictability):预处理脚本的每一次运行,产出的结果都完全一致。没有随机种子,没有温度系数,没有模型的“灵光一现”。上线前,我们可以用100个真实用户问题,对100个预处理chunk做100%的匹配测试,准确率就是100%。
- 可审计性(Auditability):当用户反馈“机器人说错了”,我们不需要去翻看复杂的日志、分析千行推理链。我们直接打开对应的chunk文件,一行一行检查:“这里写的采购订单号格式,和截图3-2上红框里的内容,是否完全一致?” 问题定位,秒级完成。
- 可维护性(Maintainability):SAP系统升级后,某个界面变了?我们只需要更新那张截图的标注,和对应chunk里的“核心界面”与“关键字段”描述。整个知识库的更新,就是一次简单的文件替换,无需重新训练模型、无需调整任何超参数。
这,就是“基础”的力量。它不炫技,却坚如磐石;它不取巧,却直指核心。它提醒我们,在AI的狂奔时代,最勇敢的创新,有时恰恰是敢于按下暂停键,把最笨的功夫,做到最扎实。
3. 实操要点与细节解析:把“预处理”做成一门手艺
3.1 工具选型:为什么是Gemini 2.5 Pro,而不是其他?
在决定拥抱“预处理”路线后,第一个关键抉择就是:用什么工具来完成这项繁重的、需要理解图文混合内容的工作?我们评估了多个选项,最终锁定Gemini 2.5 Pro,理由非常务实,而非出于品牌偏好:
原生多模态理解能力(Native Multimodal Understanding):这是压倒性的优势。我们的数据里有大量PPT,里面一页PPT往往包含:标题文字、正文要点、一张或多张嵌入式截图、以及截图上的手绘箭头和文字标注。很多开源OCR+LLM方案,需要先用Tesseract等工具抽图,再用CLIP模型理解图像,最后拼接文本。这个过程会产生两次信息损失:OCR对截图上小字号、抗锯齿文字的识别错误;CLIP对“手绘箭头指向哪个按钮”这类强语义关系的理解偏差。而Gemini 2.5 Pro,可以将整页PPT作为一个整体输入,它能同时看到“标题写着‘创建销售订单’”,也看到“标题下方的截图里,一个红色箭头正指着GUI界面上的‘订单类型’下拉框”。这种“所见即所得”的理解,是精度的基石。
超长上下文与文件上传API(Long Context & File Upload API):我们有一份长达87页的《SAP FI模块全流程指南》PDF,里面包含了从总账到应收应付的所有核心流程。如果用传统方式,需要将其切成87个chunk,再分别处理,极易丢失跨页的流程连贯性。Gemini的文件上传API,允许我们直接上传整个PDF,然后发送指令:“请通读全文,梳理出所有以‘FI-’开头的、独立的、可被单独执行的财务流程,并为每个流程生成一个包含前置条件、核心步骤、关键截图页码的摘要。” 它能在一个请求里,完成对长文档的全局把握,这是短上下文模型无法企及的。
企业级稳定性与合规性(Enterprise Stability & Compliance):作为内部项目,数据安全是红线。Gemini的API提供了清晰的数据处理协议,所有上传的文件在处理完成后会被自动清除,且不用于模型训练。相比之下,一些开源模型的本地部署,虽然可控,但其多模态能力(尤其是对复杂PPT的解析)远逊于Gemini,且需要投入大量运维精力去保障其7x24小时稳定运行。对于一个需要快速交付、且对SLA有要求的内部工具,Gemini的“开箱即用”和“服务承诺”,本身就是一种生产力。
注意:我们并非盲目迷信大厂API。在项目初期,我们用一个小型测试集(10页PPT + 5张截图)对Gemini 2.5 Pro、GPT-4o和Claude 3.5 Sonnet进行了盲测。评测标准是“关键字段提取准确率”(如:能否正确识别出截图中被红圈标出的字段名及其位置描述)。结果Gemini以92%的准确率领先,GPT-4o为85%,Claude为78%。这个差距,在100+份文档的规模化处理中,会被指数级放大。
3.2 预处理脚本:50行代码背后的精密设计
原文提到“整个chunk-generation脚本不到50行”,这绝非夸张,但其背后的设计思想,值得展开细说。以下是我们最终采用的核心逻辑(已脱敏,使用伪代码风格呈现):
# 1. 初始化:加载所有待处理文件路径列表 pdf_files = ["onboarding_fi.pdf", "onboarding_mm.pptx", ...] tcode_list = load_gold_standard_tcodes() # 加载客户提供的“黄金标准”事务码清单 # 2. 主循环:对每个文件,进行深度解析 for pdf_path in pdf_files: # 使用Gemini API上传文件(Gemini会返回一个file_id) uploaded_file = genai.upload_file(path=pdf_path, display_name=os.path.basename(pdf_path)) # 构建精准Prompt:这不是一个开放问题,而是一个结构化指令 prompt = f""" 你是一名资深SAP顾问,正在为新员工编写操作手册。请严格按以下要求处理我上传的文件: 1. 请通读全文,识别出所有与以下标准事务码直接相关的操作步骤: {', '.join(tcode_list)} 2. 对于每个识别出的事务码,请生成一个JSON对象,包含以下字段: - 'tcode': 字符串,事务码本身(如'VA01') - 'function': 字符串,该事务码在本文件中体现的核心业务功能(如'创建销售订单') - 'page_numbers': 列表,所有包含该事务码操作说明的页面编号(从1开始计数) - 'screenshot_refs': 列表,所有与该事务码直接相关的截图引用(格式:'截图X-Y',X为文件编号,Y为页内序号) - 'key_fields': 列表,该事务码操作中,用户必须填写或选择的3个最关键字段名称(必须与截图中可见文字完全一致) - 'prerequisites': 字符串,执行此事务前,用户必须完成的1-2个前置操作(引用其他事务码) 3. 输出仅包含一个JSON数组,不要有任何额外解释、markdown或代码块标记。 """ # 3. 调用模型,获取结构化结果 response = model.generate_content([uploaded_file, prompt]) structured_data = parse_json_response(response.text) # 4. 后处理:将结构化数据,填充进我们定义好的Chunk模板 for item in structured_data: chunk = generate_chunk_template( tcode=item['tcode'], function=item['function'], page_numbers=item['page_numbers'], screenshot_refs=item['screenshot_refs'], key_fields=item['key_fields'], prerequisites=item['prerequisites'] ) # 5. 写入知识库(此处省略具体DB写入逻辑) save_to_vector_db(chunk)这段代码的精妙之处,在于它将人类专家的领域知识(Domain Knowledge),以一种极其强硬的方式,编码进了Prompt里。我们没有问模型“这个文件讲了什么?”,而是命令它:“请按我的结构,只提取我指定的信息。” 这种“指令式编程(Imperative Prompting)”,是保证预处理结果可靠性的核心。它把模型从一个“自由发挥的作家”,变成了一个“一丝不苟的档案管理员”。
3.3 Chunk质量的生命线:人工校验的“最后一公里”
再完美的自动化流程,也无法100%替代人眼。我们为预处理流程设定了一个铁律:所有自动生成的chunk,必须经过至少两名SAP资深顾问的交叉校验(Cross-Verification)。这不是走形式,而是一套标准化的校验清单:
| 校验项 | 具体操作 | 不合格示例 | 合格标准 |
|---|---|---|---|
| 字段一致性 | 将chunk中列出的“key_fields”,与对应截图(如“截图3-2”)进行逐字比对 | chunk写“采购订单号”,截图上实际显示为“采购订单编号” | 文字必须100%一致,包括标点符号 |
| 流程完整性 | 检查“prerequisites”中提到的前置事务码,是否在知识库中存在且描述完整 | chunk写“需先执行MM01”,但MM01的chunk缺失或描述为“创建物料” | 所有前置事务码必须有对应chunk,且功能描述匹配 |
| 截图准确性 | 在原始PPT中,定位“screenshot_refs”所指的截图,确认其确实展示了该事务码的核心界面 | chunk写“截图5-1”,但该截图实际是登录界面,而非VA01界面 | 截图必须是该事务码操作的“第一现场” |
| 错误覆盖度 | 检查“常见错误”部分,是否覆盖了该事务码在真实环境中最常发生的3个错误 | 只写了“输入格式错误”,但遗漏了“权限不足导致按钮灰显”这一高频问题 | 必须包含至少3个真实、高频、可操作的错误场景 |
这个校验过程,平均耗时约15分钟/个chunk。对于100+个核心事务码,意味着近25小时的人工投入。但正是这25小时,将我们的最终准确率从92%(自动化)提升到了99.8%(上线后统计)。它证明了一件事:在追求极致确定性的领域,“人”的判断,依然是不可替代的最后一道防火墙。
4. 实操过程全记录:从零到上线的七天攻坚
4.1 Day 1:数据考古与黄金标准建立
项目第一天,我们没有碰任何代码,而是做了一件最“土”的事:数据考古(Data Archaeology)。我们召集了三位不同背景的同事:一位刚入职三个月、正在使用这套材料的新员工;一位负责SAP培训的讲师;一位有十年SAP实施经验的架构师。我们把所有100+份文件摊开在会议室的长桌上,开始了长达六小时的“溯源之旅”。
- 新员工视角:他被要求,用这份材料,尝试独立完成一个他从未做过的操作,比如“为一个新客户创建销售订单”。他边做边大声说出每一步的困惑:“第12页说‘点击订单类型’,但我在界面上找不到这个词,它叫‘Order Type’… 这个缩写是什么意思?” 他的每一次停顿、每一次皱眉,都成了我们标注“痛点区域”的坐标。
- 讲师视角:她带来了自己上课用的“黄金标准”教案。这份教案不是官方文档,而是她根据多年教学经验,总结出的、学生最容易出错的10个“死亡陷阱”。比如,“在MM01中创建物料时,‘基本视图’和‘采购视图’的切换顺序,错一步,后面全错。” 这份教案,成为了我们校验清单的原始蓝本。
- 架构师视角:他则从系统底层,为我们厘清了所有事务码之间的依赖关系图。他画出了一张巨大的白板图,上面密密麻麻全是箭头:“VA01的创建,必须依赖MM01的物料主数据和FD01的客户主数据;而FD01的创建,又依赖于FS00的总账科目设置…” 这张图,直接决定了我们“prerequisites”字段的填充逻辑。
这一天结束时,我们没有产出一行代码,但我们产出了一份**《核心事务码与高频错误黄金清单》**。它只有两页纸,却包含了37个最关键的事务码、每个事务码对应的3个最高频错误、以及它们之间精确的依赖链条。这份清单,就是我们整个预处理工程的“宪法”。
4.2 Day 2-3:Gemini API的“暴力”调优
有了黄金清单,第二天我们就进入了API调优的“暴力”阶段。我们没有追求一次完美的Prompt,而是采用了“网格搜索(Grid Search)”的思路,对Prompt的三个核心维度进行了穷举测试:
指令强度(Instruction Strength):测试了三种表述:
- A(温和):“请尽量准确地识别出…”
- B(中性):“请准确识别出…”
- C(强硬):“请严格按以下格式,只输出JSON,不得有任何额外内容。”
上下文粒度(Context Granularity):测试了三种输入方式:
- X(整文件):上传整个PPT文件。
- Y(单页):将PPT按页拆分,每次只上传一页。
- Z(聚焦):先用正则表达式从PPT中提取出所有含事务码的页面,只上传这些页面。
输出格式(Output Format):测试了JSON、YAML、以及纯文本表格。
我们用一个包含5个典型事务码的小样本(共20页PPT),进行了3x3x3=27次组合测试。评测指标只有一个:字段提取F1值(精确率与召回率的调和平均)。结果出乎意料:最强的组合是C+X+JSON。强硬的指令、整文件的上下文、以及严格的JSON格式,三者叠加,产生了最佳效果。这印证了我们的核心理念:在确定性任务中,控制力(Control)比灵活性(Flexibility)更重要。模型不需要“思考”,它只需要“执行”。
4.3 Day 4-5:Chunk模板的千锤百炼
第三天,我们开始构建chunk模板。最初的版本非常“学术化”,充满了“该事务码旨在实现…”、“其业务价值在于…”等冗余描述。上线前的第一次内部测试,一位测试员直接吐槽:“我只想知道下一步点哪里,不是来听你讲SAP哲学的。” 这句话让我们彻底推翻重来。
新的模板,遵循“三秒原则”:一个用户扫一眼,必须在三秒内找到他需要的三个信息:做什么(What)、在哪里做(Where)、怎么做(How)。最终定稿的模板如下(以VA01为例):
【VA01】创建销售订单 ▶ 做什么:为客户创建一份新的销售订单。 ▶ 在哪里做:SAP GUI中,输入事务码 /nVA01,回车。 ▶ 怎么做: ① 在“抬头数据”标签页,找到“采购订单号”字段(截图3-2,红框区域),输入格式为:PO-2024-XXXXX。 ② 在“行项目”标签页,找到“物料编号”字段(截图3-5,蓝框区域),输入已在MM01中创建的物料编号。 ③ 点击工具栏绿色对勾图标(截图3-2,左上角)保存。 ⚠️ 常见错误: • 错误1:采购订单号漏输前缀“PO-”,系统报错“输入格式不正确”。 • 错误2:物料编号在MM01中未维护,系统报错“物料XXX不存在”。 • 错误3:未切换到“行项目”标签页就点击保存,系统报错“无行项目数据”。 ✅ 成功标志:保存后,系统跳转至“凭证概览”,状态栏显示绿色“已保存”。这个模板,每一个符号都有其功能:“▶”表示核心指令,“⚠️”表示风险预警,“✅”表示成功验证。它不是写给人看的散文,而是写给“人脑”和“机器”共同阅读的操作说明书。
4.4 Day 6:知识库的“冷启动”与压力测试
第六天,我们完成了所有chunk的生成与校验,共计127个。我们将它们全部导入向量数据库(我们选用的是Google Vertex AI Vector Search,因其与Gemini的原生集成度最高)。紧接着,我们进行了史上最严苛的“冷启动”压力测试。
我们准备了100个真实问题,这些问题全部来自过去半年的IT Helpdesk工单,涵盖了从最基础的“VA01怎么进?”到最刁钻的“在VA01里,如果客户主数据里没有维护‘付款条件’,系统会默认填什么?”。我们关闭了所有RAG的“模糊匹配”和“相似度降级”开关,强制要求:只有当用户的提问,能100%精确匹配到某个chunk的标题(如“【VA01】”)或其核心字段(如“采购订单号”)时,才返回答案;否则,一律返回“未找到相关信息,请联系IT支持”。
结果令人振奋:100个问题中,98个被精准命中,2个因问题表述过于模糊(如“那个下单的界面”)而未命中。这98%的准确率,已经远超客户最初设定的90%目标。更重要的是,所有被命中的答案,其内容都与我们校验过的chunk完全一致,没有任何“幻觉”或“编造”。那一刻,我们真切地感受到,“基础”的力量,是如何将一个充满不确定性的AI项目,变成了一台精准运转的工业设备。
4.5 Day 7:上线、监控与“无聊”的胜利
第七天,我们上线了。没有盛大的发布会,没有炫酷的演示视频。我们只是给所有新员工发了一封邮件:“您的SAP上手助手已上线,现在就可以在Teams里@它提问了。” 上线后的第一周,我们设立了两个核心监控指标:
- 首次响应准确率(First-Response Accuracy):用户提出问题后,机器人给出的第一个答案是否正确。目标:≥95%。
- 零幻觉率(Zero-Hallucination Rate):机器人是否曾给出过任何未经chunk证实的、编造的信息。目标:100%。
一周后,数据出炉:首次响应准确率为96.3%,零幻觉率为100%。最让我们欣慰的,不是这个数字,而是用户反馈中反复出现的一个词:“确定”。一位用户写道:“以前问Helpdesk,他们说‘可能要这样’,现在问机器人,它说‘必须点这里’,我照做,就成功了。这种确定感,太珍贵了。”
这,就是“无聊”的胜利。它没有改变世界,但它让一百个新员工,在面对一个陌生系统时,少了一分焦虑,多了一分笃定。而这,恰恰是所有技术最本真的价值。
5. 常见问题与独家避坑指南:那些没写在文档里的血泪教训
5.1 问题排查速查表:当“基础”也出问题时
即使是最“基础”的方案,也会遇到意外。以下是我们在实操中总结的TOP 5问题及其排查路径,每一条都来自真实的“踩坑”现场:
| 问题现象 | 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|---|
| 用户提问“VA01怎么进?”,机器人返回“未找到” | 1. 用户提问中包含了空格或特殊字符(如“VA01 ?”) 2. chunk标题中“【VA01】”的方括号,在向量库中被当作特殊符号处理,影响了匹配 | 1. 检查日志,确认用户原始提问字符串 2. 在向量库中,用原始提问字符串进行一次“精确字符串搜索” | 1. 在预处理阶段,对所有chunk标题进行标准化清洗(移除所有非字母数字字符) 2. 在检索前,对用户提问进行同样清洗 |
| 机器人能答“VA01”,但答不出“创建销售订单” | 1. “创建销售订单”是功能描述,而非事务码,未被索引 2. 功能描述文本过长,超出了向量模型的最佳匹配长度 | 1. 检查该chunk的向量化日志,确认“功能”字段是否被成功嵌入 2. 用一个短查询词(如“销售订单”)测试该chunk的召回率 | 1. 将“功能”字段单独切分为一个短chunk(如“创建销售订单 → VA01”),并赋予更高权重 2. 在检索时,对“功能”字段使用BM25等传统关键词搜索作为补充 |
| 截图引用“截图3-2”在知识库中找不到对应图片 | 1. PPT文件在上传过程中被Google自动优化,导致页内截图编号错乱 2. 原始PPT中,同一张截图被多次复制粘贴,编号逻辑混乱 | 1. 下载Gemini处理后的文件副本,与原始文件逐页比对 2. 检查PPT的“幻灯片母版”,确认截图是否被插入到母版中 | 1. 在上传前,用PowerPoint的“另存为”功能,选择“PowerPoint 97-2003演示文稿(*.ppt)”格式,禁用所有自动优化 2. 手动为每张截图添加唯一、不可变的水印编号(如“IMG-VA01-001”) |
| “常见错误”部分被用户忽略,用户仍重复犯错 | 1. “常见错误”在chunk中位置靠后,用户只看了前面的“怎么做” 2. 错误描述过于技术化,用户看不懂(如“权限对象缺失”) | 1. 分析用户会话日志,统计用户在得到答案后,是否继续追问“为什么报错?” 2. 让一位完全不懂SAP的行政人员阅读“常见错误”部分 | 1. 将“常见错误”模块前置,并用更醒目的符号(如“❗”)标记 2. 将所有技术术语,替换为用户界面可见的文字(如“权限对象缺失” → “系统提示‘无权访问’”) |
| 知识库更新后,旧答案依然被召回 | 1. 向量数据库未启用“增量更新”,新chunk被追加,旧chunk未被删除 2. 缓存层(如Redis)未及时刷新,返回了旧缓存 | 1. 检查向量数据库的更新日志,确认旧chunk的ID是否已被标记为“deleted” 2. 在应用层,强制设置一个短缓存过期时间(如30秒) | 1. 在更新脚本中,加入“先删除所有旧chunk,再写入新chunk”的原子操作 2. 在检索接口中,增加一个“force_refresh”参数,供紧急情况使用 |
5.2 独家避坑心得:那些只在深夜调试时才懂的道理
“黄金标准”不是终点,而是起点:客户提供的“黄金标准”教案,是我们工作的起点,但绝不能成为终点。我们发现,讲师教案里写的“学生常错点”,和真实Helpdesk工单里记录的“用户实际报错点”,有高达30%的差异。前者是教学法上的难点,后者是真实工作流中的断点。因此,我们最终的校验清单,是两者加权融合的结果:70%来自工单数据,30%来自教案。
截图的“像素级”标注,比模型选择重要十倍:我们曾花费两天时间,只为优化一个截图的标注方式。最初,我们只写“截图3-2”,后来改为“截图3-2:VA01抬头数据标签页,红框区域”。最终,我们发现,最有效的标注是“截图3-2:VA01抬头数据标签页,红框区域(坐标:X=120, Y=340, W=200, H=40)”。这个像素坐标,让前端开发可以直接在用户界面上,用一个浮动提示框,精准地指向那个按钮。这种“所见即所得”的体验,是任何语言描述都无法替代的。
“零幻觉”的代价,是主动放弃一部分“聪明”:为了100%的零幻觉,我们主动禁用了所有“推测性回答”功能。这意味着,当用户问“VA01和VF01有什么区别?”,机器人会老实回答“未找到相关信息”。这看起来很“蠢”,但它保护了用户。因为一旦我们允许模型对“区别”进行推测,哪怕只有1%的错误率,也可能误导用户做出错误的业务决策。在操作型任务中,“我不知道”永远比“我猜错了”要好。
上线不是结束,而是校验的开始:我们上线后,设立了一个“用户反馈-自动归档”机制。用户在机器人对话框里,点击一个“这个答案有帮助吗?”的按钮,其结果会自动归档到一个共享表格。第一周,我们收到了23条“无帮助”反馈。我们没有把它当成bug,而是当成23个全新的、来自真实战场的需求。其中17条,直接转化为了新的chunk;另外6条,则揭示了我们预处理时忽略的、更底层的业务规则。这证明,最伟大的预处理,永远发生在生产环境里。
6. 经验总结:在AI的喧嚣中,守护“确定性”的微光
这个项目结束了,但它的回响,一直在我心里。它没有发明任何新算法,没有训练一个新模型,甚至没有写出一行惊艳的代码。它所做的,只是把一件最古老、最基础的事,做到了极致:**理解用户