Files
test2/05-LLM/03_api_deepseek_v3.py
2026-02-26 16:49:19 +08:00

113 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 先安装: pip install openai
import os
import dotenv
from sklearn.metrics import accuracy_score
from tenacity import retry, stop_after_attempt, wait_fixed
import pandas as pd
import json
from langchain_openai import ChatOpenAI
dotenv.load_dotenv()
# 获取环境变量
BASE_URL = os.getenv("BASE_URL")
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DEV2FILE = os.getenv("DEV2FILE")
CLASS_FILE = os.getenv("CLASS_FILE")
# 提前定义提示词
SYSTEM_PROMPT = """
你是一个专门用于中文新闻标题分类的助手,能够将给定的新闻标题准确地分类到以下十个预定义的类别之一:
finance财经、realty房产、stocks股市、education教育、science科技、society社会、politics政治、sports体育、game游戏和entertainment娱乐
请根据标题内容和以下关键词与示例,匹配最相关的类别。如果标题涉及教育机构但核心是社会贡献,优先归为 society。
返回 JSON 格式:{"category": "类别", "reason": "分类原因"}
例如:
- 输入“同步A股首秀港股缩量回调”应返回{"category": "stocks", "reason": "股市"}
- 输入:“布拉特:放球员一条生路吧 FIFA能消化俱乐部的攻击”应返回“sports”。{"category": "sports", "reason": "体育"}
请注意,只从上述提供的十个类别中选择一个最合适的进行返回。如果标题与多个类别相关,请选择最相关的一个。请直接返回类别名称,无需额外解释!!!
"""
# 加载配置和类别映射
id2name = {i: line.strip() for i, line in enumerate(open(CLASS_FILE, encoding="utf-8"))}
# name2id{标签:索引}
name2id = {v: k for k, v in id2name.items()}
# 创建 LLM 对象
llm = ChatOpenAI(
base_url=BASE_URL,
api_key=DEEPSEEK_API_KEY,
model="deepseek-chat",
model_kwargs={"response_format": {"type": "json_object"}}
)
# 定义带重试机制的 LLM 调用函数
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2))
def invoke_llm(prompt):
"""调用 LLM
# stop_after_attempt若失败则重试最多3次
# wait_fixed每次间隔2秒"""
return llm.invoke(prompt)
# 调用模型进行新闻标题分类获取响应
def get_deepseek_res(title: str) -> dict:
"""将新闻标题分类到指定类别,返回分类结果"""
# 定义提示词,包含类别说明和示例
prompt = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"新闻标题:'{title}',请分类并说明原因。"}
]
# print(prompt) # [{"role":'system',"content":提示词},{"role":'user',"content":''体验2D巅峰 倚天屠龙记十大创新概览''}]
# 调用 LLM 获取分类结果
response = invoke_llm(prompt)
result = json.loads(response.content)
# 返回分类结果,包含类别和原因
return {
"category": result.get("category", "society"), # 默认 社会society
"reason": result.get("reason", "未明确分类,归为社会类别")
}
# 分类并进行评估
def evaluate_classification():
"""对新闻标题分类进行评估"""
# 读取 tab 分隔的新闻标题和标签数据
df = pd.read_csv(DEV2FILE, sep='\t', header=None, names=['title', 'label'], encoding='utf-8')
# 拆包
titles = df['title'].tolist()
labels = df['label'].tolist()
print("titles-->", titles)
print("labels-->", labels)
# 如果多的话,只测试前 2 个
# titles = titles[:2]
# labels = labels[:2]
# 定义列表用于存储预测结果
pred_labels = []
# 遍历所有的标题,依次调用get_deepseek_res
for title in titles:
# 调用大模型获取结果
category_dict = get_deepseek_res(title)
print('category_dict-->', category_dict) # {'category': 'game', 'reason': '游戏'}...{'category': 'society', 'reason': '社会'}
# 获取预测类别,如果没有默认设置,则默认为 society社会
pred_category = category_dict.get("category", "society")
print('pred_category-->', pred_category) # game...society
# 添加到预测结果列表中 注意: name2id格式{标签:索引}
pred_labels.append(name2id[pred_category])
# 最终打印或者返回预测结果
print('pred_labels-->', pred_labels) # [8,5]
# 准确率
print('accuracy_score-->', accuracy_score(pred_labels, labels))
# 测试
if __name__ == '__main__':
# 测试评估
evaluate_classification()