← LLM- en AI-experimenten

Cortana: een agentische CLI op mijn eigen model, overal bereikbaar

Een eigen terminalassistent op basis van opencode en mijn lokale model, met een eigen identiteit en thema, kennisbanken via RAG en een failover-proxy die automatisch kiest tussen het thuisnetwerk en een relay.

Wat het is

cortana is mijn eigen agentische CLI, in de geest van Claude Code, maar op mijn eigen model. Het is een wrapper om opencode met:

  • een eigen systeemprompt, afgeleid van de assistent-preset in Open WebUI, waaruit de tools zijn gehaald die in de terminal niet bestaan (anders doet het model alsof het ze aanroept);
  • een eigen thema in een Halo-palet en een eigen woordmerk in de interface;
  • cortana --rag "vraag" om dezelfde kennisbanken te bevragen als in de webinterface.

RAG via de API: twee valkuilen

  1. De preset zet "denken" uit, maar dat bereikt llama.cpp niet. Zonder chat_template_kwargs: {enable_thinking: false} vult de denkstap het hele tokenbudget en blijft het antwoord leeg.
  2. Open WebUI doet geen retrieval bij een kale API-aanroep. De collectie-ID's moeten expliciet mee in files. Controleer retrieval via de sources in de stream: het model zegt soms ten onrechte dat het niets kreeg.

Overal bereikbaar: een failover-proxy

Thuis praat alles rechtstreeks met de modelserver op het LAN. Onderweg gaat het via een relay achter de reverse proxy, of via WireGuard op afroep. Eerst zat die keuze alleen in het cortana-script; de editor en een kale opencode vielen om zodra de tunnel neer was.

Nu draait er een kleine proxy op de laptop (127.0.0.1:18099, Python stdlib, systemd user-unit):

  • voorkeur voor het LAN, anders de relay; de healthcheck wordt tien seconden gecachet;
  • valt een route weg tijdens een verzoek, dan gaat datzelfde verzoek naar de volgende route en ziet de client geen fout;
  • de Authorization-header van de client wordt vervangen door de sleutel van de gekozen route, zodat sleutels op één plek staan (0600) en niet in elke config;
  • streaming gaat ongebufferd door, en tool-calling werkt erdoorheen. Dat is de stille faalmodus die ik na elke wijziging opnieuw test, want zonder tool-calling gaat agent-modus in de editor uit.

Waarom zelf bouwen?

Omdat het kan, en omdat ik zo precies begrijp wat een agent-lus nodig heeft: toolschema's, streaming, context. Die kennis gebruik ik dagelijks bij het werken met Claude Code.