LLM应用实践(1)- 物流状态判断
原文:LLM应用实践(1)- 物流状态判断
稳定输出 JSON 字符串
为了能够更好的贴合实际的业务场景的应用,我们通常期望大模型返回的数据是 JSON 格式的,这样能够降低对大模型返回内容处理的复杂度,如果返回了带 JSON 格式数据的内容,那么就可以直接通过正则匹配的方式,提取内容中的 JSON 数据,直接使用。
Bad Case:
我的问题:判断下发货物流状态?。 数据:{"status":"已签收","desc:"您的快件已签收,签收人: 前台。如有疑问请联系:1111111111,投诉电话: 025-88888888。感谢使用圆通速递,期待再次为您服务!","time":"2022-10-12 12:22:22"} 我需要你通过我的问题以及给你的数据,做出总结。
1.模型生成了一段总结性的文本,可以直接拿来用,但是一般情况下不会这样使用,我们更希望它能够返回 JSON 的格式。
2.在 Prompt 加上 “以 JSON 格式返回” 的描述可以输出 JSON 格式的文本回复,但是 JSON 格式中的 key 有太多不确定性,我们需要加上期望返回 JSON 格式的举例。
Good Case:
我的问题:判断下发货物流状态?。 数据:{"status":"已签收","desc:"您的快件已签收,签收人: 前台。如有疑问请联系:1111111111,投诉电话: 025-88888888。感谢使用圆通速递,期待再次为您服务!","time":"2022-10-12 12:22:22"}。 我需要你通过我的问题以及给你的数据,做出总结,以 JSON 格式返回:{"result":"总结的内容"}。
注意:
大模型的回复有很大的不确定性,即便 10 次的回复中,有 9 次都是返回期望的数据格式,但是也会有可能其中 1 次返回【描述文字 + JSON 格式数据】的情况,或者 JSON 格式不符合规范(一对大括号缺少一个,value中的文本带有双引号,key 缺少双引号其中的一个,逗号是中文类型的等 )。
不要在业务代码中直接使用大模型的返回结果,认为其返回的是 JSON 格式的文本数据然后对其直接 Parse。
我们可以通过正则表达式对回复的文本先提取 JSON 格式的数据,并且需要增加容错处理的逻辑,然后再 Parse 得到我们想要的 JSON 数据后再使用。
附:提取文本中 JSON 格式数据的正则表达式
const llmResponse = 'xxxxxxxx'; // 大模型的返回文本
const JSONList = llmResponse.match(/{([^}]*)}/); // JSONList : ["xxxx","xxxxxx"]
提升回复准确度
在大多数真实的业务场景下,我们期望大模型不仅仅是帮助总结内容,给出总结只能节省我们对信息提取和分析的时间,实际上我们更希望大模型能够解决实际的问题,比如在给定的选项里做出合适的选择。
假设业务场景:通过订单的物流轨迹的数据,从以下选项中做出选择?
a. 买家签收 b. 拒签退回 c. 无需物流 d. 物流途中滞留
如何编写 Prompt 才能提高大模型回复的准确度呢?
1 减少数据干扰项
在拿到物流轨迹的数据后,一般人都会想把所有的 JSON 格式的轨迹数据交给大模型来分析。复杂的 JSON 格式的数据以及大量的数据会给大模型增加很多判断的工作量以及很多干扰项,不利于大模型做出准确的判断。
在判断物流轨迹的这个场景下,通常轨迹数据是包含从开始到结束所有的数据,但是一般情况下最新的一条数据是可以决定整个轨迹的判断结果。所以我们可以只拿出最新的一条数据拼接在 Prompt 中让大模型去识别,这样识别的准确率一定比拼接整个轨迹数据在 Prompt 中去识别的要高。
2 增加对选项的描述
在拿到最新的一条轨迹数据后,数据中关于这一条轨迹的描述文字内容非常不固定,是物流公司提供的,并且五花八门。如何让大模型能够分析并且准确地做出选择,就需要对每个选项增加一些描述性的文字。
例如:
买家签收 :当物流状态是已签收,物流描述中有关键字'派送成功'、'完成取件'、'已签收'、'代理点',或签收人是'本人'、'驿站'、'代收点'、'门卫'、'前台'、'桌子'。
拒签退回:当物流状态是已签收/异常,物流描述有拒绝、拒签、已退回、返回的文字,签收人有拒绝、拒签、已退回、已返回、商家的文字 分析方法:先判断物流状态,再判断物流描述。
无需物流 :如果是虚拟类的商品,那么就选择无需物流的这个选项。
物流途中滞留:如果物流时间距离现在已经超过 2 天,就选择这个选项。
让大模型光凭选项的文本内容去做出选择,准确率也不会高。给每个选项加上描述以及通过关键字判断的方法,会大大提高模型识别的准确率,做出更符合实际情况的选择。
3 合理的流程和 few shot(少量示例)
大模型像人一样,解决问题需要分几步走,当我们把解题的步骤写在 Prompt 中,能够帮助模型更好的理解问题和解决问题。
给出选项 => 给出数据示例 => 解释分析过程 => 给出回复示例 => 给出真实数据 => 发起提问
给出示例的目的是让大模型在示例中知道提问者想要什么,给出提问者期望的回复,避免大模型胡编乱造,给出没有价值的回复内容。
4 取消时间对比
大模型没有办法识别出当前这一次的提问的时间,所以不要在 Prompt 中,使用 “现在”、“当前”、“此刻” 等文字来期望大模型能够对比两个时间之间的差别,没有任何作用。
5 适当利用规则判断
无需物流和物流途中停滞这两个选项没有办法直接通过大模型分析得出结果,那我们可以针对选项的描述,加一些业务逻辑的代码来提高识别的准确度。
例如:
当拿到商品的数据并且判断出商品属性是虚拟类商品的话,可以不调用大模型服务直接返回无需物流这个选项。物流途中滞留也同样。
6 结构化 => 语义化
在一些特殊的业务场景下比如:判断卖家是否承诺赠品?
这种场景一般是拿到买家和卖家的消息数据组装在 Prompt 中给大模型进行分析。
基于第 1 条规则去除干扰项,那么就需要过滤出只有卖家的消息数据给到大模型进行分析。但是给 JSON 格式的结构化的数据没有任何意义,因为结构化的数据中包含 ”时间“、”角色类型“、”消息 ID“ 等数据。
在这个场景下这些数据对于模型的分析是没有任何帮助的,所以我们只需要提取卖家的 “消息内容” 进行文本拼接后组装在 Prompt 中丢给大模型,大模型只需要判断数据中能否提取赠品相关的关键字来给出回复即可。
const messages = [
{"role":"卖家",content:"xxxxxx","time":"2023-12-8 10:10:10","id":"message1"},
{"role":"卖家",content:"xxxxxx1","time":"2023-12-8 10:10:10","id":"message2"},
{"role":"卖家",content:"xxxxxx2","time":"2023-12-8 10:10:10","id":"message3"}
]
// 实际上拼接在 Prompt 中的数据
const messageContent = messages.map(item => item.content).join(",");
7 减少双引号的使用
在 Prompt 中除了 JSON 格式的文本外,尽量减少双引号的使用。
因为如果你期望大模型给 JSON 格式的回复,回复中的 value 字段的值文本中可能会包含双引号,这样在对回复的文本内容提取 JSON 数据再 Parse 的话,会直接报错,降低大模型服务调用的成功率。
最终在该场景下的 Prompt 设计成:
你是一个物流轨迹分析助手。
我会给你一段关于物流轨迹的数据,格式为{"time" : "时间", "status" : "物流状态","desc":"物流描述"}。通过辨别选项的区别,从我给你的几个选项中,选出 1 个选项,并且给出理由,将用JSON对象回复,格式为{"reason" : "理由", "option" : "选项" }。
下面是我给你的 2 个选项:
买家签收:当物流状态是已签收,物流描述中有关键字'派送成功'、'完成取件'、'已签收'、'代理点',或签收人是'本人'、'驿站'、'代收点'、'门卫'、'前台'、'桌子'
拒签:当物流状态是已签收/异常,物流描述有拒绝、拒签、已退回、返回的文字,签收人有拒绝、拒签、已退回、已返回、商家的文字
分析方法:先判断物流状态,再判断物流描述。
举例:物流轨迹的数据是{"time":"2023/10/20 15:42:57","status":"已签收","desc":"您的快件已签收,签收人: 前台。如有疑问请联系: 11111112222,投诉电话: 025-88888888。感谢使用圆通速递,期待再次为您服务!"}。
分析过程:
1.物流状态是已签收,符合【买家地址签收】这个选项的描述。
2.物流描述签收人是前台,符合【买家地址签收】这个选项的描述。
回复:{"reason" : "物流状态已签收,物流描述包含签收人是前台的关键字,符合【买家地址签收】选项的描述", "option" : "买家地址签收" }。
如果物流轨迹的数据是{"time":"2023/10/20 05:19:42","status":"已签收","desc":"您的快件已签收,签收人是【门卫】"}。
不需要给我分析过程,你的回复:
大模型的返回结果和预期的一致,返回的文本内容是不带多余文字描述的纯 JSON 文本,并且返回的 key 是我们期望的格式,给出 option 的值和提供的选项文本是一致的。
降低响应时间
众所周知,大模型的实际应用场景,大多是前端调用后端提供的接口,然后后端调用大模型的服务,后端根据服务返回的结果加以处理,再返回给前端。
由图可知整个调用链路的时长决定因素在于大模型服务的响应时间。
大模型的响应可以分为流式和非流式,一般业务场景中非流式的情况比较多。
在非流式的情况下,大模型会等输出结果的文本结束后,再一次性返回文本内容。所以文本内容的长度,决定了大模型调用的响应时长,文本越少,响应速度越快。所以我们可以通过编写 Prompt 要求大模型返回精简后的结果。
示例:
我的问题:判断下发货物流状态?。
数据:{"status":"已签收","desc:"您的快件已签收,签收人: 前台。如有疑问请联系:1111111111,投诉电话: 025-88888888。感谢使用圆通速递,期待再次为您服务!","time":"2022-10-12 12:22:22"}。
我需要你通过我的问题以及给你的数据,做出总结,以 JSON 格式返回:{"result":"总结的内容"}。总结的内容不超过 10 个字
总结
在实际业务场景应用中,如果想直接用未经过微调的基础模型进行落地,那么一定是 ”规则判断 + 合理的 Prompt“ 来实现的,并且不同的场景都需要定制不同的 Prompt 的模板。
如果想只通过不停地调试修改 Prompt ,用特别通用的 Prompt 模板的方式来实现落地,那么结果的准确率一定没法达到期望值。就像目前的算法模型,一旦训练成功后,只能用在单个的场景下,换另一个场景识别的准确率就会大打折扣,没有一个通用的算法模型能解决所有的问题。