本系列是基于 基于星火大模型的群聊对话分角色要素提取挑战赛
入门教程
Step1:下载相关库
!pip install --upgrade -q spark_ai_python
Step2:配置导入
from sparkai.llm.llm import ChatSparkLLM, ChunkPrintHandler
from sparkai.core.messages import ChatMessage
import json
#星火认知大模型Spark3.5 Max的URL值,其他版本大模型URL值请前往文档(https://www.xfyun.cn/doc/spark/Web.html)查看
SPARKAI_URL = 'wss://spark-api.xf-yun.com/v3.5/chat'
#星火认知大模型调用秘钥信息,请前往讯飞开放平台控制台(https://console.xfyun.cn/services/bm35)查看
SPARKAI_APP_ID = 'eeec9680'
SPARKAI_API_SECRET = 'NTY2ZTBiZmEzNTY2NDRjYTljZGZjMDE4'
SPARKAI_API_KEY = '3590ab03022c086989a4b3b2f7394070'
# APPID
#星火认知大模型Spark3.5 Max的domain值,其他版本大模型domain值请前往文档(https://www.xfyun.cn/doc/spark/Web.html)查看
SPARKAI_DOMAIN = 'generalv3.5'
apikey选择大赛专属api,额度多多。
Step3:模型测试
def get_completions(text):
messages = [ChatMessage(
role="user",
content=text
)] # 表示用户输入的消息
spark = ChatSparkLLM(
spark_api_url=SPARKAI_URL,
spark_app_id=SPARKAI_APP_ID,
spark_api_key=SPARKAI_API_KEY,
spark_api_secret=SPARKAI_API_SECRET,
spark_llm_domain=SPARKAI_DOMAIN,
streaming=False,
)
handler = ChunkPrintHandler()
a = spark.generate([messages], callbacks=[handler]) # 用于处理从 Spark AI API 接收到的数据
return a.generations[0][0].text
# 测试模型配置是否正确
text = "你好"
get_completions(text)
Step4:数据读取
def read_json(json_file_path):
"""读取json文件"""
with open(json_file_path, 'r') as f:
data = json.load(f)
return data
def write_json(json_file_path, data):
"""写入json文件"""
with open(json_file_path, 'w') as f:
json.dump(data, f, ensure_ascii=False, indent=4) # json 模块中的 dump() 函数将 data 对象序列化为 JSON 格式并写入文件 f。ensure_ascii=False 表示允许在 JSON 输出中使用非 ASCII 字符,indent=4 表示使用 4 个空格进行缩进以提高可读性。
# 读取数据
train_data = read_json("dataset/train.json")
test_data = read_json("dataset/test_data.json")
# 查看对话数据
print(train_data[100]['chat_text'])
可以看到数据是像平时的对话窗口的聊天记录,就是从聊天记录中提取必要信息
Step5:Prompt设计
# prompt 设计
PROMPT_EXTRACT = """
你将获得一段群聊对话记录。你的任务是根据给定的表单格式从对话记录中提取结构化信息。在提取信息时,请确保它与类型信息完全匹配,不要添加任何没有出现在下面模式中的属性。
表单格式如下:
info: Array<Dict(
"基本信息-姓名": string | "", // 客户的姓名。
"基本信息-手机号码": string | "", // 客户的手机号码。
"基本信息-邮箱": string | "", // 客户的电子邮箱地址。
"基本信息-地区": string | "", // 客户所在的地区或城市。
"基本信息-详细地址": string | "", // 客户的详细地址。
"基本信息-性别": string | "", // 客户的性别。
"基本信息-年龄": string | "", // 客户的年龄。
"基本信息-生日": string | "", // 客户的生日。
"咨询类型": string[] | [], // 客户的咨询类型,如询价、答疑等。
"意向产品": string[] | [], // 客户感兴趣的产品。
"购买异议点": string[] | [], // 客户在购买过程中提出的异议或问题。
"客户预算-预算是否充足": string | "", // 客户的预算是否充足。示例:充足, 不充足
"客户预算-总体预算金额": string | "", // 客户的总体预算金额。
"客户预算-预算明细": string | "", // 客户预算的具体明细。
"竞品信息": string | "", // 竞争对手的信息。
"客户是否有意向": string | "", // 客户是否有购买意向。示例:有意向, 无意向
"客户是否有卡点": string | "", // 客户在购买过程中是否遇到阻碍或卡点。示例:有卡点, 无卡点
"客户购买阶段": string | "", // 客户当前的购买阶段,如合同中、方案交流等。
"下一步跟进计划-参与人": string[] | [], // 下一步跟进计划中涉及的人员(客服人员)。
"下一步跟进计划-时间点": string | "", // 下一步跟进的时间点。
"下一步跟进计划-具体事项": string | "" // 下一步需要进行的具体事项。
)>
请分析以下群聊对话记录,并根据上述格式提取信息:
**对话记录:**
```
{content}
```
请将提取的信息以JSON格式输出。
不要添加任何澄清信息。
输出必须遵循上面的模式。
不要添加任何没有出现在模式中的附加字段。
不要随意删除字段。
**输出:**
```
[{{
"基本信息-姓名": "姓名",
"基本信息-手机号码": "手机号码",
"基本信息-邮箱": "邮箱",
"基本信息-地区": "地区",
"基本信息-详细地址": "详细地址",
"基本信息-性别": "性别",
"基本信息-年龄": "年龄",
"基本信息-生日": "生日",
"咨询类型": ["咨询类型"],
"意向产品": ["意向产品"],
"购买异议点": ["购买异议点"],
"客户预算-预算是否充足": "充足或不充足",
"客户预算-总体预算金额": "总体预算金额",
"客户预算-预算明细": "预算明细",
"竞品信息": "竞品信息",
"客户是否有意向": "有意向或无意向",
"客户是否有卡点": "有卡点或无卡点",
"客户购买阶段": "购买阶段",
"下一步跟进计划-参与人": ["跟进计划参与人"],
"下一步跟进计划-时间点": "跟进计划时间点",
"下一步跟进计划-具体事项": "跟进计划具体事项"
}}, ...]
```
"""
prompt分成任务目标——抽取数据定义——抽取内容引入——抽取规则强调
- 任务目标:你将获得一段群聊对话记录。你的任务是根据给定的表单形式
Step6:主函数启动
import json
class JsonFormatError(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)
def convert_all_json_in_text_to_dict(text):
"""提取LLM输出文本中的json字符串"""
dicts, stack = [], []
for i in range(len(text)):
if text[i] == '{':
stack.append(i)
elif text[i] == '}':
begin = stack.pop()
if not stack: # 空
dicts.append(json.loads(text[begin:i+1]))
return dicts
# 查看对话标签
def print_json_format(data):
"""格式化输出json格式"""
print(json.dumps(data, indent=4, ensure_ascii=False))
# 如果是true,字符将被表示为 Unicode 转义序列,如 \u4e2d 代表中文字符“中” ,所以为了多语言保留,不转义
def check_and_complete_json_format(data):
required_keys = {
"基本信息-姓名": str,
"基本信息-手机号码": str,
"基本信息-邮箱": str,
"基本信息-地区": str,
"基本信息-详细地址": str,
"基本信息-性别": str,
"基本信息-年龄": str,
"基本信息-生日": str,
"咨询类型": list,
"意向产品": list,
"购买异议点": list,
"客户预算-预算是否充足": str,
"客户预算-总体预算金额": str,
"客户预算-预算明细": str,
"竞品信息": str,
"客户是否有意向": str,
"客户是否有卡点": str,
"客户购买阶段": str,
"下一步跟进计划-参与人": list,
"下一步跟进计划-时间点": str,
"下一步跟进计划-具体事项": str
}
if not isinstance(data, list):
raise JsonFormatError("Data is not a list") # 后面代码不会执行了
for item in data:
if not isinstance(item, dict):
raise JsonFormatError("Item is not a dictionary")
for key, value_type in required_keys.items():
if key not in item:
item[key] = [] if value_type == list else ""
if not isinstance(item[key], value_type):
raise JsonFormatError(f"Key '{key}' is not of type {value_type.__name__}") # 访问内置属性
if value_type == list and not all(isinstance(i, str) for i in item[key]):
raise JsonFormatError(f"Key '{key}' does not contain all strings in the list")
return data
from tqdm import tqdm # 导入 tqdm 库,用于显示进度条
retry_count = 5 # 设置重试次数为 5
result = [] # 初始化结果列表
error_data = [] # 初始化错误数据列表
# 使用 tqdm 显示进度条,遍历 test_data 中的每个元素及其索引
for index, data in tqdm(enumerate(test_data)):
index += 1 # 将索引值加 1,使其从 1 开始
is_success = False # 初始化成功标志为 False
# 最多重试 retry_count 次
for i in range(retry_count):
try:
# 调用 get_completions 函数处理数据
res = get_completions(PROMPT_EXTRACT.format(content=data["chat_text"]))
infos = convert_all_json_in_text_to_dict(res) # 将结果转换为字典
infos = check_and_complete_json_format(infos) # 检查并完善 JSON 格式
# 将处理结果添加到 result 列表中
result.append({
"infos": infos,
"index": index
})
is_success = True # 设置成功标志为 True
break # 跳出循环
except Exception as e: # 捕获异常
print("index:", index, ", error:", e) # 打印错误信息
continue # 继续下一次尝试
# 如果处理失败,将数据添加到 error_data 列表中
if not is_success:
data["index"] = index
error_data.append(data)
if error_data: # 如果 error_data 不为空
retry_count = 10 # 设置重试次数为 10
error_data_temp = [] # 初始化临时错误数据列表
while True: # 无限循环,直到所有数据都被处理或达到最大重试次数
if error_data_temp: # 如果临时错误数据列表不为空
error_data = error_data_temp # 更新 error_data 为临时错误数据列表
error_data_temp = [] # 清空临时错误数据列表
for data in tqdm(error_data): # 使用 tqdm 显示进度条,遍历 error_data 中的每个元素
is_success = False # 初始化成功标志为 False
for i in range(retry_count): # 最多重试 retry_count 次
try:
# 调用 get_completions 函数处理数据
res = get_completions(PROMPT_EXTRACT.format(content=data["chat_text"]))
infos = convert_all_json_in_text_to_dict(res) # 将结果转换为字典
infos = check_and_complete_json_format(infos) # 检查并完善 JSON 格式
# 将处理结果添加到 result 列表中
result.append({
"infos": infos,
"index": data["index"]
})
is_success = True # 设置成功标志为 True
break # 跳出循环
except Exception as e: # 捕获异常
print("index:", index, ", error:", e) # 打印错误信息
continue # 继续下一次尝试
if not is_success: # 如果处理失败
error_data_temp.append(data) # 将数据添加到临时错误数据列表中
if not error_data_temp: # 如果临时错误数据列表为空
break # 跳出无限循环
result = sorted(result, key=lambda x: x["index"]) # 按索引排序结果列表
总体概括:这段代码对之前处理失败的error_data
进行再次处理,直到所有数据都被成功处理或者达到最大重试次数。处理成功后,按索引对结果列表进行排序。
Step7:生成提交文件
# 保存输出
write_json("output.json", result)
最后在左侧文件夹里找到output文件并下载,从提交结果处上传