xalonious

Case study

xanderGPT

A ChatGPT-style web app powered by a local LLM through Ollama, featuring real-time streamed responses, persistent conversations, and web search.

xanderGPT welcome screen with its logo and new-chat prompt

Technology

  • TypeScript
  • React
  • Node.js
  • Express
  • Tailwind
  • Prisma
  • MySQL
  • Ollama
Role
Sole developer
Year
2026
Status
Local prototype

Context

Learning what sits behind an AI chat interface

xanderGPT did not begin with a problem I needed to solve. I wanted to find out how difficult it would be to build my own ChatGPT-style application and understand how the interface, model, conversation state, and external tools fit together.

I treated it as a local prototype rather than a production product, focusing on recreating the parts of an AI chat experience that users normally take for granted.

The system

A local model with persistent conversations

The React frontend communicates with an Express API that sends prompts to a local qwen2.5:7b model through Ollama. I chose that model because it was capable enough for the experiment while still running comfortably on my RTX 3070.

Prisma and MySQL store accounts, conversations, messages, and per-chat system prompts. The backend streams generated tokens to the browser, supports cancellable responses, creates automatic conversation titles, and also offers temporary chats that are not written to the database.

Tool orchestration

Connecting the model to useful tools

Before generating an answer, the backend can ask the model whether it should use a calculator or search the web. Mathematical expressions are evaluated separately, Brave Search provides web results, and URLs included in a prompt can be fetched and reduced to readable page content before being added to the model's context.

Building this flow taught me how an assistant can coordinate several specialized tools instead of expecting the language model to handle every task by itself.

Main technical challenge

Reliable web search is more than an API call

The difficult part was not sending a query to a search API; it was finding results that were relevant and trustworthy enough to support an answer. The implementation lets the model decide when to search, evaluates whether it needs more results, and adds Brave Search snippets to the final prompt.

That still leaves a fragile handoff between retrieval and generation. Search results can be incomplete or poorly matched, and the model may rely on its existing knowledge when that conflicts with the retrieved information. The result can sound confident while still being wrong, which made web search the clearest limitation of the prototype.

What I would improve

Build the answer around evidence

A stronger version would treat search as a retrieval pipeline rather than passing result snippets directly to the model. I would fetch the most promising pages, prioritize primary and reputable sources, extract only the passages relevant to the question, compare evidence across multiple sources, and require the final answer to cite the material it actually used.

I would also make conflicts and weak evidence explicit instead of asking the model to resolve them silently. That would make the system easier to evaluate and reduce the chance that prior model knowledge overrides fresher information.

What I learned

Tool use depends on the quality of the handoff

The project gave me a practical understanding of tool orchestration and showed me that adding a tool is only the first step. The difficult work is deciding when to use it, selecting useful context, and making sure the model stays grounded in what the tool returned.