How we got here: principles and tooling — ICCS Summer School 2026
Cordero Core
Tom Meltzer
Matt Archer
In collaboration with
Institutions behind this session
Plan
How we got here: ~70 years of GenAI as a timeline
Inside a transformer: tokens, embeddings, attention, inference
From next-word prediction to assistants, agents, and MCP
Tooling overview and code demo
Opencode intro and configuration
Create your own tool call with MCP + Skills
How We Got Here
Every concept in GenAI was an answer to a problem someone hit
So we’ll walk the timeline instead of a glossary
Destination: what is inside the tools you’ll use this afternoon
If You Remember Nothing Else
Every AI model is the same machine.
Your model is only as good as your harness.
Generative AI tools are powerful but fragile.
Act I
1958 – 2012
Learning from data
1958: The Perceptron
1958›1969›1986›2012›2017›2020›2022›2024›now
The 1958 machine you’re still using
Inputs, weights, sum, threshold — no layers, no magic
Weights are dials: learn by nudging them on every mistake
Geometrically: learning to draw a line between two classes
Still the irreducible unit of every model you use
%%{init: {"flowchart": {"nodeSpacing": 12, "rankSpacing": 25}, "theme": "base", "themeVariables": {"edgeLabelBackground": "#ffffff"}}}%%
flowchart LR
x1([x₁]) -->|w₁| S["Σ"]
x2([x₂]) -->|w₂| S
x3([x₃]) -->|w₃| S
S --> T["> θ ?"]
T --> O(["0 / 1"])
classDef io fill:#6c757d,stroke:#495057,color:#fff
classDef key fill:#003b6f,stroke:#001f3f,color:#fff
classDef step fill:#4b9cd3,stroke:#2c6e9e,color:#fff
class x1,x2,x3,O io
class S key
class T step
1969: The Wall
1958›1969›1986›2012›2017›2020›2022›2024›now
The book that almost killed neural networks
Minsky & Papert prove a single-layer perceptron cannot compute XOR
The proof was correct — and still is
The lethal move was extrapolation: multi-layer networks declared “sterile”
Funding dried up: the first AI winter
1986: Backpropagation
1958›1969›1986›2012›2017›2020›2022›2024›now
One wrong answer, a billion dials — how a network learns who to blame
Loss function: measures model error
Gradient descent: moves weights down the loss surface
Backpropagation: blame flows backward, layer by layer (chain rule)
Overfitting: memorises training data, fails to generalise
1986: The Training Loop
%%{init: {"flowchart": {"nodeSpacing": 15, "rankSpacing": 18}, "theme": "base", "themeVariables": {"edgeLabelBackground": "#ffffff"}}}%%
flowchart TD
A([Training data]) --> B["Forward pass"]
B --> C[Compute loss]
C --> D[Backpropagation]
D --> E[Update weights]
E -->|repeat| B
C -->|loss small enough| F([Done ✓])
classDef io fill:#6c757d,stroke:#495057,color:#fff
classDef step fill:#4b9cd3,stroke:#2c6e9e,color:#fff
classDef key fill:#003b6f,stroke:#001f3f,color:#fff
class A,F io
class B,C step
class D,E key
1989–2006: Winters and Stubborn Ideas
1958›1969›1986›90s›2012›2017›2022›now
1989 — LeCun’s convolutional network reads real ZIP codes: structure is knowledge
1990s — SVMs win on clean math and guarantees; deep nets stall on the vanishing gradient
2006 — Hinton’s layer-wise pretraining revives depth, under a new name: deep learning
huggingface_hub / transformers: The platform and library where the ML community collaborates on models, datasets, and applications.
Login: Register with Hugging Face and obtain a key to download hosted models.
Load tokenizer & model: Downloads Google Gemma-2b and its matching tokenizer.
Tokenise input: Converts your text into a tensor of token IDs the model can read.
Generate & decode: Model predicts tokens autoregressively; tokenizer converts them back to text.
Act III
2018 – now
From prediction to agents
2018: The Internet as a Textbook
1958›2012›2017›2018›2020›2022›2024›now
117MGPT-1, 2018→1.5BGPT-2, 2019
Take half the transformer, train it on one objective: predict the next token
The text is its own answer key — no human labelling, so it scales to the internet
Sounds too dumb to matter — but “The capital of France is ___” requires the fact
2020: Scaling Laws
Bigger was the whole idea
Plot loss vs. parameters, data, compute → a straight line on log-log axes
You can forecast a model’s quality before you build it
“The graph turned a leap of faith into a line item”
GPT-3: 175B params — new skills appear that nobody trained in
Nov 2022: ChatGPT
1958›2012›2017›2018›2020›2022›2024›now
The week everyone found out — the model wasn’t new, the manners were
GPT-3 had been sitting in an API for two years
RLHF: (1) fine-tune on good answers, (2) humans rank outputs → reward model, (3) optimise against learned taste
Same 1986 training loop — only the blame signal changed
1Musers in 5 days→100Musers in 2 months
2023: The Weights Get Out
The year AI escaped the API
Feb 2023: Meta’s Llama weights leak within a week of release
Open weights ≠ open source: you get the baked cake, not the recipe
Quantisation (llama.cpp): frontier-class models on a laptop
This afternoon you’ll use self-hosted models — this is why that’s possible
The Goldfish Problem, Fix #1 — RAG
Giving a frozen model an open book
The model is frozen and stateless — and it bluffs (plausible ≠ correct)
Fine-tuning is the wrong fix: knowledge dissolves into the weights like sugar into water
RAG: chunk → embed → store; at question time retrieve top-k and put it in the context
Don’t change the model — change what it can see
2023: Tool Use — The Chatbot Grows Hands
The model never runs anything. It writes the ticket.
You hand the model a menu of tools
It emits a structured request — data, not prose: get_weather(city="Cambridge")
Your harness runs the real function
The result goes back into the context; the model writes the answer
2023–24: The Agent Loop
An agent is scaffolding and a loop around an LLM
LLM: The reasoning engine. It can plan, evaluate, or decide whether to “act” or “answer.”
System Prompt: Defines the persona, available tools, and operational boundaries.
Working memory: Maintains the state, including history, tool outputs, and the current goal.
Tools: External capabilities like web search, code execution, APIs, or connecting to RAG.
The Agent Loop
%%{init: {"flowchart": {"nodeSpacing": 40, "rankSpacing": 80}, "theme": "base", "themeVariables": {"edgeLabelBackground": "#ffffff"}}}%%
flowchart LR
S([System prompt]) --> C
H([Prompt]) --> C["Context window"]
C --> L["LLM: generate text"]
L --> D{Tool call?}
D -->|yes| T["Tools (incl. RAG)"]
T -->|result appended| C
D -->|no| O([Output])
classDef io fill:#6c757d,stroke:#495057,color:#fff
classDef core fill:#003b6f,stroke:#001f3f,color:#fff
classDef support fill:#4b9cd3,stroke:#2c6e9e,color:#fff
classDef decision fill:#e9c46a,stroke:#f4a261,color:#000
class S,H,O io
class L core
class C,T support
class D decision
Nov 2024: MCP — A Universal Plug for Agents
1958›2012›2017›2020›2022›2024›now
The mess: every agent × every tool = a bespoke, brittle connector (N×M)
MCP: one open protocol between agents and tools (N+M)
We now need to configure opencode to run self-hosted LLMs
Add API key to .basrhc (or equivalent) e.g., export CAMLLM_API_KEY=sk-XXXXXXXXXXXXXXXXXXXXXX
Configure opencode (see next slide)
Note
If you already have access to UoC’s LiteLLM (https://llm.hpc.cam.ac.uk) you can create one from the virtual keys page: Virtual Keys\(\rightarrow\)Create New Key.
Setting the API Key
Add the key to your shell profile so it’s available every session:
from fastmcp import FastMCPmcp = FastMCP(name="mcp-numbers")@mcp.tooldef add(a: int, b: int) ->int:"""Add two numbers"""return a + bif__name__=="__main__": mcp.run()
MCP example (add)
Now let’s add mcp-numbers to our opencode configuration
Follow instructions in mcp/README.md
Running /status in opencode should display
Try Use mcp tool "numbers_add" to add 4 and -1
MCP examples (netcdf)
What about a more interesting example…
Can we give LLM power to inspect netcdf .nc files?
Let’s try with MCP.
MCP examples (netcdf)
Inspect file mcp/mcp-netcdf.py
../mcp/mcp-netcdf.py
# /// script# dependencies = [# "netCDF4",# "fastmcp",# ]# ///import netCDF4from fastmcp import FastMCP# Initialize the FastMCP servermcp = FastMCP("nc-mcp")@mcp.tool()def get_variables(path: str) ->str:""" Reads a NetCDF file from the given path and returns its variables. Args: path: The absolute or relative path to the NetCDF (.nc) file. Returns: A string representation of the NetCDF file's variables. """try:# Open the dataset dset = netCDF4.Dataset(path)# Capture the variables as a string to return to the client variables_output =", ".join(dset.variables.keys())# Close the dataset to free up resources dset.close()return variables_outputexceptFileNotFoundError:returnf"Error: Could not find the file at path: {path}"exceptExceptionas e:returnf"Error reading NetCDF file: {str(e)}"@mcp.tool()def get_variable_shape(path: str, variable_name: str) ->dict|str:""" Reads a NetCDF file from the given path and returns the shape of a specific variable. Args: path: The absolute or relative path to the NetCDF (.nc) file. variable_name: The name of the variable to get the shape for. Returns: A dictionary containing the shape of the specified variable. Example: {'temperature': (365, 180, 360)} Returns an error (as a string) if the variable is not found. """returndict()if__name__=="__main__": mcp.run()
MCP examples (netcdf)
mcp/mcp-netcdf.py contains 2 MCP tools
netcdf_get_variables
netcdf_get_variable_shape (to be implemented)
Try using netcdf_get_variables on file simple.nc
MCP examples (netcdf)
Implement netcdf_get_variable_shape
See stub in mcp/mcp-netcdf.py
../mcp/mcp-netcdf.py
@mcp.tool()def get_variable_shape(path: str, variable_name: str) ->dict:""" Reads a NetCDF file from the given path and returns the shape of a specific variable. ... """pass
(15 minutes for exercise)
Skills
Define reusable behavior via SKILL.md definitions
Agent skills let LLMs discover reusable instructions
Skills are loaded on-demand
Skills are “just” markdown files
Anatomy of a Skill
Many genAI tools support skills e.g., Claude code, opencode, codex etc.
Note
opencode requires that skills are stored in a specific set of locations (A full list can be found here). We will focus on these:
Project config: .opencode/skills/<name>/SKILL.md
Global config: ~/.config/opencode/skills/<name>/SKILL.md
cd project/root/GenAI-teachingmkdir-p .opencode/skills/netcdfln-sf$(pwd)/skill/netcdf/SKILL.md .opencode/skills/netcdf/
Run /skills in opencode to check registration
Skills Example (netcdf)
skill/netcdf/SKILL.md
---name: netcdf-processingdescription: Use this skill for any operations involving NetCDF (.nc) files, including inspecting metadata, reading variable shapes, extracting data slices, or generating new NetCDF datasets.---# What I doThis skill provides guidance for inspecting and generating NetCDF files usingstandard command-line utilities. Use these commands to understand datasetstructures before writing extraction scripts.# When to use this skillUse this skill whenever a user mentions climate data, multidimensional arrays,.nc files, or atmospheric datasets.## Workflow Decision Tree- **Inspecting Schema**: Use `ncdump -h` first to understand dimensions.- **Data Access**: If the file is large, only request specific variable slices (don't read entire arrays into context).- **Creating Files**: Use `ncgen` for small CDL templates or `netCDF4` Python scripts for large datasets.## Viewing Metadata with `ncdump``ncdump` is the standard tool for converting NetCDF binary files intohuman-readable text (CDL format).* **View Header Only (Recommended):** Displays dimensions, variables, and attributes without printing raw data.```bashncdump-h filename.nc```* **View Specific Variable:** Look at the data for a single variable (e.g., 'temperature').```bashncdump-v temperature filename.nc```* **Coordinate Formatting:** Use `-c` to see the header plus the values of coordinate variables (lat, lon, time).```bashncdump-c filename.nc```## Creating Files with `ncgen``ncgen` takes a text-based CDL file and compiles it into a binary `.nc` file.* **Generate Binary from CDL:**```bashncgen-o output_file.nc input_text.cdl```
Skills Example (netcdf)
Try running the following command
Note
Disable netcdf MCP server before trying to test the skill. They may conflict.
Skills Exercise
Create your own SKILL.md
Register it in opencode
Try using it
(15 minutes for exercise)
CLI
Do we really need MCP or Skills?…
CLI
Common CLI tools are already in model weights
No authentication
No configuration
CLI
Try asking model to run CLI commands
Don’t need to be specific e.g., “are there any untracked files in this repo?”
What issues do you foresee?
(5 minutes for exercise)
MCP vs CLI vs Skill
So how do I choose between MCP, CLI and Skills?
MCP Server
CLI
SKILL.md (Instruction)
Primary Purpose
Tool calling – Need auth, permissions, audit trails, or remote access? Is data format important?
Raw commands – Run terminal tools the model already knows (git, grep, docker).
Domain Expertise – Provides workflows, rules, and domain knowledge.
Context/Loading
Loaded immediately into context window (regardless of query) reducing effective context window size.
Zero cost – Knowledge is baked into model weights; no schemas loaded.
Lazy loaded when needed. Will still impact context window.
Timeout
Timeout ~ 1-2 minutes. Ideal for short, quick function calls