From f2eb98c025a171e9591c06ab14dfe15558739553 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Thu, 4 Jun 2026 21:08:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E8=AF=84=E5=88=86=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../package/yuxi/knowledge/eval/metrics.py | 14 +++++----- .../test/unit/knowledge/eval/test_metrics.py | 26 ++++++++++++++++--- docs/develop-guides/roadmap.md | 3 ++- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/backend/package/yuxi/knowledge/eval/metrics.py b/backend/package/yuxi/knowledge/eval/metrics.py index efd9499b..17a3d256 100644 --- a/backend/package/yuxi/knowledge/eval/metrics.py +++ b/backend/package/yuxi/knowledge/eval/metrics.py @@ -132,12 +132,10 @@ class EvaluationMetricsCalculator: def calculate_overall_score( retrieval_metrics_list: list[dict[str, float]], answer_metrics_list: list[dict[str, Any]] ) -> float | None: - """计算整体平均分,只聚合检索指标。""" - retrieval_scores = [] + """综合得分:有答案准确率则用准确率,否则用 recall@10。""" + if answer_metrics_list: + scores = [m.get("score", 0.0) for m in answer_metrics_list] + return sum(scores) / len(scores) if scores else None - # 计算检索平均分 - for m in retrieval_metrics_list: - if m: - retrieval_scores.append(sum(m.values()) / len(m)) - - return sum(retrieval_scores) / len(retrieval_scores) if retrieval_scores else None + recalls = [m["recall@10"] for m in retrieval_metrics_list if m and "recall@10" in m] + return sum(recalls) / len(recalls) if recalls else None diff --git a/backend/test/unit/knowledge/eval/test_metrics.py b/backend/test/unit/knowledge/eval/test_metrics.py index 17cc724c..d18dd78e 100644 --- a/backend/test/unit/knowledge/eval/test_metrics.py +++ b/backend/test/unit/knowledge/eval/test_metrics.py @@ -1,5 +1,7 @@ import os +import pytest + os.environ.setdefault("OPENAI_API_KEY", "test-key") from yuxi.knowledge.eval.metrics import EvaluationMetricsCalculator, RetrievalMetrics @@ -20,13 +22,29 @@ def test_retrieval_metrics_use_metadata_chunk_id(): assert metrics["f1@3"] == RetrievalMetrics.f1_score_at_k(["chunk_a", "chunk_b"], ["chunk_b", "chunk_c"], 3) -def test_overall_score_uses_retrieval_metrics_only(): - score = EvaluationMetricsCalculator.calculate_overall_score([{"recall@1": 1.0, "f1@1": 0.5}], [{"score": 0.25}]) +def test_overall_score_uses_answer_accuracy_when_available(): + # 有答案准确率时,综合得分取各题 score 的平均,且与检索指标无关 + retrieval = [{"recall@10": 1.0, "f1@10": 0.2}, {"recall@10": 0.0, "f1@10": 0.0}] + answers = [{"score": 1.0}, {"score": 0.0}, {"score": 1.0}, {"score": 1.0}] + + score = EvaluationMetricsCalculator.calculate_overall_score(retrieval, answers) assert score == 0.75 -def test_overall_score_returns_none_without_retrieval_metrics(): - score = EvaluationMetricsCalculator.calculate_overall_score([], [{"score": 1.0}]) +def test_overall_score_uses_recall_at_10_without_answers(): + # 无答案准确率时,综合得分取各题 recall@10 的平均,不受 f1/其它 k 影响 + retrieval = [ + {"recall@1": 0.0, "recall@5": 0.5, "recall@10": 0.8, "f1@10": 0.1}, + {"recall@1": 1.0, "recall@5": 1.0, "recall@10": 0.4, "f1@10": 0.9}, + ] + + score = EvaluationMetricsCalculator.calculate_overall_score(retrieval, []) + + assert score == pytest.approx(0.6) + + +def test_overall_score_returns_none_without_any_metrics(): + score = EvaluationMetricsCalculator.calculate_overall_score([], []) assert score is None diff --git a/docs/develop-guides/roadmap.md b/docs/develop-guides/roadmap.md index 3b58b3b3..4ee240ec 100644 --- a/docs/develop-guides/roadmap.md +++ b/docs/develop-guides/roadmap.md @@ -64,7 +64,7 @@ - 扩展知识库上传来源:添加“从工作区上传”模式,后端将当前用户工作区文件预处理上传到 MinIO,前端沿用现有 `addDocuments` 入库链路提交 MinIO URL、内容哈希和文件大小。 - 重构知识库详情页布局:`DatabaseInfo` 改为顶部详情 header + 左侧功能 tab 侧边栏 + 右侧内容区,Milvus 默认进入文件管理,并将检索测试、知识图谱、知识导图、检索配置、RAG 评估和评估基准统一纳入侧边栏导航;只读连接器保留检索测试与检索配置。 - 整合知识导图接口:移除独立 mindmap router 与前端 API 模块,思维导图生成、查询和文件列表接口统一收敛到知识库 API 下。 -- 收敛独立模型配置模块运行时:运行时 chat / embedding / rerank 均统一从 provider 模块与模型缓存读取 `provider_id:model_id`;旧版静态模型配置、v1 slash spec、旧模型列表接口和 Ollama 适配已移除。 +- 收敛独立模型配置模块运行时:运行时 chat / embedding / rerank 均统一从 provider 模块与模型缓存读取 `provider_id:model_id`;旧版静态模型配置、v1 slash spec、旧模型列表接口和 Ollama 适配已移除;内置 provider 模板补充 XiaomiMiMo、XiaomiMiMo Token Plan CN 与 Kimi Code(`kimi-for-coding`)。 - 调整智能体配置归属与字段权限:`AgentConfig` 从部门共享改为按 `uid` 隔离,所有登录用户可管理自己的配置;`BaseContext` 支持字段级 `auth` 元数据,后端按用户角色过滤可见与可保存的配置项。 - 新增用户级沙盒环境变量:增加 `agent_envs` 表与 `/api/user/agent-env` 接口,设置面板支持当前用户维护 Agent 沙盒环境变量;创建新沙盒时与全局 `sandbox.env` 合并注入,用户变量优先。 - 收敛用户身份命名:原业务登录标识统一改为 `uid`,Agent/LangGraph runtime、conversation、agent_run、sandbox 路径和前端用户态均使用字符串 `uid`;`user_id` 仅保留给外部响应中的数值 `users.id` 或真实外键场景。 @@ -77,6 +77,7 @@ - 升级 DeepAgents 到 0.6.7 并适配新版文件系统协议:SubAgentMiddleware 改为显式 subagent spec,Skills prompt 补齐新版占位符;sandbox/skills backend 复用新版 `ReadResult`、`GlobResult`、`GrepResult` 等协议类型,文件权限在 backend 层明确区分 skills、uploads、outputs 与 workspace,保留最小 `CustomCompositeBackend` 以避免非 route glob 误扫其他 route;Agent 上下文压缩改为复用 DeepAgents SummarizationMiddleware,历史摘要与大工具结果统一 offload 到 outputs。 - 优化聊天输入 @ 文件提及:未创建 Thread 时可搜索用户 workspace,创建 Thread 后按当前对话文件优先、workspace 兜底的来源顺序搜索,并拆分 workspace/thread 缓存避免假 thread 与跨用户缓存污染;输入框与用户消息支持将 raw mention 渲染为带类型图标的引用单元,文件仅显示文件名且保留原始沙盒路径文本。 - 重构子智能体为 Agent-backed 形态:移除旧 `subagents` 表与 `/api/system/subagents` 管理链路,子智能体改为 `agents.is_subagent=true` 且使用 `SubAgentBackend`,创建/编辑统一走 Agent 管理入口;内置后端收敛为 `ChatbotAgent` 与 `SubAgentBackend`,Context 分为 `BaseContext`、`ChatBotContext` 与 `SubAgentContext`;主 Agent 通过 Yuxi task middleware 启动真实子 Agent graph,子智能体不再嵌套调用子智能体。沙盒挂载同步拆分为 child checkpoint thread、父对话 uploads/outputs、用户级 workspace 与子 Agent skills scope;主线程状态记录 `subagent_runs` 并在前端 task 工具中展示子智能体名称、执行状态、child thread 和产物,task 工具结果会暴露 child thread ID 且支持传回 `thread_id` 继续既有子智能体线程;子智能体执行复用 `agent_runs(run_type=subagent)` 记录父 run、child thread 与状态,child thread state 查询以 `agent_runs` 关系为准,不再解析 thread ID 反推父线程;真实流式 E2E 覆盖子智能体输出文件可由父线程文件/Viewer API 读取。流式链路参考 DeepAgents event streaming,后端将 LangGraph v3 raw event 归一化为 Yuxi semantic stream event,按父/子线程归属隔离 run SSE chunk,并支持通过 child thread state 拉取子智能体中间过程。 +- 修正评估综合得分计算:`overall_score` 改为有答案准确率时取各题准确率平均,否则取各题 `recall@10` 平均,不再把 recall/f1/各 k 检索指标混合平均;历史已存运行不回填。 ---