evaluate_agent.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. import json
  2. import datetime
  3. import random
  4. import traceback
  5. from tqdm import tqdm
  6. from openai import OpenAI
  7. from pymysql.cursors import DictCursor
  8. from pqai_agent.database import MySQLManager
  9. from pqai_agent.agents.message_push_agent import MessagePushAgent
  10. from pqai_agent.agents.message_reply_agent import MessageReplyAgent
  11. evaluation_metrics_dict = {
  12. "1.2": "是否识别关键信息",
  13. "1.3": "是否能够理解歧义词/模糊词",
  14. "1.4": "是否能理解表情包,图片消息",
  15. "1.5": "是否能理解语音/方言",
  16. "2.1": "回复是否与用户意图相关",
  17. "2.2": "回复是否清晰简洁",
  18. "2.3": "回复是否流畅",
  19. "2.4": "回复语法是否规范",
  20. "3.1": "是否能理解代词(他,她, 她, 这个那个)",
  21. "3.2": "是否能延续上文话题",
  22. "3.3": "是否记住上文的基础信息",
  23. "3.4": "是否及时结束聊天",
  24. "4.1": "是否讨论超出角色认知范围的信息",
  25. "4.2": "是否讨论了不符合当前时代背景的语言、物品、事件、概念",
  26. "4.3": "是否表现出与agent 人设相符的专业知识、生活经验或者常识",
  27. "5.1": "agent 的言行是否反映其预设的核心性格",
  28. "5.2": "agent 的价值观和道德观是否符合其预设标准",
  29. "6.1": "agent 使用的词汇、句式、语法复杂度、行话/俚语是否符合其身份、教育背景和时代?",
  30. "6.2": "agent 语气、语调(恭敬、傲慢、亲切、疏离、热情、冷淡)是否稳定?",
  31. "6.3": "agent 表达习惯、口头禅是否符合角色预设特点",
  32. "7.1": "agent 在对话中表现出的目标、关注重心是否与其设定的核心动机一致?",
  33. "8.1": "agent 是否按照预设的互动模式与用户沟通",
  34. "8.2": "agent 是否对自身角色有正确理解",
  35. "8.3": "agent 是否回复超越用户认知的信息"
  36. }
  37. def fetch_deepseek_completion(prompt, output_type='text'):
  38. """
  39. deep_seek方法
  40. """
  41. client = OpenAI(
  42. api_key='sk-cfd2df92c8864ab999d66a615ee812c5',
  43. base_url="https://api.deepseek.com"
  44. )
  45. # get response format
  46. if output_type == "json":
  47. response_format = {"type": "json_object"}
  48. else:
  49. response_format = {"type": "text"}
  50. chat_completion = client.chat.completions.create(
  51. messages=[
  52. {
  53. "role": "user",
  54. "content": prompt,
  55. }
  56. ],
  57. model="deepseek-reasoner",
  58. response_format=response_format,
  59. )
  60. response = chat_completion.choices[0].message.content
  61. if output_type == "json":
  62. response_json = json.loads(response)
  63. return response_json
  64. return response
  65. def get_profile_info(user_id_, user_type):
  66. match user_type:
  67. case "user":
  68. sql = f"""
  69. select iconurl as 'avatar', profile_data_v1 as 'profile'
  70. from third_party_user where third_party_user_id = %s;
  71. """
  72. case "staff":
  73. sql = f"""
  74. select agent_profile as 'profile'
  75. from qywx_employee where third_party_user_id = %s;
  76. """
  77. case _:
  78. raise ValueError("user_type must be 'user' or 'staff'")
  79. return mysql_client.select(sql, cursor_type=DictCursor, args=(user_id_,))
  80. def evaluate_conversation_quality_task(dialogue_history, user_profile_, agent_profile):
  81. """
  82. :param dialogue_history:
  83. :param user_profile_:
  84. :param agent_profile:
  85. :return:
  86. """
  87. output_format = {
  88. "1.1": {
  89. "score": 5,
  90. "reason": ""
  91. },
  92. "1.2": {
  93. "score": 8,
  94. "reason": "reason"
  95. },
  96. "1.3": {
  97. "score": 10,
  98. "reason": "reason"
  99. },
  100. "1.4": {
  101. "score": 10,
  102. "reason": "reason"
  103. },
  104. "1.5": {
  105. "score": 10,
  106. "reason": "reason"
  107. },
  108. "1.6": {
  109. "score": 10,
  110. "reason": "reason"
  111. },
  112. "2.1": {
  113. "score": 9,
  114. "reason": "reason"
  115. },
  116. "2.2": {
  117. "score": 10,
  118. "reason": "reason"
  119. },
  120. "2.3": {
  121. "score": 10,
  122. "reason": "reason"
  123. },
  124. "total_score": "total_score",
  125. "improvement_suggestions": "suggestions",
  126. }
  127. prompt_ = f"""
  128. 你是一名优秀的 agent 评估员,请根据以下场景和输入,对该 agent 的回复能力进行评估,用分数量化
  129. 场景:
  130. 智能体对话场景, 智能体(agent)和用户(user)进行对话聊天
  131. 输入:
  132. agent 的人设:agent_profile: {agent_profile}
  133. 用户的人设: user_profile: {user_profile_}
  134. 对话历史:dialogue_history: {dialogue_history}
  135. 评估标准, 满分为 100分,拆分到以下每一个小项,每一个小项的得分表示该小项的能力,60% 的分表示及格,80% 的分表示优秀:
  136. 1. 对话能力(30分)
  137. 1.1 语言是否流畅(10分)
  138. 1.2 上下文是否连贯,语义是否一致(10分)
  139. 1.3 agent 是否感知用户结束聊天的意图并且适当结束聊天(10分)
  140. 1.4 agent 回复消息的时间间隔是否合理,符合真人对话规律 (10分)
  141. 1.5 agent 回复的消息是否具有高情商,互动能力是否好,能否和用户共情,提升用户的情感体验 (20分)
  142. 1.6 agent 回复的消息是否解决了用户提出的问题 (10分)
  143. 2. 角色一致性(30分)
  144. 2.1 agent 语言风格是否符合agent人设(10分)
  145. 2.2 agent 语言风格是否适合用户人设(10分)
  146. 2.3 agent 回复内容不要超越用户的认知上限(10分)
  147. 输出:
  148. 输出为 json 格式,输出格式规范 {output_format}
  149. """
  150. return prompt_
  151. def evaluate_push_agent_prompt(dialogue_history, push_message, user_profile_, agent_profile):
  152. """
  153. :param dialogue_history:
  154. :param push_message:
  155. :param user_profile_:
  156. :param agent_profile:
  157. :return:
  158. """
  159. output_format = {
  160. "1.1": {
  161. "score": 5,
  162. "reason": "push_message尝试联系用户的头像,但用户兴趣未明确提及戏曲"
  163. },
  164. "1.2": {
  165. "score": 8,
  166. "reason": "语言风格轻松友好,适合大多数用户,但未完全匹配用户特定风格"
  167. },
  168. "1.3": {
  169. "score": 10,
  170. "reason": "信息未超出用户认知范围"
  171. },
  172. "2.1": {
  173. "score": 9,
  174. "reason": "语言风格符合agent人设,友好且亲切"
  175. },
  176. "2.2": {
  177. "score": 10,
  178. "reason": "信息未超出agent人设的认知范围"
  179. },
  180. "3.1": {
  181. "score": 15,
  182. "reason": "push_message有潜力勾起用户兴趣,但未直接关联用户已知兴趣"
  183. },
  184. "3.2": {
  185. "score": 10,
  186. "reason": "信息真实"
  187. },
  188. "3.3": {
  189. "score": 12,
  190. "reason": "表现出一定的拟人化和情商,但共情程度可进一步提升"
  191. },
  192. "total_score": 79,
  193. "improvement_suggestions": "建议更深入地挖掘和利用用户已知的兴趣爱好来定制push_message,以增强相关性和用户参与度。同时,可以尝试更多共情的表达方式,以提升用户的情感体验。"
  194. }
  195. prompt_ = f"""
  196. 你是一名优秀的 agent 评估员,请根据以下场景和输入,对该 agent 的能力进行评估,用分数量化
  197. 场景:
  198. 智能体对话场景, 智能体(agent)向用户发起对话
  199. agent 需要通过分析 user 和 agent 直接的历史对话,以及 user 和 agent 的人设信息,向用户发送一条消息(push_message)
  200. 输入:
  201. agent 的人设:agent_profile: {agent_profile}
  202. 用户的人设: user_profile: {user_profile_}
  203. 对话历史:dialogue_history: {dialogue_history}
  204. agent 的唤起对话:push_message: {push_message}
  205. 评估标准, 满分为 100分,拆分到以下每一个小项,每一个小项的得分表示该小项的能力,60% 的分表示及格,80% 的分表示优秀:
  206. 1. push_message 的内容 和 user_profile的相关性(30分)
  207. 1.1 push_message 是否迎合用户的兴趣爱好 (满分 10分)
  208. 1.2 push_message 的语言风格是否适合用户语言风格 (满分 10分)
  209. 1.3 push_message 的信息是否超出用户的认知范围 (满分 10分)
  210. 2. push_message 和 agent_profile 的相关性(20分)
  211. 2.1 push_message 的语言风格是否符合 agent 人设(满分 10分)
  212. 2.2 push_message 的信息是否超出 agent人设的认知范围(满分 10分)
  213. 3. push_message 质量量化 (50分)
  214. 3.1 push_message 是否能勾起用户的兴趣,驱动用户聊天激情 (满分 25分)
  215. 3.2 push_message 的信息是否真实 (满分 10分)
  216. 3.3 push_message 是否具有拟人化,高情商,与用户共情,提升用户的情感体验(满分 15分)
  217. 输出:
  218. 输出为 json 格式,输出格式规范 {output_format}
  219. """
  220. return prompt_
  221. def evaluate_reply_agent_prompt(dialogue_history, message, user_profile_, agent_profile, push_time):
  222. """
  223. :param dialogue_history:
  224. :param message:
  225. :param user_profile_:
  226. :param agent_profile:
  227. :return:
  228. """
  229. output_format = {
  230. "1.1": {
  231. "score": 1,
  232. "reason": "理由"
  233. },
  234. "1.2": {
  235. "score": 0,
  236. "reason": "理由"
  237. }
  238. }
  239. prompt_ = f"""
  240. **评估任务:** 基于给定的对话历史和 Agent 预设信息,评估 Agent 在对话中的表现。使用以下维度和指标进行评分。
  241. **评估指标:**
  242. 1. 理解能力
  243. 1.1 是否识别用户核心意图
  244. 1.2 是否识别关键信息
  245. 1.3 是否能够理解歧义词/模糊词
  246. 1.4 是否能理解表情包,图片消息
  247. 1.5 是否能理解语音/方言
  248. 2. 回复能力
  249. 2.1 回复是否与用户意图相关
  250. 2.2 回复是否清晰简洁
  251. 2.3 回复是否流畅
  252. 2.4 回复语法是否规范
  253. 3. 上下文管理能力
  254. 3.1 是否能理解代词(他,她, 她, 这个那个)
  255. 3.2 是否能延续上文话题rye5
  256. 3.4 是否及时结束聊天
  257. 4. 背景知识一致性
  258. 4.1 是否讨论超出角色认知范围的信息
  259. 4.2 是否讨论了不符合当前时代背景的语言、物品、事件、概念
  260. 4.3 是否表现出与agent 人设相符的专业知识、生活经验或者常识
  261. 5. 性格行为一致性
  262. 5.1 agent 的言行是否反映其预设的核心性格
  263. 5.2 agent 的价值观和道德观是否符合其预设标准
  264. 6. 语言风格一致性
  265. 6.1 agent 使用的词汇、句式、语法复杂度、行话/俚语是否符合其身份、教育背景和时代?
  266. 6.2 agent 语气、语调(恭敬、傲慢、亲切、疏离、热情、冷淡)是否稳定?
  267. 6.3 agent 表达习惯、口头禅是否符合角色预设特点
  268. 7. 目标动机一致性
  269. 7.1 agent 在对话中表现出的目标、关注重心是否与其设定的核心动机一致?
  270. 8. 关系认知一致性
  271. 8.1 agent 是否按照预设的互动模式与用户沟通
  272. 8.2 agent 是否对自身角色有正确理解
  273. 8.3 agent 是否回复超越用户认知的信息
  274. **评估规则:**
  275. - 对于每个指标:
  276. - 如果符合要求,得 1 分。
  277. - 如果不符合要求,得 0 分。
  278. - 如果指标不适用(如对话未涉及相关场景),得 1 分(无需评估。
  279. - 理由必须基于对话内容,简短且客观,理由需要是中文, 如果是无需评估,则理由写无需评估
  280. **输入:**
  281. - **对话历史**: {dialogue_history}
  282. - **Agent 预设信息**: {agent_profile}
  283. - **用户预设信息**: {user_profile_}
  284. - **Agent 消息**: {message}
  285. - **Agent 发送消息时间**:{push_time}
  286. **输出格式要求:JSON 格式**
  287. 输出格式参考:{output_format}
  288. """
  289. return prompt_
  290. config = {
  291. 'host': 'rm-bp13g3ra2f59q49xs.mysql.rds.aliyuncs.com',
  292. 'port': 3306,
  293. 'user': 'wqsd',
  294. 'password': 'wqsd@2025',
  295. 'database': 'ai_agent',
  296. 'charset': 'utf8mb4'
  297. }
  298. mysql_client = MySQLManager(config)
  299. if __name__ == '__main__':
  300. import pqai_agent.logging_service
  301. pqai_agent.logging_service.setup_root_logger()
  302. with open("push_message_evaluation_result.json", "r", encoding="utf-8") as f:
  303. data = json.load(f)
  304. # dialogues = random.sample(data, 1)
  305. F = []
  306. for sub_dialogues in tqdm(data):
  307. try:
  308. # user 相关
  309. # user_id = sub_dialogues['user_id']
  310. # user_profile_response = get_profile_info(user_id, "user")
  311. # user_profile, avatar = json.loads(user_profile_response[0]['profile']), user_profile_response[0]['avatar']
  312. #
  313. # user_profile['avatar'] = avatar
  314. # user_profile['current_datetime'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  315. #
  316. # # staff 相关
  317. # staff_id = sub_dialogues['staff_id']
  318. # staff_profile_response = get_profile_info(staff_id, "staff")
  319. # staff_profile = json.loads(staff_profile_response[0]['profile'])
  320. #
  321. # user_profile['formatted_staff_profile'] = staff_profile
  322. #
  323. # push_agent = MessagePushAgent()
  324. # # reply_agent = MessageReplyAgent()
  325. #
  326. # # message 相关
  327. # message = sub_dialogues['dialogue_history']
  328. # agent_message = push_agent.generate_message(
  329. # context=user_profile,
  330. # dialogue_history=message
  331. # )
  332. message = sub_dialogues["dialogue_history"]
  333. agent_message = sub_dialogues["push_message"]
  334. push_time = sub_dialogues["push_time"]
  335. user_profile = sub_dialogues["user_profile"]
  336. staff_profile = sub_dialogues["agent_profile"]
  337. if agent_message:
  338. prompt = evaluate_reply_agent_prompt(message, agent_message, user_profile, staff_profile, push_time)
  339. # prompt = evaluate_conversation_quality_task(message, user_profile, staff_profile)
  340. response = fetch_deepseek_completion(prompt, output_type='json')
  341. obj = {
  342. "user_profile": user_profile,
  343. "agent_profile": staff_profile,
  344. "dialogue_history": message,
  345. "push_message": agent_message,
  346. "push_time": push_time,
  347. "evaluation_result": response
  348. }
  349. F.append(obj)
  350. except Exception as e:
  351. print(e)
  352. print(traceback.format_exc())
  353. with open("push_message_evaluation_result_2.json", "w", encoding="utf-8") as f:
  354. f.write(json.dumps(F, ensure_ascii=False, indent=4))