openapi: 3.0.3
info:
  title: AI Service API
  description: |
    Python AI 服务对外提供的接口契约（Provider）。

    目标：100% 覆盖并对齐 Java 端 Consumer-First 依赖契约 `java/openapi.deps.yaml`。
    - 路径与方法必须一致
    - non-streaming JSON 响应 schema 必须一致（reply/confidence/shouldTransfer 等）

    额外扩展：支持 SSE 流式输出（Accept: text/event-stream）。
  version: 1.1.0
  x-contract-level: L2
  x-provider: "python-ai-service"
  x-consumer: "java-main-framework"

servers:
  - url: http://ai-service:8080
    description: AI 服务地址

tags:
  - name: AI Chat
    description: 对话生成
  - name: Health
    description: 健康检查
  - name: Embedding Management
    description: 嵌入模型管理
  - name: LLM Management
    description: LLM 模型管理
  - name: RAG Lab
    description: RAG 实验室

paths:
  /ai/chat:
    post:
      operationId: generateReply
      summary: 生成 AI 回复
      description: |
        根据用户消息和会话历史生成 AI 回复。

        non-streaming：返回 application/json（ChatResponse）。
        streaming：当请求头包含 `Accept: text/event-stream` 时，以 SSE 推送事件流。

        覆盖验收标准（来自 Java 侧契约描述）：
        - AC-MCA-04: 主框架通过 HTTP POST 调用 AI 服务
        - AC-MCA-05: 响应包含 reply、confidence、shouldTransfer 字段
        - AC-MCA-06: AI 服务不可用时的降级处理（主框架侧实现）
        - AC-MCA-07: 超时处理（主框架侧实现）
      tags:
        - AI Chat
      x-requirements:
        - AC-MCA-04
        - AC-MCA-04-REQ
        - AC-MCA-04-OPT
        - AC-MCA-05
        - AC-MCA-06
        - AC-MCA-07
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          description: 租户ID（多租户隔离必填，便于网关/拦截器统一处理）
          schema:
            type: string
        - name: Accept
          in: header
          required: false
          description: |
            内容协商。
            - 设置为 text/event-stream 时返回 SSE 事件流
            - 其他情况返回 application/json
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatRequest'
            example:
              sessionId: "kf_001_wx123456_1708765432000"
              currentMessage: "我想了解产品价格"
              channelType: "wechat"
              metadata:
                channelUserId: "wx123456"
                extra: "..."
      responses:
        '200':
          description: |
            成功生成回复。

            注意：
            - non-streaming：响应 Content-Type 为 application/json
            - streaming：当请求头 Accept: text/event-stream 时，服务端可返回 text/event-stream（见下方 200 的第二种 content 描述）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatResponse'
              example:
                reply: "您好，我们的产品价格根据套餐不同有所差异。"
                confidence: 0.92
                shouldTransfer: false
            text/event-stream:
              schema:
                type: string
                description: |
                  SSE 事件流（按行文本）。事件模型：

                  1) event: message
                     - data: {"delta": "..."}
                     - 返回时机：模型生成过程中多次发送，用于增量渲染。

                  2) event: final
                     - data: ChatResponse（完整结构化结果，字段至少包含 reply/confidence/shouldTransfer）
                     - 返回时机：生成结束时发送一次，随后关闭连接。

                  3) event: error
                     - data: ErrorResponse（结构化错误，至少 code/message，可含 details）
                     - 返回时机：发生错误时发送一次，随后关闭连接。

                  示例（片段）：
                  event: message\n
data: {"delta":"您好，"}\n

                  event: final\n
data: {"reply":"...","confidence":0.9,"shouldTransfer":false}\n
        '400':
          description: 请求参数错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: 服务内部错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: 服务不可用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /ai/health:
    get:
      operationId: healthCheck
      summary: 健康检查
      description: 检查 AI 服务是否正常运行
      tags:
        - Health
      responses:
        '200':
          description: 服务正常
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
        '503':
          description: 服务不健康

  /admin/embedding/providers:
    get:
      operationId: listEmbeddingProviders
      summary: 获取可用的嵌入模型提供者列表
      description: |
        返回所有已注册的嵌入模型提供者及其配置参数定义。
        
        覆盖验收标准：
        - AC-AISVC-38: 返回所有已注册的提供者列表及其配置参数定义
      tags:
        - Embedding Management
      x-requirements:
        - AC-AISVC-38
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          description: 租户ID
          schema:
            type: string
      responses:
        '200':
          description: 成功返回提供者列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  providers:
                    type: array
                    items:
                      $ref: '#/components/schemas/EmbeddingProviderInfo'
        '500':
          description: 服务内部错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/embedding/config:
    get:
      operationId: getEmbeddingConfig
      summary: 获取当前嵌入模型配置
      description: |
        返回当前激活的嵌入模型提供者及其参数配置。
        
        覆盖验收标准：
        - AC-AISVC-39: 返回当前激活的提供者及其参数配置
      tags:
        - Embedding Management
      x-requirements:
        - AC-AISVC-39
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          description: 租户ID
          schema:
            type: string
      responses:
        '200':
          description: 成功返回当前配置
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmbeddingConfig'
        '500':
          description: 服务内部错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    put:
      operationId: updateEmbeddingConfig
      summary: 更新嵌入模型配置
      description: |
        更新嵌入模型配置，支持热更新（无需重启服务）。
        
        覆盖验收标准：
        - AC-AISVC-40: 验证配置有效性，更新配置并返回成功状态
        - AC-AISVC-31: 支持热更新
      tags:
        - Embedding Management
      x-requirements:
        - AC-AISVC-40
        - AC-AISVC-31
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          description: 租户ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmbeddingConfigUpdate'
            example:
              provider: "ollama"
              config:
                base_url: "http://localhost:11434"
                model: "nomic-embed-text"
                dimension: 768
      responses:
        '200':
          description: 配置更新成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
        '400':
          description: 配置参数无效
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: 服务内部错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/embedding/test:
    post:
      operationId: testEmbedding
      summary: 测试嵌入模型连接
      description: |
        调用嵌入模型生成测试向量，返回连接状态和向量维度信息。
        
        覆盖验收标准：
        - AC-AISVC-41: 调用嵌入模型生成测试向量，返回连接状态和向量维度信息
      tags:
        - Embedding Management
      x-requirements:
        - AC-AISVC-41
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          description: 租户ID
          schema:
            type: string
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                test_text:
                  type: string
                  description: 测试文本（可选，默认使用固定测试文本）
                  example: "这是一个测试文本"
                config:
                  $ref: '#/components/schemas/EmbeddingConfigUpdate'
                  description: 测试配置（可选，不传则使用当前配置）
      responses:
        '200':
          description: 测试成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmbeddingTestResult'
        '400':
          description: 配置参数无效
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: 连接测试失败
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  schemas:
    ChatRequest:
      type: object
      required:
        - sessionId
        - currentMessage
        - channelType
      properties:
        sessionId:
          type: string
          description: 会话ID（AC-MCA-04-REQ 必填）
        currentMessage:
          type: string
          description: 当前用户消息（AC-MCA-04-REQ 必填）
        channelType:
          type: string
          description: 渠道类型（AC-MCA-04-REQ 必填）
          enum:
            - wechat
            - douyin
            - jd
        history:
          type: array
          description: 历史消息列表（AC-MCA-04-OPT 可选）
          items:
            $ref: '#/components/schemas/ChatMessage'
        metadata:
          type: object
          description: 扩展元数据（AC-MCA-04-OPT 可选）
          additionalProperties: true

    ChatMessage:
      type: object
      required:
        - role
        - content
      properties:
        role:
          type: string
          enum:
            - user
            - assistant
        content:
          type: string

    ChatResponse:
      type: object
      required:
        - reply
        - confidence
        - shouldTransfer
      properties:
        reply:
          type: string
          description: AI 回复内容（AC-MCA-05 必填）
        confidence:
          type: number
          format: double
          description: 置信度评分 0.0-1.0（AC-MCA-05 必填）
        shouldTransfer:
          type: boolean
          description: 是否建议转人工（AC-MCA-05 必填）
        transferReason:
          type: string
          description: 转人工原因（可选）
        metadata:
          type: object
          description: 响应元数据（可选）
          additionalProperties: true

    ErrorResponse:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: 错误代码
        message:
          type: string
          description: 错误消息
        details:
          type: array
          description: 详细错误信息（可选）
          items:
            type: object
            additionalProperties: true

    EmbeddingProviderInfo:
      type: object
      description: 嵌入模型提供者信息
      required:
        - name
        - display_name
        - config_schema
      properties:
        name:
          type: string
          description: 提供者唯一标识
          example: "ollama"
        display_name:
          type: string
          description: 提供者显示名称
          example: "Ollama 本地模型"
        description:
          type: string
          description: 提供者描述
          example: "使用 Ollama 运行的本地嵌入模型"
        config_schema:
          type: object
          description: 配置参数定义（JSON Schema 格式）
          additionalProperties: true
          example:
            base_url:
              type: "string"
              description: "Ollama API 地址"
              default: "http://localhost:11434"
            model:
              type: "string"
              description: "模型名称"
              default: "nomic-embed-text"
            dimension:
              type: "integer"
              description: "向量维度"
              default: 768

    EmbeddingConfig:
      type: object
      description: 当前嵌入模型配置
      required:
        - provider
        - config
      properties:
        provider:
          type: string
          description: 当前激活的提供者
          example: "ollama"
        config:
          type: object
          description: 提供者配置参数
          additionalProperties: true
          example:
            base_url: "http://localhost:11434"
            model: "nomic-embed-text"
            dimension: 768
        updated_at:
          type: string
          format: date-time
          description: 配置最后更新时间

    EmbeddingConfigUpdate:
      type: object
      description: 嵌入模型配置更新请求
      required:
        - provider
      properties:
        provider:
          type: string
          description: 提供者标识
          example: "ollama"
        config:
          type: object
          description: 提供者配置参数
          additionalProperties: true

    EmbeddingTestResult:
      type: object
      description: 嵌入模型测试结果
      required:
        - success
        - dimension
      properties:
        success:
          type: boolean
          description: 测试是否成功
        dimension:
          type: integer
          description: 返回的向量维度
          example: 768
        latency_ms:
          type: number
          description: 响应延迟（毫秒）
          example: 125.5
        message:
          type: string
          description: 测试结果消息
          example: "连接成功，向量维度: 768"
        error:
          type: string
          description: 错误信息（失败时）
          example: "连接超时"

    LLMProviderInfo:
      type: object
      description: LLM 提供者信息
      required:
        - name
        - display_name
        - config_schema
      properties:
        name:
          type: string
          description: 提供者唯一标识
          example: "openai"
        display_name:
          type: string
          description: 提供者显示名称
          example: "OpenAI"
        description:
          type: string
          description: 提供者描述
          example: "OpenAI GPT 系列模型"
        config_schema:
          type: object
          description: 配置参数定义（JSON Schema 格式）
          additionalProperties: true

    LLMConfig:
      type: object
      description: 当前 LLM 配置
      required:
        - provider
        - config
      properties:
        provider:
          type: string
          description: 当前激活的提供者
          example: "openai"
        config:
          type: object
          description: 提供者配置参数（敏感字段已脱敏）
          additionalProperties: true
          example:
            api_key: "sk-***"
            base_url: "https://api.openai.com/v1"
            model: "gpt-4o-mini"
        updated_at:
          type: string
          format: date-time
          description: 配置最后更新时间

    LLMConfigUpdate:
      type: object
      description: LLM 配置更新请求
      required:
        - provider
      properties:
        provider:
          type: string
          description: 提供者标识
          example: "openai"
        config:
          type: object
          description: 提供者配置参数
          additionalProperties: true

    LLMTestResult:
      type: object
      description: LLM 测试结果
      required:
        - success
      properties:
        success:
          type: boolean
          description: 测试是否成功
        response:
          type: string
          description: LLM 响应内容
          example: "你好！我是一个 AI 助手..."
        latency_ms:
          type: number
          description: 响应延迟（毫秒）
          example: 1250.5
        prompt_tokens:
          type: integer
          description: 输入 Token 数
          example: 15
        completion_tokens:
          type: integer
          description: 输出 Token 数
          example: 50
        total_tokens:
          type: integer
          description: 总 Token 数
          example: 65
        model:
          type: string
          description: 使用的模型
          example: "gpt-4o-mini"
        message:
          type: string
          description: 测试结果消息
          example: "连接成功"
        error:
          type: string
          description: 错误信息（失败时）
          example: "API Key 无效"

    RagExperimentRequest:
      type: object
      description: RAG 实验请求
      required:
        - query
      properties:
        query:
          type: string
          description: 查询文本
          example: "什么是 RAG？"
        kb_ids:
          type: array
          items:
            type: string
          description: 知识库 ID 列表
        top_k:
          type: integer
          description: 检索数量
          default: 5
        score_threshold:
          type: number
          description: 相似度阈值
          default: 0.5
        generate_response:
          type: boolean
          description: 是否生成 AI 回复
          default: true
        llm_provider:
          type: string
          description: 指定 LLM 提供者（可选）
          example: "openai"

    RagExperimentResult:
      type: object
      description: RAG 实验结果
      properties:
        query:
          type: string
          description: 原始查询
        retrieval_results:
          type: array
          items:
            $ref: '#/components/schemas/RetrievalResult'
        final_prompt:
          type: string
          description: 最终拼接的 Prompt
        ai_response:
          $ref: '#/components/schemas/AIResponse'
        total_latency_ms:
          type: number
          description: 总耗时（毫秒）
        diagnostics:
          type: object
          additionalProperties: true
          description: 诊断信息

    RetrievalResult:
      type: object
      description: 检索结果
      properties:
        content:
          type: string
          description: 检索到的内容
        score:
          type: number
          description: 相似度分数
        source:
          type: string
          description: 来源文档
        metadata:
          type: object
          additionalProperties: true
          description: 元数据

    AIResponse:
      type: object
      description: AI 回复
      properties:
        content:
          type: string
          description: AI 回复内容
        prompt_tokens:
          type: integer
          description: 输入 Token 数
        completion_tokens:
          type: integer
          description: 输出 Token 数
        total_tokens:
          type: integer
          description: 总 Token 数
        latency_ms:
          type: number
          description: 生成耗时（毫秒）
        model:
          type: string
          description: 使用的模型

  /admin/llm/providers:
    get:
      operationId: listLLMProviders
      summary: 获取可用的 LLM 提供者列表
      description: |
        [AC-ASA-15] 返回所有支持的 LLM 提供者及其配置参数定义。
        支持的提供者：OpenAI、Ollama、Azure OpenAI
      tags:
        - LLM Management
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功返回提供者列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  providers:
                    type: array
                    items:
                      $ref: '#/components/schemas/LLMProviderInfo'
        '401':
          description: 未授权
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/llm/config:
    get:
      operationId: getLLMConfig
      summary: 获取当前 LLM 配置
      description: |
        [AC-ASA-14] 返回当前激活的 LLM 提供者及其配置参数。
        敏感字段（如 API Key）会被脱敏显示。
      tags:
        - LLM Management
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功返回当前配置
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LLMConfig'
        '401':
          description: 未授权
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    put:
      operationId: updateLLMConfig
      summary: 更新 LLM 配置
      description: |
        [AC-ASA-16] 更新 LLM 提供者和配置参数。
        配置更新后立即生效，无需重启服务。
      tags:
        - LLM Management
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LLMConfigUpdate'
      responses:
        '200':
          description: 配置更新成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
        '400':
          description: 请求参数错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: 未授权
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/llm/test:
    post:
      operationId: testLLM
      summary: 测试 LLM 连接
      description: |
        [AC-ASA-17, AC-ASA-18] 测试 LLM 提供者连接。
        发送测试提示词并返回响应结果，包含 Token 消耗和延迟统计。
      tags:
        - LLM Management
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                test_prompt:
                  type: string
                  description: 测试提示词（可选）
                  example: "你好，请简单介绍一下自己。"
                provider:
                  type: string
                  description: 指定测试的提供者（可选，默认使用当前配置）
                config:
                  $ref: '#/components/schemas/LLMConfigUpdate'
      responses:
        '200':
          description: 测试完成
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LLMTestResult'
        '401':
          description: 未授权
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/rag/experiments/run:
    post:
      operationId: runRagExperiment
      summary: 运行 RAG 实验（含 AI 输出）
      description: |
        [AC-ASA-05, AC-ASA-19, AC-ASA-21, AC-ASA-22] 运行 RAG 实验。
        返回检索结果、最终 Prompt 和 AI 回复。
      tags:
        - RAG Lab
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RagExperimentRequest'
      responses:
        '200':
          description: 实验完成
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RagExperimentResult'
        '401':
          description: 未授权
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/rag/experiments/stream:
    post:
      operationId: runRagExperimentStream
      summary: 运行 RAG 实验（流式输出）
      description: |
        [AC-ASA-20] 运行 RAG 实验并以 SSE 流式输出 AI 回复。
        事件类型：retrieval、prompt、message、final、error
      tags:
        - RAG Lab
      parameters:
        - name: X-Tenant-Id
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RagExperimentRequest'
      responses:
        '200':
          description: SSE 流式输出
          content:
            text/event-stream:
              schema:
                type: string
        '401':
          description: 未授权
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
