Skip to content

Reference Chatbot

Folder: reference_chatbot/

A reference multi-tool chat agent: a LangGraph ReAct agent with pluggable knowledge-base search, NL2SQL, and web search tools, built once so a recipe's spec can point at it instead of re-deriving a chat agent from scratch. Not token_factory-based — it's an agent-architecture pattern, the chat-entry-point counterpart to the identity-propagation patterns above.

User message
    │
    ▼
build_chat_agent() — LangGraph create_react_agent
  fresh turn (last msg ≠ ToolMessage) → force a tool call
  after tool results land               → free synthesis, no forced choice
    │              │              │
    ▼              ▼              ▼
search_knowledge_base   query_database   search_web
(KB search)             (NL2SQL)         (Tavily)
    │                        │                │
    ▼                        ▼                ▼
 mcp_sqlcl               mcp_sqlcl        Tavily API

The forced-tool-call-on-a-fresh-turn trick is what keeps every answer grounded: the model is never allowed to answer a new question from unaided training knowledge instead of an available tool. Once a tool result lands, it's free to synthesize normally.

Key files:

  • src/reference_chatbot/agent_factory.py — build_chat_agent(), the generalized ReAct factory
  • src/reference_chatbot/tools/kb_search_tool.py — vector search (OCI embeddings + Oracle VECTOR_DISTANCE)
  • src/reference_chatbot/tools/nl2sql_tool.py — schema fetch → LLM-generated SQL → execute, with a structural read-only-SELECT guard (refuses write/DDL/multi-statement SQL, not just prompt wording)
  • src/reference_chatbot/tools/websearch_tool.py — Tavily, wrapped as a first-class reusable tool
  • src/reference_chatbot/memory.py — both proven memory shapes ready to wire in: build_memory_saver() (short-term, in-process) and build_oracle_checkpointer() (long-term, Oracle-backed, survives restarts)
  • src/reference_chatbot/analytics.py — optional OracleStore question/gap/user-profile tracking
  • src/reference_chatbot/mcp_sql.py — the shared mcp_sqlcl call helper, including a documented workaround for a real mcp_sqlcl quirk that corrupts wide free-text column values (base64-encode in SQL, decode client-side)
from reference_chatbot import build_chat_agent, make_kb_search_tool, make_nl2sql_tool, make_websearch_tool

tools = [
    make_kb_search_tool(bearer_token_provider=my_token_fn, table="MY_RECIPE_KB"),
    make_nl2sql_tool(bearer_token_provider=my_token_fn),
    make_websearch_tool(),
]
agent = build_chat_agent(tools=tools, system_prompt="You are <persona>...")

examples/minimal_chat_agent.py is a runnable CLI REPL wiring all three tools, with a --memory {short,long} flag demonstrating both memory shapes. scripts/seed_reference_kb.py seeds a brand-new demo KB table with dummy content — this pattern ships no real knowledge base and never points at any recipe's existing one.

When to use: A recipe needs an open-ended, tool-using conversational entry point — the user asks free-form questions and the agent decides which tool answers each one. Don't use this for a chat surface whose job is narrow, bounded intent classification into a small fixed set of backend actions (a much smaller prompt-injection surface, since the LLM never freely decides which tool to call) — see finance_analyst_chat_agent.py for that shape instead. The inception-recipe-builder skill points new specs at whichever of the two fits.