Skip to content

Build and develop with AI Academy

Outcome: move from asking questions to building a small application and making a reviewable backend change. Run examples in a separate development checkout with non-sensitive data. These are learning instructions; they do not change the running platform until you implement them.

Complete installation and your first query. Keep your experiment separate from an existing service or shared vector store. From your development repository root in WSL Bash, start the backend with automatic reload:

Terminal window
PYTHONPATH="$PWD/backend" .venv/bin/uvicorn app:app --app-dir backend --host 127.0.0.1 --port 8000 --reload

Stop any earlier terminal-launched backend using the same port first. Reload is for local development, not production operation. The Node environment is needed for the documentation site; it is not required for this Python API client.

Create examples/ask_academy.py in your development copy with this code. It uses the Python standard library, so no additional package is required.

import json
import os
import sys
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
def main():
key = os.environ.get("API_KEY")
if not key:
raise SystemExit("Set API_KEY in this terminal before running the client.")
question = " ".join(sys.argv[1:]).strip()
if not question:
raise SystemExit("Usage: python examples/ask_academy.py <question>")
payload = {"query": question, "user_id": "development-lab", "include_sources": True}
request = Request(
"http://localhost:8000/api/v1/query",
data=json.dumps(payload).encode("utf-8"),
headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
method="POST",
)
try:
with urlopen(request, timeout=330) as response:
result = json.load(response)
except HTTPError as error:
raise SystemExit(f"API returned HTTP {error.code}; see the API error reference.")
except (URLError, TimeoutError):
raise SystemExit("Could not complete the request; check the backend and Ollama.")
if not result.get("response"):
raise SystemExit("The API returned no answer; inspect the backend logs.")
print(f"Model: {result.get('model', 'unknown')}")
print(result["response"])
print(f"Sources: {len(result.get('sources') or [])}")
if __name__ == "__main__":
main()

Set the terminal key using the hidden input procedure in your first query, then run:

Terminal window
.venv/bin/python examples/ask_academy.py "Explain why Git branches are useful."

Expected: the selected model, a nonempty answer, and a source count. Try a missing key and a stopped backend as well; the client should give a clear error. Do not automatically execute text returned by the model.

What you want to changeWhere to beginWhat to verify
Add an authenticated endpointbackend/app.py and Pydantic request modelsAuthentication, input validation, success and failure responses
Improve prompt instructionsbuild_prompt_with_context() in backend/app.pyAnswers with empty and populated context; supported source claims
Change model selectionbackend/model_router/rules.py and analyzerCoding, general, explicit-selection, unavailable-model cases
Add knowledgeIngestion API and extraction scriptCorrect document content and returned source evidence
Change conversation behaviorbackend/database.py and API handlersOwnership, ordering, deletion, and both persistent stores
Add an engineering workflowPrompt/playbook files and catalogsMetadata validity, concrete steps, and approval boundaries

In the development copy, add a small GET /api/v1/stats endpoint to backend/app.py. Its contract should return only the knowledge-document count and should require the existing verify_token dependency. It must not return credentials, conversation content, or a claim that inference is healthy.

Use the existing FastAPI patterns, restart/reload, and call the new endpoint with and without the Authorization header. Add an automated test for each case and a storage-failure case. A test that merely checks the function exists is not enough.

Completion evidence: a small diff, an authenticated response, an unauthenticated rejection, and passing meaningful tests. This is a proposed exercise endpoint, not one already available in the API reference.

Before editing the prompt builder, keep a fixed set of sample questions and known documents. Record baseline answers, selected model, retrieved sources, and generation settings. Change one instruction, then repeat the same inputs.

Evaluate factual support, useful detail, invented information, and latency. Preserve the function’s existing arguments and conversation handling. Increasing context_limit can be done per request; it does not require editing the backend default. Real ONNX embeddings already exist, so an exercise should not assume they still need to be implemented from scratch.

Run targeted tests from the repository root using the project environment:

Terminal window
.venv/bin/python -m pytest backend/test_model_router.py
git diff --check
git diff

The existing router test can print mismatches without failing. Review those results and add explicit assertions for the behavior you change; a green exit code alone is insufficient. For new endpoint tests, isolate storage and mock model calls so they do not modify your live lab.

Update the API reference and configuration reference if their contracts change. Review the diff before committing; push and deployment are separate decisions.

Next: Create a planner handoff or choose a learning progression.