最近在用大模型跑一些数据,于是就不可避免的遇到了如何让大模型输出的格式便于处理这个问题。经过一些研究发现了一套比较有用的方法,在这里总结一下。

背景

任务是这样的,我需要用大模型(比如ChatGPT,ChatGLM等等)对文本进行名词提取。输入一段文本,我需要大模型理解这段文本,然后输出这段文本中的所有代表事件的动词。

理论上讲这是一件很简单的事情,大模型也能比较精准的识别出其中的动词。但是问题就在于大模型的输出上。我该如何将大模型的非格式化的输出转化为格式化的结构化数据呢?

研究过程

某些机缘巧合读到了下面的文献[1]。文献中提出一种叫做PICa的方法:

We present PICa, a simple yet effective method to use GPT-3 for knowledge-based VQA, demonstrating the first use of GPT-3 for multimodal tasks.

虽然是用于VQA领域的问题,但是也不妨细看一下。

进一步研究PICa发现,对于一次VQA预测,它使用如下两种策略:

  • In-context example selection(上下文示例选择)
  • Multi-query ensemble(多查询集成)

其中,上下文示例选择就是在问题之外给模型提供n个样例,这样模型的输出就和样例一致。多查询集成本质上就是多问几次,然后根据问的结果通过某种指标进行排序,得到排序最靠前的一个作为答案。

不难发现,上下文示例选择这个方法对于我的任务很有帮助。

方法

经过上述研究,发现可以尝试使用上下文示例选择的方法使得模型输出固定格式的数据,然后使用Python的正则表达式库进行匹配。

鉴于常用的数据存储格式为json,我们让模型输出的格式也是json。这样一方面便于处理,另一方面,模型的语料库里面json的出现频率肯定比自定义的奇奇怪怪的格式会高,模型对json的格式的理解肯定也更好。

最后实现的效果:

import json
import re
from load_model import chatglm

model = chatglm()

background = """
我希望你能够以一名语言学家的身份帮我完成如下的任务。
首先我会给你一段文本,然后你需要尽可能多的提取出这段文本中发生过的动作事件,比如建立,标记,攻击,渗透,销毁等。
最好一段文本至少能够生成4个以上的词语,词语的长度不能大于6个字。
你的输出需要严格按照python列表的格式输出,我接下来会给你几个例子。
你需要结合下列例子理解我的上述要求,并且按照要求完成任务。
"""

example1 = """
样例1:
================
输入:CNC组织最早于2019年被发现,其命名来源于所使用的远控木马的PDB路径信息中包含的cnc_client,且该组织主要针对教育行业进行攻击。
输出:['发现','攻击','包含']
================
"""

example2 = """
样例2:
================
输入:攻击者以木尔坦的罗德兰区基于情报的反恐行动(intelligence-based operation,IBO)报告为诱饵,尝试投递一种变种木马程序MessPrint以控制受害者设备。
输出:['使用诱饵','投递','控制']
================
"""

question = """
问题1:
================
输入:{}
输出:
================
"""

prompt_base=background + example1 + example2

pattern = r"\[.*?\]"  # 匹配以 "[" 开始,以 "]" 结束的子串
cnt = -1
result = []
for i in tqdm.tqdm(res):
    prompt = prompt_base + question.format(i)
    response = model.response(prompt)[0]
    matches = re.findall(pattern, response)
    for match in matches:
        try:
            lst = eval(match)  # 使用eval将字符串转化为列表,安全性请自行考虑
            result+=lst
        except:
            pass

        print(f"========>>>>>>>\nA:{response}")
    if cnt != -1:
        if cnt > 1:
            break
        cnt += 1

最后输出的效果(部分):

结构化输出 python 结构化输出的任务_chatgpt

reference
[1] Zhengyuan Yang, Zhe Gan, Jianfeng Wang, Xiaowei Hu, Yumao Lu, Zicheng Liu, and Lijuan Wang. An empirical study of gpt-3 for few-shot knowledge-based vqa. In AAAI, pages 3081–3089, 2022.