Files as Data Source

"Chat with your spreadsheet" is the #1 demo in GenAI — and a minefield of silent wrong answers. Four patterns, from naive to production-grade.

▶ Watch this reel

What you'll learn

  1. Chat with CSV/Excel
  2. DuckDB + LLM
  3. Code-interpreter pattern
  4. Tabular RAG

Remember this

Why naive chat-with-CSV fails

DuckDB + LLM

Code-interpreter pattern

Tabular RAG

Principle: models interpret, engines compute.

Code: The tri-router: one file, three engines

async def answer_over_file(question: str, file_path: str) -> Answer:
    # 0 · one-time setup: file becomes all three things
    con = duckdb.connect()
    con.execute(f"CREATE VIEW data AS SELECT * FROM '{file_path}'")
    workspace = sandbox.put(file_path)          # code-interpreter
    chunks = index_tables_with_captions(file_path)  # tabular RAG

    # 1 · cheap router classifies the question
    route = classify(question, classes=["aggregate", "transform", "semantic"])

    if route == "aggregate":                    # DuckDB
        sql = llm(SQL_PROMPT, schema=describe(con), q=question)
        rows = con.execute(f"SELECT * FROM ({sql}) _q LIMIT 500").fetchdf()
        return llm(ANSWER_PROMPT, q=question, exact_results=rows)

    if route == "transform":                    # code interpreter
        code = llm(CODE_PROMPT, q=question, files=[workspace.name])
        out = await sandbox.run(code, timeout=60)
        return Answer(text=out.stdout, artifacts=out.files)

    return rag_answer(question, store=chunks)   # semantic → tabular RAG

# Rule of the whole reel: models interpret, engines compute.