Sfoglia il codice sorgente

fix: run from specific msg

Talegorithm 2 giorni fa
parent
commit
f6cd43c71d

+ 1 - 0
.gitignore

@@ -72,6 +72,7 @@ knowhub/knowhub.db-shm
 knowhub/knowhub.db-wal
 examples/archive/*
 examples/research/
+examples/downloader/
 
 # Milvus data
 knowhub/milvus_data/

+ 0 - 2
X

@@ -1,2 +0,0 @@
-`Merge branch 'main' of https://git.yishihui.com/howard/Agent
-#

+ 56 - 25
agent/cli/interactive.py

@@ -11,6 +11,7 @@ from pathlib import Path
 
 from agent.core.runner import AgentRunner
 from agent.trace import TraceStore
+from agent.trace.models import Message, Trace
 
 
 # ===== 非阻塞 stdin 检测 =====
@@ -373,53 +374,71 @@ class InteractiveController:
             confirm = input("\n是否重新生成这条 Assistant 消息?(y/n): ").strip().lower()
             regenerate_last = (confirm == 'y')
 
-        # 5. 调用 runner.run() 续跑
+        # 5. 询问是否插入干预消息
+        insert_message = input("\n是否插入一条干预消息?(y/n): ").strip().lower()
+        intervention_msg = None
+        if insert_message == 'y':
+            intervention_msg = read_multiline()
+            if not intervention_msg.strip():
+                print("⚠️  干预消息为空,将不插入")
+                intervention_msg = None
+
+        # 6. 调用 runner.run() 续跑
         print(f"\n从消息 {selected_msg.sequence:04d} 之后续跑...")
         if regenerate_last:
             print("将重新生成最后一条 Assistant 消息")
 
         try:
-            # 加载 trace 和消息历史
+            # 加载 trace
             trace = await self.store.get_trace(trace_id)
             if not trace:
                 print("❌ Trace 不存在")
                 return
 
-            # 截断消息到指定位置
-            truncated_messages = []
-            for msg in messages:
-                if msg.sequence <= selected_msg.sequence:
-                    truncated_messages.append({
-                        "role": msg.role,
-                        "content": msg.content,
-                        "id": msg.message_id,
-                    })
+            # 计算 after_sequence:如果需要重新生成,回退到上一条消息
+            after_seq = selected_msg.sequence
+            if regenerate_last and selected_msg.role == "assistant":
+                # 找到这条 assistant 消息的 parent_sequence
+                after_seq = selected_msg.parent_sequence or (selected_msg.sequence - 1)
 
-            # 如果需要重新生成,删除最后一条 assistant 消息
-            if regenerate_last and truncated_messages and truncated_messages[-1]["role"] == "assistant":
-                truncated_messages.pop()
+            # 导入 RunConfig
+            from agent.core.runner import RunConfig
 
-            # 调用 runner.run() 续跑
-            print("\n开始执行...")
-            async for event in self.runner.run(
-                messages=truncated_messages,
+            # 构建运行配置
+            config = RunConfig(
                 trace_id=trace_id,
+                after_sequence=after_seq,
                 model=trace.model,
                 temperature=trace.llm_params.get("temperature", 0.3),
                 max_iterations=200,
-                tools=None,  # 使用原有配置
+            )
+
+            # 准备消息列表(如果有干预消息则插入)
+            messages_to_add = []
+            if intervention_msg:
+                messages_to_add.append({"role": "user", "content": intervention_msg})
+                print(f"\n✓ 将插入干预消息")
+
+            # 调用 runner.run() 续跑
+            print("\n开始执行...")
+            async for event in self.runner.run(
+                messages=messages_to_add,
+                config=config,
             ):
-                # 简单输出事件
-                if event.get("type") == "message":
-                    msg = event.get("message")
-                    if msg and msg.get("role") == "assistant":
-                        content = msg.get("content", {})
+                # 处理事件输出
+                if isinstance(event, Message):
+                    if event.role == "assistant":
+                        content = event.content
                         if isinstance(content, dict):
                             text = content.get("text", "")
                         else:
                             text = str(content)
                         if text:
                             print(f"\n🤖 Assistant: {text[:200]}...")
+                elif isinstance(event, Trace):
+                    # Trace 状态更新
+                    if event.status in ("completed", "failed", "stopped"):
+                        print(f"\n📊 Trace 状态: {event.status}")
 
             print("\n✅ 执行完成")
 
@@ -442,8 +461,20 @@ class InteractiveController:
         if isinstance(content, dict):
             text = content.get("text", "")
             tool_calls = content.get("tool_calls", [])
-            if text:
+
+            # 处理 text 字段(可能是字符串、list、dict 或其他类型)
+            if isinstance(text, str) and text.strip():
                 preview = text.strip()
+            elif isinstance(text, list):
+                # 多模态内容:提取文本部分
+                text_parts = [
+                    part.get("text", "") for part in text
+                    if isinstance(part, dict) and part.get("type") == "text"
+                ]
+                preview = " ".join(text_parts).strip() if text_parts else "[多模态内容]"
+            elif isinstance(text, dict):
+                # text 本身是 dict,尝试提取有用信息
+                preview = str(text.get("value", text.get("text", "[复杂内容]")))
             elif tool_calls:
                 preview = f"[调用工具: {', '.join(tc.get('function', {}).get('name', '?') for tc in tool_calls)}]"
             else:

+ 20 - 0
agent/tools/builtin/feishu/chat_history/chat_孙若天.json

@@ -8,5 +8,25 @@
         "text": "你好,我需要访问小红书,但是需要登录。请帮我在这个浏览器中完成登录:\n\nhttps://live.browser-use.com?wss=https%3A//9dcf552b-18ea-4f7f-9ace-96ca6fc9a3ac.cdp3.browser-use.com\n\n登录完成后请回复我一下,谢谢!"
       }
     ]
+  },
+  {
+    "role": "assistant",
+    "message_id": "om_x100b538c2d07ec98c3b100a5fec966c",
+    "content": [
+      {
+        "type": "text",
+        "text": "论文文献下载需要协助\n\n已完成论文 `/Users/sunlit/Papers/NoteHook/UIST/main.tex` 的引用文献提取,共 46 篇参考文献。\n\n下载状态:\n✅ 成功下载:4 篇(开放获取文献)\n🔒 需要登录/付费:32 篇(ACM/IEEE/Science 等)\n❌ 下载失败:4 篇\n📋 无 DOI/URL:6 篇\n\n大部分文献(32 篇)需要机构登录才能下载,主要来自:\n- ACM Digital Library (22 篇)\n- Science (1 篇)\n- APA/PsycINFO (2 篇)\n- Emerald (2 篇)\n- 其他出版商 (5 篇)\n\n详细报告已生成:\n`/Users/sunlit/Papers/NoteHook/UIST/references_downloaded/download_report.md`\n\n请问您是否有清华大学图书馆的代理访问权限?或者需要我帮您配置浏览器登录 ACM/IEEE 等数据库来下载这些文献?"
+      }
+    ]
+  },
+  {
+    "role": "assistant",
+    "message_id": "om_x100b538ce47170b8c32938bff5524df",
+    "content": [
+      {
+        "type": "text",
+        "text": "论文下载进度更新\n\n✅ 已成功下载 **34 篇** 论文(74% 成功率)\n\n已完成下载:\n- ACM Digital Library: 26 篇 (100%)\n- arXiv: 2 篇 (100%)\n- Emerald: 2 篇 (100%)\n- IEEE: 1 篇\n- Springer: 1 篇\n\n🔒 还需要登录以下出版商下载剩余 9 篇:\n1. Science (science.org) - 1 篇\n2. APA/PsycINFO (psycnet.apa.org) - 2 篇\n3. ScienceDirect (sciencedirect.com) - 2 篇\n4. Wiley (onlinelibrary.wiley.com) - 1 篇\n5. Now Publishers (nowpublishers.com) - 1 篇\n\n📋 无 DOI/URL 需要手动查找:6 篇\n\n所有文件已保存到:\n/Users/sunlit/Papers/NoteHook/UIST/references_downloaded/\n\n详细报告:download_final_report.md\n\n请问您是否要继续登录其他出版商完成剩余论文的下载?我可以依次打开各个出版商的登录页面。"
+      }
+    ]
   }
 ]

+ 2 - 1
config/feishu_contacts.json

@@ -13,7 +13,8 @@
   {
     "name": "孙若天",
     "description": "",
-    "open_id": "ou_ede69f28c2617bf80a7574f059879c8d"
+    "open_id": "ou_ede69f28c2617bf80a7574f059879c8d",
+    "chat_id": "oc_98019f9a0419b46a215ca604b04c5cc6"
   },
   {
     "name": "刘斌",

+ 443 - 0
knowhub/docs/dashboard-design.md

@@ -0,0 +1,443 @@
+# 知识库 Dashboard 设计文档
+
+## 概述
+
+知识库 Dashboard 用于可视化展示知识库的建设情况,帮助管理者了解:
+- 内容理解的广度和深度(内容树覆盖度)
+- 制作能力的成熟度(任务表成熟度)
+- 工具资源的丰富度(工具库完备性)
+- 知识积累的质量(知识质量评估)
+
+Dashboard 采用三个维度的 Tab 切换设计,每个维度支持三层下钻。
+
+---
+
+## 一、内容树覆盖度维度
+
+### 1.1 第一层:树形结构总览
+
+**可视化形式**:交互式树状图
+
+**节点视觉编码**:
+
+- **颜色**(表示成熟度):
+  - 🟢 绿色:完整支持(有任务 + 工具已接入 + 有知识)
+  - 🟡 黄色:部分支持(有任务但工具未完全接入或缺知识)
+  - ⚪ 灰色:待探索(无任务关联)
+
+- **角标**(表示重要性和状态):
+  - 数字角标:关联的帖子数量(如 `[23]`)
+  <!-- - 图标角标:
+    - ⚠️ 工具缺失(有任务但工具未接入)
+    - 📚 知识丰富(关联知识 > 10 条)
+    - ⭐ 高质量(关联知识平均评分 > 4.0) -->
+
+<!-- **节点悬停信息**:
+- 关联帖子数:X 个
+- 关联 Pattern 数:Y 个
+- 制作任务数:Z 个
+- 知识条目数:N 条(平均评分 M)
+- 工具支持:A/B 已接入 -->
+
+**全局指标卡片**(页面顶部):
+```
+┌─────────────────────┬─────────────────────┬─────────────────────┐
+│ 节点覆盖率           │ 工具支持率           │ Pattern转化率        │
+│ 65%                 │ 45%                 │ 78%                 │
+│ 有任务的节点/总节点  │ 工具全接入的节点/总节点│ 有任务的Pattern/总Pattern│
+└─────────────────────┴─────────────────────┴─────────────────────┘
+```
+
+### 1.2 第二层:节点详情页
+
+点击某个内容树节点,展开详情面板(侧边栏)。
+
+**基本信息区**:
+- 节点路径:`内容树 > 一级分类 > 二级分类 > 当前节点`
+- 关联帖子数:X 个
+- 节点状态:完整支持 / 部分支持 / 待探索
+
+**Pattern 列表**:
+- 表格展示关联的所有 Pattern
+- 列:Pattern ID、帖子数、归纳任务数、操作(查看详情)
+- 数据来源:用频繁项集API根据内容树节点ID查
+
+**原始帖子列表**:
+- 表格展示关联的原始帖子
+- 列:帖子标题、账号、发布时间、关联 Pattern、操作(查看原文)
+- 数据来源:通过 Pattern → 帖子的关联关系
+
+**制作任务列表**:
+- 表格展示从这些 Pattern 归纳出的任务
+- 列:任务描述、成熟度等级(L0-L4)、依赖工具、关联知识数、操作(查看详情)
+- 点击"查看详情"跳转到任务详情页(见 2.3)
+
+**知识积累情况**:
+- 知识总数:X 条
+- 按类型分布:usecase Y 条、plan Z 条、tool N 条
+- 平均质量评分:M 分
+- 知识列表(简要):显示 top 5 高质量知识,可展开查看全部
+
+**工具支持情况**:
+- 列出所有任务依赖的工具
+- 每个工具显示:名称、状态(已接入/未接入/测试中)、关联知识数
+- 高亮显示未接入的工具
+
+### 1.3 第三层:Pattern / 制作任务 / 知识 / 工具 详情页 (可使用弹窗展示)
+
+---
+
+## 二、任务表维度
+
+### 2.1 第一层:任务全景矩阵
+
+**可视化形式**:热力图矩阵
+
+**横轴**:任务分类
+- 分类方式待定,可能的维度:
+  - 按内容类型:图文、视频、音频、直播等
+  - 按制作环节:选题、脚本、拍摄、剪辑、发布等
+  - 按业务场景:日常更新、活动策划、品牌宣传等
+- **建议**:先按任务表中的 `task.type` 字段分类,如果没有该字段,则需要对任务进行人工标注或 LLM 自动分类
+
+**纵轴**:成熟度等级
+- **L0 - 待完善**:缺少知识和工具
+  - 判断标准:任务的 `knowledge` 字段为空 且 `tools` 字段为空
+- **L1 - 初步支持**:有知识或有工具
+  - 判断标准:单次业务执行或单个工具触发的新任务
+  - 数据标识:任务的 `source.category` 为 "exp"(单次经验)
+- **L2 - 相对完善**:有相对完善的知识和工具
+  - 判断标准:对任务本身进行过调研
+  - 数据标识:任务的 `source.category` 为 "skill"(系统性调研)
+- **L3 - 就绪**:涉及工具全都已接入
+  - 判断标准:任务的 `tools` 字段中所有工具的 `status` 都为"已接入"
+- **L4 - 已验证**:已支持相关工作完成
+  - 判断标准:任务的 `trace` 字段有成功执行记录
+
+**热力图单元格**:
+- 颜色深度:表示该格子的任务数量
+- 点击单元格:下钻到该分类+等级的任务列表
+
+**全局指标卡片**(页面顶部):
+```
+┌─────────────────────┬─────────────────────┬─────────────────────┐
+│ 任务总数             │ 知识沉淀率           │ 可执行率             │
+│ 156                 │ 72%                 │ 38%                 │
+│                     │ L1+任务/总任务       │ L3+L4任务/总任务     │
+└─────────────────────┴─────────────────────┴─────────────────────┘
+```
+
+### 2.2 第二层:任务列表页
+
+点击矩阵单元格,展示该分类+等级的任务列表。
+
+**筛选和排序**:
+- 按成熟度等级筛选
+- 按任务类型筛选
+- 按关联知识数排序
+- 按执行次数排序
+
+**任务列表表格**:
+- 列:
+  - 任务描述(`task` 字段)
+  - 成熟度等级(L0-L4)
+  - 来源 Pattern(`source.itemset_id`)
+  - 依赖工具(`tools` 字段,显示工具名称和状态)
+  - 关联知识数(`knowledge` 字段,按 case/process 分类统计)
+  - 执行记录(`trace` 字段,成功/失败次数)
+  - 操作(查看详情)
+
+### 2.3 第三层:单任务详情页
+
+点击某个任务,展开详情。
+
+**任务基本信息**:
+- 任务描述:`task` 字段
+- 成熟度等级:L0-L4
+- 来源信息:
+  - 来源 Pattern:`source.itemset_id`
+  - 来源类型:`source.type`(itemset/tool/...)
+  - 来源分类:`source.category`(exp/skill/...)
+
+**工具清单**:
+- 表格展示依赖的所有工具(从 `tools` 字段)
+- 列:
+  - 工具名称
+  - 工具状态(已接入/未接入/测试中)
+  - 工具版本
+  - 关联知识数(从 Resource.metadata.knowledge_ids 统计)
+  - 操作(查看工具详情)
+- 高亮显示未接入的工具
+
+**知识清单**:
+- 按知识类型分组展示(从 `knowledge` 字段)
+- **Case 知识**(types 包含 "usecase"):
+  - 列表展示,每条显示:task、content 摘要、质量评分、操作(查看详情)
+- **Process 知识**(types 包含 "plan"):
+  - 列表展示,每条显示:task、content 摘要、质量评分、操作(查看详情)
+- **Tool 知识**(types 包含 "tool"):
+  - 列表展示,每条显示:task、content 摘要、质量评分、操作(查看详情)
+- 每条知识显示质量徽章(见第四章)
+
+<!-- **执行历史**:
+- 从 `trace` 字段解析执行记录
+- 表格展示:
+  - 执行时间
+  - 执行结果(成功/失败)
+  - 使用的工具
+  - 调用的知识
+  - 失败原因(如果失败)
+- 统计:总执行次数、成功率、平均耗时 -->
+
+**改进建议**(自动生成):
+- 如果 L0:建议补充工具和知识
+- 如果 L1:建议进行系统性调研
+- 如果 L2:建议接入相关工具
+- 如果 L3:建议进行实际验证
+
+---
+
+## 三、工具能力维度
+
+### 3.1 第一层:工具库全景
+
+**可视化形式**:工具卡片墙 + 分类统计
+
+**分类统计**(页面顶部):
+- 按 `Resource.metadata.category` 分类:
+  - image_gen:X 个
+  - image_process:Y 个
+  - model:Z 个
+  - plugin:N 个
+  - workflow:M 个
+  - other:K 个
+- 按 `Resource.metadata.status` 分类:
+  - 已接入:X 个
+  - 未接入:Y 个
+  - 测试中:Z 个
+
+**全局指标卡片**:
+```
+┌─────────────────────┬─────────────────────┬─────────────────────┐
+│ 工具总数             │ 工具可用率           │ 工具成熟度           │
+│ 48                  │ 62%                 │ 35%                 │
+│                     │ 已接入/总数          │ 有完整知识/总数      │
+└─────────────────────┴─────────────────────┴─────────────────────┘
+```
+
+**工具卡片墙**:
+- 每个工具一个卡片
+- 卡片内容:
+  - 工具名称(`Resource.title`)
+  - 工具分类(`metadata.category`)
+  - 工具状态(`metadata.status`)- 用颜色标识
+  - 知识积累度:
+    - Case 知识:X 条
+    - Process 知识:Y 条
+    - Tool 知识:Z 条
+  - 业务支持度:
+    - 被 N 个任务依赖
+    - 关联 M 个内容树节点
+  - 操作:查看详情
+
+**筛选和排序**:
+- 按分类筛选
+- 按状态筛选
+- 按知识数量排序
+- 按任务依赖数排序
+
+### 3.2 第二层:工具卡片详情
+
+点击某个工具卡片,展开详情面板。
+
+**工具元信息**:
+- 基本信息:
+  - ID:`Resource.id`
+  - 名称:`Resource.title`
+  - 分类:`metadata.category`
+  - 状态:`metadata.status`
+  - 版本:`metadata.version`
+  - Slug:`metadata.tool_slug`
+- 描述信息:
+  - 功能描述:`metadata.description`
+  - 使用方法:`metadata.usage`
+  - 应用场景:`metadata.scenarios`(列表)
+  - 输入类型:`metadata.input`
+  - 输出类型:`metadata.output`
+  - 来源链接:`metadata.source`
+
+**知识积累情况**:
+- 从 `metadata.knowledge_ids` 获取关联的知识列表
+- 按知识类型分组展示:
+  - **Case 知识**(types 包含 "usecase"):
+    - 数量统计
+    - 列表展示(task、content 摘要、质量评分)
+  - **Process 知识**(types 包含 "plan"):
+    - 数量统计
+    - 列表展示(task、content 摘要、质量评分)
+  - **Tool 知识**(types 包含 "tool"):
+    - 数量统计
+    - 列表展示(task、content 摘要、质量评分)
+- 知识来源分布:
+  - Agent 生成:X 条
+  - 人工审核:Y 条
+  - 外部导入:Z 条
+- 知识时效性:
+  - 最近更新时间
+  - 最近使用时间
+
+**业务支持情况**:
+- 关联任务列表:
+  - 从任务表的 `tools` 字段反查
+  - 表格展示:任务描述、成熟度等级、执行次数、成功率
+- 关联内容树节点:
+  - 通过任务 → Pattern → 内容树节点的路径
+  - 列表展示:节点路径、关联帖子数
+
+**改进建议**(自动生成):
+- 如果 case 知识 < 3 条:建议补充用例
+- 如果 process 知识 = 0:建议补充流程
+- 如果 status = "未接入" 且被多个任务依赖:高优先级接入
+- 如果最近 90 天无使用记录:建议评估是否保留
+
+### 3.3 第三层:知识详情页
+
+点击某条知识,展开知识详情(见第四章)。
+
+---
+
+## 四、知识质量(横切面)
+
+知识质量作为横切面,贯穿上述三个维度。每条知识都需要标注质量属性。
+
+### 4.1 质量维度定义
+
+**1. 评分(Score)**
+- 数据来源:`Knowledge.eval.score`(1-5 分)
+- 展示方式:星级 ⭐⭐⭐⭐⭐
+
+**2. 验证度(Validation)**
+- 数据来源:`Knowledge.eval.helpful` vs `Knowledge.eval.harmful`
+- 计算方式:验证度 = helpful - harmful
+- 展示方式:`+5/-1`(绿色/红色)
+
+**3. 可信度(Credibility)**
+- 分级:
+  - 🟢 高可信:人工审核通过 + 有使用验证(helpful > 3)
+  - 🟡 中可信:Agent 生成 + 有使用验证(helpful > 0)
+  - 🔵 待验证:Agent 生成 + 无使用验证(helpful = 0)
+  - 🔴 低可信:有负面反馈(harmful > 0)
+- 判断逻辑:
+  ```
+  if harmful > 0:
+      可信度 = 低可信
+  elif source.submitted_by != "" and helpful > 3:
+      可信度 = 高可信
+  elif helpful > 0:
+      可信度 = 中可信
+  else:
+      可信度 = 待验证
+  ```
+
+**4. 时效性(Recency)**
+- 数据来源:`Knowledge.updated_at` 或最近使用时间(从 eval.helpful_history 提取)
+- 分级:
+  - 🟢 新鲜:< 30 天
+  - 🟡 一般:30-90 天
+  - 🔴 陈旧:> 90 天
+- 展示方式:显示距今天数(如"15 天前")
+
+**5. 挂载状态(Attachment)**
+- 判断逻辑:
+  - ✅ 已挂载到工具:通过 Resource.metadata.knowledge_ids 反查
+  - ✅ 已挂载到任务:通过任务表的 knowledge 字段反查
+  - ⚠️ 孤立知识:两者都无
+- 展示方式:图标 + 文字说明
+
+### 4.2 质量等级计算
+
+**综合质量等级**:A / B / C / D
+
+计算公式:
+```
+质量分数 = 评分 × 验证度权重 × 可信度权重 × 时效性权重 × 挂载权重
+
+其中:
+- 评分:1-5 分,直接使用
+- 验证度权重:
+  - helpful - harmful > 5: 1.2
+  - helpful - harmful > 0: 1.0
+  - helpful - harmful = 0: 0.8
+  - helpful - harmful < 0: 0.5
+- 可信度权重:
+  - 高可信:1.2
+  - 中可信:1.0
+  - 待验证:0.8
+  - 低可信:0.5
+- 时效性权重:
+  - 新鲜:1.0
+  - 一般:0.9
+  - 陈旧:0.7
+- 挂载权重:
+  - 挂载到工具或任务:1.0
+  - 孤立知识:0.8
+
+质量等级:
+- A:质量分数 >= 4.5
+- B:质量分数 >= 3.5
+- C:质量分数 >= 2.5
+- D:质量分数 < 2.5
+```
+
+### 4.3 知识详情页
+
+点击任何地方的知识条目,展开知识详情。
+
+**基本信息**:
+- 知识 ID:`Knowledge.id`
+- 任务场景:`Knowledge.task`
+- 知识内容:`Knowledge.content`
+- 知识类型:`Knowledge.types`(可多选)
+- 标签:`Knowledge.tags`
+- 可见范围:`Knowledge.scopes`
+- 所有者:`Knowledge.owner`
+
+**质量评估**:
+- 综合质量等级:A / B / C / D(大号徽章)
+- 详细质量维度:
+  - 评分:⭐⭐⭐⭐⭐ (4.5 分)
+  - 验证度:+5/-1
+  - 可信度:🟢 高可信
+  - 时效性:🟢 15 天前
+  - 挂载状态:✅ 已挂载到 2 个工具、3 个任务
+
+**来源信息**:
+- 资源名称:`source.name`
+- 来源类别:`source.category`
+- 参考链接:`source.urls`
+- 创建者:`source.agent_id`
+- 提交者:`source.submitted_by`
+- 创建时间:`source.timestamp`
+- 溯源消息:`source.message_id`(可点击跳转)
+
+**关联资源**:
+- 从 `resource_ids` 获取关联的 Resource
+- 列表展示:资源 ID、资源标题、资源类型、操作(查看资源)
+
+**使用历史**:
+- Helpful 案例(`eval.helpful_history`):
+  - 表格展示:任务描述、结果、时间
+- Harmful 案例(`eval.harmful_history`):
+  - 表格展示:任务描述、结果、原因、时间
+
+**关系网络**:
+- 从 `relationships` 字段获取与其他知识的关系
+- 展示:关系类型(duplicate/subset/superset/conflict/complement)、关联知识 ID
+
+**操作按钮**:
+- 更新评分
+- 添加 Helpful 案例
+- 添加 Harmful 案例
+- 触发知识进化(提供改进建议)
+
+---