Metadata-Version: 2.4
Name: ikc-sdk-lib
Version: 0.12.3
Summary: IKC RAG 对外接口 SDK（独立解析 / 查询解析结果 / 下载解析结果）
Author-email: shark8848 <admin@sharky-ai.com>
Keywords: ikc,rag,sdk,parse,knowledge-base,retrieval
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: pydantic>=2.7
Requires-Dist: python-dotenv>=1.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"

# ikc-sdk-lib

IKC SDK 家族仓库（Python 模型层），与 `/home/open-ikc` 对外接口一脉相承、独立维护。
当前整个 SDK 定义为 **core**：`docs/RAG SDK接口v1.1.xlsx` 中的 **4 个免知识库接口** 的请求/响应模型（Pydantic v2）。
后续新增 SDK 以 `ikc_sdk.<sdk_name>` 兄弟子包扩展，不进入 core。

## 安装

**PyPI（推荐）**

```bash
pip install ikc-sdk-lib                # 最新版（已发布至 PyPI）
pip install "ikc-sdk-lib==0.7.0"       # 固定版本（推荐）
```

- 运行环境：Python `>=3.10`；依赖 `pydantic>=2.7`（自动安装）。
- 源码开发态：`pip install -e .` 后可使用 `src/examples/` 中的示例。

**内网仓库安装（不依赖 PyPI）**

仓库 `dist/` 保存每次发版的 wheel 与 sdist，**历史版本全部保留**并打对应标签（`v0.1.0`、`v0.2.0`、`v0.3.0`、`v0.4.0`、`v0.4.1`、`v0.4.2`、`v0.5.0`、`v0.5.1`、`v0.6.0`、`v0.6.1`、`v0.7.0`）；
内网环境克隆仓库后安装任一历史版本的 wheel（仓库地址向内部索取）：

```bash
git clone <ikc-sdk-lib 内部仓库地址>
pip install ikc-sdk-lib/dist/ikc_sdk_lib-0.7.0-py3-none-any.whl   # 可指定任意历史版本
```

安装后 `import ikc_sdk` 行为与 PyPI 安装一致。

## 当前接口范围（core）

| # | 接口（Excel Sheet） | 请求 | 响应 | 实现位置 |
| --- | --- | --- | --- | --- |
| 1 | 解析—独立解析（免知识库）SERVICE | `ServiceParseDirectRequest` | `ParseResponse` | `ikc_sdk/core/api/parse/direct.py` |
| 2 | 解析—独立解析（免知识库）SDK | `SdkParseDirectRequest` | `ParseResponse` | `ikc_sdk/core/api/parse/direct.py` |
| 3 | 查询解析结果（免知识库）SDK | `QueryParseResultRequest` | `QueryParseResultResponse` | `ikc_sdk/core/api/parse/query.py` |
| 4 | 下载解析结果（免知识库）SDK | `DownloadParseResultRequest` | `DownloadParseResultResponse` | `ikc_sdk/core/api/parse/download.py` |

### 跨层共享契约（非 Excel 面，按归位批次增量落地）

| 批次 | 内容 | 模型/实现位置 |
| --- | --- | --- |
| v0.5 | 知识库/文档/检索模型、共享 `ids`/`queues`/`headers`/`codes`/`page`、wiki/graph 稳定 ID 派生 | `ikc_sdk/core/api/{knowledge_base,document,search}/`、`ikc_sdk/core/{ids,queues,headers,codes,graph_ids,wiki_ids}.py` |
| v0.6 | 任务横切：`TaskStatus.PARTIAL_FAILED`/`is_running()`、`TaskKind`、`EngineJob`、`PipelineRun`、`DocumentSource`、检索响应 | `ikc_sdk/core/{enums,queues}.py`、`ikc_sdk/core/models/{task,source}.py`、`ikc_sdk/core/api/search/universal.py` |
| v0.7 | 图谱资产与 G 域接口（G-01~G-05 + 引擎面邻居/路径）、traceId 纯函数、引擎作业视图与状态映射 | `ikc_sdk/core/models/graph.py`、`ikc_sdk/core/api/graph/`、`ikc_sdk/core/trace.py` |
| v0.8 | Wiki 资产与 W 域接口（W-01/W-02/W-04/W-05 只读） | `ikc_sdk/core/models/wiki.py`、`ikc_sdk/core/api/wiki/` |

图谱资产归位的提炼/不提炼清单与字段口径差异见 `docs/提案_graph资产模型归位_sdk-lib.md`。

任务状态判定（`is_terminal()` / `is_success()` 等）内置于模型层；
Task 管理、端到端任务链路（`client → 网关 → TaskServiceManagement → celery`）与扩展设计
（取消 / 列表 / 定时任务 / 优先级）见 `docs/Task管理与任务链路设计.md`。

## AI 网关 SDK（`ikc_sdk.ai_gateway`，v0.11.0）

`core` 之外的兄弟子包，承载 **ikc-ai-gateway**（公共模型访问网关）对外六类能力的请求/响应模型契约（纯 Pydantic，不含传输）。契约唯一源为 `ikc-ai-gateway/AGENTS.md` + `ikc-ai-gateway/docs/接口契约.md`；详见本仓 `AGENTS.md` §9。

| 能力域 | 请求模型 | 响应模型（`Envelope.data`） | 位置 |
| --- | --- | --- | --- |
| 文本对话 / vLLM | `ChatCompletionRequest` | `ChatCompletionResult` | `ikc_sdk/ai_gateway/api/chat.py` |
| 向量化 | `EmbedRequest` | `EmbedResult` | `ikc_sdk/ai_gateway/api/embed.py` |
| 重排 | `RerankRequest` | `RerankResult` | `ikc_sdk/ai_gateway/api/rerank.py` |
| 语音识别 | `TranscribeRequest` | `TranscribeResult` | `ikc_sdk/ai_gateway/api/asr.py` |
| 多模态 | `AnalyzeRequest` | `AnalyzeResult` | `ikc_sdk/ai_gateway/api/multimodal.py` |
| 异步任务视图 | — | `TaskView` | `ikc_sdk/ai_gateway/api/task.py` |

```python
from ikc_sdk.ai_gateway import ChatCompletionRequest, ChatCompletionResult, Provider
from ikc_sdk.core import Envelope

req = ChatCompletionRequest(
    provider=Provider.OPENAI, model="gpt-4o-mini",
    messages=[{"role": "user", "content": "hi"}],
    hyperParams={"temperature": 0.2}, modelInfo={"apiBase": "http://x/v1", "apiKey": "k"},
)
```

统一壳 `Envelope`/`TaskEnvelope`、trace 头、通用错误码、`TaskStatus` 复用 `core`；子包只新增 `X-AI-*` 模型参数头与模型域错误码（`100102`/`509101`/`509102`/`509103`）。

## 检索引擎 SDK（`ikc_sdk.kb_search`，v0.12.0）

`core` / `ai_gateway` 之外的兄弟子包，承载 **universal-retriever**（导入包 `kb_search`，服务 `kb_search_service`）索引面（写侧）与检索面（读侧，预占位）的北向请求/响应模型契约（纯 Pydantic，不含传输）。契约唯一源为 `universal-retriever/docs/IMPLEMENTATION_SPEC.md` + `contracts/projection_contract.json`；详见本仓 `AGENTS.md` §10。

| 平面 | 请求模型 | 响应模型（`Envelope.data`） | 位置 |
| --- | --- | --- | --- |
| 索引（写侧） | `InstallTemplatesRequest` / `CreateIndexesRequest` / `SwitchAliasesRequest` / `BackfillRequest`（+ `SchemaProfileOverride`） | `BackfillAsyncReceipt` / `IndexTaskStatus` | `ikc_sdk/kb_search/api/index.py` |
| 检索（读侧，占位） | `UniversalSearchRequest` | —（北向由 core Search V2 承载） | `ikc_sdk/kb_search/api/search.py` |

```python
from ikc_sdk.kb_search import BackfillRequest, BackfillTarget, CODE_VERIFICATION_DRIFT
from ikc_sdk.core import Envelope

req = BackfillRequest(kbIds=["kb_1"], target=BackfillTarget.WRITE_ALIAS, verify=True)
```

统一壳 `Envelope`（`traceId/reqId/errCode/errMsg/data`）、trace 头与 traceId 纯函数、通用错误码复用 `core`；子包只新增索引面错误码（`600001`~`600004`）、`Authorization`/`X-Internal-Token`/`X-Req-Id` 线缆头、`QUEUE_SEARCH` 读侧队列与 kb_search 任务名。请求模型 `extra="forbid"`（拒绝注入内部字段），与 ai_gateway 的 `extra="allow"` 不同，详见 `AGENTS.md` §10.4。

## Celery 应用工厂（`ikc_sdk.celery`，v0.12.1）

`core` / `ai_gateway` / `kb_search` 之外的兄弟子包，但性质不同：前三者是**纯 Pydantic 契约**，本子包是
**运行期连接面装配**（唯一会 import `celery` 的子包）。各引擎用 `<PREFIX>_*` 环境变量声明 broker /
result 形态，业务配置（队列 / 路由 / beat）仍归各引擎自己 `conf.update(...)`。

| 形态 | 必需环境变量 | 说明 |
| --- | --- | --- |
| `single` / `replica` | `<PREFIX>_BROKER_URL`、`<PREFIX>_RESULT_BACKEND` | 直接给 URL |
| `sentinel` | `<PREFIX>_SENTINEL_NODES`（`host:port,...`）、`<PREFIX>_SENTINEL_MASTER_NAME`、`<PREFIX>_SENTINEL_PASSWORD` | 工厂拼 `sentinel://` URL 并下发 `sentinel_kwargs`；可选 `<PREFIX>_SENTINEL_AUTH_PASSWORD`（哨兵节点口令，缺省复用 master 口令）、`<PREFIX>_SENTINEL_BROKER_DB`（缺省 3）、`<PREFIX>_SENTINEL_BACKEND_DB`（缺省 4） |

```python
from ikc_sdk.celery import CeleryFactory

app = CeleryFactory.create(
    "ikc_core",
    prefix="IKC_CORE_CELERY",
    broker_url=settings.celery_broker_url,        # single/replica 形态的 URL（可省）
    result_backend=settings.celery_result_backend,
)
app.conf.update(task_default_queue="gov", ...)   # 业务配置仍由调用方覆盖
```

连接参数口径：**形态**由 `<PREFIX>_REDIS_MODE` 决定；`single` / `replica` 用入参 URL（引擎自身 Settings 为主口径，未给时退回 `<PREFIX>_BROKER_URL` / `_RESULT_BACKEND`）；`sentinel` 的 URL **只**由 `<PREFIX>_SENTINEL_NODES` + 库号生成，入参与 `<PREFIX>_BROKER_URL` 都不参与（要连单点 / 代理用 `mode=single`）——否则残留的单机 URL 会静默顶掉哨兵。

哨兵模式的三个坑（2026-09-23 真实站点实测修正，详见 `AGENTS.md` §11.2 与 `celery_factory.py`
docstring）：① 哨兵节点鉴权必须走 `sentinel_kwargs`（URL 里的口令只作用于 master）；② broker URL 必须
带库号（否则落到 master 的 db 0，与同实例其它 Celery 应用撞命名空间）；③ celery 对
`CELERY_BROKER_URL` / `CELERY_RESULT_BACKEND` 有**硬编码环境变量优先级**，工厂装配前会清掉它们，
避免哨兵模式被静默降级成固定 master。`<PREFIX>_*` 取值是 `os.environ` 优先、其次当前工作目录的
`.env`（只读兜底，不写回环境——写回会连带改掉引擎自身 Settings）；`python-dotenv` 是本子包硬依赖（已在 `pyproject.toml` 声明）；
`celery` 由宿主引擎自带，SDK 不声明，故顶层 `ikc_sdk/__init__.py` **不** eager import 本子包
（否则 `import ikc_sdk` 会硬依赖 celery）。

## Redis 客户端工厂（`ikc_sdk.redis`，v0.12.3）

`ikc_sdk.celery` 的姊妹子包：celery 子包装配 **Celery 应用**（broker / result），本子包装配
**redis-py 直连客户端**（限流 / 缓存 / 进度 / 短期租约等非 Celery 用途），两者共用同一套
`<PREFIX>_*` 形态口径。**只装配连接面**，业务键名 / 前缀仍归调用方。

| 形态 | 必需环境变量 | 说明 |
| --- | --- | --- |
| `single` / `replica` | `<PREFIX>_REDIS_URL` | 直接给 URL（含库号；要连哨兵代理就是这一形态 + 代理地址） |
| `sentinel` | `<PREFIX>_SENTINEL_NODES`（`host:port,...`）、`<PREFIX>_SENTINEL_MASTER_NAME`、`<PREFIX>_SENTINEL_PASSWORD` | 工厂组装 `Sentinel` 并 `master_for(...)`；可选 `<PREFIX>_SENTINEL_AUTH_PASSWORD`（哨兵节点口令，缺省复用 master 口令）、`<PREFIX>_SENTINEL_DB`（缺省 0）、`<PREFIX>_SOCKET_TIMEOUT` / `_SOCKET_CONNECT_TIMEOUT`（缺省 5s） |

```python
from ikc_sdk.redis import RedisConfig, RedisFactory

cfg = RedisConfig.from_env("UPLOAD")
client = RedisFactory.create(cfg, decode_responses=True)       # redis.asyncio.Redis（异步）
sync_client = RedisFactory.create_sync(cfg, decode_responses=True)  # redis.Redis（同步上下文）
await client.ping()
```

两种客户端形态共用同一份 `RedisConfig`：同步上下文（Celery worker 内的 Stream 发布、`/ready`
就绪探针）用 `create_sync()`，异步请求路径用 `create()`。

哨兵口径与 `ikc_sdk.celery` 同源（`AGENTS.md` §12）：① 哨兵节点鉴权走 `sentinel_kwargs`
（`password=` 只作用于 master）；② 库号必须显式给（否则落到 master 的 db 0）；③ 哨兵节点连接带
socket 超时，快速跳过不可达节点。`sentinel` 形态下 `<PREFIX>_REDIS_URL` **不参与**（要连单点 / 代理
用 `mode=single`）。`redis` 由宿主服务自带（SDK 不声明），故顶层 `ikc_sdk/__init__.py` **不**
eager import 本子包。

## 目录结构

```
docs/
  RAG SDK接口v1.1.xlsx   # 当前接口契约唯一定义源（v1.1，含 ParsingEngine）
  RAG SDK接口.xlsx       # v1.0 归档
  开发手册.md            # 四接口开发手册（pip 安装 / 流程 / 字段 / 端到端 / 发布）
  Task管理与任务链路设计.md  # Task 管理与任务链路（独立章节：链路 / SDK 设计 / 扩展草案）
src/ikc_sdk/
  __init__.py            # 命名空间门面：re-export core 公开 API
  _version.py            # 版本号（分发级）
  core/                  # 核心 SDK（当前整个 SDK）
    __init__.py          # core 公开导出
    enums.py             # 契约枚举（取值以 Excel 为准）
    exceptions.py        # SDK 异常体系（IkcSdkError 基类；契约校验 / 引擎目录异常）
    headers.py           # 跨层线缆头常量（trace 透传头 / 身份信任头）
    trace.py             # traceId 纯函数：生成 / 校验 / 归一 / 从请求头提取
    models/              # 共享模型：响应壳 / 来源 / 解析 / 分段 / 输出 / 任务 / 图谱资产 / Wiki 资产
    api/                 # 按能力域组织的接口定义
      parse/             # 解析域（已定义）：direct（独立解析 SERVICE/SDK）/ query / download
      knowledge_base/    # 知识库域（占位）：create / update / get / query
      document/          # 文档域：ingest / parse / ingest_and_parse / get（v0.5）+ upload（v0.9）；parse_result/ 仍占位
      search/            # 检索域（占位）：universal / deep / query
      graph/             # 图谱域（v0.7）：stat / nodes / edges / neighbors / paths / export
      wiki/              # Wiki 域（v0.8）：tree / page / stat / export
  ai_gateway/ kb_search/ # 兄弟子包（v0.11.0 / v0.12.0）：AI 网关契约 / 检索服务面契约（纯模型层，不并入顶层 *）
  celery/                # 运行期子包（v0.12.1）：Celery 应用工厂（单机 / 副本 / 哨兵）——含 celery 依赖，顶层不 eager import
  redis/                 # 运行期子包（v0.12.3）：redis-py 客户端工厂（单机 / 副本 / 哨兵；create/create_sync）——redis 由宿主服务自带，顶层不 eager import
  _env.py                # 两个运行期工厂共用的 <PREFIX>_* 读取（os.environ 优先 / cwd 的 .env 只读兜底）
  <future_sdk>/          # 后续新增 SDK：兄弟子包（如 client 等），不进入 core
src/examples/            # 4 接口开发示例（非包、不参与打包）
scripts/publish-pypi.sh  # PyPI 发布脚本
config/pypi.env.example  # PyPI 凭据模板（真实凭据 pypi.env 不入库）
dist/                    # 发布产物（wheel + sdist，随仓库提交，对应标签 v0.12.3）
AGENTS.md                # 设计与实现契约
pyproject.toml / README.md
```

## 使用

规范导入路径为 `ikc_sdk.core`；顶层 `ikc_sdk` 门面 re-export core，两种写法等价：

```python
from ikc_sdk import SdkParseDirectRequest          # 门面（兼容）
from ikc_sdk.core import SdkParseDirectRequest     # 规范路径
from ikc_sdk.core import (
    DeclaredSource, SourceMetadata, ParsingOptions, OutputOptions,
    SourceType, DocumentFormat, OutputFormat,
)

req = SdkParseDirectRequest(
    processingOperation="EXTRACT_CHUNK",
    source=DeclaredSource(
        type=SourceType.URL,
        url="https://example.com/doc.pdf",
        metadata=SourceMetadata(docTitle="示例文档"),
    ),
    parsing=ParsingOptions(docFormat=DocumentFormat.PDF),
    output=OutputOptions(formats={OutputFormat.MARKDOWN}),
)
print(req.model_dump_json())
```

## 开发手册

面向开发者的四接口完整开发手册（总体流程、公共契约、每个接口的请求/响应字段与代码示例、
端到端链路、错误码、类索引）见 `docs/开发手册.md`。

## 开发示例

4 个接口的可运行示例位于 `src/examples/`（请求构建、契约校验、序列化、响应解析）：

```bash
cd /home/sharkyai/ikc-sdk-lib
PYTHONPATH=src python3 src/examples/parse_direct_sdk.py
PYTHONPATH=src python3 src/examples/parse_direct_service.py
PYTHONPATH=src python3 src/examples/query_parse_result.py
PYTHONPATH=src python3 src/examples/download_parse_result.py
```

## 占位目录（契约待定义）

知识库 / 文档 / 检索三个域目前仅有目录骨架，接口契约待 `docs/RAG SDK接口v1.1.xlsx` 增补后定义
（参考 open-ikc V2 接口清单占位），在契约落定前**不定义模型**：

| 域 | 计划接口 | 参考 |
| --- | --- | --- |
| 知识库 | `create` / `update` / `get` / `query` | open-ikc A-01~A-04 |
| 文档 | `ingest` / `parse` / `ingest_and_parse` / `get`（v0.5 初版）+ `upload`（v0.9.0 初版，`DocumentUploadResult`）；`parse_result/{query,issue_ticket,download}` 仍占位 | open-ikc B-01~B-07 |
| 检索 | `universal` / `deep` / `query` | open-ikc D-01/D-02 |

## 版本与发布

| 项 | 值 |
| --- | --- |
| 当前版本 | `0.12.1`（历史：`0.1.0`、`0.2.0`、`0.3.0`、`0.4.0`、`0.4.1`、`0.4.2`、`0.5.0`、`0.5.1`、`0.6.0`、`0.6.1`、`0.7.0`、`0.8.0`、`0.8.1`、`0.8.2`、`0.8.3`、`0.9.0`、`0.9.1`、`0.9.2`、`0.10.0`、`0.11.0`、`0.12.0`、`0.12.1`） |
| PyPI 项目页 | `https://pypi.org/project/ikc-sdk-lib/` |
| 仓库版本标签 | `v0.1.0` … `v0.12.0`（annotated，逐个版本标签；`v0.12.1` 待打） |
| 仓库发布产物 | `dist/` 保留全部历史版本（`ikc_sdk_lib-0.1.0` ~ `-0.12.1`，wheel + sdist），索引见 `dist/README.md` |

- 发布到 PyPI：`bash scripts/publish-pypi.sh`（参考 `/home/ikc-log-center`）；选项 `--test`、`--skip-build`、`--no-skip-existing`、`IKC_SDK_VERSION=<ver>`。
- 仓库直装：见「安装」章节 git 标签 / dist wheel 两种方式，不依赖 PyPI。
- 发版约定：每次发版更新版本号 → 构建产物入 `dist/`（**保留历史，不清理旧版本**）→ 提交推送 → 打标签 `vX.Y.Z` → 发布 PyPI。
- 分支约定：`main` 为发布基线；功能在 `dev_*` 分支开发，合并后打版本标签（如 `v0.4.1`）。
- 凭据：`config/pypi.env`（gitignored，勿提交），模板见 `config/pypi.env.example`。

## 契约约定

- 字段命名（camelCase）与枚举值一律以 `docs/RAG SDK接口v1.1.xlsx` 为准，含 Excel 原文拼写（如 `keyswordNum`、`docMetadataPormpt`），不得“顺手修正”。
- 统一响应壳：`errCode / errMsg / data / traceId`（独立解析与下载接口额外带 `taskId`）。
- SDK 版请求面向 API 调用方（source 自声明），SERVICE 版为 API 之后调用后端 service（source 指向已登记文档）；两版以 `ParseDirectRequestBase` 为基类派生，类名严格遵循 Excel Sheet 定义。
- Excel 引用的对象类型均有对应模型类（映射见 `AGENTS.md` §3.4，如 `ModelConfig`）；`ModelReferences` 各字段为 `ModelConfig` 的 DES 加密串。
- 完整的设计与实现契约见 `AGENTS.md`（能力域地图、目录/命名规范、落地工作流、硬性约束）。
