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.
1. Prepare your development environment
Section titled “1. Prepare your development environment”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:
PYTHONPATH="$PWD/backend" .venv/bin/uvicorn app:app --app-dir backend --host 127.0.0.1 --port 8000 --reloadStop 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.
2. Build a small API client
Section titled “2. Build a small 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 jsonimport osimport sysfrom urllib.error import HTTPError, URLErrorfrom 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:
.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.
3. Locate the right extension point
Section titled “3. Locate the right extension point”| What you want to change | Where to begin | What to verify |
|---|---|---|
| Add an authenticated endpoint | backend/app.py and Pydantic request models | Authentication, input validation, success and failure responses |
| Improve prompt instructions | build_prompt_with_context() in backend/app.py | Answers with empty and populated context; supported source claims |
| Change model selection | backend/model_router/rules.py and analyzer | Coding, general, explicit-selection, unavailable-model cases |
| Add knowledge | Ingestion API and extraction script | Correct document content and returned source evidence |
| Change conversation behavior | backend/database.py and API handlers | Ownership, ordering, deletion, and both persistent stores |
| Add an engineering workflow | Prompt/playbook files and catalogs | Metadata validity, concrete steps, and approval boundaries |
4. Try an authenticated endpoint exercise
Section titled “4. Try an authenticated endpoint exercise”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.
5. Evaluate a prompt change
Section titled “5. Evaluate a prompt change”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.
6. Validate and review
Section titled “6. Validate and review”Run targeted tests from the repository root using the project environment:
.venv/bin/python -m pytest backend/test_model_router.pygit diff --checkgit diffThe 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.