在上次的task2中,我们实现了初步的方案(baseline),但是baseline也存在一些缺陷。
首先,让我们重新回到官网查看需求:
需求如下:
该模型应具备自然语言处理(NLP)能力,能够理解用户自然语言问题中的意图(如查询始发站、终到站、检票口等),以支持多种问题类型,例如:
- 单字段查询:如"Z152次列车的终到站是哪里?"
- 多条件筛选:如"在综合候乘中心候车、发车时间晚于08:00的列车有哪些?"
- 跨行计算:如"从兰州到北京西的列车中,哪趟运行时间最短?"
- 时间推理:如"K420次列车在兰州站的停留时长是多久?"
- 复杂时间范围过滤:如"在'综合候乘中心',到点时间介于06:00至08:00之间且站台为2的车次有哪些?"
- 缺失数据处理:如"检票口为'5B'且开点时间缺失的车次有哪些?"
- 复杂单位换算:如"K2095/8次列车的开点时间为05:51,若延误1小时15分钟,新的开点时间是几点?"
- 模型的输出应该是包含数值结果、文本描述及必要推理步骤的结构化回答,能够直接展示提取的指标和相关信息。
由此可以看出,当前数据集的格式已难以满足任务需求 ------ 任务中涉及大量跨行数据关联分析(如通过同一车次关联不同候车厅的检票信息、结合多站到点、开点计算全程时长等),而现有格式未对这类关联逻辑进行结构化标注,导致模型需额外耗费算力识别数据间的隐性联系,影响响应效率。
进一步分析数据集可发现,数据按照候车厅类别分区排列,合理利用这一点可以提高模型的响应速度。
因此,我们需要完成的第一件事是用更合理的方式处理并存放数据集 。
不仅如此, 通过分析需求我们也可以发现,其中涉及到了许多需要精确计算时间的任务。
比如:
- 多条件筛选 :如"在综合候乘中心候车、发车时间晚于08:00的列车有哪些?"(需要计算发车/到达时间是否早于或者晚于某个时刻)
- 跨行计算 :如"从兰州到北京西的列车中,哪趟运行时间最短?"(不仅要计算运行时间,还要比较不同的车次)
- 时间推理 :如"K420次列车在兰州站的停留时长是多久?"(需要计算停留时长)
- 复杂时间范围过滤 :如"在'综合候乘中心',到点时间介于06:00至08:00之间且站台为2的车次有哪些?"(不仅要计算时间,而且还要当作过滤条件筛选车次)
- 复杂单位换算:如"K2095/8次列车的开点时间为05:51,若延误1小时15分钟,新的开点时间是几点?" (需要拥有强大的时间计算能力)
所以,我们要做的第二件事就是增强时间计算能力 。
而且,在得到了更合理的数据集,以及更强的时间计算能力后,可以发现我们在baseline
中给出的question_list
太过于简单了,并且prompt也缺乏对复杂任务的适配性,无法满足比赛的需求:
Python
question_list = []
# ----------- 添加问题列表数据 begin ----------- #
# 检票口
question_list.append(f'{row["车次"]}号车次应该从哪个检票口检票?')
# 站台
question_list.append(f'{row["车次"]}号车次应该从哪个站台上车?')
# 目的地
question_list.append(f'{row["车次"]}次列车的终到站是哪里?')
Python
# 简单问题的prompt
prompt = '''你是列车的乘务员,请你基于给定的列车班次信息回答用户的问题。
# 列车班次信息
{}
# 用户问题列表
{}
'''
从代码中可以发现,我们的问题列表与prompt主要涉及的需求只有单字段查询,其他需求要么没有涉及,要么涉及得很薄弱。
所以,我们要做的第三件事就是丰富问题列表,优化prompt格式 ,通过人工提供更加丰富的问题列表、设定更贴合需求的prompt格式来确保模型能够解决比赛的需求。问题跟prompt涉及的方面应该还要有:跨行分析统计结果、按照给定条件筛选过滤等。
最后,通过分析需求还可以发现,比赛对模型的输出也有要求。
模型的输出应该是包含数值结果、文本描述及必要推理步骤的结构化回答,能够直接展示提取的指标和相关信息。
相比之下,我们的output_format:
Python
output_format = '''# 输出格式
按json格式输出,且只需要输出一个json即可
```json
[{
"q": "用户问题",
"a": "问题答案"
},
...
]
```'''
格式太过于简单了,需要做修改来符合比赛的需求。
因此,第四件事是修改output的格式。
接着,在下面的篇幅中,我将分析如何完成这四件事。
第一件事:用更合理的方式处理并存放数据集
PS:这一部分本来是想要对时间字段做特殊处理方便比对时间,计算停留时间等等,但是最后还是选择了相信大模型的处理能力,没有对时间字段做特殊处理,而是全部转化成了字符串格式。
第二件事:增强时间计算能力
PS:同上。 没有在时间字段的格式上做处理,而是在问题列表中进行了处理。在问题生成函数中,增加了条件判断,当数据满足计算条件时,就生成相应的计算类问题。这使得我们的数据集能够专门用于训练模型的数学和逻辑推理能力。例如下面的代码段:
Python
# 增加一个计算问题,使其更强大
if row["到点"] != "无数据" and row["开点"] != "无数据":
question_list.append(f"计算 {train_num} 次列车在本站的停留时长。")
return question_list
Python
f"比较从 {start} 开往 {end} 的所有列车中,哪一趟在本站的停留时间最长?请列出所有车次及其停留时间。"
第三件事:丰富问题列表,优化prompt格式
这里做了三个处理。
- 为了增强跨行比较能力,在生成问题列表时,增加了对多行合成的一组数据生成,而且问题列表的格式也相应地进行了调整。也增加了对应的prompt生成格式。
- 对每种生成方式都增加了问题列表的数量。
- 优化了Prompt格式。从简单的字符串拼接,升级为结构化、指令清晰的Prompt模板。一个好的Prompt就像一个好的老师,能清晰地告诉模型它的角色、任务、参考资料和输出要求,这能极大地提升生成答案的准确性和稳定性。 代码如下:
Python
# --- 问题生成函数 ---
def create_single_row_questions(row: dict):
"""根据您的版本,为单行数据生成问题列表"""
question_list = []
train_num = row["车次"]
question_list.append(f'{train_num}号车次应该从哪个检票口检票?')
question_list.append(f'{train_num}号车次应该从哪个站台上车?')
question_list.append(f'{train_num}次列车的终到站是哪里?')
# 增加一个计算问题,使其更强大
if row["到点"] != "无数据" and row["开点"] != "无数据":
question_list.append(f"计算 {train_num} 次列车在本站的停留时长。")
return question_list
def create_cross_row_question(group: pd.DataFrame):
"""为跨行分组生成一个问题"""
if len(group) < 2: return None
start = group['始发站'].iloc[0]
end = group['终到站'].iloc[0]
return f"比较从 {start} 开往 {end} 的所有列车中,哪一趟在本站的停留时间最长?请列出所有车次及其停留时间。"
# --- Prompt 模板 ---
single_row_prompt_template = '''你是专业的列车信息查询助手。请根据下面单条"列车班次信息",回答"用户问题列表"中的所有问题。
# 列车班次信息:
{}
# 用户问题列表:
{}
# 输出格式要求:
你的回答必须是一个包含所有问题答案的JSON数组。
```json
[
{{ "q": "问题1", "a": "答案1" }},
{{ "q": "问题2", "a": "答案2" }}
]
```'''
cross_row_prompt_template = '''你是专业的列车数据分析师。请根据下面多条"列车班次信息",回答"用户问题"。
# 列车班次信息 (一个列表):
{}
# 用户问题:
{}
# 输出格式要求:
你的回答必须是一个JSON对象,包含问题和答案。
```json
{{ "q": "用户问题", "a": "这里是详细的分析和答案" }}
```'''
第四件事:修改output的格式
PS:跟上面的prompt格式合并在一块了。