feat(backend): knowledge iteration + vision + neo4j + response contract source

dependencies.py 拆分为 dependencies/ 包; 新增 vision/ragflow_ingestion/neo4j 客户端与 h5_ai_task; alembic 045 图置信度迁移; 响应契约统一收尾。
This commit is contained in:
Simon
2026-07-09 11:47:16 +08:00
parent f5374fce9b
commit ead5f83bee
39 changed files with 5276 additions and 545 deletions
+123
View File
@@ -54,6 +54,34 @@ class WingmanService:
"输出格式:{\"suggested_tags\": [\"标签1\", \"标签2\"], \"category\": \"分类\", \"priority\": \"low/medium/high\"}"
)
# --------------------------------------------------------------------------
# 知识建议生成专用 PromptTier0 / T03 — 通道 A/B 复用)
# --------------------------------------------------------------------------
_KNOWLEDGE_SUGGESTION_PROMPT: str = (
"你是一个IT知识库优化助手,基于对话上下文分析知识库的不足,"
"生成结构化的知识库优化建议。\n\n"
"分析以下对话,判断是否需要新增FAQ或更新已有知识条目。\n"
"如果AI回复被标记为无用,生成更新建议;如果AI无法解决需转人工,生成新增FAQ建议。\n\n"
"必须以JSON格式输出,包含以下字段:\n"
"- suggestion_type: 建议类型,\"new_faq\"\"update\"\n"
"- title: 问题标题(简洁明了)\n"
"- content: 答案内容(分步骤、可操作)\n"
"- category: 分类,只能是 硬件/软件/网络/安全/账号/其他 之一\n"
"- tags: 标签列表,如 [\"VPN\", \"连接\"]\n"
"- confidence: 你对这个建议的信心度,0.0-1.0之间\n"
"- issue: 对应的Neo4j图问题节点名称,如\"VPN问题\"\n"
"- action: 对应的Neo4j图动作节点名称,如\"VPN连接修复\"\n"
"- relation_type: 图关系类型,\"LEADS_TO\"\"RELATES_TO\"\n"
"- parent_issue: 父问题名称(如果没有则为空字符串)\n\n"
"输出格式示例:\n"
"{\"suggestion_type\": \"new_faq\", \"title\": \"VPN连不上怎么办\", "
"\"content\": \"1.检查网络连接 2.重启VPN客户端 3.联系IT支持\", "
"\"category\": \"网络\", \"tags\": [\"VPN\", \"连接\"], "
"\"confidence\": 0.86, \"issue\": \"VPN问题\", "
"\"action\": \"VPN连接修复\", \"relation_type\": \"LEADS_TO\", "
"\"parent_issue\": \"网络问题\"}"
)
def __init__(self):
"""初始化 Wingman 服务。
@@ -264,6 +292,101 @@ class WingmanService:
logger.error(f"Wingman 标签建议失败: {e}")
return default_tags
# --------------------------------------------------------------------------
# 核心方法 4:生成知识库优化建议(Tier0 / T03 — 复用现有范式)
# --------------------------------------------------------------------------
async def generate_knowledge_suggestion(
self,
context_messages: List[Dict[str, Any]],
) -> Dict[str, Any]:
"""生成知识库优化建议(用于知识库自动迭代)。
传入对话上下文,让 Wingman Agent 分析并生成结构化的知识库优化建议。
复用 _build_context_messages + _call_wingman_api + _parse_json_response 范式。
Args:
context_messages: 对话消息历史列表
Returns:
Dict: {
"suggestion_type": str, # "new_faq" / "update"
"title": str, # 问题标题
"content": str, # 答案内容
"category": str, # 分类
"tags": list[str], # 标签列表
"confidence": float, # 置信度(0.0-1.0
"issue": str, # 图节点:问题名称
"action": str, # 图节点:动作名称
"relation_type": str, # 图关系类型
"parent_issue": str, # 父 Issue 名称
}
"""
# 构建对话上下文消息列表(使用知识建议专用 Prompt)
context = self._build_context_messages(
context_messages, self._KNOWLEDGE_SUGGESTION_PROMPT
)
# 默认建议(降级时使用)
default_suggestion: Dict[str, Any] = {
"suggestion_type": "new_faq",
"title": "",
"content": "",
"category": "其他",
"tags": [],
"confidence": 0.0,
"issue": "",
"action": "",
"relation_type": "LEADS_TO",
"parent_issue": "",
}
try:
result = await self._call_wingman_api(context)
if result is None:
logger.warning("Wingman 知识建议生成失败(API 返回 None)")
return default_suggestion
# 尝试解析 JSON 格式的建议
parsed = self._parse_json_response(result, default_suggestion)
# 规范化字段
suggestion: Dict[str, Any] = {
"suggestion_type": parsed.get(
"suggestion_type", default_suggestion["suggestion_type"]
),
"title": parsed.get("title", default_suggestion["title"]),
"content": parsed.get("content", default_suggestion["content"]),
"category": parsed.get("category", default_suggestion["category"]),
"tags": parsed.get("tags", default_suggestion["tags"]),
"confidence": float(parsed.get("confidence", 0.0)),
"issue": parsed.get("issue", default_suggestion["issue"]),
"action": parsed.get("action", default_suggestion["action"]),
"relation_type": parsed.get(
"relation_type", default_suggestion["relation_type"]
),
"parent_issue": parsed.get(
"parent_issue", default_suggestion["parent_issue"]
),
}
# 如果 Dify 未返回 confidence,使用启发式估算
if suggestion["confidence"] == 0.0:
suggestion["confidence"] = self._estimate_confidence(
suggestion["content"]
)
logger.info(
f"知识建议生成完成: type={suggestion['suggestion_type']}, "
f"title={suggestion['title'][:50]}, "
f"confidence={suggestion['confidence']}"
)
return suggestion
except Exception as e:
logger.error(f"Wingman 知识建议生成异常: {e}")
return default_suggestion
# --------------------------------------------------------------------------
# 内部方法
# --------------------------------------------------------------------------