前述
本项目基于文心一言构造了一个相亲辅助工具,能够帮你准备一份个人介绍,并且在不暴露隐私的前提下进行相亲。
在新版飞桨星河社区探索页面-项目大厅搜索“相亲判官”即可找到此项目。
在新版飞桨星河社区探索页面-应用中心搜索“相亲判官”可以找到此项目的体验版本。
此外,飞桨星河社界面全新升级,给人一种“Wow~真的很新”的感觉,欢迎大家去用一用 & 体验更多有趣项目和应用(最好是体验我的项目)。
项目介绍
相亲场上总的来说,存在两种人,第一种人是真的想相亲的人,第二种是不太想相亲却被逼着相亲的人。前者总是希望能够尽可能地增加双方之间地了解,确定双方是否合适,但大家终究是萍水相逢的陌生人,很难做到坦诚相待。后者总是希望能够尽可能圆滑地回绝对方,一方面是希望不要让对方难办,另一方面也是希望能用一个适当的理由回绝父母、长辈。
但总的来说,双方的沟通总是有所保留的,都有一些不太方便告诉对方的信息。为了能够圆滑、优雅、高效地进行相亲,相亲判官这款应用应运而生。它能够基于LLM,判断相亲的双方是否合适,无需将你的个人信息泄露给相亲对象;另外,基于LLM/Agent,它也能帮用户整理一份个人介绍,从而避免每个人都在以不同的标尺写个人介绍。
判断双方是否合适
相亲双方将自己的个人介绍输入到应用中,由应用生成加密的文件,再将双方加密后的文件输入到应用中,由应用进行解密,并通过文心一言判断这两个人是否合适。在整个过程中,只有你和文心一言知道你的个人信息,对方完全不知情。
交互式生成用户画像
如果每份个人介绍都由用户自己准备,则会出现“提笔忘词”、“描述风格不统一”的情况。当大模型出现之后,我们可以使用大模型诱导用户发言,并根据用户的发言结果,由大模型生成人物介绍。一方面实现了交互式访谈生成用户画像的效果,另一方面可以促进相亲双方的描述都是基于相同“标准”的。
在下文中,我们将分别从方案设计、代码实现两个方面对该项目进行介绍。
基于LLM的相亲判断——
隐私保护&调用ERNIE SDK&结构化输出
对于第一个功能,基于LLM的相亲判断,可以进一步细分为几个子功能:
1) 加密解密文本
2) 基于大模型判断两个用户是否合适
该功能的技术路线可以用下图来概括:
加解密策略
当加解密过程是可逆的时候,知道加密策略后,只需要顺势执行解密策略即可获得明文。
具体来说,本项目的加密流程如下:
1) 随机生成八位数密钥
2) 通过密钥对用户信息(明文)进行加密(使用AES对文本进行加密),即可获得密文
3) 通过配置的密文对密钥信息进行加密(直接对密钥进行重排即可),得到密钥密文
4) 创建TXT文件,将密钥密文作为文件名,将密文作为文件内容
之后需要使用文件内容的时候,只需要反过来执行,先根据文件名解析密钥,再通过密钥解析获得明文。整个过程中,用户只能获得密文和密钥密文,无法直接观察到个人信息。唯一能够轻松观察到明文的人只有程序开发者/部署工程师/维护工程师,因此,只要开发/维护/管理人员不监守自盗,用户信息基本能够做到保密。
对密钥进行加密的步骤仅一步:根据配置,将密钥顺序重排,例如密钥为32145678,配置为21345678,根据配置,重排后第一位的元素是原密钥中第2位的元素。
对文本进行加密时采用库pycryptodome,代码如下:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import os
def encrypt(plaintext, password):
# plaintext为str,password为str,输出为btypes,因此输出必须采用with open('example.txt','rw+')来进行读写
# 确保密码长度是16的倍数(AES-128)
if len(password) > 16:
password = password[:16]
elif len(password) < 16:
password += '\0' * (16 - len(password))
key = password.encode() # 在实际应用中,应该使用更安全的密钥派生函数
plaintext = plaintext.encode()
iv = get_random_bytes(16) # 初始化向量
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
iv_ciphertext = iv+ciphertext
return iv_ciphertext
对文本进行解密的代码如下:
def decrypt(iv_ciphertext, password):
# password为str,iv_ciphertext为btypes,输出为str,因此iv_ciphertext必须采用with open('example.txt','rw+')来进行读写
# 确保密码长度是16的倍数(AES-128)
if len(password) > 16:
password = password[:16]
elif len(password) < 16:
password += '\0' * (16 - len(password))
key = password.encode() # 在实际应用中,应该使用更安全的密钥派生函数
iv = iv_ciphertext[:16]
ciphertext = iv_ciphertext[16:]
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
plaintext = plaintext.decode()
return plaintext
对密钥加密的代码如下:
# 重排
import random
# 加密函数
def encrypt(key, data):
if len(str(data)) != 8 or len(key) != 8 or not all("1" <= k <= "8" for k in key):
raise ValueError("Both key and data must be sequences of 8 digits, and key must contain numbers from 1 to 8.")
# 将数据转换为字符串并确保它是八位数
data_str = str(data).zfill(8)
# 根据密钥重新排列数据
encrypted_text = [None] * 8
for i, k in enumerate(key):
encrypted_text[int(k) - 1] = data_str[i]
# 连接重新排列后的字符以形成加密文本
return ''.join(encrypted_text)
调用文心一言进行结构化输出
调用ERNIE SDK可以快速使用对话补全功能,详细的官方文档见
https://github.com/PaddlePaddle/ERNIE-SDK/。
本项目仅针对对话补全进行介绍。
为了使用ERNIE SDK,你需要进行以下操作
pip install erniebot
import erniebot
erniebot.api_type = 'aistudio'
erniebot.access_token = "***********************************" #请从AI Studio首页获取key
完成配置后,只需要简单几行即可进行对话补全
response = erniebot.ChatCompletion.create(
model='ernie-3.5',
messages=[{'role': 'user', 'content': Your_Words}],
top_p=0,
temperature=0.1,
)
result = response.get_result()
通常,对话补全功能不能很好的遵循结构化指令,为了能够获得结构化输出,我们可以让LLM按照json格式进行输出。即,
Your_Words = f"""
你是一个相亲判断机器人,你将获得两个人的个人信息,对对方的要求等信息。请你综合两个人的信息进行判断。判断结果通过json的格式返回。
返回内容是一个字典{"{"}'判断结果':bool{"}"}。其中,判断结果为True时,表明双方较为合适,有进一步发展的可能;False表明双方不适合。
相亲人1的信息是:{decrypted_data1}。
相亲人2的信息是:{decrypted_data2}。
"""
如果相亲人信息如下:
decrypted_data1 = "大家好,我是刘婷,今年29岁,现在是一家时尚杂志的编辑。我的性格比较外向,喜欢社交和聚会,业余时间我会和朋友一起逛街、看电影或者旅行。我认为生活应该是多姿多彩的,充满了欢笑和惊喜。对于我的另一半,我希望他能够陪我一起享受生活,给我足够的关心和浪漫。我希望我们的生活能够充满乐趣和爱意,而不是单调和乏味。"
decrypted_data2 = "大家好,我是王磊,今年32岁,目前在一家大型企业担任高级工程师。我的性格比较内向,喜欢安静的环境,业余时间多用来研究新技术和编程。我认为生活应该简单而有条理,不喜欢太过复杂和混乱的事物。对于我的另一半,我希望她能够温柔、贤惠,能够理解和支持我的工作。我不希望她过多地干涉我的生活,更希望我们能够有各自的空间和自由。"
我们解析返回的文本中的json字段就可以获得False。
基于ERNIE SDK快速搭建问答式评价工具
上文中,我们已经基于加密和LLM构造了一种可以在保护自己隐私的基础下进行相亲和适度判断的策略。但实际上,我们会发现写自我介绍并不是一个容易的事情,并且每个人对自己的介绍总是独特的,从而缺乏统一的标准。为了能够以统一的标准,并且让用户更为轻松地创建自我介绍,我们希望使用大模型来生成用户介绍。具体流程如下:
1) 用户进行简短地开场(例如:简单描述自己的年龄,姓名)
2) 大模型根据对话信息生成介绍文本
3) 大模型判断介绍文本的信息对于相亲来说是否充足
4) 根据历史对话信息,生成新的问题,引导用户回复
5) 不断重复上面的过程,直到介绍文本对于相亲来说足够充分。
该功能的技术路线可以用下图概况:
相比于上面的单轮对话逻辑,问答式评价需要进行多轮对话,并且适当的进行历史记录管理。
首先,我们对多轮对话的方式进行介绍:
response = erniebot.ChatCompletion.create(
model='ernie-3.5',
messages=msg,
top_p=0,
temperature = 0.1,
)
result = response.get_result()
其中meg的格式是,{'role': 'assistant', 'content': words},{'role': 'user', 'content': words}, ... ]
其中,user和assistant总是成对出现的,并且最后一个元素的role属性始终为user。
为了能够进行问答式对话,我们需要创建一些变量用于存储相关信息:
customer_information: 当前的用户评价结果
can_stop: 对话是否结束
chat_history: 对话记录,格式是[{'role': 'user', 'content': words},{'role': 'assistant', 'content': words},{'role': 'user', 'content': words}, ... ],其中,user和assistant总是成对出现的,并且最后一个元素的role属性始终为assitant。
customer_response: 当前的用户回复信息
第一步,我们先根据当前的用户回复和历史信息,生成新的评价
prompt_user_infor = f'''
你是一个相亲信息记录机器人,你需要对<用户回复>进行分析,从中挖掘用户的信息,以及你对用户的评价(例如情绪、性格特点等),
将这些信息补充到<用户信息>中,你也可以对<用户信息>中已有的信息进行修正。
返回内容是一个字典
{"{"}
"整理后的用户信息":String
{"}"}
<用户信息>:{customer_information},
<用户回复>:{customer_response}。
'''
input_msg = chat_history + [{"role": "user", "content": prompt_user_infor}]
输入input_msg即可获取对应的结果,之后按照json格式计息即可获取到整理后的用户信息。
第二步,我们需要判断当前用户是否提供了充足的信息:
prompt_question = f'''
在每个人进行相亲之前,都需要先录入自己的信息,但是自己对自己的评价可能较为主观。
因此,通过对话、一问一答的方式,除了能够获取这个人的个人信息之外,还能够挖掘这个人的能够更好地采集到这个人的性格特征。
你作为一个相亲信息记录机器人,需要通过对话的方式收集用户信息,对于一些事实性的信息,例如姓名、年龄,可以从用户对话中抽取,或者直接询问。
但对于一些具有抽象特征的信息,例如脾气、心态、性格等,需要从对话中,根据言谈特征自行总结。
具体来说,你需要检查<用户信息>并考虑你是否从用户那里获取了足够的信息,从而支持你根据这份资料向其他人介绍这位相亲对象。如果信息并不充分,请继续询问。
如果信息充分,则结束询问,输出中<结束判断>为1,否则为0,请检查对话历史,保证对话的连贯性,用户的最近一次回复在<用户回复>中,而非对话历史中。
返回内容是一个字典
{"{"}
"结束判断":int,
"新的问题":String
{"}"}
<用户信息>:{customer_information},
<用户回复>:{customer_response}。
'''
input_msg = chat_history + [{"role": "user", "content": prompt_question}]
如果结束判断为1,can_stop就设置为True,将当前的用户回复以及新的问题添加到对话历史记录中,并且向用户抛出新的问题。用户回复新的问题后,从步骤一再次开始执行。
如果结果判断为0,结束对话,用户即可获取LLM生成的评价~
总结——Summary & 体验链接
本项目结合文心一言构建了一个相亲助手,一方面能够帮助大家快速地保护隐私的情况下判断相亲对象是否合适,另一方面能够帮助大家对话式生成个人评价。
更多代码细节请参考
https://aistudio.baidu.com/projectdetail/7466675
应用体验请前往
https://aistudio.baidu.com/application/detail/17916
关注【飞桨PaddlePaddle】公众号
获取更多技术内容~