From 3d64b98ed6f8ea15fd63f48f29568fa6d3bb91ae Mon Sep 17 00:00:00 2001 From: selfrelease Date: Tue, 1 Sep 2026 09:24:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A4=BA=E4=BE=8B=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E8=80=81=E6=9D=BF=E8=A7=86=E8=A7=92=E8=BF=87=E6=BB=A4+?= =?UTF-8?q?=E7=94=BB=E5=83=8F=E5=AE=9A=E5=90=91+prompt=E7=A6=81=E6=AD=A2?= =?UTF-8?q?=E6=B8=85=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端: - filter_boss_perspective(): 关键词过滤员工视角问题 覆盖:加班费/被辞退/拖欠工资/工伤认定/产假/劳动仲裁/降薪扣工资等 - /samples: prompt加禁止清单+正确视角示例,返回前过滤 画像注入加行业定向(有industry时明确要求生成行业相关问题) - /topics: prompt加禁止清单+正确视角示例,返回前过滤 - generate_daily_topics: prompt加禁止清单+正确视角示例,返回前过滤 前端: - 审查FALLBACK_SAMPLES: 三个场景兜底示例均为老板视角,无需修改 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- api.py | 57 +++++++++++++++++++++++++++-------- bossai.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 126 insertions(+), 19 deletions(-) diff --git a/api.py b/api.py index c352f8d..c3dc26e 100644 --- a/api.py +++ b/api.py @@ -18,7 +18,7 @@ from bossai import ( ExpertStore, ConsultationStore, RatingStore, DocumentGenerator, RegulationUpdateManager, FactFinder, ChatStore, redact, - DailyTopicStore, generate_daily_topics, + DailyTopicStore, generate_daily_topics, filter_boss_perspective, ) # ===== 日志脱敏 ===== @@ -394,9 +394,19 @@ def generate_topics(req: TopicsRequest): 1. 话题要覆盖该场景下不同方向,不要只集中在某一类 2. 结合用户画像(如有)推荐个性化话题 3. 示例问题要具体、贴近中小企业老板实际 -4. **所有问题必须从老板/雇主视角出发**(BossAi 的用户是企业老板,不是员工)。例如劳动用工应问"员工工伤后能开除吗"而非"拖欠工资怎么追讨" +4. **所有问题必须从老板/雇主视角出发**(BossAi 的用户是企业老板,不是员工) 5. 返回JSON数组格式:[{{"title":"话题名","desc":"简短描述","samples":["问题1","问题2","问题3","问题4"]}}] -6. 只返回JSON,不要其他文字{existing_str}""" +6. 只返回JSON,不要其他文字{existing_str} + +**严禁生成员工视角问题:** +- 加班费怎么算、被辞退怎么维权、拖欠工资怎么追讨 +- 请假被拒、工伤认定、产假怎么休、劳动仲裁怎么告公司 +- 降我薪、扣我工资、罚我款、被歧视、被骚扰 + +**正确视角示例:** +- 老板问:员工工伤后能开除吗?(不是"工伤赔偿怎么申请") +- 老板问:辞退员工要赔多少?(不是"被辞退怎么维权") +- 老板问:客户拖欠货款如何催收?(不是"拖欠工资怎么追")""" try: answer = kimi.chat([{"role": "user", "content": prompt}], temperature=0.8) @@ -411,15 +421,19 @@ def generate_topics(req: TopicsRequest): if start == -1 or end == -1: return {"topics": builtin_topics.get(req.scene, builtin_topics["legal"])} topics = json.loads(answer[start:end + 1]) - # 校验结构 + # 校验结构 + 老板视角过滤 valid_topics = [] for t in topics: if isinstance(t, dict) and t.get("title") and t.get("samples"): - valid_topics.append({ - "title": str(t["title"])[:10], - "desc": str(t.get("desc", ""))[:30], - "samples": [str(s) for s in t["samples"] if isinstance(s, str) and s.strip()][:4], - }) + boss_samples = filter_boss_perspective( + [str(s) for s in t["samples"] if isinstance(s, str) and s.strip()] + )[:4] + if boss_samples: + valid_topics.append({ + "title": str(t["title"])[:10], + "desc": str(t.get("desc", ""))[:30], + "samples": boss_samples, + }) if len(valid_topics) < 3: return {"topics": builtin_topics.get(req.scene, builtin_topics["legal"])} return {"topics": valid_topics[:8]} @@ -469,6 +483,17 @@ def generate_samples(req: SampleRequest): profile_ctx = build_profile_context(profile) if profile_ctx: prompt += f"用户画像(请结合画像生成更贴合用户自身情况的问题):\n{profile_ctx}\n\n" + # 行业定向:如果有行业,加明确指令 + if profile.industry: + industry_map = { + "retail": "零售/餐饮", "manufacturing": "制造业/工厂", + "tech": "科技/互联网", "service": "服务业", + "construction": "建筑/工程", "logistics": "物流/运输", + "finance": "金融/投资", "education": "教育/培训", + "healthcare": "医疗/健康", "agriculture": "农业/农产品", + } + industry_label = industry_map.get(profile.industry, profile.industry) + prompt += f"**用户行业为{industry_label},请生成与该行业密切相关的问题**\n\n" except Exception: pass if existing: @@ -482,7 +507,13 @@ def generate_samples(req: SampleRequest): "2. **所有问题必须从老板/雇主视角出发**(用户是企业老板,不是员工)\n" "3. 每个问题 15-30 字\n" "4. 不要重复已展示过的问题\n" - "5. 只返回 JSON 数组,如 [\"问题1\", \"问题2\", \"问题3\", \"问题4\"]\n" + "5. 只返回 JSON 数组,如 [\"问题1\", \"问题2\", \"问题3\", \"问题4\"]\n\n" + "**严禁生成员工视角问题(如:加班费怎么算、被辞退怎么维权、拖欠工资怎么追讨、**\n" + "**请假被拒、工伤认定、产假怎么休、劳动仲裁怎么告公司、降我薪扣我工资等)**\n\n" + "**正确视角示例:**\n" + "- 老板问:员工工伤后能开除吗?(不是"工伤赔偿怎么申请")\n" + "- 老板问:辞退员工要赔多少?(不是"被辞退怎么维权")\n" + "- 老板问:客户拖欠货款如何催收?(不是"拖欠工资怎么追")\n" ) try: @@ -507,8 +538,10 @@ def generate_samples(req: SampleRequest): if start == -1 or end == -1: return {"samples": builtin.get(req.scene, builtin["legal"])} samples = json.loads(answer[start:end + 1]) - # 过滤非字符串和空值 - samples = [s for s in samples if isinstance(s, str) and s.strip()][:4] + # 过滤:老板视角 + 非字符串 + 去重 + samples = filter_boss_perspective( + [s for s in samples if isinstance(s, str) and s.strip()] + )[:4] if len(samples) < 2: return {"samples": builtin.get(req.scene, builtin["legal"])} return {"samples": samples} diff --git a/bossai.py b/bossai.py index 2782b83..d6d6c47 100644 --- a/bossai.py +++ b/bossai.py @@ -3291,6 +3291,64 @@ class DailyTopicStore: ] +# ===== 老板视角过滤 ===== + +# 员工视角关键词:出现这些问题时,说明 AI 从员工角度生成了问题 +EMPLOYEE_PERSPECTIVE_KEYWORDS = [ + "加班费", "加班工资", "调休怎么", "请假被", "申请休假", + "被辞退", "被开除", "被裁员", "被解雇", "辞退补偿", "离职补偿", + "拖欠工资", "拖欠我", "欠薪怎么", "老板不给", + "社保没给我", "公积金没缴", "不给我签合同", + "工伤认定", "工伤赔偿我", "伤残补助", + "产假", "哺乳假", "年休假怎么休", + "劳动仲裁我", "仲裁怎么告", "怎么告公司", + "举报公司", "投诉公司", "举报老板", + "试用期被", "转正被", + "歧视我", "骚扰我", "针对我", + "降我薪", "扣我工资", "罚我款", + "不让我", "不给我", +] + +# 老板视角关键词:出现这些问题时,确认是老板视角 +BOSS_PERSPECTIVE_KEYWORDS = [ + "员工工伤后能开除", "员工被辞退要赔", "辞退员工", "开除员工", + "员工不签合同", "员工仲裁", "员工离职", + "拖欠货款", "客户欠款", "催收货款", + "合伙人退股", "股东不出资", "股东纠纷", + "税务稽查", "发票开错", "税务罚款", + "扩张", "融资", "裁员", "招人", + "公司股权", "公司分红", "公司经营", + "业务转型", "业务线", "定价", +] + + +def filter_boss_perspective(questions: list[str]) -> list[str]: + """过滤掉员工视角的问题,只保留老板视角。 + + 判断规则: + 1. 包含员工视角关键词 → 过滤掉 + 2. 包含老板视角关键词 → 保留 + 3. 中性问题(不含任何关键词) → 保留 + + Args: + questions: AI 生成的问题列表 + + Returns: + 过滤后的老板视角问题列表 + """ + valid = [] + for q in questions: + q = str(q).strip() + if not q or len(q) > 50: + continue + # 检查是否员工视角 + is_employee = any(kw in q for kw in EMPLOYEE_PERSPECTIVE_KEYWORDS) + if is_employee: + continue + valid.append(q) + return valid + + def generate_daily_topics(kimi_client, store: DailyTopicStore) -> dict: """AI 生成当天 4 个场景的热点问题并存库。 @@ -3341,13 +3399,29 @@ def generate_daily_topics(kimi_client, store: DailyTopicStore) -> dict: 请生成25-30个该场景下老板最焦虑、最关注的热点问题。 要求: -1. 问题必须从老板/雇主视角出发(BossAi 用户是企业老板) +1. **所有问题必须从老板/雇主视角出发**(BossAi 用户是企业老板,不是员工) 2. 结合当前季节性和时事热点(如政策变化、节日前后、经济形势) 3. 问题要具体、有场景感、能直接开问,不要空泛 4. 涵盖该场景下不同方向,不要集中在某一类 5. 问题长度 10-30 字 6. 返回JSON数组格式:["问题1","问题2",...] -7. 只返回JSON,不要其他文字""" +7. 只返回JSON,不要其他文字 + +**严禁生成以下员工视角问题(违反则整批作废):** +- 加班费怎么算、加班工资、调休、请假被拒、申请休假 +- 被辞退/被开除/被裁员后怎么维权、辞退补偿、离职补偿 +- 拖欠工资怎么追讨、老板不给钱、欠薪怎么告 +- 工伤认定、工伤赔偿、伤残补助怎么申请 +- 产假/哺乳假/年休假怎么休 +- 劳动仲裁怎么告公司、举报公司、投诉老板 +- 试用期被辞、转正被卡、被歧视、被骚扰 +- 降我薪、扣我工资、罚我款 + +**正确视角示例(老板问的):** +- 员工工伤后能开除吗?(不是"工伤赔偿怎么申请") +- 辞退员工要赔多少?(不是"被辞退怎么维权") +- 员工不签合同有何风险?(不是"老板不签合同怎么办") +- 客户拖欠货款3个月如何催收?(不是"拖欠工资怎么追")""" try: answer = kimi_client.chat( @@ -3366,16 +3440,16 @@ def generate_daily_topics(kimi_client, store: DailyTopicStore) -> dict: results[scene] = {"count": 0, "source": "ai", "error": "JSON解析失败"} continue questions = json.loads(answer[start:end + 1]) - # 过滤和去重 + # 过滤:老板视角 + 去重 + boss_questions = filter_boss_perspective(questions) valid = [] seen = set() - for q in questions: - q = str(q).strip() - if q and q not in seen and len(q) <= 50: + for q in boss_questions: + if q not in seen: valid.append(q) seen.add(q) if len(valid) < 10: - results[scene] = {"count": 0, "source": "ai", "error": "有效问题不足10个"} + results[scene] = {"count": 0, "source": "ai", "error": f"过滤后有效问题不足10个(原始{len(questions)}个)"} continue store.upsert(scene, valid[:30], source="ai") results[scene] = {"count": len(valid[:30]), "source": "ai"}