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 factorysrc/reference_chatbot/tools/kb_search_tool.py— vector search (OCI embeddings + OracleVECTOR_DISTANCE)src/reference_chatbot/tools/nl2sql_tool.py— schema fetch → LLM-generated SQL → execute, with a structural read-only-SELECTguard (refuses write/DDL/multi-statement SQL, not just prompt wording)src/reference_chatbot/tools/websearch_tool.py— Tavily, wrapped as a first-class reusable toolsrc/reference_chatbot/memory.py— both proven memory shapes ready to wire in:build_memory_saver()(short-term, in-process) andbuild_oracle_checkpointer()(long-term, Oracle-backed, survives restarts)src/reference_chatbot/analytics.py— optionalOracleStorequestion/gap/user-profile trackingsrc/reference_chatbot/mcp_sql.py— the sharedmcp_sqlclcall helper, including a documented workaround for a realmcp_sqlclquirk 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.