beginner5 min· python · siftq · openai
RAG with the OpenAI Responses API
Same recipe, different model — drop-in OpenAI grounding.
Prerequisites
- $
pip install openai requests - $
export SIFTQ_API_KEY=mk-... - $
export OPENAI_API_KEY=sk-...
How it works
The retrieval primitive is model-agnostic. If your stack is on OpenAI rather than Anthropic, the loop is identical — same SiftQ call, same system instructions, swap the synthesis layer. This is the value of separating retrieval and generation: you keep model optionality without rewriting your search code.
The recipe
import os
import requests
from openai import OpenAI
client = OpenAI()
SIFTQ_KEY = os.environ["SIFTQ_API_KEY"]
def search(q: str, n: int = 8) -> list[dict]:
r = requests.post(
"https://api.siftq.com/v1/search",
headers={"Authorization": f"Bearer {SIFTQ_KEY}"},
json={"q": q, "scope": "webpage", "size": str(n), "conciseSnippet": True},
timeout=20,
)
r.raise_for_status()
return r.json().get("webpages", [])
def answer(question: str) -> str:
hits = search(question)
sources = "\n\n".join(
f"[{i + 1}] {h['title']}\n{h['snippet']}\nURL: {h['link']}"
for i, h in enumerate(hits)
)
resp = client.responses.create(
model="gpt-5",
instructions=(
"Answer using only the provided sources. "
"Cite as [N] inline next to every factual claim. "
"Refuse to answer if the sources do not contain the information."
),
input=f"SOURCES:\n{sources}\n\nQUESTION: {question}",
)
return resp.output_text
if __name__ == "__main__":
print(answer("What are the latest open-source LLM benchmarks?"))
Variations
Structured outputs (JSON)
Pass response_format with a JSON schema so the LLM returns {answer, citations:[]} parsed objects instead of free text.
Function calling
Expose SiftQ as a tool the model decides when to call, rather than hard-coding retrieval before every prompt.