feat(rag): show cited sources and exit cleanly on interrupt/errors

- After a synthesized answer, print a legend mapping the [n] tags the
  model actually cited to their source files (on stderr, so piping the
  answer stays clean). Only cited tags are listed, not every retrieved
  chunk.
- Catch KeyboardInterrupt/BrokenPipeError for a quiet abort and collapse
  other exceptions to a one-line message; set RAG_DEBUG=1 for the full
  traceback.
This commit is contained in:
Harald Hoyer 2026-05-22 09:12:10 +02:00
parent 89c82cf804
commit 2b1bba0703

View file

@ -16,6 +16,7 @@ writers.writePython3Bin "rag"
import hashlib import hashlib
import os import os
import pathlib import pathlib
import re
import sys import sys
from openai import OpenAI from openai import OpenAI
@ -128,12 +129,24 @@ writers.writePython3Bin "rag"
{"role": "user", "content": f"Context:\n{context}\n\nQuestion: {args.text}"}, {"role": "user", "content": f"Context:\n{context}\n\nQuestion: {args.text}"},
] ]
stream = client.chat.completions.create(model=CHAT_MODEL, messages=messages, stream=True) stream = client.chat.completions.create(model=CHAT_MODEL, messages=messages, stream=True)
answer = []
for ev in stream: for ev in stream:
delta = ev.choices[0].delta.content delta = ev.choices[0].delta.content
if delta: if delta:
answer.append(delta)
sys.stdout.write(delta) sys.stdout.write(delta)
sys.stdout.flush() sys.stdout.flush()
sys.stdout.write("\n") sys.stdout.write("\n")
# Legend for only the [n] tags actually cited (stderr keeps stdout pipe-clean).
cited = sorted({int(n) for n in re.findall(r"\[(\d+)\]", "".join(answer))})
cited = [i for i in cited if 1 <= i <= len(hits)]
if cited:
print("\nQuellen:", file=sys.stderr)
for i in cited:
h = hits[i - 1]
src = h.payload.get("source", "?")
chunk = h.payload.get("chunk", "?")
print(f" [{i}] {src}#{chunk} ({h.score:.3f})", file=sys.stderr)
def main(): def main():
@ -157,5 +170,15 @@ writers.writePython3Bin "rag"
if __name__ == "__main__": if __name__ == "__main__":
main() try:
main()
except KeyboardInterrupt:
sys.exit(130)
except BrokenPipeError:
sys.exit(0)
except Exception as e:
if os.environ.get("RAG_DEBUG"):
raise
print(f"rag: {type(e).__name__}: {e}", file=sys.stderr)
sys.exit(1)
'' ''