openapi: 3.1.0
info:
  title: Component Search Benchmark API
  version: 1.0.0
  description: BM25、向量、混合召回与固定候选重排序接口。
servers:
  - url: /
security:
  - bearerAuth: []
  - apiKeyAuth: []
paths:
  /open-api/v1/search:
    post:
      operationId: searchComponents
      summary: 召回并可选重排元器件
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchRequest'
      responses:
        '200':
          description: 检索成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/InvalidRequest'
        '429':
          $ref: '#/components/responses/RateLimited'
        '502':
          $ref: '#/components/responses/UpstreamFailure'
  /open-api/v1/rerank:
    post:
      operationId: rerankComponents
      summary: 对固定候选元器件进行重排序
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RerankRequest'
      responses:
        '200':
          description: 重排序成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RerankResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/InvalidRequest'
        '429':
          $ref: '#/components/responses/RateLimited'
        '502':
          $ref: '#/components/responses/UpstreamFailure'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'Authorization: Bearer axs_live....'
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
  schemas:
    SearchRequest:
      type: object
      additionalProperties: false
      required: [query]
      properties:
        query:
          type: string
          minLength: 1
          maxLength: 1000
        mode:
          type: string
          enum: [bm25, vector, hybrid]
          default: hybrid
        candidate_k:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
          description: 进入可选重排序阶段的召回数量；启用 rerank 时最大 100。
        top_k:
          type: integer
          minimum: 1
          maximum: 100
          default: 10
          description: 最终返回数量，不得超过 candidate_k。
        rerank:
          type: boolean
          default: false
    RerankRequest:
      type: object
      additionalProperties: false
      required: [query, candidate_ids]
      properties:
        query:
          type: string
          minLength: 1
          maxLength: 1000
        candidate_ids:
          type: array
          minItems: 1
          maxItems: 100
          uniqueItems: true
          items:
            oneOf:
              - type: string
                pattern: '^\d+$'
              - type: integer
                minimum: 0
        top_k:
          type: integer
          minimum: 1
          maximum: 100
          default: 10
    SearchResult:
      type: object
      required:
        - component_id
        - retrieval_rank
        - retrieval_score
      properties:
        component_id:
          type: string
        part_number:
          type: [string, 'null']
        mpn:
          type: [string, 'null']
        manufacturer:
          type: [string, 'null']
        supplier:
          type: [string, 'null']
        category_id:
          type: [string, 'null']
        category_path:
          type: array
          items:
            type: string
        source_category:
          type: [string, 'null']
        description:
          type: [string, 'null']
        product_status:
          type: [string, 'null']
        product_url:
          type: [string, 'null']
        datasheet_url:
          type: [string, 'null']
        image_url:
          type: [string, 'null']
        retrieval_rank:
          type: integer
        retrieval_score:
          type: [number, 'null']
          description: Milvus/BM25/RRF 原始分数；数值越大越相关。
        rerank_rank:
          type: [integer, 'null']
        rerank_score:
          type: [number, 'null']
          description: 当前序列模型只输出次序，因此固定为 null。
    Versions:
      type: object
      properties:
        api:
          type: string
        collection:
          type: string
        retrieval_pipeline:
          type: string
        embedding_model:
          type: [string, 'null']
        rerank_model:
          type: [string, 'null']
        rerank_prompt:
          type: [string, 'null']
    Timings:
      type: object
      additionalProperties:
        type: number
      description: 各阶段毫秒耗时。
    SearchData:
      type: object
      required: [query, mode, rerank, rerank_applied, candidate_k, candidate_count, top_k, results, timings_ms, versions]
      properties:
        query:
          type: string
        mode:
          type: string
          enum: [bm25, vector, hybrid]
        rerank:
          type: boolean
        rerank_applied:
          type: boolean
          description: false 表示未启用重排，或重排模型没有返回有效次序。
        candidate_k:
          type: integer
        candidate_count:
          type: integer
        top_k:
          type: integer
        results:
          type: array
          items:
            $ref: '#/components/schemas/SearchResult'
        timings_ms:
          $ref: '#/components/schemas/Timings'
        versions:
          $ref: '#/components/schemas/Versions'
    SearchResponse:
      type: object
      required: [success, data]
      properties:
        success:
          type: boolean
          const: true
        data:
          $ref: '#/components/schemas/SearchData'
    RerankData:
      type: object
      required: [query, candidate_count, top_k, rerank_applied, results, timings_ms, versions]
      properties:
        query:
          type: string
        candidate_count:
          type: integer
        top_k:
          type: integer
        rerank_applied:
          type: boolean
        results:
          type: array
          items:
            $ref: '#/components/schemas/SearchResult'
        timings_ms:
          $ref: '#/components/schemas/Timings'
        versions:
          $ref: '#/components/schemas/Versions'
    RerankResponse:
      type: object
      required: [success, data]
      properties:
        success:
          type: boolean
          const: true
        data:
          $ref: '#/components/schemas/RerankData'
    ErrorResponse:
      type: object
      required: [success, error]
      properties:
        success:
          type: boolean
          const: false
        error:
          type: string
        code:
          type: string
        details:
          type: array
          items:
            type: object
            properties:
              path:
                type: string
              message:
                type: string
  responses:
    Unauthorized:
      description: API Key 缺失或无效
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InvalidRequest:
      description: 请求参数无效
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: 分钟或每日额度用尽
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    UpstreamFailure:
      description: 检索后端不可用或执行失败
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
