D1正式合并: 后端双模支持(主Dify读intent_type,无字段降级旧路径)+ ai_service透传路由字段 + Dify Prompt v1.3(新增路由意图标注规则+场景4)
This commit is contained in:
+100
-12
@@ -1033,11 +1033,82 @@ async def _step_byod_intercept(db, conversation, employee_id, content, msg_type)
|
||||
return False
|
||||
|
||||
|
||||
async def _step_routing_intercept(db, conversation, employee_id, content, msg_type) -> bool:
|
||||
"""步骤3:非IT业务路由拦截。命中并发送名片返回 True(终止管线)。"""
|
||||
if msg_type != "text" or not routing_keyword_prefilter(content):
|
||||
async def _step_routing_from_result(db, conversation, employee_id, content, result) -> bool:
|
||||
"""步骤3(D1 合并版):从主 Dify 结果读取路由意图,命中则发送名片(终止管线)。
|
||||
|
||||
双模支持:
|
||||
- 主结果含 intent_type 字段(新 Prompt)→ 直接使用,零额外 Dify 调用
|
||||
- 主结果无 intent_type 字段(旧 Prompt 过渡期)→ 降级调 detect_routing_intent(旧路径)
|
||||
|
||||
Returns:
|
||||
bool: True 表示已发送路由名片(终止管线),False 继续正常 AI 流程
|
||||
"""
|
||||
from app.config import settings
|
||||
|
||||
intent_type = result.get("intent_type")
|
||||
|
||||
# 兼容模式:主 Dify 未输出路由字段(Prompt 未更新)→ 旧路径兜底
|
||||
if intent_type is None:
|
||||
logger.info("[D1] 主结果无 intent_type 字段,降级 detect_routing_intent 旧路径")
|
||||
return await _handle_routing(db, conversation, employee_id, content)
|
||||
|
||||
# 合并模式:主 Dify 直接输出路由意图
|
||||
business_category = result.get("business_category")
|
||||
routing_confidence = float(result.get("routing_confidence") or 0.0)
|
||||
|
||||
logger.info(
|
||||
f"[D1] 路由意图(主Dify): intent_type={intent_type}, "
|
||||
f"business_category={business_category}, routing_confidence={routing_confidence}"
|
||||
)
|
||||
|
||||
# 审批意图不拦截(让审批流程处理)
|
||||
if intent_type == "approval":
|
||||
return False
|
||||
return await _handle_routing(db, conversation, employee_id, content)
|
||||
|
||||
threshold = settings.routing_confidence_threshold
|
||||
if intent_type != "non_it_routing" or routing_confidence < threshold:
|
||||
return False
|
||||
|
||||
if not business_category:
|
||||
logger.warning("[D1] 路由意图为 non_it_routing 但 business_category 为空,跳过")
|
||||
return False
|
||||
|
||||
# 查询联系人
|
||||
contact = await get_contact_by_category(db, business_category)
|
||||
if not contact:
|
||||
logger.warning(f"未找到 {business_category} 类别的联系人,跳过路由推荐")
|
||||
return False
|
||||
|
||||
# 构建路由说明文本
|
||||
category_display = business_category.replace("行政-物业", "物业")
|
||||
reason = (
|
||||
f"您的问题属于{category_display}业务范畴,不在IT服务台服务范围内 😊\n\n"
|
||||
f"为您推荐{category_display}服务相关联系人,您可以直接点击名片联系TA:"
|
||||
)
|
||||
|
||||
# 发送名片三段式消息
|
||||
await send_contact_card(
|
||||
db=db,
|
||||
conversation=conversation,
|
||||
employee_id=employee_id,
|
||||
contact=contact,
|
||||
reason=reason,
|
||||
business_category=business_category,
|
||||
routing_confidence=routing_confidence,
|
||||
)
|
||||
|
||||
# 记录路由事件
|
||||
await record_routing_event(
|
||||
db=db,
|
||||
conversation_id=str(conversation.id),
|
||||
employee_id=employee_id,
|
||||
message_content=content,
|
||||
business_category=business_category,
|
||||
routing_confidence=routing_confidence,
|
||||
contact=contact,
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def _step_local_quick_reply(db, conversation, employee_id, content, msg_type, dify_conversation_id) -> bool:
|
||||
@@ -1208,6 +1279,13 @@ async def _step_call_dify(db, conversation, employee_id, conversation_id, conten
|
||||
except Exception as fallback_err:
|
||||
logger.error(f"[Fallback] 降级推送失败: {fallback_err}")
|
||||
|
||||
# D1 合并:审批关键词未命中时,路由关键词兜底(超时场景路由不丢失)
|
||||
if routing_keyword_prefilter(content):
|
||||
logger.info("[D1] 超时降级:审批未命中,尝试路由名片兜底")
|
||||
routed = await _handle_routing(db, conversation, employee_id, content)
|
||||
if routed:
|
||||
return None # 已发名片,终止管线
|
||||
|
||||
# 降级也失败 -> 建议转人工
|
||||
await _step_notify_failure(conversation_id, employee_id, "AI 响应时间较长,建议转人工坐席处理。")
|
||||
return None
|
||||
@@ -1263,15 +1341,19 @@ async def process_h5_ai_reply(
|
||||
v4.0 批次 3 管线化重构:原 12 步/11 对 try/except 编排为 9 个步骤函数,
|
||||
主函数仅最外层 1 个 try/except,行为与 v3.2 外部表现一致。
|
||||
|
||||
v4.0 D1 合并:路由意图识别并入主 Dify 调用(同一请求返回 text+action+intent_type),
|
||||
消除原 detect_routing_intent 前置串行调用(最坏 15+30=45s → 主调用一次)。
|
||||
过渡期双模:主结果无 intent_type 字段时自动降级旧路径。
|
||||
|
||||
流程:
|
||||
1. _step_load_conversation 加载会话(重试3次)
|
||||
2. _step_byod_intercept BYOD 关键词拦截
|
||||
3. _step_routing_intercept 非IT业务路由拦截(名片推荐)
|
||||
4. _step_local_quick_reply 本地快判断(打招呼/呼叫人工)
|
||||
5. _step_enrich_image 图片消息 VisionService 增强
|
||||
5b. _enrich_with_last_ai_context 简短回复上下文拼接(v2.3)
|
||||
6. _step_graph_shortcut Neo4j 图谱短路
|
||||
7. _step_call_dify Dify 主推理(含超时/无action关键词降级)
|
||||
3. _step_local_quick_reply 本地快判断(打招呼/呼叫人工)
|
||||
4. _step_enrich_image 图片消息 VisionService 增强
|
||||
4b. _enrich_with_last_ai_context 简短回复上下文拼接(v2.3)
|
||||
5. _step_graph_shortcut Neo4j 图谱短路
|
||||
6. _step_call_dify Dify 主推理(含超时/无action关键词降级)
|
||||
7. _step_routing_from_result D1 路由判断(主结果读 intent_type,命中发名片)
|
||||
8. _step_persist 持久化 + 双 WS 推送
|
||||
9. _step_assets 资产推荐推送
|
||||
|
||||
@@ -1293,11 +1375,12 @@ async def process_h5_ai_reply(
|
||||
# 前置拦截管线(任一命中即终止)
|
||||
if await _step_byod_intercept(db, conversation, employee_id, content, msg_type):
|
||||
return
|
||||
if await _step_routing_intercept(db, conversation, employee_id, content, msg_type):
|
||||
return
|
||||
if await _step_local_quick_reply(db, conversation, employee_id, content, msg_type, dify_conversation_id):
|
||||
return
|
||||
|
||||
# D1 合并:路由关键词预标记(不调用 Dify,仅用于主结果返回后判断是否走路由分支)
|
||||
is_routing_candidate = (msg_type == "text" and routing_keyword_prefilter(content))
|
||||
|
||||
# 内容增强管线
|
||||
enriched_content = await _step_enrich_image(
|
||||
db, content, msg_type, media_url, conversation_id, employee_id,
|
||||
@@ -1318,6 +1401,11 @@ async def process_h5_ai_reply(
|
||||
if result is None:
|
||||
return # 降级路径已全部处理(超时转人工 或 已推送降级卡片)
|
||||
|
||||
# D1 合并:路由候选消息 → 从主结果读路由意图,命中则发名片(终止管线)
|
||||
if is_routing_candidate:
|
||||
if await _step_routing_from_result(db, conversation, employee_id, content, result):
|
||||
return
|
||||
|
||||
# 后置处理管线
|
||||
await _step_persist(db, conversation, employee_id, result)
|
||||
await _step_assets(db, employee_id, content, result)
|
||||
|
||||
Reference in New Issue
Block a user