• 基于LLM+场景识别+词槽实体抽取实现多轮问答


    前言

    随着人工智能技术的不断进步,大语言模型(LLM)已成为技术前沿的热点。它们不仅能够理解和生成文本,还能在多种应用场景中实现复杂的交互。本文将深入探讨一段结合了大语言模型能力、意图识别和词槽实体抽取的Python代码,这段代码展示了如何实现智能的多轮问答能力,为用户提供更加丰富和个性化的交互体验。

    正文

    完整代码

    这段代码的核心在于集成了最新的大语言模型(LLM)能力,结合了意图识别和词槽实体抽取的技术,以实现智能的多轮问答。

    import json
    import re
    import requests
    from datetime import datetime
    
    
    
    url = 'https://api.openai.com/v1/chat/completions'
    
    # 替换为您自己的chatGPT API密钥
    api_key = 'sk-xxxxxx'
    
    # 调试日志
    debug = False
    
    def check_values_not_empty(json_data):
        """
        检查是否所有元素value都不为空
        """
        # 遍历JSON数据中的每个元素
        for item in json_data:
            # 检查value字段是否为空字符串
            if item.get('value') == '':
                return False  # 如果发现空字符串,返回False
        return True  # 如果所有value字段都非空,返回True
    
    
    def format_title_value_for_logging(json_data):
        """
        抽取参数名称和value值
        """
        log_strings = []
        for item in json_data:
            title = item.get('title', 'Unknown Title')  # 获取title,如果不存在则使用'Unknown Title'
            value = item.get('value', 'N/A')  # 获取value,如果不存在则使用'N/A'
            log_string = f"Title: {title}, Value: {value}"
            log_strings.append(log_string)
        return '\n'.join(log_strings)
    
    
    def extract_json_from_string(input_string):
        """
        JSON抽取函数
        返回包含JSON对象的列表
        """
        try:
            # 正则表达式假设JSON对象由花括号括起来
            matches = re.findall(r'\{.*?\}', input_string, re.DOTALL)
    
            # 验证找到的每个匹配项是否为有效的JSON
            valid_jsons = []
            for match in matches:
                try:
                    json_obj = json.loads(match)
                    valid_jsons.append(json_obj)
                except json.JSONDecodeError:
                    continue  # 如果不是有效的JSON,跳过该匹配项
    
            return valid_jsons
        except Exception as e:
            print(f"Error occurred: {e}")
            return []
    
    
    def send_message(message, user_input):
        """
        请求LLM函数
        """
        print('--------------------------------------------------------------------')
        if debug:
            print('用户输入:', message)
        else:
            print('用户输入:', user_input)
        print('----------------------------------')
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        }
    
        data = {
            "model": "gpt-3.5-turbo",
            "messages": [
                {"role": "system", "content": "You are a helpful assistant."},
                {"role": "user", "content": f"{message}"}
            ]
        }
        response = requests.post(url, headers=headers, json=data, verify=False)
        if response.status_code == 200:
            answer = response.json()["choices"][0]["message"]['content']
            print('LLM输出:', answer)
            print('--------------------------------------------------------------------')
            return answer
        else:
            print(f"Error: {response.status_code}")
            return None
    
    
    # 问天气
    # 参数:
    # 1. 时间time(口语:今天明天、日期:10号、范围:未来一周)
    # 2. 地点location(国家省市区)
    # todo "transform": "时间格式转换工具?是自己做一个还是用大模型。建议自己开发一个",
    dict_weather = [
        {
            "title": "时间",
            "desc": "口语表述:昨天、今天、明天;具体日期:10号、1月1号、2月3日;范围:未来一周、最近十四天",
            "transform": "时间统一转换格式,如果是时间点:yyyy-MM-dd;如果是时间段:yyyy-MM-dd#yyyy-MM-dd",
            "util": "",
            "value": "",
            "required": True
        },
        {
            "title": "地点",
            "desc": "口语表述:建邺区、南京、河北省、江苏南通、上海虹桥、北京朝阳区",
            "transform": "地点统一转换格式为省市区(如果有区)或省市,如南京市建邺区、南京市,如果提取不到市只有省份则不填写value",
            "util": "",
            "value": "",
            "required": True
        }
    ]
    
    prompt_weather_info_update = """
    JSON每个元素代表一个参数信息,我先给你提供一些基本介绍:
    '''
    title字段是参数名称,如果需要让用户填写该参数时你应该告诉用户你需要的参数名称
    desc字段是参数描述,可以做为title字段的补充,更好的引导用户补充参数
    transform字段是填写value字段值的格式要求说明
    required字段为true表示该元素的value是必填参数,如果value为空则必须让用户补充该参数信息,如果required字段为false表示该参数不是必须补充的字段
    '''
    
    需求:
    #01 根据用户输入信息提取有用的信息更新到JSON中的value字段并返回更新后的JSON
    #02 仅更新value字段,其他字段都原样返回
    #03 如果没有可更新的value则原样返回
    #04 当前时间为{}
    
    参考示例:
    '''
    JSON: [
        {{
            "title": "时间",
            "desc": "口语表述:昨天、今天、明天;具体日期:10号、1月1号、2月3日;范围:未来一周、最近十四天",
            "transform": "时间统一转换格式,如果是时间点:yyyy-MM-dd;如果是时间段:yyyy-MM-dd#yyyy-MM-dd",
            "util": "",
            "value": "",
            "required": true
        }},
        {{
            "title": "地点",
            "desc": "口语表述:建邺区、南京、河北省、江苏南通、上海虹桥、北京朝阳区",
            "transform": "地点统一转换格式为省市区(如果有区)或省市,如南京市建邺区、南京市,如果提取不到市只有省份则不填写value",
            "util": "",
            "value": "",
            "required": true
        }}
    ]
    问:今天南京天气怎么样?
    答:[
        {{
            "title": "时间",
            "desc": "口语表述:昨天、今天、明天;具体日期:10号、1月1号、2月3日;范围:未来一周、最近十四天",
            "transform": "时间统一转换格式,如果是时间点:yyyy-MM-dd;如果是时间段:yyyy-MM-dd#yyyy-MM-dd",
            "util": "",
            "value": "{}",
            "required": true
        }},
        {{
            "title": "地点",
            "desc": "口语表述:建邺区、南京、河北省、江苏南通、上海虹桥、北京朝阳区",
            "transform": "地点统一转换格式为省市区(如果有区)或省市,如南京市建邺区、南京市,如果提取不到市只有省份则不填写value",
            "util": "",
            "value": "南京",
            "required": true
        }}
    ]
    '''
    
    JSON:{}
    问:{}
    答:
    """
    
    prompt_weather_query_user = """
    JSON每个元素代表一个参数信息,我先给你提供一些基本介绍:
    '''
    title字段是参数名称,如果需要让用户填写该参数时你应该告诉用户你需要的参数名称
    desc字段是参数描述,可以做为title字段的补充,更好的引导用户补充参数
    required字段为true表示该元素的value是必填参数,如果value为空则必须让用户补充该参数信息,如果required字段为false表示该参数不是必须补充的字段
    '''
    
    需求:
    #01 如果有多个未填写value的参数则可以一起向用户提问
    #02 value已经填写的参数不用再次提问
    
    参考示例:
    '''
    问:[
        {{
            "title": "时间",
            "desc": "口语表述:昨天、今天、明天;具体日期:10号、1月1号、2月3日;范围:未来一周、最近十四天",
            "transform": "时间统一转换格式,如果是时间点:yyyy-MM-dd;如果是时间段:yyyy-MM-dd#yyyy-MM-dd",
            "util": "",
            "value": "2022-01-01",
            "required": true
        }},
        {{
            "title": "地点",
            "desc": "口语表述:建邺区、南京、河北省、江苏南通、上海虹桥、北京朝阳区",
            "transform": "地点统一转换格式为省市区(如果有区)或省市,如南京市建邺区、南京市,如果提取不到市只有省份则不填写value",
            "util": "",
            "value": "",
            "required": true
        }}
    ]
    答:请问你想查询天气的地点是什么?
    '''
    
    问:{}
    答:
    """
    
    # 公积金咨询
    # 参数:
    # 1. 事件(买房、租房、退休)
    # 2. 购买房屋类型(买房事件时需要 经济适用房、新房、二手房)
    dict_consult = {
        "event": "",
        "purchase_type": ""
    }
    
    prompt_global_purpose = """
    有下面多种场景,需要你根据用户输入进行判断
    1. 问天气
    2. 公积金咨询
    3. 其他场景
    
    参考示例:
    '''
    问:今天天气如何
    答:问天气
    '''
    
    问:{}
    答:
    """
    
    global_purpose = ''
    
    
    def multi_question(user_input):
        global global_purpose
        global dict_weather
        current_purpose = send_message(prompt_global_purpose.format(user_input), user_input)
        if current_purpose != '其他场景':
            global_purpose = current_purpose
        if global_purpose == '问天气':
            # 先检查本次用户输入是否有信息补充,保存补充后的结果   编写程序进行字符串value值diff对比,判断是否有更新
            current_time = datetime.now().strftime("%Y-%m-%d")
            new_info_json_raw = send_message(prompt_weather_info_update.format(current_time, current_time, json.dumps(dict_weather, ensure_ascii=False), user_input), user_input)
            dict_weather = extract_json_from_string(new_info_json_raw)
            # 判断参数是否已经全部补全
            if check_values_not_empty(dict_weather):
                print('问天气 ------ 参数已完整,详细参数如下')
                print(format_title_value_for_logging(dict_weather))
                print('正在请求天气查询API,请稍后……')
            else:
                str = json.dumps(dict_weather, ensure_ascii=False)
                send_message(prompt_weather_query_user.format(str), user_input)
        elif global_purpose == '公积金咨询':
            pass
        else:
            pass
        pass
    
    
    def user_input():
        while True:
            question = input("请输入您的问题:")
            multi_question(question)
    
    # test
    # multi_question("明天天气怎么样呢")
    # multi_question("苏州天气怎么样呢")
    # multi_question("苏州明天天气怎么样呢")
    
    user_input()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    代码解析

    整合大语言模型(LLM):代码通过与一个语言模型API的交互,利用了大语言模型的强大文本生成和理解能力。这使得脚本能够处理复杂的用户查询,并生成合理的响应。

    意图识别:通过分析用户的输入,脚本可以识别用户的意图(例如查询天气或获取公积金咨询),这是通过向LLM发送特定的提示(prompt)实现的。

    词槽实体抽取:代码能够从用户输入中提取关键信息(如时间和地点),并将这些信息填充到预定义的JSON结构中。这是通过正则表达式和JSON操作实现的。

    多轮交互:脚本支持多轮交互,能够根据用户输入的不同,动态地提问和响应,为用户提供连贯且自然的对话体验。

    代码的实用性

    这个脚本不仅展示了如何在Python中处理复杂的数据结构和执行HTTP请求,还展示了大语言模型在实际应用中的巨大潜力。它为开发者提供了一个实用的框架,用于构建可以理解和响应人类语言的智能应用程序。LLM+场景识别+词槽实体抽取,实现人机交互多轮会话,遥遥领先~

    结尾

    我们可以看到大语言模型在理解和生成自然语言方面的巨大潜力。结合意图识别和词槽实体抽取,它能够实现复杂且自然的多轮对话。这种技术的应用范围非常广泛,从简单的信息查询到复杂的交互式任务都能得到有效的支持。

    希望这篇文章能够启发你探索大语言模型和智能问答系统的更多可能性。如果你觉得这篇文章有用,别忘了点赞和收藏!作者gallonyin,持续关注AI自动化。

  • 相关阅读:
    “数智+绿色”驱动,宏工科技助力线缆线材稳定高品质生产
    训练ChatGPT提示词,实现Excel函数操作
    朋友圈一键转发(可修改文案),无需多个账号复制粘贴
    浅析ArkTS的起源和演进
    【Android】点击按钮播放音乐,再次点击停止播放
    如何计算掩膜图中多个封闭图形的面积
    【计算机考研】【英语一】必备词组
    七、安装Centos7+8系统+超级优化
    java项目接口重复提交解决方案
    T1080 余数相同问题(信息学一本通C++)
  • 原文地址:https://blog.csdn.net/u012960155/article/details/134496798