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) }}
- 候选切片与取舍
{{ row.selected ? '是' : '否' }}
+ 候选切片与取舍
{{ row.selected ? '是' : '否' }}
最终回答
{{ 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. 柔性额度提醒