Mandag 31. august og tirsdag 1. september 2026 · kl. 8 til 12 begge dage · dansk tekst, engelske fagbegreber
Forløbets to mål: (1) du kan forklare præcist hvad en harness er, hvad den indeholder, og hvorfor den i 2026 driver mere af agenters ydelse end selve modellen. (2) Du har selv bygget og kørt en agentisk pipeline end-to-end: opgave ind, agentløkke med værktøjer, verifikation, artefakt ud, plus en lille evaluering ovenpå. Snittet mellem dagene er lagt så hver formiddag står på egne ben: mandag er begreb og selvbyg, tirsdag er produktionsharness, evaluering og konsolidering.
Planen bygger videre på din agentic-ai-wiki. Wikiens lagmodel i syntheses/agentisk-vaerktoejslandskab dækker allerede orkestrering (LangGraph, Claude Agent SDK), adgang (MCP, A2A), viden (RAG), kontrol og måling (guardrails, tracing, evaluering) samt kørsel (vLLM). Det wikien endnu ikke har en side om, er selve harness-begrebet, som binder lagene sammen. Forløbet slutter derfor tirsdag med at du skriver den side selv.
En sprogmodel er tilstandsløs og producerer kun tekst. Alt der gør den til en agent, dvs. i stand til at handle over mange skridt, ligger i softwaren omkring den: løkken, værktøjerne, konteksthåndteringen, rettighederne, verifikationen og sporbarheden. Den samlede infrastruktur kaldes en harness, og formlen Agent = Model + Harness er i 2026 blevet feltets standarddefinition. Pointen med hele forløbet: to agenter på samme model kan opføre sig vidt forskelligt, alene på grund af harnessen.
Begrebet krystalliserede i februar 2026: Mitchell Hashimoto beskrev vanen med at ombygge agentens miljø hver gang den fejler, så samme fejl ikke kan gentages, og få dage senere fulgte OpenAI, Anthropic og Martin Fowler-siden med hver deres udlægning. Effekten er målbar: Vercel fjernede 80 % af agentens værktøjer og så succesraten stige fra 80 til 100 % med halveret tokenforbrug; LangChains coding agent gik fra bund til top 5 på Terminal-Bench 2.0 alene på harness-ændringer; og CORE-Bench målte samme model til 42 % med ét scaffold og 78 % med et andet. Prompt engineering optimerer én tur, context engineering styrer hvad modellen ser, og harness engineering designer det miljø agenten opererer i. Det er tredje lag der er forløbets emne.
| Tid | Blok | Materiale |
|---|---|---|
| 08.00 | 1. Fundament: hvad er en agent, og hvornår er den det rigtige valg | Video 1 (15 min) + artikel [1] |
| 08.45 | 2. Harness-begrebet: læsning og video | [3], [5], [6], [7] + video 2 (22 min) |
| 10.00 | Pause | |
| 10.15 | 3. Lab 1: byg en minimal harness i ren Python | Kode nedenfor + [9] som følgetekst |
| 11.45 | Opsamling: notér harness-komponenter og observationer | Bruges tirsdag i blok 6 |
| Tid | Blok | Materiale |
|---|---|---|
| 08.00 | 4. Lab 2: end-to-end pipeline med Claude Agent SDK | Quickstart [10] + skitse nedenfor + video 4 som opslagsværk |
| 10.00 | Pause | |
| 10.15 | 5. Lab 3: evaluering og tracing af pipelinen | Wiki: methods/agent-evaluering + mini-eval nedenfor |
| 11.15 | 6. Konsolidering: skriv wikiens harness-side | Din agentic-ai-wiki + Narayanan [21] |
Mellem de to formiddage, valgfrit: Lopopolo-talken [16] som aftenvideo mandag, og perspektivboksen om Narayanans konfigurationer nedenfor som fem minutters læsning inden tirsdag.
ANTHROPIC_API_KEY i miljøet, en tom projektmappe, pip install anthropic claude-agent-sdk. Regn med et par dollars i API-forbrug for begge formiddage tilsammen. Kør labs i en mappe (eller container) du ikke er øm over; Lab 1 giver bevidst agenten shell-adgang uden sikkerhedsnet, fordi netop det problem er en af øvelserne.
Se Barry Zhangs talk fra AI Engineer Summit [2] og skim Anthropics Building Effective Agents [1]. Det vigtigste at tage med: skellet mellem workflows (foruddefinerede kodeveje med LLM-kald i) og agents (modellen styrer selv sin proces og værktøjsbrug ud fra feedback fra miljøet), og rådet om at bruge agenter dér hvor opgaven er for åben til et workflow, ikke som default. Det matcher din wikis pointe om at LangGraph tegner forløbet eksplicit, mens agent-tilgangen giver modellen en computer.
Læs i denne rækkefølge: Hashimotos oprindelsestekst [3] (kort, personlig, giver princippet), Böckelers analyse på martinfowler.com [5] (den mest strukturerede: indre vs. ydre harness, guides vs. sensorer), og LangChains anatomi af en harness [6] (komponentlisten set fra et frameworkhold). Slut med Wikipedia-artiklen [7] som opsummering. Se derefter videoen Harness Engineering Explained in 22 Minutes [17]. Notér undervejs, med figur 1 som skabelon, hvilke komponenter hver kilde nævner; du skal bruge noterne tirsdag i blok 6.
Thorsten Balls klassiker [9] viste at en fungerende kodeagent er "an LLM, a loop, and enough tokens", under 400 linjer. Her er en dansk minimudgave (ca. 70 linjer) mod Anthropics Messages API. Skriv den selv af, linje for linje; det er dér forståelsen sætter sig.
# minimal_harness.py pip install anthropic
import subprocess, pathlib, json
import anthropic
client = anthropic.Anthropic() # ANTHROPIC_API_KEY i miljøet
MODEL = "claude-sonnet-5" # udskift evt. med nyeste model
WORKDIR = pathlib.Path("workspace").resolve()
TOOLS = [
{"name": "list_files", "description": "List alle filer i arbejdsmappen.",
"input_schema": {"type": "object", "properties": {}, "required": []}},
{"name": "read_file", "description": "Læs en tekstfil.",
"input_schema": {"type": "object",
"properties": {"path": {"type": "string"}}, "required": ["path"]}},
{"name": "write_file", "description": "Skriv tekst til en fil (overskriver).",
"input_schema": {"type": "object",
"properties": {"path": {"type": "string"}, "content": {"type": "string"}},
"required": ["path", "content"]}},
{"name": "run_bash", "description": "Kør en bash-kommando i arbejdsmappen.",
"input_schema": {"type": "object",
"properties": {"command": {"type": "string"}}, "required": ["command"]}},
]
def execute(name, args):
try:
if name == "list_files":
return "\n".join(str(p.relative_to(WORKDIR))
for p in WORKDIR.rglob("*") if p.is_file()) or "(tom)"
if name == "read_file":
return (WORKDIR / args["path"]).read_text()
if name == "write_file":
p = WORKDIR / args["path"]
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(args["content"])
return f"skrev {args['path']}"
if name == "run_bash":
r = subprocess.run(args["command"], shell=True, cwd=WORKDIR,
capture_output=True, text=True, timeout=60)
return (r.stdout + r.stderr)[-4000:] or "(intet output)"
return f"ukendt værktøj: {name}"
except Exception as e:
return f"FEJL: {e}" # fejlen sendes tilbage til modellen, intet crash
def agent(task):
messages = [{"role": "user", "content": task}]
while True: # selve agentløkken
resp = client.messages.create(
model=MODEL, max_tokens=4096,
system="Du er en agent i mappen ./workspace. "
"Løs opgaven med værktøjerne, og stop når den er løst.",
tools=TOOLS, messages=messages)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason != "tool_use": # modellen er færdig
return "".join(b.text for b in resp.content if b.type == "text")
results = []
for block in resp.content:
if block.type == "tool_use":
print("->", block.name,
json.dumps(block.input, ensure_ascii=False)[:120])
results.append({"type": "tool_result", "tool_use_id": block.id,
"content": execute(block.name, block.input)})
messages.append({"role": "user", "content": results})
if __name__ == "__main__":
WORKDIR.mkdir(exist_ok=True)
print(agent("Undersøg workspace og skriv en kort README.md om indholdet."))
Udvidelsesøvelser (vælg mindst to; hver enkelt er et harness-greb du netop har læst om):
WORKDIR (path traversal) og kræv tastet godkendelse før run_bash. Det er en computational guide i Böckelers terminologi.AGENTS.md med regler i workspace og injicér den i systemprompten. Mærk forskellen på agentens adfærd.Nu skifter du fra selvbygget harness til en produktionsharness: Claude Agent SDK er samme harness som driver Claude Code, jf. din wikiside frameworks/claude-agent-sdk. Følg quickstart i dokumentationen [10]; brug workshoppen [11] som opslagsvideo hvis du sidder fast. Målet er en pipeline: rå data ind, agent med både indbyggede og egne værktøjer, verifikation, rapport ud.
./workspace/data/ (generér dem evt. med Lab 1-agenten).query() med indbyggede fil- og bashværktøjer, der skal analysere data og skrive rapport.md.# pipeline.py pip install claude-agent-sdk
import anyio
from claude_agent_sdk import (query, ClaudeAgentOptions,
tool, create_sdk_mcp_server)
@tool("hent_kpi", "Henter en KPI fra det interne system", {"navn": str})
async def hent_kpi(args):
return {"content": [{"type": "text",
"text": f"{args['navn']}: 42,3 (uge 35)"}]}
server = create_sdk_mcp_server(name="internt", version="1.0.0",
tools=[hent_kpi])
options = ClaudeAgentOptions(
cwd="./workspace",
mcp_servers={"internt": server},
allowed_tools=["Read", "Write", "Glob", "Bash",
"mcp__internt__hent_kpi"],
permission_mode="acceptEdits",
)
async def main():
async for msg in query(
prompt="Analysér data/*.csv, hent KPI'en 'churn', og skriv "
"rapport.md med fund, tal og anbefalinger.",
options=options):
print(msg)
anyio.run(main)
mcp_servers, og lad pipelinen arbejde mod et rigtigt system i stedet for dummy-KPI'en.frameworks/langgraph og LangGraph-oversigten [20]: samme løkke, men tegnet som graf med checkpoints og interrupts.Genlæs din wikiside methods/agent-evaluering og dens fire niveauer: komponent, trajektorie, resultat, drift. Byg så den mindste eval der overhovedet giver mening for pipelinen fra Lab 2: kør samme opgave 5 gange (husk wikiens pointe om at temperatur 0 kun skjuler variansen), og tjek deterministiske kriterier plus simple trajektoriemål fra din JSONL-log:
# mini_eval.py: kør pipelinen N gange og saml resultater
import pathlib
W = pathlib.Path("workspace")
CHECKS = [
("rapport.md findes", lambda: (W/"rapport.md").exists()),
("nævner churn", lambda: "churn" in
(W/"rapport.md").read_text().lower()),
("har et talafsnit", lambda: any(c.isdigit() for c in
(W/"rapport.md").read_text())),
]
# trajektorie: antal værktøjskald, vægtid og fejl pr. kørsel fra JSONL-loggen
Notér spredningen mellem kørslerne. Det er den asymmetri wikiens syntese kalder feltets svageste punkt: modne værktøjer til at bygge, umodne til at afgøre om det blev bedre. Til produktion peger materialet på regressionssuiter der køres ved hver prompt- eller harnessændring, og på at fejl vægtes efter alvor frem for tælles.
Afslut med Feynman-metoden: skriv concepts/harness.md i agentic-ai-wikien med egne ord, ud fra begge dages noter. Forslag til disposition: definition og formlen; anatomien (figur 1-komponenterne); indre vs. ydre harness; forholdet til prompt- og context engineering; hvilken firm/worker/agent-konfiguration harnessen antager [21]; hvorfor det flytter mere end modelvalg (tallene fra [8]); kilder. Overvej samtidig om syntesens lagdiagram skal have harnessen tegnet ind som det bindende lag. Når siden er skrevet, har forløbet sat sig.
syntheses/agentisk-vaerktoejslandskab.frameworks/langgraph viser samme løkke tegnet som eksplicit graf. Kilde: Ball, How to Build an Agent [9].frameworks/model-context-protocol.concepts/guardrails-og-human-in-the-loop.methods/agent-evaluering.concepts/agent-observability-og-tracing.Forløbets videoer (i den rækkefølge de indgår):
Hvis du vil videre bagefter:
syntheses/agentisk-vaerktoejslandskab, frameworks/claude-agent-sdk, frameworks/langgraph, concepts/guardrails-og-human-in-the-loop.Øvelser til de kommende uger: