Engineering

Shipping AI features responsibly

Patterns for portfolio chat: server-side RAG, rate limits, sanitized markdown, and honest guardrails.

Adding an AI chat surface to a portfolio is easy. Shipping one you can defend in production is harder.

Keep retrieval on the server

Never trust the client to supply context. The chat API should:

  1. Accept user messages only
  2. Run RAG retrieval server-side
  3. Inject grounded context as a system message
ts
const results = await retrieveForQuery(lastUserMessage)const retrievedContext = buildRetrievedContext(results)

Render markdown safely

Assistant responses use the same Streamdown pipeline as this blog — sanitized HTML, hardened links, and syntax highlighting via @streamdown/code.

That means code blocks, lists, and inline formatting work consistently without dangerouslySetInnerHTML.

Set honest expectations

The system prompt should say what the assistant can and cannot do:

  • Answer from indexed portfolio content
  • Link to projects and public pages
  • Refuse to invent employment history or private details

Protect the API

Even on a personal site, unauthenticated chat endpoints get abused:

  • Rate limit by IP
  • Cap token usage per request
  • Return generic errors; log upstream failures server-side

Learn more about the implementation on .