sieve-context 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.
- sieve_context-0.1.0/.env +3 -0
- sieve_context-0.1.0/.env.example +3 -0
- sieve_context-0.1.0/.gitignore +0 -0
- sieve_context-0.1.0/.python-version +1 -0
- sieve_context-0.1.0/CONTRIBUTING.md +16 -0
- sieve_context-0.1.0/LICENSE +21 -0
- sieve_context-0.1.0/PKG-INFO +310 -0
- sieve_context-0.1.0/README.md +261 -0
- sieve_context-0.1.0/SIEVE_LOGO.txt +9 -0
- sieve_context-0.1.0/examples/benchmark.json +52 -0
- sieve_context-0.1.0/examples/context.txt +16 -0
- sieve_context-0.1.0/main.py +64 -0
- sieve_context-0.1.0/pyproject.toml +88 -0
- sieve_context-0.1.0/sieve/__init__.py +29 -0
- sieve_context-0.1.0/sieve/benchmark.py +132 -0
- sieve_context-0.1.0/sieve/calibrate.py +140 -0
- sieve_context-0.1.0/sieve/cli.py +248 -0
- sieve_context-0.1.0/sieve/config.py +69 -0
- sieve_context-0.1.0/sieve/documents.py +123 -0
- sieve_context-0.1.0/sieve/integrations/__init__.py +1 -0
- sieve_context-0.1.0/sieve/integrations/langchain.py +62 -0
- sieve_context-0.1.0/sieve/llm.py +87 -0
- sieve_context-0.1.0/sieve/mcp/__init__.py +1 -0
- sieve_context-0.1.0/sieve/mcp/server.py +34 -0
- sieve_context-0.1.0/sieve/mcp/tools.py +79 -0
- sieve_context-0.1.0/sieve/metrics.py +21 -0
- sieve_context-0.1.0/sieve/models.py +125 -0
- sieve_context-0.1.0/sieve/scorer.py +72 -0
- sieve_context-0.1.0/sieve/sieve.py +245 -0
- sieve_context-0.1.0/sieve/ui.py +182 -0
- sieve_context-0.1.0/sieve/vector_store.py +86 -0
- sieve_context-0.1.0/sieve.yaml +27 -0
- sieve_context-0.1.0/sieve.yaml.example +27 -0
- sieve_context-0.1.0/tests/__init__.py +0 -0
- sieve_context-0.1.0/tests/test_calibrate.py +35 -0
- sieve_context-0.1.0/tests/test_documents.py +21 -0
- sieve_context-0.1.0/tests/test_langchain.py +30 -0
- sieve_context-0.1.0/tests/test_mcp.py +44 -0
- sieve_context-0.1.0/tests/test_metrics.py +20 -0
- sieve_context-0.1.0/tests/test_optimize.py +51 -0
- sieve_context-0.1.0/tests/test_sieve.py +46 -0
- sieve_context-0.1.0/uv.lock +2081 -0
- sieve_context-0.1.0/workspace/documents/APPL SEC FILINGS.pdf +0 -0
- sieve_context-0.1.0/workspace/documents/Apple_Sec_File.txt +2165 -0
- sieve_context-0.1.0/workspace/indexes/chunks.json +2662 -0
- sieve_context-0.1.0/workspace/indexes/embeddings.npy +0 -0
sieve_context-0.1.0/.env
ADDED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Contributing to Sieve
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to Sieve!
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Clone your fork locally
|
|
9
|
+
3. Install dependencies using `uv`: `uv sync`
|
|
10
|
+
4. Run tests: `uv run pytest`
|
|
11
|
+
|
|
12
|
+
## Guidelines
|
|
13
|
+
|
|
14
|
+
- Follow existing style. We recommend using `ruff` and `black`.
|
|
15
|
+
- Write tests for new features.
|
|
16
|
+
- Ensure the benchmark suite (`sieve benchmark`) still functions correctly and metrics are honest.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sieve Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sieve-context
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Cut retrieved context your RAG application sends to LLMs using local cross-encoder filtering.
|
|
5
|
+
Project-URL: Homepage, https://github.com/kuhinthewuh/Sieve
|
|
6
|
+
Project-URL: Repository, https://github.com/kuhinthewuh/Sieve
|
|
7
|
+
Project-URL: Issues, https://github.com/kuhinthewuh/Sieve/issues
|
|
8
|
+
Author-email: Kushaagra Patel <kushaagra.patel@outlook.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,context compression,cross-encoder,developer tools,embeddings,information retrieval,llm,mcp,nlp,prompt compression,rag,retrieval augmented generation,semantic search
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: numpy>=1.24.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
|
26
|
+
Requires-Dist: rich>=13.0.0
|
|
27
|
+
Requires-Dist: sentence-transformers>=3.0.0
|
|
28
|
+
Requires-Dist: tiktoken>=0.7.0
|
|
29
|
+
Requires-Dist: typer>=0.9.0
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: beautifulsoup4>=4.12.0; extra == 'all'
|
|
32
|
+
Requires-Dist: google-genai>=0.5.0; extra == 'all'
|
|
33
|
+
Requires-Dist: mcp>=1.0.0; extra == 'all'
|
|
34
|
+
Requires-Dist: pymupdf>=1.23.0; extra == 'all'
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: build>=1.0.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: twine>=5.0.0; extra == 'dev'
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: beautifulsoup4>=4.12.0; extra == 'docs'
|
|
41
|
+
Requires-Dist: pymupdf>=1.23.0; extra == 'docs'
|
|
42
|
+
Provides-Extra: google
|
|
43
|
+
Requires-Dist: google-genai>=0.5.0; extra == 'google'
|
|
44
|
+
Provides-Extra: langchain
|
|
45
|
+
Requires-Dist: langchain-core; extra == 'langchain'
|
|
46
|
+
Provides-Extra: mcp
|
|
47
|
+
Requires-Dist: mcp>=1.0.0; extra == 'mcp'
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# Sieve
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
____ ___ ______ _______
|
|
54
|
+
/ ___|_ _| ____\ \ / / ____|
|
|
55
|
+
\___ \| || _| \ \ / /| _|
|
|
56
|
+
___) | || |___ \ V / | |___
|
|
57
|
+
|____/___|_____| \_/ |_____|
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
> **Less noise. Better retrieval.**
|
|
61
|
+
> *Sift the signal from your retrieval pipeline.*
|
|
62
|
+
|
|
63
|
+
[](https://pypi.org/project/sieve-context/)
|
|
64
|
+
[](https://opensource.org/licenses/MIT)
|
|
65
|
+
[](https://www.python.org/)
|
|
66
|
+
|
|
67
|
+
**Sieve** is a lightweight, post-retrieval context optimizer for Retrieval-Augmented Generation (RAG). It runs locally between your retriever and your LLM, evaluating retrieved sentences with a cross-encoder to prune irrelevant noise before generation.
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
Retriever ──► [ Retrieved Chunks ] ──► Sieve (Local Cross-Encoder) ──► [ Pruned Context ] ──► LLM
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Your vector database over-retrieves by design: embedding top-k similarity search returns large blocks of text where often only a few sentences answer the query. Sieve removes the noise, preserves document metadata, and passes a physically smaller, denser prompt to your downstream model.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Why Sieve?
|
|
78
|
+
|
|
79
|
+
Every irrelevant token retrieved into your prompt creates measurable friction:
|
|
80
|
+
- **Cost:** You pay per input token on hosted APIs (OpenAI, Anthropic, Gemini, Groq).
|
|
81
|
+
- **Latency:** Prompt processing time grows with input token volume.
|
|
82
|
+
- **Attention Degradation:** Irrelevant sentences compete with crucial facts for the model's attention budget ("lost in the middle" effect).
|
|
83
|
+
- **Zero API Key Requirement:** Filtering runs locally on your machine using a compact cross-encoder (`ms-marco-MiniLM-L-6-v2`). Your LLM API keys are never needed for context compression.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
Install via pip:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pip install sieve-context
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Optional Extras
|
|
96
|
+
|
|
97
|
+
- **LangChain Integration:**
|
|
98
|
+
```bash
|
|
99
|
+
pip install "sieve-context[langchain]"
|
|
100
|
+
```
|
|
101
|
+
- **Model Context Protocol (MCP) Server:**
|
|
102
|
+
```bash
|
|
103
|
+
pip install "sieve-context[mcp]"
|
|
104
|
+
```
|
|
105
|
+
- **Document Ingestion (PDF & HTML):**
|
|
106
|
+
```bash
|
|
107
|
+
pip install "sieve-context[docs]"
|
|
108
|
+
```
|
|
109
|
+
- **All Capabilities:**
|
|
110
|
+
```bash
|
|
111
|
+
pip install "sieve-context[all]"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Quickstart
|
|
117
|
+
|
|
118
|
+
### 1. Document-Level Optimization (Preserving Metadata)
|
|
119
|
+
|
|
120
|
+
Pass retrieved documents directly into `Sieve.optimize()`. Sieve filters sentences while maintaining each document's identity and metadata:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from sieve import Document, Sieve
|
|
124
|
+
|
|
125
|
+
sieve = Sieve(threshold=0.5)
|
|
126
|
+
|
|
127
|
+
retrieved_docs = [
|
|
128
|
+
Document(
|
|
129
|
+
text=(
|
|
130
|
+
"Apple Inc. reported total net sales of $391,035 million in fiscal year 2024. "
|
|
131
|
+
"Apple Park's main circular building features solar panels generating 17 megawatts."
|
|
132
|
+
),
|
|
133
|
+
metadata={"source": "apple-10k.pdf", "page": 28}
|
|
134
|
+
),
|
|
135
|
+
Document(
|
|
136
|
+
text="Steve Jobs co-founded Apple in Los Altos in 1976. iPhone net sales reached $201,183 million.",
|
|
137
|
+
metadata={"source": "apple-10k.pdf", "page": 31}
|
|
138
|
+
)
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
result = sieve.optimize(
|
|
142
|
+
query="What was Apple's total net sales and iPhone sales in 2024?",
|
|
143
|
+
documents=retrieved_docs,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Ready-to-inject string for your LLM prompt
|
|
147
|
+
print(result.context)
|
|
148
|
+
|
|
149
|
+
# Filtered documents preserving metadata
|
|
150
|
+
for doc in result.documents:
|
|
151
|
+
print(doc.metadata, "->", doc.text)
|
|
152
|
+
|
|
153
|
+
# Inspect exact token and reduction metrics
|
|
154
|
+
print(f"Original tokens: {result.metrics.original_tokens}")
|
|
155
|
+
print(f"Retained tokens: {result.metrics.filtered_tokens}")
|
|
156
|
+
print(f"Reduction: {result.metrics.reduction_percent}%")
|
|
157
|
+
print(f"Latency: {result.metrics.filtering_latency_ms} ms")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### 2. Direct String Filtering
|
|
163
|
+
|
|
164
|
+
If you have a raw context string:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from sieve import filter_context
|
|
168
|
+
|
|
169
|
+
result = filter_context(
|
|
170
|
+
query="What was Apple's 2024 revenue?",
|
|
171
|
+
context="Apple's fiscal 2024 revenue reached $391,035 million. The cafeteria serves lunch daily.",
|
|
172
|
+
threshold=0.5,
|
|
173
|
+
max_tokens=500,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
print(result.filtered_context)
|
|
177
|
+
# Output: "Apple's fiscal 2024 revenue reached $391,035 million."
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### 3. LangChain Integration
|
|
183
|
+
|
|
184
|
+
Drop Sieve into your existing LangChain retrieval chains as a document compressor:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from sieve.integrations.langchain import SieveCompressor
|
|
188
|
+
|
|
189
|
+
compressor = SieveCompressor(threshold=0.5)
|
|
190
|
+
optimized_docs = compressor.compress_documents(retrieved_docs, query="Apple 2024 revenue")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### 4. Model Context Protocol (MCP)
|
|
196
|
+
|
|
197
|
+
Sieve includes a native MCP server for Claude Desktop, Cursor, and any MCP-compliant agent.
|
|
198
|
+
|
|
199
|
+
Start the server:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
sieve-mcp
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Or configure it in your `claude_desktop_config.json`:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"mcpServers": {
|
|
210
|
+
"sieve": {
|
|
211
|
+
"command": "sieve-mcp"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### Available MCP Tools
|
|
218
|
+
|
|
219
|
+
1. **`sieve_filter`**:
|
|
220
|
+
- Inputs: `query` (str), `context` (str), `threshold` (float, default 0.5), `max_tokens` (optional int).
|
|
221
|
+
- Returns: Filtered context string, token counts, reduction percentage, and filtering latency.
|
|
222
|
+
2. **`sieve_score`**:
|
|
223
|
+
- Inputs: `query` (str), `context` (str).
|
|
224
|
+
- Returns: Unfiltered sentence-by-sentence relevance scores (0 to 1) for inspectability.
|
|
225
|
+
3. **`sieve_stats`**:
|
|
226
|
+
- Returns cumulative session statistics: total calls, tokens processed, tokens pruned, and average reduction.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Sieve Calibrate
|
|
231
|
+
|
|
232
|
+
How aggressively can you filter context before answer accuracy degrades?
|
|
233
|
+
|
|
234
|
+
**Sieve Calibrate** sweeps a spectrum of thresholds across a benchmark dataset of `{question, context, expected_answer}` cases, evaluating answer preservation at each threshold to compute the **minimum sufficient context**.
|
|
235
|
+
|
|
236
|
+
Run calibration from the CLI:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
sieve calibrate --benchmark examples/benchmark.json --thresholds 0.20,0.35,0.50,0.65,0.80 --offline
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Example output:
|
|
243
|
+
|
|
244
|
+
```text
|
|
245
|
+
SIEVE CALIBRATION RESULTS
|
|
246
|
+
+---------------------------------------------------------------------+
|
|
247
|
+
| Threshold | Context Kept | Accuracy | Correct | Avg Latency |
|
|
248
|
+
|-------------------+--------------+----------+---------+-------------|
|
|
249
|
+
| — (WITHOUT SIEVE) | 100.0% | 100.0% | 10/10 | 0.0ms |
|
|
250
|
+
| 0.20 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
251
|
+
| 0.35 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
252
|
+
| 0.50 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
253
|
+
| 0.65 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
254
|
+
| 0.80 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
255
|
+
+---------------------------------------------------------------------+
|
|
256
|
+
|
|
257
|
+
Minimum sufficient context: Threshold 0.20, 38.1% of context retained, 100.0% accuracy.
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Configuration & Parameters
|
|
263
|
+
|
|
264
|
+
| Parameter | Type | Default | Description |
|
|
265
|
+
| :--- | :--- | :--- | :--- |
|
|
266
|
+
| `threshold` | `float` | `0.50` | Sigmoid-squashed cross-encoder logit cutoff (0.0 to 1.0). Sentences below this score are pruned. |
|
|
267
|
+
| `max_tokens` | `int` or `None` | `None` | Optional token budget limit for the retained context. |
|
|
268
|
+
| `context_window`| `int` | `0` | Number of neighboring sentences within the same document to retain around high-scoring hits. |
|
|
269
|
+
| `model_name` | `str` | `cross-encoder/ms-marco-MiniLM-L-6-v2` | Hugging Face cross-encoder model ID. |
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Architecture & How It Works
|
|
274
|
+
|
|
275
|
+
1. **Sentence Segmentation:** Text is parsed into discrete sentences without external NLP runtime dependencies.
|
|
276
|
+
2. **Local Batch Cross-Encoding:** Query and sentence pairs are evaluated in parallel batches with `cross-encoder/ms-marco-MiniLM-L-6-v2`. The model is loaded once per process and reused.
|
|
277
|
+
3. **Thresholding & Context Preservation:** Sentences scoring above the threshold are selected. Optional `context_window` preserves adjacent sentences to maintain numerical and pronoun coherence.
|
|
278
|
+
4. **Original Order Reconstruction:** Retained sentences are reconstructed in their original document order to preserve narrative flow for the LLM.
|
|
279
|
+
5. **Deterministic Metrics:** Token reductions are measured locally via `tiktoken` (`cl100k_base`).
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Limitations
|
|
284
|
+
|
|
285
|
+
- **Sentence-level granularity:** Sieve operates at sentence boundaries. It does not rewrite or partially redact sentences.
|
|
286
|
+
- **Cross-Encoder Inference Time:** Running a local neural model adds 50ms–300ms of local compute depending on CPU/GPU hardware.
|
|
287
|
+
- **Non-probability scoring:** Scores are sigmoid-squashed cross-encoder logits for ranking; a score of 0.8 represents ranking confidence, not an absolute statistical probability.
|
|
288
|
+
- **Tabular Data:** Regex sentence segmentation is designed for narrative prose and reports; complex ASCII/markdown tables should be handled prior to sentence chunking.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Contributing
|
|
293
|
+
|
|
294
|
+
Contributions are welcome! Please open an issue or pull request on GitHub:
|
|
295
|
+
- **Repository:** [https://github.com/kuhinthewuh/Sieve](https://github.com/kuhinthewuh/Sieve)
|
|
296
|
+
- **Issues:** [https://github.com/kuhinthewuh/Sieve/issues](https://github.com/kuhinthewuh/Sieve/issues)
|
|
297
|
+
|
|
298
|
+
To set up development:
|
|
299
|
+
```bash
|
|
300
|
+
git clone https://github.com/kuhinthewuh/Sieve.git
|
|
301
|
+
cd Sieve
|
|
302
|
+
pip install -e ".[dev,all]"
|
|
303
|
+
pytest
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Sieve
|
|
2
|
+
|
|
3
|
+
```text
|
|
4
|
+
____ ___ ______ _______
|
|
5
|
+
/ ___|_ _| ____\ \ / / ____|
|
|
6
|
+
\___ \| || _| \ \ / /| _|
|
|
7
|
+
___) | || |___ \ V / | |___
|
|
8
|
+
|____/___|_____| \_/ |_____|
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> **Less noise. Better retrieval.**
|
|
12
|
+
> *Sift the signal from your retrieval pipeline.*
|
|
13
|
+
|
|
14
|
+
[](https://pypi.org/project/sieve-context/)
|
|
15
|
+
[](https://opensource.org/licenses/MIT)
|
|
16
|
+
[](https://www.python.org/)
|
|
17
|
+
|
|
18
|
+
**Sieve** is a lightweight, post-retrieval context optimizer for Retrieval-Augmented Generation (RAG). It runs locally between your retriever and your LLM, evaluating retrieved sentences with a cross-encoder to prune irrelevant noise before generation.
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
Retriever ──► [ Retrieved Chunks ] ──► Sieve (Local Cross-Encoder) ──► [ Pruned Context ] ──► LLM
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Your vector database over-retrieves by design: embedding top-k similarity search returns large blocks of text where often only a few sentences answer the query. Sieve removes the noise, preserves document metadata, and passes a physically smaller, denser prompt to your downstream model.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Why Sieve?
|
|
29
|
+
|
|
30
|
+
Every irrelevant token retrieved into your prompt creates measurable friction:
|
|
31
|
+
- **Cost:** You pay per input token on hosted APIs (OpenAI, Anthropic, Gemini, Groq).
|
|
32
|
+
- **Latency:** Prompt processing time grows with input token volume.
|
|
33
|
+
- **Attention Degradation:** Irrelevant sentences compete with crucial facts for the model's attention budget ("lost in the middle" effect).
|
|
34
|
+
- **Zero API Key Requirement:** Filtering runs locally on your machine using a compact cross-encoder (`ms-marco-MiniLM-L-6-v2`). Your LLM API keys are never needed for context compression.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
Install via pip:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install sieve-context
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Optional Extras
|
|
47
|
+
|
|
48
|
+
- **LangChain Integration:**
|
|
49
|
+
```bash
|
|
50
|
+
pip install "sieve-context[langchain]"
|
|
51
|
+
```
|
|
52
|
+
- **Model Context Protocol (MCP) Server:**
|
|
53
|
+
```bash
|
|
54
|
+
pip install "sieve-context[mcp]"
|
|
55
|
+
```
|
|
56
|
+
- **Document Ingestion (PDF & HTML):**
|
|
57
|
+
```bash
|
|
58
|
+
pip install "sieve-context[docs]"
|
|
59
|
+
```
|
|
60
|
+
- **All Capabilities:**
|
|
61
|
+
```bash
|
|
62
|
+
pip install "sieve-context[all]"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Quickstart
|
|
68
|
+
|
|
69
|
+
### 1. Document-Level Optimization (Preserving Metadata)
|
|
70
|
+
|
|
71
|
+
Pass retrieved documents directly into `Sieve.optimize()`. Sieve filters sentences while maintaining each document's identity and metadata:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from sieve import Document, Sieve
|
|
75
|
+
|
|
76
|
+
sieve = Sieve(threshold=0.5)
|
|
77
|
+
|
|
78
|
+
retrieved_docs = [
|
|
79
|
+
Document(
|
|
80
|
+
text=(
|
|
81
|
+
"Apple Inc. reported total net sales of $391,035 million in fiscal year 2024. "
|
|
82
|
+
"Apple Park's main circular building features solar panels generating 17 megawatts."
|
|
83
|
+
),
|
|
84
|
+
metadata={"source": "apple-10k.pdf", "page": 28}
|
|
85
|
+
),
|
|
86
|
+
Document(
|
|
87
|
+
text="Steve Jobs co-founded Apple in Los Altos in 1976. iPhone net sales reached $201,183 million.",
|
|
88
|
+
metadata={"source": "apple-10k.pdf", "page": 31}
|
|
89
|
+
)
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
result = sieve.optimize(
|
|
93
|
+
query="What was Apple's total net sales and iPhone sales in 2024?",
|
|
94
|
+
documents=retrieved_docs,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Ready-to-inject string for your LLM prompt
|
|
98
|
+
print(result.context)
|
|
99
|
+
|
|
100
|
+
# Filtered documents preserving metadata
|
|
101
|
+
for doc in result.documents:
|
|
102
|
+
print(doc.metadata, "->", doc.text)
|
|
103
|
+
|
|
104
|
+
# Inspect exact token and reduction metrics
|
|
105
|
+
print(f"Original tokens: {result.metrics.original_tokens}")
|
|
106
|
+
print(f"Retained tokens: {result.metrics.filtered_tokens}")
|
|
107
|
+
print(f"Reduction: {result.metrics.reduction_percent}%")
|
|
108
|
+
print(f"Latency: {result.metrics.filtering_latency_ms} ms")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### 2. Direct String Filtering
|
|
114
|
+
|
|
115
|
+
If you have a raw context string:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from sieve import filter_context
|
|
119
|
+
|
|
120
|
+
result = filter_context(
|
|
121
|
+
query="What was Apple's 2024 revenue?",
|
|
122
|
+
context="Apple's fiscal 2024 revenue reached $391,035 million. The cafeteria serves lunch daily.",
|
|
123
|
+
threshold=0.5,
|
|
124
|
+
max_tokens=500,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
print(result.filtered_context)
|
|
128
|
+
# Output: "Apple's fiscal 2024 revenue reached $391,035 million."
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### 3. LangChain Integration
|
|
134
|
+
|
|
135
|
+
Drop Sieve into your existing LangChain retrieval chains as a document compressor:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from sieve.integrations.langchain import SieveCompressor
|
|
139
|
+
|
|
140
|
+
compressor = SieveCompressor(threshold=0.5)
|
|
141
|
+
optimized_docs = compressor.compress_documents(retrieved_docs, query="Apple 2024 revenue")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### 4. Model Context Protocol (MCP)
|
|
147
|
+
|
|
148
|
+
Sieve includes a native MCP server for Claude Desktop, Cursor, and any MCP-compliant agent.
|
|
149
|
+
|
|
150
|
+
Start the server:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
sieve-mcp
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Or configure it in your `claude_desktop_config.json`:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"mcpServers": {
|
|
161
|
+
"sieve": {
|
|
162
|
+
"command": "sieve-mcp"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Available MCP Tools
|
|
169
|
+
|
|
170
|
+
1. **`sieve_filter`**:
|
|
171
|
+
- Inputs: `query` (str), `context` (str), `threshold` (float, default 0.5), `max_tokens` (optional int).
|
|
172
|
+
- Returns: Filtered context string, token counts, reduction percentage, and filtering latency.
|
|
173
|
+
2. **`sieve_score`**:
|
|
174
|
+
- Inputs: `query` (str), `context` (str).
|
|
175
|
+
- Returns: Unfiltered sentence-by-sentence relevance scores (0 to 1) for inspectability.
|
|
176
|
+
3. **`sieve_stats`**:
|
|
177
|
+
- Returns cumulative session statistics: total calls, tokens processed, tokens pruned, and average reduction.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Sieve Calibrate
|
|
182
|
+
|
|
183
|
+
How aggressively can you filter context before answer accuracy degrades?
|
|
184
|
+
|
|
185
|
+
**Sieve Calibrate** sweeps a spectrum of thresholds across a benchmark dataset of `{question, context, expected_answer}` cases, evaluating answer preservation at each threshold to compute the **minimum sufficient context**.
|
|
186
|
+
|
|
187
|
+
Run calibration from the CLI:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
sieve calibrate --benchmark examples/benchmark.json --thresholds 0.20,0.35,0.50,0.65,0.80 --offline
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Example output:
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
SIEVE CALIBRATION RESULTS
|
|
197
|
+
+---------------------------------------------------------------------+
|
|
198
|
+
| Threshold | Context Kept | Accuracy | Correct | Avg Latency |
|
|
199
|
+
|-------------------+--------------+----------+---------+-------------|
|
|
200
|
+
| — (WITHOUT SIEVE) | 100.0% | 100.0% | 10/10 | 0.0ms |
|
|
201
|
+
| 0.20 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
202
|
+
| 0.35 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
203
|
+
| 0.50 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
204
|
+
| 0.65 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
205
|
+
| 0.80 | 38.1% | 100.0% | 10/10 | 0.3ms |
|
|
206
|
+
+---------------------------------------------------------------------+
|
|
207
|
+
|
|
208
|
+
Minimum sufficient context: Threshold 0.20, 38.1% of context retained, 100.0% accuracy.
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Configuration & Parameters
|
|
214
|
+
|
|
215
|
+
| Parameter | Type | Default | Description |
|
|
216
|
+
| :--- | :--- | :--- | :--- |
|
|
217
|
+
| `threshold` | `float` | `0.50` | Sigmoid-squashed cross-encoder logit cutoff (0.0 to 1.0). Sentences below this score are pruned. |
|
|
218
|
+
| `max_tokens` | `int` or `None` | `None` | Optional token budget limit for the retained context. |
|
|
219
|
+
| `context_window`| `int` | `0` | Number of neighboring sentences within the same document to retain around high-scoring hits. |
|
|
220
|
+
| `model_name` | `str` | `cross-encoder/ms-marco-MiniLM-L-6-v2` | Hugging Face cross-encoder model ID. |
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Architecture & How It Works
|
|
225
|
+
|
|
226
|
+
1. **Sentence Segmentation:** Text is parsed into discrete sentences without external NLP runtime dependencies.
|
|
227
|
+
2. **Local Batch Cross-Encoding:** Query and sentence pairs are evaluated in parallel batches with `cross-encoder/ms-marco-MiniLM-L-6-v2`. The model is loaded once per process and reused.
|
|
228
|
+
3. **Thresholding & Context Preservation:** Sentences scoring above the threshold are selected. Optional `context_window` preserves adjacent sentences to maintain numerical and pronoun coherence.
|
|
229
|
+
4. **Original Order Reconstruction:** Retained sentences are reconstructed in their original document order to preserve narrative flow for the LLM.
|
|
230
|
+
5. **Deterministic Metrics:** Token reductions are measured locally via `tiktoken` (`cl100k_base`).
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Limitations
|
|
235
|
+
|
|
236
|
+
- **Sentence-level granularity:** Sieve operates at sentence boundaries. It does not rewrite or partially redact sentences.
|
|
237
|
+
- **Cross-Encoder Inference Time:** Running a local neural model adds 50ms–300ms of local compute depending on CPU/GPU hardware.
|
|
238
|
+
- **Non-probability scoring:** Scores are sigmoid-squashed cross-encoder logits for ranking; a score of 0.8 represents ranking confidence, not an absolute statistical probability.
|
|
239
|
+
- **Tabular Data:** Regex sentence segmentation is designed for narrative prose and reports; complex ASCII/markdown tables should be handled prior to sentence chunking.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Contributing
|
|
244
|
+
|
|
245
|
+
Contributions are welcome! Please open an issue or pull request on GitHub:
|
|
246
|
+
- **Repository:** [https://github.com/kuhinthewuh/Sieve](https://github.com/kuhinthewuh/Sieve)
|
|
247
|
+
- **Issues:** [https://github.com/kuhinthewuh/Sieve/issues](https://github.com/kuhinthewuh/Sieve/issues)
|
|
248
|
+
|
|
249
|
+
To set up development:
|
|
250
|
+
```bash
|
|
251
|
+
git clone https://github.com/kuhinthewuh/Sieve.git
|
|
252
|
+
cd Sieve
|
|
253
|
+
pip install -e ".[dev,all]"
|
|
254
|
+
pytest
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## License
|
|
260
|
+
|
|
261
|
+
This project is licensed under the [MIT License](LICENSE).
|