From 4e872febd53df48bc674d1b36cc4a1870c490b2b Mon Sep 17 00:00:00 2001 From: Nelson <1475262689@qq.com> Date: Fri, 31 Jul 2026 16:09:27 +0800 Subject: [PATCH] feat: expose knowledge type priority traces --- .../apps/admin-web/src/App.vue | 2 +- .../src/components/KnowledgeManagementView.vue | 10 ++++++++++ .../backend/app/api/admin_agent_records.py | 18 ++++++++++++++++++ .../app/services/knowledge_agent_service.py | 13 +++++++++++-- .../docs/qianwen_product_todo.md | 4 ++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/ai_knowledge_base_v2/apps/admin-web/src/App.vue b/ai_knowledge_base_v2/apps/admin-web/src/App.vue index 327322e..b908de5 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/App.vue +++ b/ai_knowledge_base_v2/apps/admin-web/src/App.vue @@ -1556,7 +1556,7 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {

本轮 KnowledgeList

{{ JSON.stringify(selectedRetrievalLog.catalogSnapshot, null, 2) }}

Agent 工具轨迹

{{ JSON.stringify(selectedRetrievalLog.toolTrace, null, 2) }}
-

候选切片与取舍

+

候选切片与取舍

最终回答

{{ selectedRetrievalLog.finalAnswer || '尚未生成回答' }}
diff --git a/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeManagementView.vue b/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeManagementView.vue index 6edc8bb..aa81cce 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeManagementView.vue +++ b/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeManagementView.vue @@ -379,6 +379,15 @@ function typeLabel(value: string) { return knowledgeTypeOptions.find((item) => item.value === value)?.label || value; } +function typeDescription(value: string) { + return ({ + fixed: "固定信息类用于上课时间、带练安排、回放音频、课程作业、会议链接、服务权益、助理联系方式等当前安排;与其他库冲突时优先采用固定信息类。", + course: "课程知识库用于课程概念、功课步骤、老师观点和课程原文解释;优先级高于答疑和通用知识。", + qa: "答疑知识库用于参考过往问答和常见问题,但不能覆盖课程原文或固定信息类的当前安排。", + general: "通用知识库只做背景补充,不能覆盖课程知识、答疑知识或固定信息类。", + } as Record)[value] || "用于补充背景信息。"; +} + function contentItemTypeLabel(value: string) { return ({ section: "章节", card: "知识卡", chunk: "切片" } as Record)[value] || value; } @@ -552,6 +561,7 @@ async function confirmAction(

基本信息

编辑基本信息
后台名称
{{ detail.knowledge.name }}
知识库类型
{{ typeLabel(detail.knowledge.knowledgeType) }}
版本更新
同步成功后自动替换
SpaceID
{{ detail.knowledge.feishuSpaceId }}
NodeID
{{ detail.knowledge.feishuNodeId }}
当前版本
{{ detail.currentVersion ? `V${detail.currentVersion.versionNo}` : '暂无' }}
+

Knowledge Manifest

用途:{{ detail.manifest.purpose }}

适用:{{ detail.manifest.applicableQuestions }}

不适用:{{ detail.manifest.inapplicableQuestions }}

核心主题:{{ detail.manifest.coreTopics }}

边界:{{ detail.manifest.boundaries }}

diff --git a/ai_knowledge_base_v2/apps/backend/app/api/admin_agent_records.py b/ai_knowledge_base_v2/apps/backend/app/api/admin_agent_records.py index eab3ffa..09f6e00 100644 --- a/ai_knowledge_base_v2/apps/backend/app/api/admin_agent_records.py +++ b/ai_knowledge_base_v2/apps/backend/app/api/admin_agent_records.py @@ -14,6 +14,7 @@ from app.models.admin import Admin from app.models.knowledge import ( HumanAttentionHistory, HumanAttentionRecord, + Knowledge, KnowledgeRetrievalCandidate, KnowledgeRetrievalLog, ) @@ -113,11 +114,19 @@ def retrieval_detail( .where(KnowledgeRetrievalCandidate.retrieval_log_id == log.id) .order_by(KnowledgeRetrievalCandidate.selected.desc(), KnowledgeRetrievalCandidate.id) ).all() + knowledge_ids = {item.knowledge_id for item in candidates} + knowledge_map = { + item.id: item + for item in db.scalars(select(Knowledge).where(Knowledge.id.in_(knowledge_ids))).all() + } if knowledge_ids else {} data = _retrieval_dict(log, detail=True) data["candidates"] = [ { "id": item.id, "knowledgeId": item.knowledge_id, + "knowledgeName": knowledge_map[item.knowledge_id].name if item.knowledge_id in knowledge_map else "", + "knowledgeType": knowledge_map[item.knowledge_id].knowledge_type if item.knowledge_id in knowledge_map else "general", + "knowledgeTypeLabel": _knowledge_type_label(knowledge_map[item.knowledge_id].knowledge_type if item.knowledge_id in knowledge_map else "general"), "versionId": item.version_id, "chunkId": item.chunk_id, "sectionId": item.section_id, @@ -131,6 +140,15 @@ def retrieval_detail( return api_success(data) +def _knowledge_type_label(value: str) -> str: + return { + "fixed": "固定信息类·最高优先级", + "course": "课程知识库", + "qa": "答疑知识库", + "general": "通用知识库", + }.get(value, value or "通用知识库") + + @router.get("/attention/list") def attention_list( priority: str = Query(default=""), diff --git a/ai_knowledge_base_v2/apps/backend/app/services/knowledge_agent_service.py b/ai_knowledge_base_v2/apps/backend/app/services/knowledge_agent_service.py index 27cdb73..7c0a55b 100644 --- a/ai_knowledge_base_v2/apps/backend/app/services/knowledge_agent_service.py +++ b/ai_knowledge_base_v2/apps/backend/app/services/knowledge_agent_service.py @@ -154,7 +154,7 @@ class KnowledgeAgentService: candidate_limit=candidate_limit, prefer_fixed_information=cls._is_fixed_information_query(retrieval_question), ) - trace.append(cls._trace("search_knowledge", len(trace) + 1, {"queryTerms": terms, "knowledgeIds": selected_ids, "candidateLimit": candidate_limit}, {"candidateCount": len(candidates), "candidates": [cls._candidate_trace(x) for x in candidates]}, started)) + trace.append(cls._trace("search_knowledge", len(trace) + 1, {"queryTerms": terms, "knowledgeIds": selected_ids, "candidateLimit": candidate_limit, "preferFixedInformation": cls._is_fixed_information_query(retrieval_question)}, {"candidateCount": len(candidates), "candidates": [cls._candidate_trace(x) for x in candidates]}, started)) await cls._rerank(db, retrieval_question, candidates, trace, started) selected = cls._select_sections( candidates, @@ -391,7 +391,7 @@ class KnowledgeAgentService: @staticmethod def _candidate_trace(item: Candidate) -> dict: - return {"knowledgeId": item.knowledge.id, "knowledgeName": item.knowledge.name, "versionId": item.version.id, "chunkId": item.chunk.id, "sectionId": item.section.id, "title": item.chunk.title, "lexicalScore": item.lexical_score, "rerankScore": item.rerank_score, "selected": item.selected, "discardReason": item.discard_reason} + return {"knowledgeId": item.knowledge.id, "knowledgeName": item.knowledge.name, "knowledgeType": item.knowledge.knowledge_type, "knowledgeTypePriority": _knowledge_type_priority_label(item.knowledge.knowledge_type), "versionId": item.version.id, "chunkId": item.chunk.id, "sectionId": item.section.id, "title": item.chunk.title, "lexicalScore": item.lexical_score, "rerankScore": item.rerank_score, "selected": item.selected, "discardReason": item.discard_reason} @classmethod def search_knowledge( @@ -732,6 +732,15 @@ def _json_trace_value(value): return str(value) +def _knowledge_type_priority_label(value: str) -> str: + return { + "fixed": "最高优先级:固定信息类冲突时优先", + "course": "课程内容优先于答疑和通用知识", + "qa": "过往答疑参考,不覆盖课程原文", + "general": "背景补充,不覆盖业务知识", + }.get(value, "背景补充") + + def _heading_level(content: str) -> int | None: match = re.match(r"^(#{1,6})\s+", content.lstrip()) return len(match.group(1)) if match else None diff --git a/ai_knowledge_base_v2/docs/qianwen_product_todo.md b/ai_knowledge_base_v2/docs/qianwen_product_todo.md index d36a864..2c4588e 100644 --- a/ai_knowledge_base_v2/docs/qianwen_product_todo.md +++ b/ai_knowledge_base_v2/docs/qianwen_product_todo.md @@ -539,6 +539,10 @@ Agent 已经可以: - 检索日志能看到知识库类型和优先级; - 知识冲突时能说明采用固定信息类。 +#### 开发进度 + +- 2026-07-31:已有固定信息类优先召回、Prompt 类型规则注入和冲突处理规则;本次补充检索日志候选切片的知识库类型/优先级展示,并在知识库详情页展示类型使用规则说明。 + --- ### 08. 柔性额度提醒