Siirry sisältöön

Roolit, politiikat ja minimal factory

Sama backend, eri politiikka → eri käyttäytyminen. Analyzer (read-only), Planner (no execution), Fixer (scoped writes), Reviewer (pass/fail). Rakenna minimaalisin mahdollinen tehdas: yksi agentti, yksi kutsu, jäsennelty I/O.

SW Builders
Edistynyt
60 min

Factoryn tärkein säädin ei ole "parempi prompt". Se on policy — tarkka määrittely siitä, mitä rooli saa tehdä ja mitä ei.

Role-based policy

Role-based policy = määritelmä, joka kertoo yhdelle agentille: 1) mitkä työkalut sillä on käytössä, 2) mitä se EI saa tehdä, 3) mikä on sen output-muoto. Sama LLM-backend (esim. Claude Sonnet) tuottaa täysin eri käyttäytymistä eri policyilla. Tämä on factoryn vaikuttavin yksittäinen säädin — ei prompt-engineering.

Neljä perusroolia

RooliPermissionsOutputConstraints
AnalyzerRead-onlyFindings reportEi modifikaatioita
PlannerRead-onlyStep-by-step planEi suoritusta
FixerRead + write targetedMinimal diffVain scoped muutokset
ReviewerRead-onlyPass/fail + rationaleAnnetut kriteerit

Miksi neljä, ei yksi?

Single Responsibility -periaate, sovellettuna agentteihin. Yksi agentti, yksi vastuu — ei sekoiteta:

  • ❌ "Analyze and fix" → fixaa väärin, koska kiirehtii korjaukseen
  • ✅ "Analyze" → "Plan" → "Fix" → "Review" → jokainen on hyvä omassaan

Pro-vinkki

Anti-pattern: "Yksi älykäs super-agentti, joka tekee kaiken." Se on bag-of-agents -ongelma yhden agentin sisällä. Erottele rooleihin samalla logiikalla millä erottelet mikropalveluita: yksi vastuu, selkeä rajapinta, helppo testata.

Policy esimerkkinä: Analyzer

analyzer_role.pypython
ANALYZER_POLICY = {
  "role": "analyzer",
  "system_prompt": """You are a code analyzer.
  
Your job: read the codebase and produce a findings report.
You CANNOT modify files. You CANNOT execute shell commands
that change state. Output a structured report only.""",
  "allowed_tools": [
      "read_file",
      "grep",
      "glob",
  ],
  "forbidden_tools": [
      "edit_file",
      "write_file",
      "bash",       # No shell — can't risk side effects
      "git",
  ],
  "output_schema": {
      "type": "object",
      "required": ["findings", "severity_summary"],
      "properties": {
          "findings": {
              "type": "array",
              "items": {
                  "type": "object",
                  "required": ["file", "line", "severity", "description"],
                  "properties": {
                      "file": {"type": "string"},
                      "line": {"type": "integer"},
                      "severity": {"enum": ["info", "warn", "error"]},
                      "description": {"type": "string"},
                  },
              },
          },
          "severity_summary": {"type": "object"},
      },
  },
  "max_iterations": 5,
  "max_cost_usd": 0.20,
}

Minimal factory — alle 50 riviä

Pieni esimerkki: yksi rooli, yksi kutsu, jäsennelty I/O.

01_minimal_factory.pypython
#!/usr/bin/env python3
"""Minimal factory: one agent, one call, structured output."""
import json
import sys
from anthropic import Anthropic

POLICY = {
  "role": "summarizer",
  "system": "You produce JSON summaries. Output ONLY valid JSON.",
  "model": "claude-sonnet-4-6",
  "max_tokens": 800,
  "schema": {
      "type": "object",
      "required": ["title", "key_points", "risks"],
  },
}

def run_factory(input_text: str) -> dict:
  client = Anthropic()
  response = client.messages.create(
      model=POLICY["model"],
      max_tokens=POLICY["max_tokens"],
      system=POLICY["system"],
      messages=[{
          "role": "user",
          "content": f"Summarize the following with schema {POLICY['schema']}:\n\n{input_text}",
      }],
  )
  text = response.content[0].text
  try:
      result = json.loads(text)
  except json.JSONDecodeError:
      return {"status": "error", "reason": "invalid_json", "raw": text}

  # Validate schema (simple check — use jsonschema for real)
  missing = [k for k in POLICY["schema"]["required"] if k not in result]
  if missing:
      return {"status": "error", "reason": "schema_violation", "missing": missing}

  return {"status": "success", "data": result}

if __name__ == "__main__":
  text = sys.stdin.read()
  print(json.dumps(run_factory(text), indent=2))

Aja se:

Käyttöbash
echo "We're refactoring the auth module to use OAuth2..." \
  | python 01_minimal_factory.py

Output:

Stdoutjson
{
"status": "success",
"data": {
  "title": "OAuth2 Migration for Auth Module",
  "key_points": [
    "Replacing legacy session-based auth",
    "OAuth2 with PKCE flow"
  ],
  "risks": [
    "Existing sessions invalidated on cutover",
    "Need backwards compat shim for 30 days"
  ]
}
}

Mikä tekee tästä factoryn, ei vain LLM-kutsun?

OminaisuusVain LLM-kutsuMinimal factory
Role/personaImplisiittinenEksplisiittinen POLICY
Model lukittuEiKyllä (POLICY["model"])
Output schemaEiPakollinen JSON schema
ValidaatioEiSchema-check + virhe-status
VersioitavissaEiPolicy = commit hash

Minimaalinen factory on jo voitto: voit testata sen, voit version-controlloida sen, voit ajaa sen rinnakkain CI:ssä.

Hands-on rehearsal: Three roles, same backend

Rehearsal komentojabash
# Saman backend, kolme roolia — eri käyttäytyminen
python 02_factory_catalog.py analyzer "Analyze backend_runner.py"
python 02_factory_catalog.py planner  "Plan logging for backend_runner.py"
python 02_factory_catalog.py fixer    "Add logging to backend_runner.py"
RooliAllowed toolsModeTarkoitus
analyzerRead, Glob, GrepRead-onlyTarkasta ja selitä
plannerRead, Glob, GrepPlan-onlyTuota suunnitelma
fixerRead, Grep, Edit, BashAccept editsTee turvalliset muutokset

Haaste: Suunnittele oma rooli

Suunnittele 5. rooli omasta tiimisi tarpeesta. Mitä se tekee, mitkä työkalut sillä on, mitkä on sen forbidden tools, mikä on output schema?

Session resume — pitkät factoryt

Real-world factory voi ajaa minuutteja. Tarvitset session resume:

Session resumebash
# Aloita
python 03_resumable_factory.py start \
  --backend opencode "Inspect auth subsystem"
# → tallentaa state /tmp/factory-session-abc123.json

# Jatka samasta kohtaa
python 03_resumable_factory.py resume \
  --backend opencode "Now propose fixes"
# → lukee state, jatkaa kontekstista

Session resume

Session resume tallentaa agentin working memory levylle (esim. JSON-tiedostoon /tmp/-polkuun). Seuraava ajo lukee tämän tilan ja jatkaa siitä, mihin jäätiin. Tärkeää pitkille tehtäville (>5 min) ja kalliille LLM-kutsuille — älä menetä kontekstia jokaisella crashilla tai timeoutilla.

Yhteenveto

  • 🎭 Roolit > yksi super-agentti — Single Responsibility myös agenteille
  • 📋 Policy on factoryn säädin — sama backend, eri käyttäytyminen
  • 📐 Schema pakollinen — validoi output, palauta virhe-status
  • 💾 Session resume pitkille tehtäville
  • 📦 Minimal factory < 50 riviä mutta jo version-controlable, testattavissa, ajettavissa

Seuraavassa oppitunnissa: Spec-driven delivery loops — miten factory ajaa Read Spec → Implement → Run Checks → Review -silmukkaa, kunnes hyväksytty.

Kirjaudu seurataksesi edistymistäsi

Kirjaudu sisään

Kysymykset ja vastaukset

Kirjaudu sisään osallistuaksesi keskusteluun