From 20c7d1a25fd2dffafd76310e3ed0de778026bc72 Mon Sep 17 00:00:00 2001 From: "qinyong@9artedu.com" Date: Tue, 14 Jul 2026 16:29:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=84=8F=E5=9B=BE=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/chat_qa/classification/intent_test.py | 181 +++--- app/chat_qa/classification/qa.json | 31 + app/chat_qa/classification/qa.txt | 574 ++++++++++++++++++ app/chat_qa_query/query_graph.py | 2 +- app/chat_qa_query/query_nodes/node_rewrite.py | 91 +-- .../query_nodes/node_search_embedding.py | 2 +- app/chat_qa_query/query_qa_state.py | 2 +- .../intent_classification_repository.py | 125 ++++ 8 files changed, 894 insertions(+), 114 deletions(-) create mode 100644 app/chat_qa/classification/qa.json create mode 100644 app/chat_qa/classification/qa.txt create mode 100644 app/repository/milvus/intent_classification_repository.py diff --git a/app/chat_qa/classification/intent_test.py b/app/chat_qa/classification/intent_test.py index 8f3b0f9..8dea6fb 100644 --- a/app/chat_qa/classification/intent_test.py +++ b/app/chat_qa/classification/intent_test.py @@ -1,91 +1,119 @@ import asyncio -from typing import List, Dict, Any +import json +from pathlib import Path +from typing import Dict, List from app.repository.milvus.intent_classification_repository import IntentClassificationRepository from app.client.embedding_client_manager import embedding_client +from app.client.milvus_client_manager import milvus_client -INTENT_DATA = { - "课程内容": [ - "课程针对零基础,涵盖动作设计、场景建模等方向,推荐游戏动画方向,并建议考虑场景建模以规避美术基础劣势。", - "UE5相关有3门课(场景建模地编、UE特效、UE开发),但'人物动起来'属于动作课,不使用虚幻,用3dmax/Maya,仅线下班,周期6个月,学费31800元。" - ], - "其他": [ - "课程覆盖游戏设计全流程,特效线上课8-10个月,每周2-3次直播(晚7:30-9:30),提供录播和答疑,费用11800元。特效行业需求大,薪资6000-9000元起,需自身具备制作能力,AI是工具而非替代,可推荐就业。", - "UE5相关有3门课(场景建模地编、UE特效、UE开发),但'人物动起来'属于动作课,不使用虚幻,用3dmax/Maya,仅线下班,周期6个月,学费31800元。" - ], - "就业支持": [ - "课程周期8-10个月,当前班级(5月14日开课)预计12月结业。内推渠道包括公司自留岗位和合作企业,就业老师会按学历、技术、城市、薪资匹配,测试流程3-5个工作日,并提供面试辅导。", - "有专门就业老师负责对接,提供内推服务。" - ], - "开班时间": [ - "销售邀请用户于6月1日前入班学习,新班将于6.1开课,用户可据此安排时间。", - "人满即止,七月份班已有两三人。" - ], - "费用咨询": [ - "第九联盟(点晴科技)提供线上课程11800元/8-10个月和线下课程33800元/6个月全日制,大学生可线上+寒暑假线下结合(按线下收费)。支持包括3年回放和答疑、重读机会,以及简历辅导、模拟面试、测试指导、校招群内推等服务。", - "课程方案有:31800元/7个月全日制;11800元/8-10个月。" - ], - "校区地址": [ - "西安有分校区授课;上海总部授课;武汉校区仅做项目(不授课),并非关闭;青岛、厦门、合肥、漯河分公司也仅做项目。", - "机构名称为第九联盟,地址在漕河泾,是点晴科技旗下品牌,主营游戏动漫美术人才孵化。" - ], - "退款政策": ['原画对新人要求高,需原创和设计能力,建议造型能力强者考虑角色建模。退款政策:7天无理由全额退款,8-30天退一半,超过30天不退,可休学。', '7天无理由退全款,30天内退一半,之后不退。', '5月27日起7天内可无理由全额退款。'], - "优惠活动": [ - "是的,如果尾款不连续交满6个月则没有优惠,需补尾款19800元(原价31800元减去已付12000元)。", - "报名线下班会额外赠送一套线上正式课程,线上课程可让学生在校提前打基础,寒暑假可集中线下学习直接入班。该课程也可以结合线上内容赶时间进度。" - ], - "报名流程": [ - "两种模式:先线上后补差价转线下,或直接全款预留线下位置。线上课程8-10个月,学费11800元,含直播(每周三次,19:30-21:30)、录播、老师答疑及就业辅导。", - "需要填写姓名、学历、学校、城市、出生日期、学习目的、联系方式等信息。" - ], - "报到时间": [ - "建议与家人确定后尽早来。" - ], - "住宿咨询": [ - "合作宿舍约1000元/月,4/6人间,按空房分配。", - "不需要,上海有宿舍可选,分4人间和6人间,费用约1000元/月;也可以自行租房,单间费用约2000-3000元/月。" - ], - "上课方式": ['可寒暑假线下累积学习(7-8个月),在校期间免费开通线上班辅助', '可寒暑假线下累积学习(7-8个月),在校期间免费开通线上班辅助'], - "职业方向": [ - "动画特效岗适合基础;地编需综合能力,可从模型岗转;TA难度大需美术+代码。课程为6个月线下周一至周五上课,就业方向以游戏行业为主,有学生入职腾讯、网易、米哈游的案例。" - ], - "课程建议": [ - "动画特效岗适合基础;地编需综合能力,可从模型岗转;TA难度大需美术+代码。课程为6个月线下周一至周五上课,就业方向以游戏行业为主,有学生入职腾讯、网易、米哈游的案例。" - ] -} +QA_JSON_PATH = Path(__file__).parent / "qa.json" -async def insert_intent_data(): +def parse_qa_json(file_path: Path = None) -> Dict[str, List[str]]: + """ + 解析 qa.json 文件,key 对应 intent_category,value 对应 content + """ + if file_path is None: + file_path = QA_JSON_PATH + + print(f"读取文件: {file_path}") + + if not file_path.exists(): + print(f"文件不存在: {file_path}") + return {} + + content = file_path.read_text(encoding="utf-8") + + try: + data = json.loads(content) + except json.JSONDecodeError as e: + print(f"JSON 解析失败: {e}") + return {} + + result: Dict[str, List[str]] = {} + for key, value in data.items(): + if isinstance(value, str): + result[key] = [value] + elif isinstance(value, list): + result[key] = [str(item) for item in value] + else: + result[key] = [json.dumps(value, ensure_ascii=False)] + + print(f"解析成功,共 {len(result)} 个类别") + return result + + +async def insert_intent_data(intent_data: Dict[str, List[str]] = None): """ 将意图分类数据入库到Milvus """ + if intent_data is None: + intent_data = parse_qa_json() + + if not intent_data: + print("没有数据可入库") + return [] + repo = IntentClassificationRepository() - + milvus_client.init() + repo.create_collection() - + all_data = [] all_contents = [] - - for category, contents in INTENT_DATA.items(): + + for category, contents in intent_data.items(): for content in contents: all_data.append({ "intent_category": category, "content": content }) all_contents.append(content) - - print(f"开始向量化 {len(all_contents)} 条内容...") - vectors = await embedding_client.aembed_documents(all_contents) - print(f"向量化完成") - + + total = len(all_contents) + print(f"开始向量化 {total} 条内容...") + + batch_size = 5 + all_vectors = [] + for start in range(0, total, batch_size): + end = min(start + batch_size, total) + batch = all_contents[start:end] + batch_num = start // batch_size + 1 + total_batches = (total + batch_size - 1) // batch_size + print(f" 向量化批次 {batch_num}/{total_batches}: {len(batch)} 条") + + vectors = await embedding_client.aembed_documents(batch) + print(f" 返回 {len(vectors)} 个向量") + + if len(vectors) != len(batch): + print(f" 警告: 向量数量不匹配 (期望 {len(batch)}, 实际 {len(vectors)}),尝试逐条向量化") + for single_text in batch: + single_vector = await embedding_client.aembed_documents([single_text]) + if single_vector: + all_vectors.append(single_vector[0]) + print(f" 单条成功: {single_text[:30]}...") + else: + print(f" 单条失败,跳过: {single_text[:30]}...") + else: + all_vectors.extend(vectors) + + print(f"向量化完成,共 {len(all_vectors)} 个向量") + + if len(all_vectors) != len(all_data): + print(f"警告: 向量数量({len(all_vectors)})与数据数量({len(all_data)})不匹配,仅入库成功的数据") + all_data = all_data[:len(all_vectors)] + for i, item in enumerate(all_data): - item["content_vector"] = vectors[i] - - ids = await repo.save_intent_data(all_data) - print(f"入库成功,插入 {len(ids)} 条记录") - - return ids + item["content_vector"] = all_vectors[i] + + try: + ids = await repo.save_intent_data(all_data) + print(f"入库成功,插入 {len(ids)} 条记录") + return ids + finally: + await embedding_client.close() async def query_by_category(category: str): @@ -96,17 +124,22 @@ async def query_by_category(category: str): results = await repo.search_by_intent_category(category) print(f"\n查询 '{category}' 结果:") for i, item in enumerate(results): - print(f" {i+1}. {item.get('content', '')[:50]}...") + print(f" {i+1}. {item.get('content', '')[:80]}...") async def main(): - print("=== 意图分类数据入库 ===") - await insert_intent_data() - - # print("\n=== 查询测试 ===") - # await query_by_category("课程内容") - # await query_by_category("就业支持") - # await query_by_category("费用咨询") + print("=== 读取 qa.json 并入库 ===") + + intent_data = parse_qa_json() + + if intent_data: + print(f"\n解析到的类别 ({len(intent_data)} 个):") + for category, contents in intent_data.items(): + print(f" {category}: {len(contents)} 条内容") + for content in contents: + print(f" -> {content[:80]}...") + + await insert_intent_data(intent_data) if __name__ == "__main__": diff --git a/app/chat_qa/classification/qa.json b/app/chat_qa/classification/qa.json new file mode 100644 index 0000000..a738d6a --- /dev/null +++ b/app/chat_qa/classification/qa.json @@ -0,0 +1,31 @@ +{ + "公司介绍": "[\"母公司:点睛科技,成立于2013年,是一家专业的数字艺术教育机构。旗下品牌:第九联盟和GGAC,专注于CG游戏、动漫、影视等数字艺术教育,提供原画、3D建模、动画、特效等核心课程,与腾讯、网易、米哈游、盛趣、莉莉丝等数百家游戏企业有人才合作,校区分布有上海、西安、青岛、厦门等校区地址,相关网站:https://www.alchemyart.com.cn/ 、https://9artedu.com/ 、https://www.ggac.com/home\"]", + "课程咨询": "[\"3D建模、2D原画、动作/分镜、游戏特效、开发、3D大师课、GGAC绘啦课程、兴趣/提升班等课程体系,课程不同相关的价格和内容也有所不同,如果需要了解某一个课程,请告诉我课程名称\"]", + "3D建模": "{\"3D场景建模\": {\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"7个月\", \"价格\": \"31800元\"}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"回校开通线上直播与答疑学习服务\"]}], \"课程介绍链接\": \"https://www.9artedu.com/3d/\"}, \"3D角色建模\": {\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"8个月\", \"价格\": \"33800元\"}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"33800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"回校开通线上直播与答疑学习服务\"]}], \"课程介绍链接\": \"https://www.9artedu.com/3d-role/\"}}", + "3D场景建模": "{\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"7个月\", \"价格\": \"31800元\"}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"回校开通线上直播与答疑学习服务\"]}], \"课程介绍链接\": \"https://www.9artedu.com/3d/\"}", + "3D角色建模": "{\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"8个月\", \"价格\": \"33800元\"}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"33800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"回校开通线上直播与答疑学习服务\"]}], \"课程介绍链接\": \"https://www.9artedu.com/3d-role/\"}", + "2D原画": "{\"2D角色原画\": {\"二次元风格\": {\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"31800元\"}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校开通线上直播与答疑学习服务\"]}]}, \"写实风格\": {\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"31800元\", \"备注\": [\"项目组实训教学\"]}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校开通线上直播与答疑学习服务\"]}]}, \"介绍链接\": \"https://www.9artedu.com/2d\"}}", + "二次元风格": "{\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"31800元\"}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校开通线上直播与答疑学习服务\"]}]}", + "写实风格": "{\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"31800元\", \"备注\": [\"项目组实训教学\"]}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"8-10个月\", \"价格\": \"11800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校开通线上服务\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校开通线上直播与答疑学习服务\"]}]}", + "动作/分镜": "{\"游戏动作/分镜\": {\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"33800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校提供线上答疑指导\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校做练习提供线上答疑指导服务\"]}], \"介绍链接\": \"https://www.9artedu.com/animation/\"}}", + "游戏动作/分镜": "{\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"33800元\"}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校提供线上答疑指导\", \"价格\": \"31800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校做练习提供线上答疑指导服务\"]}], \"介绍链接\": \"https://www.9artedu.com/animation/\"}", + "开发": "{\"UE引擎开发\": {\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"33800元\", \"备注\": [\"以线下学习时间为主,回校开通线上直播与答疑学习服务\"]}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校提供线上答疑指导\", \"价格\": \"33800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校做练习提供线上答疑指导服务\"]}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"6-8个月\", \"价格\": \"13800元\", \"备注\": [\"白天线上授课及答疑\"]}], \"介绍链接\": \"https://www.9artedu.com/ue/\"}}", + "UE引擎开发": "{\"课程列表\": [{\"课程类型\": \"线下就业班\", \"学习时长\": \"6个月\", \"价格\": \"33800元\", \"备注\": [\"以线下学习时间为主,回校开通线上直播与答疑学习服务\"]}, {\"课程类型\": \"线上线下结合就业班\", \"学习时长\": \"线下寒暑假学习,回校提供线上答疑指导\", \"价格\": \"33800元\", \"备注\": [\"限大一大二大三在校生\", \"线下寒暑假学习送线上\", \"以线下学习时间为主,回校做练习提供线上答疑指导服务\"]}, {\"课程类型\": \"线上就业班\", \"学习时长\": \"6-8个月\", \"价格\": \"13800元\", \"备注\": [\"白天线上授课及答疑\"]}], \"介绍链接\": \"https://www.9artedu.com/ue/\"}", + "3D大师课": "{\"介绍\": \"第九联盟联合十余位3D美术大咖,针对紧缺技术方向设课。涵盖场景、角色、Blender动画全流程,16位老师精讲11大主题,直播可回放,赠入门课,总课时超300小时。\", \"课程形式\": \"直播教学、同步录播\", \"课程链接\": {\"第三期\": \"https://www.huilahujila.com/3ddsk3.0/pc/\", \"第二期\": \"https://www.ggac.com/v2/edu/dsk\", \"第一期\": \"http://m.9artedu.com/\"}, \"合适人群\": [\"在校大学生\", \"在职从业者\", \"兴趣爱好\", \"预算较少\"], \"课程设置\": {\"基础课\": [\"软件基础教学\", \"结合案例、物件制作\"], \"进阶课\": [\"深度系统教学,直播+录播+答疑,性价比高非常适合小白\", \"多个流行技术点\"], \"就业课\": \"邀请行业大厂hr和制作负责人进行就业分享\"}, \"优势\": [\"价格实惠 - 1500-2500\", \"性价比高\", \"顶尖师资\", \"系统化全流程教学\"], \"费用\": \"1580-2500\"}", + "GGAC绘殓课程": "{\"造型力\": {\"课程详细链接\": \"https://www.9artedu.com/xinqi/\", \"适合人群\": [\"从业者提升\", \"美院学生\"], \"费用\": {\"旁听席(不单独改作业)\": \"4500元\", \"vip\": \"6800元\"}}, \"大学生扶持计划\": {\"课程亮点\": [\"一线大厂亲授,全流程实战,直播可回放,作业答疑超值。\"], \"适合人群\": [\"预算少\", \"在校生\", \"兴趣学生\", \"作品集\"], \"优势\": [\"费用低\", \"师资强\", \"服务号\", \"系统教学\"], \"费用\": \"2500元\", \"链接\": \"\"}}", + "造型力": "{\"课程详细链接\": \"https://www.9artedu.com/xinqi/\", \"适合人群\": [\"从业者提升\", \"美院学生\"], \"费用\": {\"旁听席(不单独改作业)\": \"4500元\", \"vip\": \"6800元\"}}", + "大学生扶持计划": "{\"课程亮点\": [\"一线大厂亲授,全流程实战,直播可回放,作业答疑超值。\"], \"适合人群\": [\"预算少\", \"在校生\", \"兴趣学生\", \"作品集\"], \"优势\": [\"费用低\", \"师资强\", \"服务号\", \"系统教学\"], \"费用\": \"2500元\", \"链接\": \"\"}", + "兴趣/提升班": "{\"线下面授\": [{\"时长\": \"2个月\", \"价格\": \"13800元\"}, {\"时长\": \"3个月\", \"价格\": \"19800元\"}], \"备注\": \"无推荐就业服务\"}", + "学习模式": "{\"线下面授教学\": {\"上课时间\": {\"时段\": \"9:30-18:00\", \"日期\": \"周一到周五\"}, \"自习时间\": {\"时段\": \"18:00-22:30\", \"安排\": \"周末自行安排\", \"备注\": \"入学录入指纹,学员可随时自行出入\"}}, \"线上直播教学\": {\"上课时间\": {\"课次\": \"135或245晚\", \"时段\": \"19:30-21:30\"}, \"直播教学\": \"最多跟两期\", \"同步录播\": \"反复回放,永久有效\"}, \"寒暑假\": {\"上课形式\": {\"假期安排\": \"寒暑假线下面授教学\", \"回校安排\": \"回校开通线上直播、录播课程持续学习,线上答疑与指导\", \"上课时间\": \"同线上模式\"}, \"课时统计\": \"以线下实际授课市场为准,线上赠送\"}}", + "线下面授教学": "{\"上课时间\": {\"时段\": \"9:30-18:00\", \"日期\": \"周一到周五\"}, \"自习时间\": {\"时段\": \"18:00-22:30\", \"安排\": \"周末自行安排\", \"备注\": \"入学录入指纹,学员可随时自行出入\"}}", + "线上直播教学": "{\"上课时间\": {\"课次\": \"135或245晚\", \"时段\": \"19:30-21:30\"}, \"直播教学\": \"最多跟两期\", \"同步录播\": \"反复回放,永久有效\"}", + "寒暑假教学": "{\"上课形式\": {\"假期安排\": \"寒暑假线下面授教学\", \"回校安排\": \"回校开通线上直播、录播课程持续学习,线上答疑与指导\", \"上课时间\": \"同线上模式\"}, \"课时统计\": \"以线下实际授课市场为准,线上赠送\"}", + "提供服务": "{\"基础服务\": [\"住宿推荐与对接\", \"保险\", \"职业规划建议\"], \"多对一教学服务\": {\"服务角色\": [\"教学老师\", \"班主任\", \"就业老师\"]}, \"就业相关服务\": [\"就业推荐\", \"项目化作品实训\", \"游戏公司氛围\", {\"实习章\": \"学习2个月以后\"}]}", + "优势/竞争力": "{\"公司\": {\"规模\": [\"公司成立12年\", \"700多人\", \"全国6家分公司\", \"公司整体规模比所有纯培训机构都大,靠谱,不像刚成立不久的小公司可能经营不好随时跑路倒闭\"], \"资质\": [\"坐拥多项市级权威资质,规模实力远非同行可比。\"], \"专业\": [\"游戏公司背景,大厂合作认证,深耕行业,品质实力保障。\"], \"口碑\": [\"公司特别注重口碑,每一个业务和品牌再行业内都有非常好的口碑,可以网上了解一下或者找行业内懂的人打听一下\"]}, \"就业资源\": [\"合作数百家游戏企业,就业资源丰富,毕业渠道更广。\"], \"氛围\": {\"上课\": [\"游戏公司环境,上课氛围完全区别于传统培训机构\"], \"游戏公司氛围\": [\"年轻,活力,轻松,开放\"]}}", + "校区分布": "{\"上海\": {\"地址\": \"上海市徐汇区桂箐路7号3号楼3楼\", \"课程\": [\"原画角色设计\", \"3d场景建模\", \"3d角色建模\", \"游戏动画/分镜\", \"游戏特效\", \"引擎开发\"]}, \"西安\": {\"地址\": \"西安市浐灞生态区兴泰南路1555号发展大厦16层\", \"课程\": [\"场景建模\", \"角色建模\", \"特效\", \"动画\", \"角色原画\"]}, \"青岛\": {\"地址\": \"青岛市长江中路519号建国大厦1604室\", \"课程\": [\"场景建模\"]}, \"厦门\": {\"地址\": \"厦门市思明区前埔东路1733号万科创想中心A座\", \"课程\": [\"场景建模\"], \"备注\": \"仅寒暑假\"}}", + "退费咨询": "{\"标准\": {\"计算方式\": \"缴费日起计算\", \"规则\": [\"不含缴费但未进班\", \"不含缴费但线上课程为学习超5课时\", \"7天无理由退费\", \"7-30日 退50%\", \"超过30天 不退\"]}, \"特殊情况\": \"如因自身原因无法学习,可休学,保留学习权限\"}", + "住宿咨询": "{\"对接说明\": \"为了学生方便我们合作的公寓,尽可能协调,但可太挑;学生也可以自己找住宿\", \"环境\": \"4-6人间,上下铺,多数为4人间\", \"费用\": {\"房租\": \"800-1200之间\", \"水电网\": \"未标注\"}, \"优势\": {\"方便(省心)\": [\"可随时拎包入住\", \"毕业或返校按天计算,不扣押金,不为住满月费用\"], \"安全便捷(安心)\": [\"离学校1-2公里以内,5-10分钟到达\", \"室友都是第九联盟学生,无社会人同住\", \"大多为在校生或应届毕业生,素质层次相同\", \"有问题第九联盟老师可以协助沟通协调\"], \"实惠(放心)\": [\"价格便宜\", \"按照公寓原价给学生分摊没有中间商赚差价\", \"没住满或空房,第九联盟为学员补贴\"]}}", + "学不会怎么办": "{\"就业情况说明\": \"多年办学,学员认真学基本都能就业。学得好进大厂月薪1-2万,一般4-8千,差的先入行积累经验再跳槽。能力决定薪资,我们与学员共成长。\", \"前提\": [\"不经常逃课\", \"不做练习和作品\"], \"方案\": [\"只要认真学习,按照老师的节奏来,真没学会我们认为是我们自己的问题,可以免费重修,个别同学基础差点,接受能力慢点,一般跟着老师继续多学1-2个月都能就业,再不济也可以免费重修一期\", \"合同里面有关于不就业和重修的承诺来保证学员学习效果和权益\"], \"工资多少\": [\"平均工资4-8千之间\", \"部分学得好的,进大厂的1-2万之间\"]}", + "就业咨询": "{\"核心说明\": \"不包就业,我们推荐就业\"}", + "学历咨询": "{\"大厂态度\": \"大厂会看学历,技术优先,如果技术足够强可以降低学历要求\", \"学历优势\": \"当然你学历好技术也好的话有优势的\"}" +} \ No newline at end of file diff --git a/app/chat_qa/classification/qa.txt b/app/chat_qa/classification/qa.txt new file mode 100644 index 0000000..623b6c1 --- /dev/null +++ b/app/chat_qa/classification/qa.txt @@ -0,0 +1,574 @@ +{ + "公司介绍": [ + "母公司:点睛科技,成立于2013年,是一家专业的数字艺术教育机构。旗下品牌:第九联盟和GGAC,专注于CG游戏、动漫、影视等数字艺术教育,提供原画、3D建模、动画、特效等核心课程,与腾讯、网易、米哈游、盛趣、莉莉丝等数百家游戏企业有人才合作,校区分布有上海、西安、青岛、厦门等校区地址,相关网站:https://www.alchemyart.com.cn/ 、https://9artedu.com/ 、https://www.ggac.com/home" + ], + "课程咨询": [ + "3D建模、2D原画、动作/分镜、游戏特效、开发、3D大师课、GGAC绘啦课程、兴趣/提升班等课程体系,课程不同相关的价格和内容也有所不同,如果需要了解某一个课程,请告诉我课程名称" + ], + "3D建模": { + "3D场景建模": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "7个月", + "价格": "31800元" + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "回校开通线上直播与答疑学习服务" + ] + } + ], + "课程介绍链接": "https://www.9artedu.com/3d/" + }, + "3D角色建模": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "8个月", + "价格": "33800元" + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "33800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "回校开通线上直播与答疑学习服务" + ] + } + ], + "课程介绍链接": "https://www.9artedu.com/3d-role/" + } + }, + "3D场景建模": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "7个月", + "价格": "31800元" + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "回校开通线上直播与答疑学习服务" + ] + } + ], + "课程介绍链接": "https://www.9artedu.com/3d/" + }, + "3D角色建模": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "8个月", + "价格": "33800元" + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "33800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "回校开通线上直播与答疑学习服务" + ] + } + ], + "课程介绍链接": "https://www.9artedu.com/3d-role/" + }, + "2D原画": { + "2D角色原画": { + "二次元风格": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "31800元" + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校开通线上直播与答疑学习服务" + ] + } + ] + }, + "写实风格": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "31800元", + "备注": [ + "项目组实训教学" + ] + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校开通线上直播与答疑学习服务" + ] + } + ] + }, + "介绍链接": "https://www.9artedu.com/2d" + } + }, + "二次元风格": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "31800元" + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校开通线上直播与答疑学习服务" + ] + } + ] + }, + "写实风格": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "31800元", + "备注": [ + "项目组实训教学" + ] + }, + { + "课程类型": "线上就业班", + "学习时长": "8-10个月", + "价格": "11800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校开通线上服务", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校开通线上直播与答疑学习服务" + ] + } + ] + }, + "动作/分镜": { + "游戏动作/分镜": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "33800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校提供线上答疑指导", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校做练习提供线上答疑指导服务" + ] + } + ], + "介绍链接": "https://www.9artedu.com/animation/" + } + }, + "游戏动作/分镜": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "33800元" + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校提供线上答疑指导", + "价格": "31800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校做练习提供线上答疑指导服务" + ] + } + ], + "介绍链接": "https://www.9artedu.com/animation/" + }, + "开发": { + "UE引擎开发": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "33800元", + "备注": [ + "以线下学习时间为主,回校开通线上直播与答疑学习服务" + ] + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校提供线上答疑指导", + "价格": "33800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校做练习提供线上答疑指导服务" + ] + }, + { + "课程类型": "线上就业班", + "学习时长": "6-8个月", + "价格": "13800元", + "备注": [ + "白天线上授课及答疑" + ] + } + ], + "介绍链接": "https://www.9artedu.com/ue/" + } + }, + "UE引擎开发": { + "课程列表": [ + { + "课程类型": "线下就业班", + "学习时长": "6个月", + "价格": "33800元", + "备注": [ + "以线下学习时间为主,回校开通线上直播与答疑学习服务" + ] + }, + { + "课程类型": "线上线下结合就业班", + "学习时长": "线下寒暑假学习,回校提供线上答疑指导", + "价格": "33800元", + "备注": [ + "限大一大二大三在校生", + "线下寒暑假学习送线上", + "以线下学习时间为主,回校做练习提供线上答疑指导服务" + ] + }, + { + "课程类型": "线上就业班", + "学习时长": "6-8个月", + "价格": "13800元", + "备注": [ + "白天线上授课及答疑" + ] + } + ], + "介绍链接": "https://www.9artedu.com/ue/" + }, + "3D大师课": { + "介绍": "第九联盟联合十余位3D美术大咖,针对紧缺技术方向设课。涵盖场景、角色、Blender动画全流程,16位老师精讲11大主题,直播可回放,赠入门课,总课时超300小时。", + "课程形式": "直播教学、同步录播", + "课程链接": { + "第三期": "https://www.huilahujila.com/3ddsk3.0/pc/", + "第二期": "https://www.ggac.com/v2/edu/dsk", + "第一期": "http://m.9artedu.com/" + }, + "合适人群": ["在校大学生", "在职从业者", "兴趣爱好", "预算较少"], + "课程设置": { + "基础课": ["软件基础教学", "结合案例、物件制作"], + "进阶课": ["深度系统教学,直播+录播+答疑,性价比高非常适合小白", "多个流行技术点"], + "就业课": "邀请行业大厂hr和制作负责人进行就业分享" + }, + "优势": ["价格实惠 - 1500-2500", "性价比高", "顶尖师资", "系统化全流程教学"], + "费用": "1580-2500" + }, + "GGAC绘殓课程": { + "造型力": { + "课程详细链接": "https://www.9artedu.com/xinqi/", + "适合人群": ["从业者提升", "美院学生"] + "费用": { + "旁听席(不单独改作业)": "4500元", + "vip": "6800元" + } + }, + "大学生扶持计划": { + "课程亮点": [ + "一线大厂亲授,全流程实战,直播可回放,作业答疑超值。" + ], + "适合人群": ["预算少", "在校生", "兴趣学生", "作品集"], + "优势": ["费用低", "师资强", "服务号", "系统教学"], + "费用": "2500元", + "链接": "" + } + }, + "造型力": { + "课程详细链接": "https://www.9artedu.com/xinqi/", + "适合人群": ["从业者提升", "美院学生"], + "费用": { + "旁听席(不单独改作业)": "4500元", + "vip": "6800元" + } + }, + "大学生扶持计划": { + "课程亮点": [ + "一线大厂亲授,全流程实战,直播可回放,作业答疑超值。" + ], + "适合人群": ["预算少", "在校生", "兴趣学生", "作品集"], + "优势": ["费用低", "师资强", "服务号", "系统教学"], + "费用": "2500元", + "链接": "" + }, + "兴趣/提升班": { + "线下面授": [ + { + "时长": "2个月", + "价格": "13800元" + }, + { + "时长": "3个月", + "价格": "19800元" + } + ], + "备注": "无推荐就业服务" + }, + "学习模式": { + "线下面授教学": { + "上课时间": { + "时段": "9:30-18:00", + "日期": "周一到周五" + }, + "自习时间": { + "时段": "18:00-22:30", + "安排": "周末自行安排", + "备注": "入学录入指纹,学员可随时自行出入" + } + }, + "线上直播教学": { + "上课时间": { + "课次": "135或245晚", + "时段": "19:30-21:30" + }, + "直播教学": "最多跟两期", + "同步录播": "反复回放,永久有效" + }, + "寒暑假": { + "上课形式": { + "假期安排": "寒暑假线下面授教学", + "回校安排": "回校开通线上直播、录播课程持续学习,线上答疑与指导", + "上课时间": "同线上模式" + }, + "课时统计": "以线下实际授课市场为准,线上赠送" + } + }, + "线下面授教学": { + "上课时间": { + "时段": "9:30-18:00", + "日期": "周一到周五" + }, + "自习时间": { + "时段": "18:00-22:30", + "安排": "周末自行安排", + "备注": "入学录入指纹,学员可随时自行出入" + } + }, + "线上直播教学": { + "上课时间": { + "课次": "135或245晚", + "时段": "19:30-21:30" + }, + "直播教学": "最多跟两期", + "同步录播": "反复回放,永久有效" + }, + "寒暑假教学": { + "上课形式": { + "假期安排": "寒暑假线下面授教学", + "回校安排": "回校开通线上直播、录播课程持续学习,线上答疑与指导", + "上课时间": "同线上模式" + }, + "课时统计": "以线下实际授课市场为准,线上赠送" + }, + "提供服务": { + "基础服务": [ + "住宿推荐与对接", + "保险", + "职业规划建议" + ], + "多对一教学服务": { + "服务角色": [ + "教学老师", + "班主任", + "就业老师" + ] + }, + "就业相关服务": [ + "就业推荐", + "项目化作品实训", + "游戏公司氛围", + { + "实习章": "学习2个月以后" + } + ] + }, + "优势/竞争力": { + "公司": { + "规模": [ + "公司成立12年", + "700多人", + "全国6家分公司", + "公司整体规模比所有纯培训机构都大,靠谱,不像刚成立不久的小公司可能经营不好随时跑路倒闭" + ], + "资质": [ + "坐拥多项市级权威资质,规模实力远非同行可比。" + ], + "专业": [ + "游戏公司背景,大厂合作认证,深耕行业,品质实力保障。" + ], + "口碑": [ + "公司特别注重口碑,每一个业务和品牌再行业内都有非常好的口碑,可以网上了解一下或者找行业内懂的人打听一下" + ] + } + "就业资源": [ + "合作数百家游戏企业,就业资源丰富,毕业渠道更广。" + ] + "氛围": { + "上课": [ + "游戏公司环境,上课氛围完全区别于传统培训机构" + ], + "游戏公司氛围": [ + "年轻,活力,轻松,开放" + ] + } + }, +"校区分布": { + "上海": { + "地址": "上海市徐汇区桂箐路7号3号楼3楼", + "课程": ["原画角色设计", "3d场景建模", "3d角色建模", "游戏动画/分镜", "游戏特效", "引擎开发"] + }, + "西安": { + "地址": "西安市浐灞生态区兴泰南路1555号发展大厦16层", + "课程": ["场景建模", "角色建模", "特效", "动画", "角色原画"] + }, + "青岛": { + "地址": "青岛市长江中路519号建国大厦1604室", + "课程": ["场景建模"] + }, + "厦门": { + "地址": "厦门市思明区前埔东路1733号万科创想中心A座", + "课程": ["场景建模"], + "备注": "仅寒暑假" + } + }, + "退费咨询": { + "标准": { + "计算方式": "缴费日起计算", + "规则": [ + "不含缴费但未进班", + "不含缴费但线上课程为学习超5课时", + "7天无理由退费", + "7-30日 退50%", + "超过30天 不退" + ] + }, + "特殊情况": "如因自身原因无法学习,可休学,保留学习权限" + }, + "住宿咨询": { + "对接说明": "为了学生方便我们合作的公寓,尽可能协调,但可太挑;学生也可以自己找住宿", + "环境": "4-6人间,上下铺,多数为4人间", + "费用": { + "房租": "800-1200之间", + "水电网": "未标注" + }, + "优势": { + "方便(省心)": ["可随时拎包入住", "毕业或返校按天计算,不扣押金,不为住满月费用"], + "安全便捷(安心)": [ + "离学校1-2公里以内,5-10分钟到达", + "室友都是第九联盟学生,无社会人同住", + "大多为在校生或应届毕业生,素质层次相同", + "有问题第九联盟老师可以协助沟通协调" + ], + "实惠(放心)": [ + "价格便宜", + "按照公寓原价给学生分摊没有中间商赚差价", + "没住满或空房,第九联盟为学员补贴" + ] + } + }, + "学不会怎么办": { + "就业情况说明": "多年办学,学员认真学基本都能就业。学得好进大厂月薪1-2万,一般4-8千,差的先入行积累经验再跳槽。能力决定薪资,我们与学员共成长。", + "前提": [ + "不经常逃课", + "不做练习和作品" + ], + "方案": [ + "只要认真学习,按照老师的节奏来,真没学会我们认为是我们自己的问题,可以免费重修,个别同学基础差点,接受能力慢点,一般跟着老师继续多学1-2个月都能就业,再不济也可以免费重修一期", + "合同里面有关于不就业和重修的承诺来保证学员学习效果和权益" + ], + "工资多少": [ + "平均工资4-8千之间", + "部分学得好的,进大厂的1-2万之间" + ] + }, + "就业咨询": { + "核心说明": "不包就业,我们推荐就业" + }, + "学历咨询": { + "大厂态度": "大厂会看学历,技术优先,如果技术足够强可以降低学历要求", + "学历优势": "当然你学历好技术也好的话有优势的" + } + +} diff --git a/app/chat_qa_query/query_graph.py b/app/chat_qa_query/query_graph.py index de83287..9f5331f 100644 --- a/app/chat_qa_query/query_graph.py +++ b/app/chat_qa_query/query_graph.py @@ -45,7 +45,7 @@ if __name__ == '__main__': archive_messages_mysql_repository = ArchiveMessagesRepository(db_session) qa_milvus_repository = QARepository() - state: QueryQAState = QueryQAState(original_query="老师这个课程多少钱啊,老师 我想报班,", history=['2026-07-10T15:42:13 EXTERNAL 老师这个课程多少钱啊\n', '2026-07-10T15:40:34 EXTERNAL 老师 我想报班\n']) + state: QueryQAState = QueryQAState(original_query="老师你好,我想咨询一下3d建模费用和就业情况", history=['2026-07-10T15:42:13 EXTERNAL 老师这个课程多少钱啊\n', '2026-07-10T15:40:34 EXTERNAL 老师 我想报班\n']) context = QueryQAContext(meta_mysql_repository=archive_messages_mysql_repository, qa_milvus_repository=qa_milvus_repository ) diff --git a/app/chat_qa_query/query_nodes/node_rewrite.py b/app/chat_qa_query/query_nodes/node_rewrite.py index a909645..770febb 100644 --- a/app/chat_qa_query/query_nodes/node_rewrite.py +++ b/app/chat_qa_query/query_nodes/node_rewrite.py @@ -11,86 +11,105 @@ from app.core.log import logger problem_rewriting_prompt = """ 你是一名智能客服意图分类助手。你的任务是根据用户的历史会话和当前问题,提取用户的核心诉求,并输出标准化的意图标签。 -## 分类规则(必须严格遵守) +## 核心原则(必须严格遵守) -1. **核心诉求提取**: - - 从当前问题中提取用户明确表达的诉求(可能有一个或多个,去重) - - 如果当前问题包含代词(如"这个"、"它"、"那"等),必须结合历史会话进行指代消解,用具体名词替换代词 +### 1. 双维度提取原则 +每个用户问题通常包含两个维度的意图,必须分别识别: +- **课程/服务主题维度**:用户想咨询的具体课程类型或业务主题(如3D建模、2D原画、UE引擎开发等) +- **诉求/动作维度**:用户想了解的方面(如课程咨询、就业咨询、校区分布等) -2. **信息补全**: - - 如果当前问题缺少主语或关键上下文(如只问"费用多少"),必须从历史会话中提取相关主题补全 - - 确保意图标签不依赖历史会话也能被独立理解 +这两个维度相互独立,必须同时提取,不得遗漏任何一个。 -3. **语义保持**: - - 不得改变用户的原始意图 - - 不得引入历史会话中不存在的新信息 - - 不得遗漏当前问题中的任何关键诉求 +### 2. 主题维度提取规则 +- 如果用户明确提到了具体课程名称或类型(如"3D建模"、"2D原画"、"UE引擎开发"),必须作为独立意图标签输出 +- 如果当前问题使用代词(如"这个"、"它"),结合历史会话进行指代消解,还原具体课程名称 +- 如果历史会话中也没有明确课程类型,则不输出主题维度标签 -4. **输出格式**: - - 仅输出JSON,不要任何解释性文字 - - 输出为结构化的意图标签数组,**不要改写成完整问句** - - 每个意图标签应简洁、标准化,适合用于分类路由 - - 多诉求时拆分为多个意图标签,用数组形式输出 +### 3. 诉求维度提取规则 +- 从当前问题中提取用户明确表达的动作诉求(费用、就业、退费、住宿等) +- 将动作诉求映射到标准诉求类型标签 -## 意图标签规范 +### 4. 信息补全与语义保持 +- 如果当前问题缺少主语,从历史会话补全 +- 不得改变用户原始意图,不得引入历史会话中不存在的新信息 +- 不得遗漏当前问题中的任何关键诉求 -- 每个标签格式为:"{{诉求类型}}" -- 常见诉求类型:费用咨询、课程内容、报名流程、就业支持、开班时间、校区地址、优惠活动、退款政策、住宿咨询、其他 -- 标签应简洁、无歧义,便于系统直接匹配路由 -- 从当前问题中提取用户明确表达的诉求,可以提取多个意图标签 +## 输出格式 +- 仅输出JSON,不要任何解释性文字 +- 多诉求时用数组形式输出,每个意图标签独立 +- 标签从以下列表中选择,不得自创: + +**课程/服务主题标签**:公司介绍、3D建模、3D场景建模、3D角色建模、2D原画、二次元风格、写实风格、动作/分镜、游戏动作/分镜、开发、UE引擎开发、3D大师课、GGAC绘殓课程、造型力、大学生扶持计划、兴趣/提升班、学习模式、线下面授教学、线上直播教学、寒暑假教学、提供服务、优势/竞争力、校区分布 + +**诉求/动作标签**:课程咨询、退费咨询、住宿咨询、学不会怎么办、就业咨询、学历咨询 ## 分类示例 -### 示例1(信息补全) +### 示例1(主题+诉求双维度) +历史会话:(空) +当前问题:3D建模培训的课程内容有哪些? +分析:主题="3D建模",诉求="课程内容"→课程咨询 +分类结果: +{{ + "intents": ["3D建模", "课程咨询"] +}} + +### 示例2(主题+诉求双维度,信息补全) 历史会话: - 用户:我想了解游戏特效培训 - 助手:好的,请问您想了解哪方面? 当前问题:培训的费用 +分析:主题从历史会话补全="游戏特效培训",诉求="费用"→课程咨询 分类结果: {{ - "intents": "费用咨询" + "intents": ["课程咨询"] }} -### 示例2(指代消解) +### 示例3(主题+诉求双维度,指代消解) 历史会话: - 用户:你们有Python课程吗? - 助手:有的,我们有Python基础班和进阶班。 当前问题:这个课程的时长是多久? +分析:主题="Python课程",诉求="课程时长"→课程咨询 分类结果: {{ - "intents": ["课程内容", "报名流程"] + "intents": ["课程咨询"] }} -### 示例3(多诉求提取) +### 示例4(多诉求提取) 历史会话: - 用户:我想报名数据分析培训 当前问题:流程、费用和就业支持 +分析:主题="数据分析培训",诉求="流程/费用"→课程咨询,"就业支持"→就业咨询 分类结果: {{ - "intents": ["报名流程"] + "intents": ["课程咨询", "就业咨询"] }} -### 示例4(无需改写) +### 示例5(主题+诉求双维度) 历史会话:(空) -当前问题:Java培训的课程内容有哪些? +当前问题:老师3D大师课课程多少钱啊,老师我想报班 +分析:主题="3D大师课",诉求="多少钱/报班"→课程咨询 分类结果: {{ - "intents": ["课程内容"] + "intents": ["3D大师课", "课程咨询"] }} -### 示例5(用户提供的案例) -历史会话:(空) -当前问题:老师这个课程多少钱啊,老师我想报班 +### 示例6(关键示例:主题必须独立提取) +历史会话: +- 用户:老师 我想报班 +- 用户:老师这个课程多少钱啊 +当前问题:老师我想咨询3D建模费用问题 +分析:主题="3D建模"(当前问题明确提及),诉求="费用问题"→课程咨询 分类结果: {{ - "intents": ["报名流程"] + "intents": ["3D建模", "课程咨询"] }} --- ## 现在请处理以下输入 - 当前问题:{query} 历史聊天:{history_text} 请直接输出JSON: @@ -112,8 +131,6 @@ async def rewrite_query(state:QueryQAState): try: result = await chain.ainvoke({"history_text": history_text, "query": query}) rewritten_query = result.get("intents", "") - if rewritten_query: - rewritten_query = rewritten_query[0] logger.info(f"原问题:{query},历史会话:{history_text},改写后问题:{rewritten_query}") return {"rewritten_query": rewritten_query} except Exception as e: diff --git a/app/chat_qa_query/query_nodes/node_search_embedding.py b/app/chat_qa_query/query_nodes/node_search_embedding.py index 8286a54..7934f62 100644 --- a/app/chat_qa_query/query_nodes/node_search_embedding.py +++ b/app/chat_qa_query/query_nodes/node_search_embedding.py @@ -12,7 +12,7 @@ from app.core.log import logger async def search_embed(state: QueryQAState): logger.info("search_embed") - rewritten_query = state.get("rewritten_query", "") + rewritten_query: List[str] = state.get("rewritten_query", "") original_query = state.get("original_query", "") #batch_embeddings = await embedding_client.aembed_query(rewritten_query) diff --git a/app/chat_qa_query/query_qa_state.py b/app/chat_qa_query/query_qa_state.py index d376c99..59cc0b6 100644 --- a/app/chat_qa_query/query_qa_state.py +++ b/app/chat_qa_query/query_qa_state.py @@ -3,6 +3,6 @@ from typing import TypedDict, List, Dict, Optional, Any class QueryQAState(TypedDict): original_query: str # 原始问题 - rewritten_query: str # 改写后的问题 + rewritten_query: List[str] # 改写后的问题 history: list # 历史对话记录 qa_pairs: Dict[str, Any] # 匹配到的QA对 \ No newline at end of file diff --git a/app/repository/milvus/intent_classification_repository.py b/app/repository/milvus/intent_classification_repository.py new file mode 100644 index 0000000..27c395b --- /dev/null +++ b/app/repository/milvus/intent_classification_repository.py @@ -0,0 +1,125 @@ +from datetime import datetime +from typing import Optional, List, Dict, Any + +from pymilvus import MilvusClient, DataType + +from app.client.milvus_client_manager import milvus_client +from app.conf.app_config import app_config +from app.core.log import logger + + +class IntentClassificationRepository: + collection_name: str = 'intent_classification' + + def __init__(self): + self.dim = app_config.milvus.embedding_size + self._ensure_connection() + + def _ensure_connection(self): + if milvus_client.client is None: + milvus_client.init() + + def create_collection(self, dim: int = None) -> bool: + if dim is not None: + self.dim = dim + + if milvus_client.has_collection(self.collection_name): + return False + + schema = milvus_client.client.create_schema( + auto_id=True, + enable_dynamic_field=True, + description="意图分类向量集合" + ) + + schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True) + schema.add_field(field_name="intent_category", datatype=DataType.VARCHAR, max_length=128) + schema.add_field(field_name="content", datatype=DataType.VARCHAR, max_length=65535) + schema.add_field(field_name="content_vector", datatype=DataType.FLOAT_VECTOR, dim=1024) + schema.add_field(field_name="created_at", datatype=DataType.INT64) + + index_params = milvus_client.client.prepare_index_params() + index_params.add_index( + field_name="content_vector", + index_type="HNSW", + metric_type="COSINE", + params={"M": 32, "efConstruction": 300} + ) + milvus_client.client.create_collection( + collection_name=self.collection_name, + schema=schema, + index_params=index_params + ) + + return True + + async def save_intent_data(self, data: List[Dict[str, Any]]) -> List[int]: + try: + created_at = int(datetime.now().timestamp()) + insert_data = [] + for item in data: + insert_data.append({ + "intent_category": item.get("intent_category", ""), + "content": item.get("content", ""), + "content_vector": item.get("content_vector", []), + "created_at": created_at + }) + + result = milvus_client.client.insert( + collection_name=self.collection_name, + data=insert_data + ) + + logger.info(f"意图分类数据入库成功,插入 {len(data)} 条记录") + return result.get("ids", []) + + except Exception as e: + logger.error(f"意图分类数据入库失败: {str(e)}", exc_info=True) + return [] + + async def search_by_intent_category(self, intent_category: List[str], top_k: int = 100) -> List[Dict[str, Any]]: + if isinstance(intent_category, str): + intent_category = [intent_category] + categories_str = ", ".join(f'"{c}"' for c in intent_category) + expr = f'intent_category in [{categories_str}]' + result = milvus_client.client.query( + collection_name=self.collection_name, + filter=expr, + output_fields=["intent_category", "content", "created_at"], + limit=top_k + ) + return result + + async def search_by_vector(self, query_vector: List[float], top_k: int = 5) -> List[Dict[str, Any]]: + res = milvus_client.client.search( + collection_name=self.collection_name, + anns_field="content_vector", + data=[query_vector], + limit=top_k, + search_params={ + "metric_type": "COSINE", + "efSearch": 300 + }, + output_fields=["intent_category", "content", "created_at"] + ) + + results = [] + for hits in res: + for hit in hits: + item = { + "intent_category": hit.entity.get("intent_category"), + "content": hit.entity.get("content"), + "created_at": hit.entity.get("created_at"), + "score": hit.get("distance", 0) + } + results.append(item) + return results + + async def get_all_intent_categories(self) -> List[str]: + result = milvus_client.client.query( + collection_name=self.collection_name, + output_fields=["intent_category"], + limit=1000 + ) + categories = list(set([item.get("intent_category", "") for item in result])) + return categories \ No newline at end of file