test_knowledge.md 11 KB

routers/knowledge.py 接口测试文档

文件功能概述

该文件提供知识库相关的接口,包括:

  • ChromaDB 向量数据库文档查询(语义检索)
  • 知识库文件高级搜索(关键词 + 分类 + 日期 + 分页)

路由前缀:/apiv1(以 routers/__init__.py 中注册为准)

注意: 这两个接口均未在代码中显式检查 request.state.user,但仍受全局中间件的 Token 校验影响。


接口列表


1. GET /apiv1/get_chromadb_document — 获取 ChromaDB 文档

功能说明: 使用语义查询从 ChromaDB 向量数据库中检索相关文档。如果 ChromaDB 服务不可用,会返回基于查询关键词的模拟数据(fallback)。

是否需要认证: 是(全局中间件)

请求方式: GET

请求参数(Query): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | query | string | 是 | — | 查询文本(用于语义检索) | | n | int | 否 | 5 | 返回结果数量(最多返回 n 条) |

业务逻辑:

  • 延迟导入 chromadb_servicefrom services.chromadb_service import chromadb_service
  • 调用 chromadb_service.query(query, n) 执行语义检索
  • 如果 ChromaDB 服务抛出异常,返回模拟数据(最多 5 条),msg 标记为 "success (fallback)"

成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data | array | 文档结果列表,每项含 content、score、metadata |

测试用例:

用例 1:正常查询(ChromaDB 可用)

// 请求
GET /apiv1/get_chromadb_document?query=隧道施工安全规范&n=3
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": [
    {
      "content": "隧道施工安全规范相关内容...",
      "score": 0.95,
      "metadata": {"source": "tunnel_safety.pdf"}
    },
    {
      "content": "另一段相关内容...",
      "score": 0.88,
      "metadata": {"source": "construction_guide.pdf"}
    },
    {
      "content": "第三段相关内容...",
      "score": 0.82,
      "metadata": {"source": "safety_manual.pdf"}
    }
  ]
}

用例 2:使用默认 n 值

// 请求
GET /apiv1/get_chromadb_document?query=桥梁工程
token: <有效Token>

// 预期响应 (HTTP 200)
// 默认返回最多 5 条结果
{
  "statusCode": 200,
  "msg": "success",
  "data": [
    // ... 最多 5 条文档结果
  ]
}

用例 3:ChromaDB 服务不可用(fallback 模拟数据)

// 请求(ChromaDB 服务异常时)
GET /apiv1/get_chromadb_document?query=路基施工&n=3
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success (fallback)",
  "data": [
    {
      "content": "关于路基施工的文档内容1",
      "score": 0.8,
      "metadata": {"source": "doc_1.pdf"}
    },
    {
      "content": "关于路基施工的文档内容2",
      "score": 0.7,
      "metadata": {"source": "doc_2.pdf"}
    },
    {
      "content": "关于路基施工的文档内容3",
      "score": 0.6,
      "metadata": {"source": "doc_3.pdf"}
    }
  ]
}

注意:fallback 模式下 score 是固定计算的(0.9 - i * 0.1),最多返回 5 条。

用例 4:未提供 query 参数

// 请求
GET /apiv1/get_chromadb_document
token: <有效Token>

// 预期响应 (HTTP 422)
{
  "detail": [
    {
      "loc": ["query", "query"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

用例 5:未认证

// 请求
GET /apiv1/get_chromadb_document?query=测试

// 预期响应 (HTTP 401)
{
  "statusCode": 401,
  "msg": "未提供认证Token"
}

2. GET /apiv1/knowledge/files/advanced-search — 知识库高级搜索

功能说明: 在数据库 PolicyFile 表中按多条件组合搜索知识库文件,支持关键词模糊匹配、分类筛选、日期范围筛选和分页。

是否需要认证: 是(全局中间件)

请求方式: GET

请求参数(Query): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | keyword | string | 否 | None | 关键词(模糊匹配 policy_name) | | category | string | 否 | None | 分类名称(支持:"国家规范"、"行业规范"、"地方规范"、"内部条例") | | date_from | string | 否 | None | 起始日期(格式 YYYY-MM-DD) | | date_to | string | 否 | None | 截止日期(格式 YYYY-MM-DD) | | page | int | 否 | 1 | 页码 | | page_size | int | 否 | 20 | 每页条数 |

业务逻辑:

  • 关键词:PolicyFile.policy_name LIKE '%keyword%'
  • 分类映射:{"国家规范": 1, "行业规范": 2, "地方规范": 3, "内部条例": 4},非映射值时忽略该条件
  • 日期:将 YYYY-MM-DD 格式转为 Unix 时间戳进行范围过滤(created_at 字段)
  • 分页:offset = (page - 1) * page_size

成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data.total | int | 匹配结果总数 | | data.page | int | 当前页码 | | data.page_size | int | 每页条数 | | data.items | array | 文件列表 | | data.items[].id | int | 文件 ID | | data.items[].policy_name | string | 文件名 | | data.items[].policy_file_url | string | 文件 URL | | data.items[].policy_type | int | 文件分类(1-4) | | data.items[].view_count | int | 浏览次数 | | data.items[].file_type | string | 文件类型 | | data.items[].created_at | int | 创建时间(Unix 时间戳) |

测试用例:

用例 1:无条件搜索(获取全部,默认分页)

// 请求
GET /apiv1/knowledge/files/advanced-search
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 50,
    "page": 1,
    "page_size": 20,
    "items": [
      {
        "id": 1,
        "policy_name": "公路隧道施工技术规范",
        "policy_file_url": "https://oss.example.com/files/tunnel_spec.pdf",
        "policy_type": 1,
        "view_count": 120,
        "file_type": "pdf",
        "created_at": 1700000000
      }
      // ... 最多 20 条
    ]
  }
}

用例 2:关键词搜索

// 请求
GET /apiv1/knowledge/files/advanced-search?keyword=隧道
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 5,
    "page": 1,
    "page_size": 20,
    "items": [
      {
        "id": 1,
        "policy_name": "公路隧道施工技术规范",
        "policy_file_url": "...",
        "policy_type": 1,
        "view_count": 120,
        "file_type": "pdf",
        "created_at": 1700000000
      }
      // ... 所有 policy_name 包含"隧道"的记录
    ]
  }
}

用例 3:分类筛选

// 请求
GET /apiv1/knowledge/files/advanced-search?category=国家规范
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 15,
    "page": 1,
    "page_size": 20,
    "items": [
      // ... 所有 policy_type == 1 的记录
    ]
  }
}

用例 4:不支持的分类值(忽略该条件)

// 请求
GET /apiv1/knowledge/files/advanced-search?category=其他分类
token: <有效Token>

// 预期响应 (HTTP 200)
// category 不在映射中,等同于不筛选分类
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 50,
    "page": 1,
    "page_size": 20,
    "items": [...]
  }
}

用例 5:日期范围筛选

// 请求
GET /apiv1/knowledge/files/advanced-search?date_from=2024-01-01&date_to=2024-12-31
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 20,
    "page": 1,
    "page_size": 20,
    "items": [
      // ... created_at 在 2024-01-01 至 2024-12-31 之间的记录
    ]
  }
}

用例 6:多条件组合搜索

// 请求
GET /apiv1/knowledge/files/advanced-search?keyword=安全&category=行业规范&date_from=2024-06-01&page=1&page_size=10
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 3,
    "page": 1,
    "page_size": 10,
    "items": [
      // ... policy_name 包含"安全" 且 policy_type == 2 且 created_at >= 2024-06-01 的记录
    ]
  }
}

用例 7:分页 — 第二页

// 请求
GET /apiv1/knowledge/files/advanced-search?page=2&page_size=10
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 50,
    "page": 2,
    "page_size": 10,
    "items": [
      // ... 第 11-20 条记录
    ]
  }
}

用例 8:搜索结果为空

// 请求
GET /apiv1/knowledge/files/advanced-search?keyword=不存在的关键词xxxyyy
token: <有效Token>

// 预期响应 (HTTP 200)
{
  "statusCode": 200,
  "msg": "success",
  "data": {
    "total": 0,
    "page": 1,
    "page_size": 20,
    "items": []
  }
}

用例 9:日期格式错误

// 请求
GET /apiv1/knowledge/files/advanced-search?date_from=2024/01/01
token: <有效Token>

// 预期响应 (HTTP 500)
// time.strptime 会抛出 ValueError
// 具体行为取决于全局异常处理器

注意:代码中 time.strptime(date_from, "%Y-%m-%d") 对日期格式有严格要求,非 YYYY-MM-DD 格式会引发异常。

用例 10:未认证

// 请求
GET /apiv1/knowledge/files/advanced-search?keyword=测试

// 预期响应 (HTTP 401)
{
  "statusCode": 401,
  "msg": "未提供认证Token"
}

依赖说明

依赖项 说明
database.get_db SQLAlchemy 数据库会话
models.total.PolicyFile 政策文件模型(字段:id, policy_name, policy_file_url, policy_type, view_count, file_type, created_at)
services.chromadb_service ChromaDB 向量数据库服务(延迟导入),提供 query(text, n) 方法
request.state.user 从中间件注入的用户信息(本文件接口未显式使用但受全局中间件保护)

代码备注

  1. get_chromadb_document 使用延迟导入(函数内 from ... import ...),避免在 ChromaDB 服务未部署时导致模块加载失败。
  2. get_chromadb_document 有完善的 fallback 机制:ChromaDB 不可用时返回基于查询关键词的模拟数据,不会返回错误。
  3. advanced_search 的分类映射是硬编码的字典 {"国家规范": 1, "行业规范": 2, "地方规范": 3, "内部条例": 4},不在映射内的分类值会被静默忽略(不会筛选也不会报错)。
  4. advanced_search 的日期筛选使用 time.strptime 解析,仅支持 YYYY-MM-DD 格式,其他格式会导致未捕获的 ValueError 异常。
  5. advanced_search 的两个接口参数中 request 都标注为 = None,但在全局中间件保护下 request 实际始终可用。