Zum Hauptinhalt springen
connic

KI-Agenten in YAML.
Tools in Python.

Jeder Agent ist eine Datei mit KI-Modell, Prompt, Tools und Guardrails. Tools sind normale Python-Funktionen, und ihre Type Hints liefern das Schema für das Modell.

agents/invoice-processor.yaml
name: invoice-processor
model: connic/gpt-5.6-sol
system_prompt: |
  Extract every field from the invoice
  and check that the totals add up.
tools:
  - invoices.parse_pdf
  - invoices.extract_fields   # tools/invoices.py
  - invoices.save_invoice
output_schema: invoice
tools/invoices.py
def extract_fields(text: str, currency: str = "EUR") -> dict:
    """Pull vendor, line items and totals from invoice text.

    Args:
        text: Plain text returned by parse_pdf
        currency: Used when the invoice names no currency
    """
    return read_invoice(text, default_currency=currency)

Jede Erweiterung ist eine Datei neben dem Agenten.

Gib einer Middleware- oder Hook-Datei den Namen des Agenten, und connic lädt sie automatisch. Registrieren musst du nichts.

middleware/invoice-processor.py

Läuft vor und nach jedem Run. Damit lädst du Daten aus deinen Systemen, hängst Dateien an oder loggst das Ergebnis.

from typing import Any, Dict
import httpx

async def before(content: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
    """Give the agent the customer's booking rules before it reads the invoice."""
    customer_id = context.get("payload", {}).get("customer_id")
    async with httpx.AsyncClient() as client:
        resp = await client.get(f"https://erp.example.com/customers/{customer_id}/rules")

    content["parts"].insert(0, {"text": f"Booking rules: {resp.text}"})
    return content

async def after(response: str, context: Dict[str, Any]) -> str:
    print(f"Run {context.get('run_id')} finished")
    return response
hooks/invoice-processor.py

Läuft um jeden Tool-Aufruf. Damit änderst du Parameter, schwärzt Ergebnisse oder stoppst einen Aufruf mit AbortTool.

import re
from typing import Any
from connic import AbortTool

IBAN = re.compile(r"\b[A-Z]{2}\d{2}[A-Z0-9]{11,30}\b")

async def before(tool_name: str, params: dict[str, Any]) -> dict[str, Any]:
    if tool_name == "save_invoice" and params.get("total", 0) > 50_000:
        raise AbortTool({"error": "Totals above 50,000 need a manual booking."})
    return params

async def after(tool_name: str, params: dict[str, Any], result: Any) -> Any:
    if tool_name == "parse_pdf":
        result["text"] = IBAN.sub("[IBAN]", result["text"])
    return result
guardrails/totals-match.py

Deine eigene Prüfung in Python. Sie steht in der Agentendatei neben den integrierten Guardrails.

import json
from connic import GuardrailResult

def check(content: str, context: dict) -> GuardrailResult:
    """Block answers whose line items do not add up to the total."""
    invoice = json.loads(content)
    line_sum = sum(line["amount"] for line in invoice["lines"])

    if abs(line_sum - invoice["total"]) > 0.01:
        return GuardrailResult(
            passed=False,
            message="Line items do not match the total.",
        )

    return GuardrailResult(passed=True)
schemas/invoice.json

Das JSON Schema, an das sich jede finale Antwort halten muss.

{
  "type": "object",
  "description": "Extracted invoice data",
  "properties": {
    "vendor": { "type": "string" },
    "invoice_date": { "type": "string", "description": "YYYY-MM-DD" },
    "currency": { "type": "string" },
    "lines": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "description": { "type": "string" },
          "amount": { "type": "number" }
        },
        "required": ["description", "amount"]
      }
    },
    "total": { "type": "number" }
  },
  "required": ["vendor", "lines", "total"]
}
tests/invoice-processor.yaml

Payloads, Dateien und Assertions. connic test führt sie aus, und Deployments können sie voraussetzen.

version: "1.0"

tests:
  - name: extracts_totals
    payload: "Extract this invoice"
    files:
      - invoice_acme.pdf
    expected_tool_calls:
      - invoices.extract_fields
    expected_result: output.total == 1249.5

  - name: reads_currency
    payload: "Extract this invoice"
    files:
      - invoice_globex_chf.pdf
    expected_result: output.currency == "CHF"

Vom leeren Ordner in die Produktivumgebung. Alles im Terminal.

connic dev lädt jede gespeicherte Änderung in ein isoliertes Dev Environment, und schon der nächste Run nutzt sie.

Git brauchst du nicht: connic deploy lädt den Projektordner hoch. Mit verbundenem Git reicht ein Push auf den Branch des Environments.

~/invoice-agents
Anlegen
$ pip install connic-composer-sdk
$ connic init invoice-agents --skill
Entwickeln
$ connic dev
→ Validating project files...
✓ 1 agent(s): invoice-processor (agents/invoice-processor.yaml)
→ Watching for file changes...
[14:02:11] → Detected change: invoices.py
[14:02:12] ✓ Uploaded 18342 bytes
Testen
$ connic test
PASS invoice-processor::extracts_totals 1/1 100%
PASS invoice-processor::reads_currency 1/1 100%
✓ 2/2 cases passed.
Bereitstellen
$ connic deploy --env production --yes
→ Validating project files...
✓ Lint passed
→ Packaging upload...
✓ 9 files, 24,816 bytes
✓ Deployment created.

Jede Änderung am Verhalten ist ein Diff.

Ein neues KI-Modell, ein weiteres Tool, eine strengere Guardrail: Alles sind Dateiänderungen, und dein Team sieht sie im Review.

Feste Modell-IDs
Das genaue Modell steht im YAML. Es ändert sich nur, wenn jemand diese Zeile bearbeitet.
Erst testen, dann aktivieren
Liegen Suites in tests/, geht ein Deployment erst live, wenn jeder Testfall besteht.
Rollback ohne neuen Build
Aktivier ein früheres erfolgreiches Deployment im Dashboard, und es nimmt wieder Anfragen an.
agents/invoice-processor.yaml
+6 -1
name: invoice-processor
model: connic/gpt-5.6-terra
model: connic/gpt-5.6-sol
fallback_model: connic/gpt-5.6-terra
tools:
- invoices.parse_pdf
- invoices.extract_fields
- invoices.flag_duplicate
- invoices.save_invoice
guardrails:
input:
- type: prompt_injection
mode: block
output:
- type: custom
name: totals-match
2/2 cases passedconnic test

Mit einem Befehl von LangChain oder Google ADK umsteigen.

connic migrate macht aus einem LangChain-, LangGraph- oder ADK-Projekt Agenten in YAML und Tools in Python. Was sich nicht umwandeln ließ, steht in MIGRATION_REPORT.md.

$ connic migrate --source ./support-bot --dest ./support-bot-connic
→ Scanning source project...
✓ Framework: langchain
✓ Agents found: 3
✓ Tools found: 11
→ Generating connic project...
✓ Generated at support-bot-connic
→ Running connic lint on the migrated project...
Report: support-bot-connic/MIGRATION_REPORT.md
✓ Migration complete.

Häufig gestellte Fragen

Im YAML steht alles, was den Agenten ausmacht: KI-Modell, Prompt, Tools, Schema und Guardrails. Diese eine Datei liest sich im Review leicht. Alles mit Logik bleibt in Python, unter tools/, middleware/, hooks/ und guardrails/.

Ja. Tools sind normale Python-Funktionen, synchron oder asynchron. Middleware läuft um den ganzen Run, Hooks laufen um jeden Tool-Aufruf, und eigene Guardrails prüfen nach deinen Regeln. Jedes Paket aus requirements.txt kannst du dabei nutzen.

Die IDs der KI-Modelle stehen ausgeschrieben im YAML, zum Beispiel connic/glm-5.2 oder anthropic/claude-opus-4-7. Tools, Middleware, Hooks und Guardrails sind Dateien im selben Projekt, jede Änderung ist also ein Diff im Review. Für ein Rollback aktivierst du ein früheres erfolgreiches Deployment, und es geht ohne neuen Build wieder live.

Jedes Projekt kann connic/* KI-Modelle ohne eigene Zugangsdaten beim Anbieter nutzen, gehostet in der EU. Per BYOK bindest du außerdem OpenAI, Azure OpenAI, Anthropic, Google Gemini, OpenRouter, AWS Bedrock, Google Vertex AI oder eigene OpenAI-kompatible Endpoints an.

Starte connic migrate mit --source für das bestehende Projekt und --dest für das neue. Der Befehl erkennt Code für LangChain, LangGraph und Google ADK, erzeugt Agenten als YAML und Tools als Python unter tools/ und führt danach connic lint aus. In MIGRATION_REPORT.md steht, was du noch von Hand anpassen musst.

Nein. connic deploy packt den Projektordner und lädt ihn in das gewählte Environment hoch. Verbindest du stattdessen einen Git-Anbieter, folgt jedes Environment einem Branch, und ein Push startet das Deployment.