|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +This is a boilerplate for creating AI educational chatbots that integrate with the **Lambda-Feedback** educational platform. It deploys as an AWS Lambda function (containerized via Docker) that receives student chat messages with educational context and returns LLM-powered chatbot responses. |
| 8 | + |
| 9 | +## Commands |
| 10 | + |
| 11 | +**Testing:** |
| 12 | +```bash |
| 13 | +pytest # Run all unit tests |
| 14 | +python tests/manual_agent_run.py # Test agent locally with example inputs |
| 15 | +python tests/manual_agent_requests.py # Test running Docker container |
| 16 | +``` |
| 17 | + |
| 18 | +**Docker:** |
| 19 | +```bash |
| 20 | +docker build -t llm_chat . |
| 21 | +docker run --env-file .env -p 8080:8080 llm_chat |
| 22 | +``` |
| 23 | + |
| 24 | +**Manual API test (while Docker is running):** |
| 25 | +```bash |
| 26 | +curl -X POST http://localhost:8080/2015-03-31/functions/function/invocations \ |
| 27 | + -H 'Content-Type: application/json' \ |
| 28 | + -d '{"body":"{\"conversationId\": \"12345Test\", \"messages\": [{\"role\": \"USER\", \"content\": \"hi\"}], \"user\": {\"type\": \"LEARNER\"}}"}' |
| 29 | +``` |
| 30 | + |
| 31 | +**Run a single test:** |
| 32 | +```bash |
| 33 | +pytest tests/test_module.py # Run specific test file |
| 34 | +pytest tests/test_index.py::test_function_name # Run specific test |
| 35 | +``` |
| 36 | + |
| 37 | +## Architecture |
| 38 | + |
| 39 | +### Request Flow |
| 40 | + |
| 41 | +``` |
| 42 | +Lambda event → index.py (handler) |
| 43 | + → validates via lf_toolkit ChatRequest schema |
| 44 | + → src/module.py (chat_module) |
| 45 | + → extracts muEd API context (messages, conversationId, question context, user type) |
| 46 | + → parses educational context to prompt text via src/agent/context.py |
| 47 | + → src/agent/agent.py (BaseAgent / LangGraph) |
| 48 | + → routes to call_llm or summarize_conversation node |
| 49 | + → calls LLM provider (OpenAI / Google / Azure / Ollama) |
| 50 | + → returns ChatResponse (output, summary, conversationalStyle, processingTime) |
| 51 | +``` |
| 52 | + |
| 53 | +### Key Files |
| 54 | + |
| 55 | +| File | Role | |
| 56 | +|------|------| |
| 57 | +| `index.py` | AWS Lambda entry point; parses event body, validates schema | |
| 58 | +| `src/module.py` | Transforms muEd API request → invokes agent → builds ChatResponse | |
| 59 | +| `src/agent/agent.py` | LangGraph stateful graph; manages message history and summarization | |
| 60 | +| `src/agent/prompts.py` | System prompts for tutor behavior, summarization, style detection | |
| 61 | +| `src/agent/llm_factory.py` | Factory classes for each LLM provider (OpenAI, Google, Azure, Ollama) | |
| 62 | +| `src/agent/context.py` | Converts muEd question/submission context dicts to LLM prompt text | |
| 63 | +| `tests/utils.py` | Shared test helpers: `assert_valid_chat_request`, `assert_valid_chat_response` | |
| 64 | +| `tests/example_inputs/` | Real muEd payloads used for end-to-end tests | |
| 65 | + |
| 66 | +### Agent Logic (LangGraph) |
| 67 | + |
| 68 | +`BaseAgent` maintains a state graph with two nodes: |
| 69 | +- **`call_llm`**: Invokes the LLM with system prompt + conversation summary + conversational style preference |
| 70 | +- **`summarize_conversation`**: Triggered when message count exceeds ~11; summarizes history and also extracts the student's preferred conversational style |
| 71 | + |
| 72 | +Messages are trimmed after summarization to keep context window manageable. The `summary` and `conversationalStyle` fields persist across calls via the `ChatRequest` metadata. |
| 73 | + |
| 74 | +### muEd API Format |
| 75 | + |
| 76 | +`src/module.py` handles the muEd request format (https://mued.org/). The `context` field in `ChatRequest` contains nested educational data (question parts, student submissions, task info) and the `user` field contains user-specific information (e.g., user type, preferences, task progress) that gets parsed into a tutoring prompt via `src/agent/context.py`. |
| 77 | + |
| 78 | +### LLM Configuration |
| 79 | + |
| 80 | +LLM provider and model are set via environment variables (see `.env.example`). The `llm_factory.py` selects the provider at runtime. The Lambda function name/identity is set in `config.json`. |
| 81 | + |
| 82 | +The agent uses **two separate LLM instances** — `self.llm` for chat responses and `self.summarisation_llm` for conversation summarisation and style analysis. By default both use the same provider, but you can point them at different models (e.g. a cheaper model for summarisation) by changing the class in `agent.py`. |
| 83 | + |
| 84 | +## Deployment |
| 85 | + |
| 86 | +- Pushing to `dev` branch triggers the dev deployment GitHub Actions workflow |
| 87 | +- Pushing to `main` triggers staging deployment, with manual approval required for production |
| 88 | +- All environment variables (API keys, model names) are injected via GitHub Actions secrets/variables — do not hardcode them |
0 commit comments