proofdb/apidoc/searchapi.md
2026-05-08 00:05:51 +08:00

9.5 KiB
Raw Blame History

搜索 API

接口说明

Proof DB 的搜索接口基于 OpenSearch proofdb_chunks 索引。当前版本已实现全文搜索,检索单位是 chunk返回结果包含档案元数据、页码范围和 chunk 文本,便于后续 evidence reconstruction。

OpenSearch 中每个 chunk 文档同时包含:

  • text 等全文字段,用于 BM25 检索。
  • summary 档案摘要字段,会参与全文检索,也会随搜索结果一起返回。
  • embedding 2048 维向量字段,用于后续 vector / hybrid 检索。

全文搜索

POST /api/search/fulltext

请求格式

Content-Type: application/json

字段 类型 必填 说明
query string 搜索关键词或短语
limit int 返回条数,默认 10,最大 50
filters object 过滤条件
filters.archive_uid string 只搜索某个 archive
filters.chunk_uid string 只搜索某个 chunk
filters.source string 精确匹配 source
filters.author string 精确匹配 author
filters.series string 精确匹配 series
filters.year int 精确匹配年份
filters.tags string|array 匹配一个或多个 tag

请求示例

curl -X POST <APIdomain>/api/search/fulltext \
  -H 'Content-Type: application/json' \
  --data '{
    "query": "policy documents",
    "limit": 5
  }'

带过滤条件:

curl -X POST <APIdomain>/api/search/fulltext \
  -H 'Content-Type: application/json' \
  --data '{
    "query": "Iraq Kuwait",
    "limit": 10,
    "filters": {
      "year": 1992,
      "tags": ["NSD 76"]
    }
  }'

成功响应

状态码:

200 OK

响应示例:

{
  "code": 0,
  "message": "Full-text search completed.",
  "data": {
    "mode": "fulltext",
    "query": "policy documents",
    "limit": 5,
    "filters": [],
    "total": 1,
    "hits": [
      {
        "score": 12.34,
        "chunk_uid": "01KQHVREB6XPYF604RVZAP9NNY_1_39003",
        "archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
        "chunk_index": 1,
        "page_start": 1,
        "page_end": 1,
        "title": "NSD 76 Disposition of NSC Policy Documents",
        "summary": "Summary text...",
        "source": "archive://nsc/nsd-76",
        "author": "Brent Scowcroft",
        "year": 1992,
        "series": null,
        "tags": ["NSD 76", "政策文件"],
        "text": "chunk text...",
        "embedding_model": "embedding-3",
        "embedding_dimensions": 2048
      }
    ]
  }
}

说明:

  • hits 是当前返回的结果数组。
  • total 是当前 full-text 查询下的命中总数。
  • 全文搜索当前会综合匹配 texttitlesummarysourceauthorseriestags

错误响应

JSON 格式错误

状态码:

400 Bad Request
{
  "code": 400,
  "message": "Invalid JSON body.",
  "errors": {
    "body": "Syntax error"
  }
}

缺少 query

状态码:

422 Unprocessable Entity
{
  "code": 422,
  "message": "Search request validation failed.",
  "errors": {
    "query": "query is required."
  }
}

搜索失败

状态码:

500 Internal Server Error
{
  "code": 500,
  "message": "Full-text search failed.",
  "errors": {
    "search": "error message"
  }
}

向量搜索

POST /api/search/vector

请求格式

Content-Type: application/json

字段 类型 必填 说明
query string 搜索语句。系统会先调用智谱 embedding-3 转成 2048 维向量
limit int 返回条数,默认 10,最大 50
k int OpenSearch kNN 候选数,默认等于 limit,最大 50
filters object 过滤条件,同全文搜索

请求示例

curl -X POST <APIdomain>/api/search/vector \
  -H 'Content-Type: application/json' \
  --data '{
    "query": "Iraq invasion and Desert Storm",
    "limit": 5,
    "k": 10
  }'

中文 query 也可以提交给向量搜索:

curl -X POST <APIdomain>/api/search/vector \
  -H 'Content-Type: application/json' \
  --data '{
    "query": "伊拉克入侵科威特与沙漠风暴",
    "limit": 5
  }'

成功响应

状态码:

200 OK

响应示例:

{
  "code": 0,
  "message": "Vector search completed.",
  "data": {
    "mode": "vector",
    "query": "Iraq invasion and Desert Storm",
    "limit": 5,
    "k": 10,
    "filters": [],
    "embedding_model": "embedding-3",
    "embedding_dimensions": 2048,
    "total": 5,
    "hits": [
      {
        "score": 0.91,
        "chunk_uid": "01KQHVREB6XPYF604RVZAP9NNY_14_97554",
        "archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
        "chunk_index": 14,
        "page_start": 8,
        "page_end": 8,
        "title": "NSD 76 Disposition of NSC Policy Documents",
        "summary": "Summary text...",
        "source": "archive://nsc/nsd-76",
        "author": "Brent Scowcroft",
        "year": 1992,
        "series": null,
        "tags": ["NSD 76", "政策文件"],
        "text": "chunk text...",
        "embedding_model": "embedding-3",
        "embedding_dimensions": 2048
      }
    ]
  }
}

说明:

  • hits 是当前返回的结果数组。
  • total 是当前 vector 查询返回的候选总数。
  • embedding_dimensions 是本次 query embedding 的维度,而不是索引总维度统计字段。

错误响应

错误响应格式与全文搜索一致。常见错误包括:

  • JSON 格式错误:400 Bad Request
  • 缺少 query422 Unprocessable Entity
  • embedding API 或 OpenSearch 查询失败:500 Internal Server Error

混合搜索

POST /api/search/hybrid

接口说明

混合搜索会对同一个 query 同时执行:

  1. BM25 全文搜索。
  2. 2048 维向量 kNN 搜索。
  3. 使用 Reciprocal Rank FusionRRF合并排序。

第一版不做额外 reranker。RRF 不直接比较 BM25 分数和向量分数,而是根据两路结果中的排名融合,适合作为稳定的 hybrid baseline。

请求格式

Content-Type: application/json

字段 类型 必填 说明
query string 搜索语句
limit int 最终返回条数,默认 10,最大 50
candidate_limit int 每一路召回候选数,默认 max(limit * 3, 20),最大 50
rrf_k int RRF 平滑参数,默认 60
filters object 过滤条件,同全文搜索
ai bool 默认 false。传 true 时,系统先调用现有 LLM chat 通道把原始 query 改写为 BM25 关键词;全文搜索使用 AI 关键词,向量搜索仍使用原始 query

如果 AI 关键词生成失败或超时,系统会回退为使用原始 query 做全文搜索,并在响应的 keywords.error 中返回错误信息;向量搜索不受影响。

请求示例

curl -X POST <APIdomain>/api/search/hybrid \
  -H 'Content-Type: application/json' \
  --data '{
    "query": "Iraq invasion and Desert Storm",
    "limit": 5,
    "candidate_limit": 20
  }'

中文 query

curl -X POST <APIdomain>/api/search/hybrid \
  -H 'Content-Type: application/json' \
  --data '{
    "query": "伊拉克入侵科威特与沙漠风暴",
    "limit": 5,
    "ai": true
  }'

成功响应

状态码:

200 OK

响应示例:

{
  "code": 0,
  "message": "Hybrid search completed.",
  "data": {
    "mode": "hybrid",
    "query": "Iraq invasion and Desert Storm",
    "limit": 5,
    "candidate_limit": 20,
    "rrf_k": 60,
    "filters": [],
    "ai": true,
    "fulltext_query": "Iraq Kuwait invasion Desert Storm",
    "vector_query": "Iraq invasion and Desert Storm",
    "keywords": {
      "enabled": true,
      "attempted": true,
      "error": null,
      "keywords": ["Iraq", "Kuwait", "invasion", "Desert Storm"],
      "query": "Iraq Kuwait invasion Desert Storm",
      "model": "glm-4.7-flash"
    },
    "total": 10,
    "sources": {
      "fulltext_total": 1,
      "vector_total": 20,
      "fulltext_hits": 1,
      "vector_hits": 20
    },
    "hits": [
      {
        "score": 4.13,
        "hybrid_score": 0.0325,
        "rank_sources": {
          "fulltext": {
            "rank": 1,
            "score": 4.13,
            "rrf": 0.0163934426
          },
          "vector": {
            "rank": 1,
            "score": 0.79,
            "rrf": 0.0163934426
          }
        },
        "chunk_uid": "01KQHVREB6XPYF604RVZAP9NNY_14_97554",
        "archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
        "page_start": 8,
        "page_end": 8,
        "summary": "Summary text...",
        "text": "chunk text..."
      }
    ]
  }
}

说明:

  • hits 是融合排序后的结果数组。
  • total 是融合后的候选总数。
  • sources.fulltext_totalsources.vector_total 分别表示两路召回的原始统计。
  • rank_sources 用于说明某条结果在 fulltext / vector 两路中的排名与 RRF 贡献。
  • summary 来自 archive 级摘要元数据,不是 chunk 单独生成的摘要。

错误响应

错误响应格式与全文搜索一致。常见错误包括:

  • JSON 格式错误:400 Bad Request
  • 缺少 query422 Unprocessable Entity
  • embedding API、全文搜索或向量搜索失败500 Internal Server Error

相关接口

与搜索结果配套的证据查看接口见: