Knowhere Python SDK
Official Python SDK for the Knowhere document parsing API.
Installation
pip install knowhere-python-sdk
Or with uv:
uv add knowhere-python-sdk
Usage
import knowhere
client = knowhere.Knowhere(api_key="sk_...")
result = client.parse(
url="https://example.com/report.pdf",
)
print(result.statistics.total_chunks)
print(result.full_markdown[:200])
for chunk in result.text_chunks:
print(chunk.content[:80])
for page in result.page_chunks:
print(page.content_source) # "summary"
print(page.content[:120]) # page-level summary
print(page.metadata.page_nums) # [4, 5, 6]
Retrieval and document lifecycle
New documents are published into a retrieval namespace. The server returns a
stable document_id on job create when it has a planned id, and on the
completed job_result after publication.
job = client.jobs.create(
source_type="url",
source_url="https://example.com/manual.pdf",
namespace="support-center",
document_metadata={"title": "Support manual"},
)
document_id = job.document_id
job_result = client.jobs.wait(job.job_id)
document_id = document_id or job_result.document_id
if document_id is None:
raise RuntimeError("Expected document_id after successful publication.")
After the job is done and published, query the canonical document content:
response = client.retrieval.query(
namespace="support-center",
query="How do I reset Bluetooth pairing?",
chunk_types=["page"],
top_k=5,
channels=["path", "term"],
filter_mode="keep",
signal_paths=["Bluetooth", "Pairing"],
)
print(response.router_used)
print(response.answer_text)
print(response.evidence_text)
print(response.stop_reason)
print(response.failure_reason)
for reference in response.referenced_chunks:
print(reference.chunk_id, reference.chunk_type, reference.content_source)
print(reference.metadata, reference.asset_url)
for result in response.results:
print(result.chunk_id, result.chunk_type, result.content_source)
print(result.content)
print(result.score)
print(result.source.source_file_name, result.source.section_path)
Use document_id to update or archive a document:
update_job = client.jobs.create(
source_type="url",
source_url="https://example.com/manual-v2.pdf",
document_id=document_id,
)
document = client.documents.get(document_id)
print(document.status)
chunks = client.documents.list_chunks(
document_id,
page=1,
page_size=50,
chunk_type="page",
include_asset_urls=True,
)
print(chunks.pagination.total)
if chunks.chunks:
chunk = client.documents.get_chunk(
document_id,
chunks.chunks[0].id,
include_asset_urls=True,
)
print(chunk.chunk.content)
print(chunk.chunk.metadata.get("page_nums")) # Page citations.
print(chunk.chunk.asset_url) # Requested 7-day URL when available.
page_assets = chunk.chunk.metadata.get("pageAssets") or []
print(page_assets)
source = client.documents.get_page_citation_source(document_id)
print(source.url)
client.documents.archive(document_id)
You can also list documents in a namespace:
documents = client.documents.list(
namespace="support-center",
page=1,
page_size=50,
)
for document in documents.documents:
print(document.document_id, document.status)
print(documents.pagination.total_pages)
Retrieval can limit documents for one request and exclude documents or sections.
Omitting include_document_ids leaves documents unrestricted by inclusion;
passing [] matches no documents. Exclusions take precedence over inclusions.
response = client.retrieval.query(
namespace="support-center",
query="battery charging",
include_document_ids=["doc_123", "doc_old"],
exclude_document_ids=["doc_old"],
exclude_sections=[
{"document_id": "doc_123", "section_path": "Appendix / Legal"}
],
)
While you can provide an api_key keyword argument, we recommend using python-dotenv to add KNOWHERE_API_KEY="sk_..." to your .env file so that your API key is not stored in source control.
Short-lived dashboard tokens can use auth_token_provider instead of a static key. If api_key is also set, the static key wins.
client = knowhere.Knowhere(auth_token_provider=lambda: current_access_token())
Parse a local file
from pathlib import Path
result = client.parse(
file=Path("report.pdf"),
parsing_params={"model": "advanced", "ocr_enabled": True},
)
print(result.manifest.source_file_name) # "report.pdf"
print(len(result.chunks)) # 152
print(result.namespace) # "default" or your explicit namespace
print(result.document_id) # Published canonical document id
Bring your own LLM keys (BYOK)
Pass OpenAI-compatible credentials for parsing or agentic retrieval.
Flat root applies to both channels (one multimodal model). Use models for
different model ids on the same endpoint, or text / vision for different
provider endpoints:
# Multimodal shorthand — one model for text + vision
llm_config = {
"api_key": "sk-...",
"model": "gpt-4o",
"base_url": "https://api.openai.com/v1",
}
# Same endpoint, different models per channel
llm_config = {
"api_key": "sk-...",
"base_url": "https://api.openai.com/v1",
"models": {"text": "gpt-4o-mini", "vision": "gpt-4o"},
}
# Or two different endpoints
llm_config = {
"text": {
"api_key": "sk-...",
"model": "gpt-4o-mini",
"base_url": "https://api.openai.com/v1",
},
"vision": {
"api_key": "sk-ali-...",
"model": "qwen-vl-max",
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
},
}
result = client.parse(file=Path("report.pdf"), llm_config=llm_config)
response = client.retrieval.query(
namespace="support-center",
query="refund policy",
use_agentic=True,
llm_config=llm_config,
)
Access different chunk types
result = client.parse(url="https://example.com/report.pdf")
# Text chunks
for chunk in result.text_chunks:
print(chunk.metadata.keywords)
print(chunk.metadata.summary)
# Page chunks (v2 page-memory results)
for chunk in result.page_chunks:
print(chunk.content_source) # "summary"
print(chunk.content[:120])
print(chunk.metadata.page_nums) # citation pages
print(chunk.metadata.entities)
# Image chunks (raw bytes loaded from ZIP)
for chunk in result.image_chunks:
print(chunk.file_path)
print(len(chunk.data)) # bytes
chunk.save("./output/") # writes image to disk
# Table chunks (HTML loaded from ZIP)
for chunk in result.table_chunks:
print(chunk.file_path)
print(chunk.html[:100])
Save all results to disk
result = client.parse(file=Path("report.pdf"))
result.save("./output/report/")
Async usage
import asyncio
import knowhere
async def main():
async with knowhere.AsyncKnowhere(api_key="sk_...") as client:
result = await client.parse(url="https://example.com/report.pdf")
print(result.statistics.total_chunks)
for chunk in result.text_chunks:
print(chunk.summary)
asyncio.run(main())
Step-by-step control
For granular control over the parsing workflow, use the jobs resource directly:
from pathlib import Path
# Step 1: Create a parsing job
job = client.jobs.create(
source_type="file",
file_name="report.pdf",
namespace="support-center",
parsing_params={"model": "advanced", "ocr_enabled": True},
)
# Step 2: Upload file to presigned URL
client.jobs.upload(job, file=Path("report.pdf"))
# Step 3: Poll until done (adaptive backoff)
job_result = client.jobs.wait(job.job_id, poll_interval=10.0, poll_timeout=1800.0)
print(job_result.document_id) # Persist this to update/archive the document later.
# Step 4: Download and parse results
result = client.jobs.load(job_result)
print(result.statistics)
Handling errors
All errors inherit from knowhere.KnowhereError.
import knowhere
try:
result = client.parse(url="https://example.com/report.pdf")
except knowhere.AuthenticationError:
print("Invalid API key")
except knowhere.APIStatusError as e:
print(f"{e.status_code}: {e.message}")
Configuration
The SDK reads configuration from constructor arguments, environment variables, or defaults (in that priority order):
| Variable | Description | Default |
|---|---|---|
KNOWHERE_API_KEY |
API key (required) | — |
KNOWHERE_BASE_URL |
API base URL | https://api.knowhereto.ai |
KNOWHERE_LOG_LEVEL |
Log level | WARNING |
# Uses environment variables automatically
client = knowhere.Knowhere()
# Or configure explicitly
client = knowhere.Knowhere(
api_key="sk_...",
base_url="https://api.knowhereto.ai",
timeout=30.0, # HTTP request timeout (default: 60s)
upload_timeout=300.0, # File upload timeout (default: 600s)
max_retries=3, # Max retry attempts (default: 5)
)
Retries
Connection errors, 429 Rate Limit, and >=500 Internal errors are automatically retried with exponential backoff.
client = knowhere.Knowhere(
api_key="sk_...",
max_retries=3, # default is 5
)
Determining the installed version
import knowhere
print(knowhere.__version__)
Versioning
This package follows Semantic Versioning.
We publish stable releases to PyPI. To install the latest unreleased changes directly from the repository: https://github.com/Ontos-AI/knowhere-python-sdk
Requirements
- Python 3.9+
- httpx
>=0.25.0,<1.0 - pydantic
>=2.0.0,<3.0 - typing-extensions
>=4.7.0
Community
- Contributing guide: CONTRIBUTING.md
- Security policy: SECURITY.md
- Code of conduct: CODE_OF_CONDUCT.md
License
MIT
Metadata
Release files for knowhere-python-sdk 2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| knowhere_python_sdk-2.1.0.tar.gz | 539.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| knowhere_python_sdk-2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 581.0 kB
Release files / knowhere_python_sdk-2.1.0.tar.gz
| Download URL | knowhere_python_sdk-2.1.0.tar.gz |
|---|---|
| Size | 539.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7254ba3d7ed3a0e9fd84a21d4444e933e151cb3c6b41dfe5169215868a4bfe98
|
|
BLAKE2b-256 checksum How to use checksums |
7483439b0a04e7f95ea6d2879a42ca16f4d47c6f3238f0b8b188d275e9f81b2a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / knowhere_python_sdk-2.1.0-py3-none-any.whl
| Download URL | knowhere_python_sdk-2.1.0-py3-none-any.whl |
|---|---|
| Size | 41.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
04e41bdd4498ba8e348ab11dac33db194c55020f499485ce398e6d6a077dcbd6
|
|
BLAKE2b-256 checksum How to use checksums |
2c0a447e093b050e228ace725227fd4bd08925b5c859dca0741aef8c5fcf6da8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|