上一篇讲的是 AI 怎么解决工单提交之后的事(分派给谁);这一篇讲我们怎么把 AI 再往前挪一步——让用户在写工单的过程中就把内容、类别、优先级都填对填全,避免分派之后来回追问。
一、为什么做这件事
每天我们都会遇到这样的工单:
- 描述只写一行——“系统报错”,处理人不得不一来一回去问“什么模块、什么单号、什么报错”。
- 选错类别——本来是“财务分析”问题,用户选成了“账单支付”。分派 AI 收到错误的类别,自然分给了错误的人。
- 紧急程度全凭感觉——所有提交人都觉得自己的事最紧急,于是“紧急”这个标签也就贬值了。
- 写完点完提交才想起来漏传截图或附件。
这些问题的本质是:工单质量问题没在源头处理。 我们越靠后干预,代价越大——处理人来回追问、分派被迫返工、用户被打断好几次。
如果 AI 能在用户写描述的过程中就把这些事处理掉,整个链路就顺了。
二、整体设计
我们给这套功能定了一个明确的定位:让 AI 帮忙,而不是替用户做主。
具体落到交互上,提交工单页变成这样:
graph TD
A[用户开始写描述] --> B{描述够长 / 用户停手?}
B -- 是 --> C[后台调用 AI]
C --> D[返回: 类别 + 优先级 + 完整性 + 改写]
D --> E[类别/优先级字段为空 → 自动采纳, 标 ✨]
D --> F{完整性达标?}
F -- 是 --> G[显示提交按钮]
F -- 否 --> H[暂时不显示提交按钮 + 提示补充]
E --> I[用户可一键改 / 直接覆盖]
几个关键的设计选择:
1. 字段渐进显示。 用户打开页面时,看到的只是“工单描述”一个输入框。类别和紧急程度这两个下拉框默认是隐藏的——等 AI 跑完一轮再出现。这避免了用户在 AI 给出建议之前就先手动填了一个错的,然后又被建议绕回来改一次。
2. 自动采纳但留标记。 如果用户从来没填过类别,AI 一旦有建议就自动采纳,下拉框上加一个 ✨ 图标提示“这是 AI 填的”。用户改动后标记就清掉,回到“我的选择”。这样做的好处是大多数人不用动手,少数明确知道自己在做什么的人,可以直接修改。
3. 完整性挡的是“提交按钮”,不是表单。 当 AI 判定描述不够完整时,我们不弹任何错误,只是暂时不显示提交按钮,并在下方给一个柔和的黄色提示框说明缺什么。用户继续补充描述会自动重新分析,分够了按钮自然出现。比 disabled + 红色报错友好得多。
4. AI 不可用 = 传统模式。 后端有个 /tickets/draft/status 接口,前端启动时探一下。如果 AI 场景没启用、没绑定模型、或者干脆挂了,前端立刻把所有字段显示出来,提交按钮也直接放出来,让用户像以前那样手动填。AI 永远不是用户能否提交工单的卡点。
三、抽象“AI 场景”
上一次做智能分派时,AI 配置散落在好几个地方——模型在一处、提示词在一处、阈值在自动化规则里。这次做智能填单,我们直接把这块抽象出来了,引入了一个新概念:LLM 场景(Scenario)。
每个场景就是一个用途,结构很简单:
| 字段 | 含义 |
|---|---|
code | 场景标识符,比如 ticket_analysis、draft_assistant |
llm_model_id | 绑定哪个模型 |
llm_prompt_id | 绑定哪个提示词 |
config (JSON) | 场景独有的参数:阈值、防抖时长、子能力开关…… |
is_active | 一键禁用 |
后台给管理员一个表格,每行就是一个场景。打开能改模型、改提示词关联、改 JSON 配置、一键禁用。改完不用发版,下一次请求就生效。
这次智能填单就是新加的一个场景(draft_assistant),它的 config 长这样:
{
"trigger_min_chars": 10,
"trigger_debounce_ms": 1500,
"min_confidence_to_show": 0.6,
"enable_completeness": true,
"enable_rewrite": false,
"min_completeness_to_submit": 0.6
}
要不要启用“完整性检查”、要不要启用“AI 改写描述”、防抖多长、阈值多少——全是管理员后台一键切换。研发把能力做出来,业务部门按需开关,不需要再问研发要发版窗口。
我们把“场景”这一层做出来之后,未来再加新的 AI 能力(比如“自动生成回复”“故障归因”),就只是在表格里加一行的事,整套 LLM 调用、提示词渲染、配置管理的管道都能复用。
四、提示词的反复拉锯:完整性怎么算
整个项目最有意思(也最折腾)的部分,是“完整性怎么判定”。
我们一开始想得很简单:在提示词里写一句“请评估描述完整性,给出 0-1 的分数和缺失要素”,剩下交给 AI。结果:
V1:太严。 AI 默认按“理想工单模板”打分——必须有背景、复现步骤、期望结果、截图、影响范围……结果几乎所有真实工单都被判到 0.6 以下,没人能提交。举个例子,用户写“XXX 单号 改价 5680”,处理人一看就懂,AI 给了 0.4,理由是“缺少审批依据、未提供截图、未说明完成时间”。
V2:太松。 我们把规则改成“三要素之一明确即可 ≥0.8,不要因为缺少附加信息扣分到 0.7 以下”。这次 LLM 反而走向了另一个极端——用户只写了“2026060517101257954 xxx有限公司”(只有单号和客户名,完全没说要做什么),居然也给了 0.6。原因是“提供了具体单号和客户,对象明确”。
V3:写规则,不光写标准。 我们最终把提示词改成了带评分细则的版本:
判定标准:处理人能否据此直接开始工作,而非工单格式是否完美。
三要素:
① 做什么/什么问题(动作或故障现象,必须有)
② 涉及对象(系统/单号/客户/模块)
③ 期望结果(可由①隐含)
评分规则(严格执行):
- ①缺失或只列了对象/单号而没说"要做什么/出了什么问题" → score ≤ 0.4
- ①明确但②缺失 → score 0.5-0.6
- ①②都明确 → score ≥ 0.8(即使没截图、没审批依据也不要再扣分)
严禁仅凭"提供了对象/单号"就给 ≥0.6。
这一版终于稳定了。
经验: 让 LLM 做主观判断,不能只描述"我想要什么",必须把"按什么规则打分"写死,最好附上反例。 LLM 没有你的业务直觉,它有的只是预训练时见过的“工单应该长什么样”——而那个样本里全是大企业的规范模板,跟我们小团队的实际需求八竿子打不着。
附带教训:阈值是兜底,提示词的判定规则才是核心。 我们前后调过两次阈值,0.7 → 0.6 → 0.6,每次都是被错误的评分逼着调,结果根本没用。等把规则写清楚了,阈值就再没动过。
五、踩过的坑
这次又踩了一些不起眼但很关键的坑。
5.1 富文本不要 strip_tags
工单描述用的是富文本编辑器,输出是 HTML。我们一开始按习惯先 strip_tags 再喂给 LLM,结果完整性判定经常翻车——用户用列表写了三条复现步骤,AI 看到的是粘在一起的纯文本,判定“没有结构”。
后来直接把 HTML 原文喂进去,现代 LLM 完全能读懂这种结构化文本,效果立刻好转。
5.2 附件信息也要喂给 AI
最初的提示词只传了描述。结果用户在描述里写“详见附件截图”,AI 因为不知道有附件,判定“信息缺失,无法判断”。
解决方案:把附件的元数据(文件名、MIME、大小)也注入提示词,明确告诉 AI“你看不到文件内容,但可以根据文件名推测”。
## 用户已上传的附件
- error-screenshot.png (image/png, 245.3 KB)
- order-export.xlsx (application/vnd...sheet, 12 KB)
5.3 防抖 + 限频
前端用 1.5 秒的 debounce,只有用户“停手”时才发请求。后端再加一道 RateLimiter:每用户每分钟 10 次、每秒最多 1 次。两层兜底,不怕前端被改坏。
5.4 重复请求要去重
用户改了一次描述触发了 AI,AI 还没返回,用户又敲了一个字。第二次请求如果带的描述跟上次完全一样,前端会直接跳过——避免无意义的重复扣费。
六、成本与效果
工程投入
- 开发时间:1 人 × 1 天(依然全程 AI 辅助开发)
- 复用了上一次智能分派的全部基础设施:LLM Service、Prompt 渲染器、模型/提示词管理后台
- 新增主要是“场景”这一层抽象 + 智能填单的专属交互组件
运行成本
每次描述变更触发一次 AI 调用,描述通常只有几百字符,单次成本比智能分派的“分析完整工单”还便宜。配合防抖和限频,实际调用量并不大。
业务效果
- 工单提交后被处理人退回让补充信息的情况大幅减少
- 类别准确率上去了——下游智能分派的准确率也间接被拉高
本系列后续会继续记录我们在 AI 落地过程中的心得,欢迎关注。如果你也在企业内部跑类似的项目,欢迎交流。如果本文对你有帮助,欢迎分享,让更多需要的人看到。😊