Why I Built AskRich
Most recruiting conversations start with the same challenge: people want signal quickly. A resume gives breadth, but not always the system details behind impact statements. AskRich was built to shorten that gap.
The goal was simple: give recruiters and hiring managers a way to ask specific technical questions and get direct answers grounded in source material from my portfolio and writing.
What the Experience Is Optimized For
The AskRich page uses prompt starters tuned for realistic recruiter workflows, including project impact, architecture trade-offs, and staff-level ownership examples.
- fast onboarding through one-click prompt chips
- a low-friction chat input for custom questions
- citations attached to assistant responses for validation
- an optional API endpoint override for staging and local testing
Implementation Notes
The chat UI is intentionally lightweight and dependency-free: plain JavaScript, semantic HTML, and a minimal state model for busy handling, validation, and message rendering.
The client posts questions to a dedicated /api/chat endpoint and expects a structured response containing an answer plus citation metadata. When citations include source URLs, links are sanitized before rendering and opened safely in a new tab.
I built both an embedded page experience and a standalone widget script. The widget mounts a floating launcher, opens a keyboard-accessible dialog, traps focus while open, and restores focus on close for accessibility.
Since the first release, the API layer has shifted from a simple retrieval pipeline to a LangGraph-orchestrated chat workflow with explicit retrieval, filtering, evidence bounding, generation, post-processing, and citation construction nodes.
On the edge side, the Cloudflare Worker now supports three runtime modes: upstream (proxy to retrieval API), local (serve from built-in corpus), and openai (direct model path with retrieval-aware constraints).
The Worker also includes response caching for repeated prompt shapes, bounded cache TTL controls, and follow-up resolution logic that normalizes short confirmations (like yes/ok) against recent chat history. That keeps common recruiter flows fast while reducing unnecessary repeated inference work.
High-Level Architecture
At a high level, AskRich is a thin web client over a retrieval-backed chat API. The browser handles input, rendering, and citation display. The API layer handles retrieval, answer synthesis, and structured citation output.
{question, top_k}"| G[AskRich API Gateway] G --> K{Cache hit?} K -->|yes| A[Answer text] K -->|no| M{Worker mode} M -->|upstream| O[LangGraph Orchestrator] M -->|local| W[Worker Local Corpus Path] M -->|openai| X[Direct OpenAI Path] O -->|retrieve relevant context| I[Content Index] O -->|compose grounded response| L[LLM Response Layer] I --> C[Citations + supporting chunks] L --> A[Answer text] W --> A X --> A C --> R[Web UI Message Renderer] A --> R R --> V[Visible answer + source links]
This split keeps the front end lightweight while allowing retrieval quality, ranking strategy, and response composition to evolve independently in the API stack.
Why Citations Matter
The key product decision is citation-backed output. Recruiters can inspect supporting references instead of taking a generated answer at face value. That keeps the tool useful as a screening aid rather than a black-box demo.
It also encourages better questions. Once someone sees where answers come from, they tend to ask more precise follow-ups around architecture constraints, rollout sequencing, and measurable outcomes.
What Is Implemented Today
The system now runs with production-style controls: rate limiting at the edge, structured question and answer event recording, and thumbs-up/thumbs-down feedback capture with explicit privacy and review workflows. That shifted iteration from anecdotal edits to observable answer-quality improvements.
Rate limiting is enforced before chat execution in the Worker on POST /api/chat. Client identity is derived from a one-way hash of request context
(cf-connecting-ip/x-forwarded-for/x-real-ip + origin + user-agent), so raw IP values are not used as persistent identifiers.
The current policy combines two guards: an hourly quota (RATE_LIMIT_QPS_HOUR, default 30) and a burst interval
(RATE_LIMIT_BURST_SECONDS, default 1). If a request exceeds either guard, the API returns 429 with
Retry-After and a stable event ID for traceability.
The limiter uses KV-backed sliding-window state and computes reset time from the oldest in-window request. If KV is unavailable, the implementation degrades gracefully (fail-open) to preserve availability while still keeping normal enforcement active when storage is healthy.
There is also a working analytics and corpus-improvement loop in place: event schema documentation, triage playbooks, lightweight content versioning, and A/B testing patterns for retrieval and prompt changes. In practice, prompt and retrieval updates can be evaluated with explicit hypotheses instead of one-off edits.
Rate Limiting Decision Flow
Request Lifecycle
Quality and Feedback Loop
The feedback loop is event-linked end to end. Each question and answer is assigned stable event IDs, and feedback is attached to that interaction pair. That makes it possible to inspect a specific low-rated answer with its exact question text, citation count, latency, and backend mode instead of debugging in the abstract.
Practically, the loop captures three signal types: question events, answer events, and feedback events. Answer events include response latency and citation counts, which lets triage separate retrieval problems (weak or missing evidence), generation problems (response quality), UX/prompting problems (question ambiguity), and mode-specific behavior differences.
Triage then classifies low-satisfaction interactions into concrete action buckets: corpus gap, retrieval/ranking issue, prompt/format issue, or out-of-scope question pattern. Changes are tested, compared, and only promoted when they improve answer quality without regressing citation clarity.
Feedback Triage Flow
What I’d Improve Next
- continue latency profiling, routing, and ranking improvements in the live path
- promote successful A/B variants into default retrieval/prompt behavior
- expand corpus gap-closing cadence using the weekly triage workflow
- tighten citation quality metrics and regression gating for high-frequency recruiter questions
Related Reading: Interview Signal in the AI Era
AskRich is about improving recruiter and hiring-manager signal quality. If you want the candidate-side and interviewer-side view of how technical signal changes when AI is allowed in coding interviews, start with Coding With AI in Interviews: Why the Bar Is Higher, Not Lower, continue to What Experienced Engineers Are Actually Being Measured on in AI-Assisted Coding Interviews, and use the series hub Coding Interviews in the AI Era for the full reading path.
Try It
You can use AskRich directly at Ask Rich to explore architecture decisions, migration strategy, and platform outcomes.