structured-llm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # tmp
10
+ sample
11
+ .mypy_cache
12
+ .ruff_cache
13
+
14
+ # Virtual environments
15
+ .venv
16
+
17
+ # env
18
+ .env
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,16 @@
1
+ .PHONY: setup lint test check
2
+ VENV_BIN ?= .venv/bin
3
+
4
+ setup:
5
+ @command -v uv >/dev/null 2>&1 || pip install uv --break-system-packages
6
+ @[ -d .venv ] || uv venv .venv --python 3.13
7
+ . .venv/bin/activate && uv sync
8
+
9
+ lint:
10
+ $(VENV_BIN)/ruff check --fix
11
+ $(VENV_BIN)/mypy .
12
+
13
+ test:
14
+ $(VENV_BIN)/python -m pytest . -q
15
+
16
+ check: lint test
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.4
2
+ Name: structured-llm
3
+ Version: 0.1.0
4
+ Summary: Lightweight structured output runtime for Python LLM calls.
5
+ Author: structured-llm contributors
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: openai>=1.0.0
9
+ Requires-Dist: pydantic>=2.0.0
10
+ Requires-Dist: python-dotenv>=1.2.2
11
+ Description-Content-Type: text/markdown
12
+
13
+ # structured-llm
14
+
15
+ 一个轻量的 Python 结构化输出运行时。
16
+
17
+ 它直接使用 Pydantic 类型作为 schema,不需要 `.baml` 文件、CLI、代码生成,也不需要额外的运行时编译器。默认行为是 BAML 风格的「output format prompt + 本地 JSON 提取/轻量修复 + Pydantic 校验」,因此不依赖特定供应商是否支持 `response_format`。
18
+
19
+ ## 安装依赖
20
+
21
+ 普通运行依赖:
22
+
23
+ ```bash
24
+ uv sync --no-config --default-index https://pypi.org/simple
25
+ ```
26
+
27
+ 开发依赖安装在 `dev` dependency group 中,包括 `pytest`、`pytest-asyncio`、`ruff`、`mypy`:
28
+
29
+ ```bash
30
+ uv sync --group dev --no-config --default-index https://pypi.org/simple
31
+ ```
32
+
33
+ 如果需要新增开发工具依赖:
34
+
35
+ ```bash
36
+ uv add <package> --group dev --no-config --default-index https://pypi.org/simple
37
+ ```
38
+
39
+ ## 使用示例
40
+
41
+ ```python
42
+ from pydantic import BaseModel, Field
43
+ from structured_llm import StructuredClient
44
+
45
+
46
+ class Receipt(BaseModel):
47
+ merchant: str = Field(description="商户或店铺名称")
48
+ total: float = Field(description="收据最终支付总金额")
49
+
50
+
51
+ client = StructuredClient(model="gpt-4o-mini", debug=True)
52
+ receipt = client.run("Extract the receipt: Coffee $4.50", Receipt)
53
+
54
+ print(receipt.merchant)
55
+ print(receipt.total)
56
+ ```
57
+
58
+ 默认 OpenAI-compatible provider 会从 `OPENAI_API_KEY` 和 `OPENAI_BASE_URL` 读取配置;如果代码里显式传入 `api_key` 或 `base_url`,会优先使用显式参数。`examples/receipt_extraction.py` 会通过 `python-dotenv` 自动加载本地 `.env`。
59
+
60
+ `Field(description=...)` 会渲染到默认 output format prompt。`debug=True` 会把传给 OpenAI-compatible SDK 的 request payload 和模型解析前的原始输出打印到 stderr。默认不会发送 `response_format`;只有显式设置 `mode="native"` 或 `mode="auto"` 时才会尝试 provider-native structured output。
61
+
62
+ 只解析已有的 LLM 文本输出:
63
+
64
+ ```python
65
+ raw = """
66
+ ```json
67
+ {"merchant": "Coffee Shop", "total": 4.5}
68
+ ```
69
+ """
70
+
71
+ receipt = client.parse(raw, Receipt)
72
+ ```
73
+
74
+ ## 开发命令
75
+
76
+ 运行测试:
77
+
78
+ ```bash
79
+ PYTHONDONTWRITEBYTECODE=1 uv run --no-config --default-index https://pypi.org/simple --group dev python -m pytest -p no:cacheprovider
80
+ ```
81
+
82
+ 运行 Ruff:
83
+
84
+ ```bash
85
+ uv run --no-config --default-index https://pypi.org/simple --group dev ruff check .
86
+ ```
87
+
88
+ 运行 mypy:
89
+
90
+ ```bash
91
+ uv run --no-config --default-index https://pypi.org/simple --group dev mypy structured_llm
92
+ ```
93
+
94
+ ## 当前范围
95
+
96
+ - 支持同步调用:`StructuredClient.run(...)`
97
+ - 支持异步调用:`StructuredClient.arun(...)`
98
+ - 支持本地解析:`StructuredClient.parse(...)`
99
+ - 支持 Pydantic `BaseModel`、`list[...]`、`dict[...]`、`Literal`、`Enum` 等 `TypeAdapter` 可处理的类型
100
+ - 暂不支持流式 partial object、多 provider 内置适配、BAML DSL/codegen
@@ -0,0 +1,88 @@
1
+ # structured-llm
2
+
3
+ 一个轻量的 Python 结构化输出运行时。
4
+
5
+ 它直接使用 Pydantic 类型作为 schema,不需要 `.baml` 文件、CLI、代码生成,也不需要额外的运行时编译器。默认行为是 BAML 风格的「output format prompt + 本地 JSON 提取/轻量修复 + Pydantic 校验」,因此不依赖特定供应商是否支持 `response_format`。
6
+
7
+ ## 安装依赖
8
+
9
+ 普通运行依赖:
10
+
11
+ ```bash
12
+ uv sync --no-config --default-index https://pypi.org/simple
13
+ ```
14
+
15
+ 开发依赖安装在 `dev` dependency group 中,包括 `pytest`、`pytest-asyncio`、`ruff`、`mypy`:
16
+
17
+ ```bash
18
+ uv sync --group dev --no-config --default-index https://pypi.org/simple
19
+ ```
20
+
21
+ 如果需要新增开发工具依赖:
22
+
23
+ ```bash
24
+ uv add <package> --group dev --no-config --default-index https://pypi.org/simple
25
+ ```
26
+
27
+ ## 使用示例
28
+
29
+ ```python
30
+ from pydantic import BaseModel, Field
31
+ from structured_llm import StructuredClient
32
+
33
+
34
+ class Receipt(BaseModel):
35
+ merchant: str = Field(description="商户或店铺名称")
36
+ total: float = Field(description="收据最终支付总金额")
37
+
38
+
39
+ client = StructuredClient(model="gpt-4o-mini", debug=True)
40
+ receipt = client.run("Extract the receipt: Coffee $4.50", Receipt)
41
+
42
+ print(receipt.merchant)
43
+ print(receipt.total)
44
+ ```
45
+
46
+ 默认 OpenAI-compatible provider 会从 `OPENAI_API_KEY` 和 `OPENAI_BASE_URL` 读取配置;如果代码里显式传入 `api_key` 或 `base_url`,会优先使用显式参数。`examples/receipt_extraction.py` 会通过 `python-dotenv` 自动加载本地 `.env`。
47
+
48
+ `Field(description=...)` 会渲染到默认 output format prompt。`debug=True` 会把传给 OpenAI-compatible SDK 的 request payload 和模型解析前的原始输出打印到 stderr。默认不会发送 `response_format`;只有显式设置 `mode="native"` 或 `mode="auto"` 时才会尝试 provider-native structured output。
49
+
50
+ 只解析已有的 LLM 文本输出:
51
+
52
+ ```python
53
+ raw = """
54
+ ```json
55
+ {"merchant": "Coffee Shop", "total": 4.5}
56
+ ```
57
+ """
58
+
59
+ receipt = client.parse(raw, Receipt)
60
+ ```
61
+
62
+ ## 开发命令
63
+
64
+ 运行测试:
65
+
66
+ ```bash
67
+ PYTHONDONTWRITEBYTECODE=1 uv run --no-config --default-index https://pypi.org/simple --group dev python -m pytest -p no:cacheprovider
68
+ ```
69
+
70
+ 运行 Ruff:
71
+
72
+ ```bash
73
+ uv run --no-config --default-index https://pypi.org/simple --group dev ruff check .
74
+ ```
75
+
76
+ 运行 mypy:
77
+
78
+ ```bash
79
+ uv run --no-config --default-index https://pypi.org/simple --group dev mypy structured_llm
80
+ ```
81
+
82
+ ## 当前范围
83
+
84
+ - 支持同步调用:`StructuredClient.run(...)`
85
+ - 支持异步调用:`StructuredClient.arun(...)`
86
+ - 支持本地解析:`StructuredClient.parse(...)`
87
+ - 支持 Pydantic `BaseModel`、`list[...]`、`dict[...]`、`Literal`、`Enum` 等 `TypeAdapter` 可处理的类型
88
+ - 暂不支持流式 partial object、多 provider 内置适配、BAML DSL/codegen
@@ -0,0 +1,31 @@
1
+ from dotenv import load_dotenv
2
+ from pydantic import BaseModel, Field
3
+
4
+ from structured_llm import StructuredClient
5
+
6
+ OPENAI_MODEL = "gpt-5.4-mini"
7
+
8
+
9
+ class ReceiptItem(BaseModel):
10
+ name: str = Field(description="购买的商品名称")
11
+ quantity: int = Field(description="该商品的购买数量")
12
+ price: float = Field(description="该商品的单价")
13
+
14
+
15
+ class Receipt(BaseModel):
16
+ merchant: str = Field(description="商户或店铺名称")
17
+ items: list[ReceiptItem] = Field(description="收据中的商品明细")
18
+ total: float = Field(description="收据最终支付总金额")
19
+
20
+
21
+ load_dotenv()
22
+
23
+ client = StructuredClient(model=OPENAI_MODEL, debug=True)
24
+
25
+ receipt: Receipt = client.run(
26
+ prompt="提取收据信息: 咖啡店, 2杯卡布奇诺, 每杯4.50, 总计9块。",
27
+ schema=Receipt,
28
+ )
29
+ print(receipt)
30
+ print("---")
31
+ print(receipt.model_dump_json(indent=4))
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "structured-llm"
7
+ version = "0.1.0"
8
+ description = "Lightweight structured output runtime for Python LLM calls."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "structured-llm contributors" }]
13
+ dependencies = [
14
+ "openai>=1.0.0",
15
+ "pydantic>=2.0.0",
16
+ "python-dotenv>=1.2.2",
17
+ ]
18
+
19
+ [[tool.uv.index]]
20
+ url = "https://pypi.org/simple"
21
+ default = true
22
+
23
+ [tool.pytest.ini_options]
24
+ testpaths = ["tests"]
25
+ norecursedirs = ["sample", ".git", ".venv", ".ruff_cache"]
26
+ asyncio_mode = "auto"
27
+
28
+ [dependency-groups]
29
+ dev = [
30
+ "mypy>=2.1.0",
31
+ "pytest>=7.0.0",
32
+ "pytest-asyncio>=0.21.0",
33
+ "ruff>=0.15.20",
34
+ ]
35
+
36
+ [tool.mypy]
37
+ exclude = [
38
+ "^sample/"
39
+ ]
@@ -0,0 +1,22 @@
1
+ from .client import StructuredClient
2
+ from .errors import (
3
+ ProviderError,
4
+ StructuredLLMError,
5
+ StructuredParseError,
6
+ StructuredValidationError,
7
+ UnsupportedSchemaError,
8
+ )
9
+ from .parser import parse_structured_text
10
+ from .schema import build_schema_spec
11
+
12
+ __all__ = [
13
+ "ProviderError",
14
+ "StructuredClient",
15
+ "StructuredLLMError",
16
+ "StructuredParseError",
17
+ "StructuredValidationError",
18
+ "UnsupportedSchemaError",
19
+ "build_schema_spec",
20
+ "parse_structured_text",
21
+ ]
22
+