Zum Hauptinhalt springen
connic

Agententests in YAML.
Vor jedem Deployment geprüft.

Jeder Testfall prüft die Antwort, die aufgerufenen Tools und die Tools, die tabu sind. Dieselbe Suite läuft per CLI, in Pull Requests und vor jedem Deployment.

tests/ticket-triage.yaml
version: "1.0"

tests:
  - name: routes_billing_question
    payload: "I was charged twice for order 4471"
    expected_result: output.priority == "normal"
    expected_tool_calls:
      - tickets.assign_queue: params.queue == "billing"
    expected_no_tool_calls:
      - oncall.page

  - name: pages_oncall_for_outage
    payload: "Checkout returns a 500 error for every customer"
    mocks: triage_mocks
    runs: 5
    success_threshold: 80
    expected_result: output.priority == "urgent"
    expected_tool_calls:
      - oncall.page: invocations == 1
5/5 runs passedpages_oncall_for_outage · 80% to pass

Die Antwort prüfen. Und jeden Schritt davor.

Ein Testfall besteht, wenn jede Assertion zutrifft. Das reicht von der Reihenfolge der Tool-Aufrufe bis zur Reaktion auf eine abgelehnte Freigabe.

tests/billing-handoff.yaml
version: "1.0"

tests:
  - name: hands_double_charge_to_billing
    payload: "I was charged twice for order 4471"
    expected_tool_call_order:
      - crm.lookup_customer
      - tickets.assign_queue
    expected_child_agents:
      billing-desk:
        expected_triggered: 1
    approval_decisions:
      - tool: tickets.issue_credit
        decision: reject
        reason: Billing confirms the double charge first
    expected_result: status == "completed"
  1. Aufrufe in der richtigen Reihenfolge

    Die Tools müssen in dieser Reihenfolge vorkommen. Andere Aufrufe dürfen dazwischen liegen.

  2. Übergaben an andere Agenten

    Welche Agenten dieser Agent startet, samt Payload, Ausgabe und Tool-Aufrufen.

  3. Menschliche Entscheidungen simulieren

    Wartet ein Tool auf eine Person, gibst du approve, reject oder timeout vor. Dann prüfst du, was der Agent danach tut.

  4. Das Ergebnis des Runs

    Ausgabe, Status und Fehler des Runs. Ohne das Feld reicht ein fertiger Run.

Echte Testdaten anlegen. Seiteneffekte per Mock abfangen.

Builder legen die Datensätze an, die ein Testfall braucht. Mocks halten den Test von Tools fern, die er nie erreichen darf.

Builder
build() liefert den Payload und legt IDs für die Assertions in context ab. cleanup() läuft nach jedem Versuch, auch nach Timeouts und Fehlern.
Mocks
Sie ersetzen eigene Tools, Middleware, Hooks oder eigene Guardrails Funktion für Funktion. Gemockte Aufrufe zählen trotzdem für Tool-Assertions.
Dateien
PDFs, Bilder und Audio aus tests/files/ hängst du über den Dateinamen an den Payload.
tests/ticket-triage.yaml
- name: routes_a_real_ticket
  builder: open_ticket
  builder_args:
    subject: "Charged twice for order 4471"
  mocks: triage_mocks
  expected_tool_call_order:
    - crm.lookup_customer
    - tickets.assign_queue
  expected_tool_calls:
    - tickets.assign_queue: params.ticket_id == context.ticket_id
tests/builders/open_ticket.py
import os
import httpx

HELPDESK = os.environ["HELPDESK_API_URL"]

def build(context, builder_args, test_name, payload, files):
    subject = builder_args["subject"]
    ticket = httpx.post(f"${HELPDESK}/tickets", json={"subject": subject}).json()
    context["ticket_id"] = ticket["id"]
    return {"ticket_id": ticket["id"], "message": subject}

def cleanup(run, context, builder_args):
    httpx.delete(f"${HELPDESK}/tickets/{context['ticket_id']}")
tests/mocks/triage_mocks.py
def mock_oncall_page(tool_name, params, context):
    return {"paged": False, "incident_id": "test-incident"}

Alle Suites mit einem Befehl starten. Im Terminal oder in CI.

connic test führt jede Suite auf connic aus. Du bekommst ein Ergebnis pro Testfall und einen Link zu Runs und Traces.

Exit Codes für CI
0, wenn alles besteht, 1 bei einem Fehlschlag und 2 bei Infrastrukturfehlern. Mit --json bekommst du maschinenlesbare Ergebnisse.
Abdeckung ohne Zugangsdaten
--coverage liest agents/ und tests/ offline und listet die Tools, die noch keine Assertion abdeckt.
Gezielt einzelne Testfälle
--filter führt nur die Testfälle aus, deren Name eine bestimmte Zeichenfolge enthält.
~/support-agents
Ausführen
$ connic test
→ Resolving target environment...
✓ Production.test_environment_id (5b0e7c2a-91d4-4f3e-8a62-0c7d9e1f4b38)
→ Test runner is executing your test cases...
Running 3 test case(s)...
PASS ticket-triage::routes_billing_question 1/1 100%
PASS ticket-triage::pages_oncall_for_outage 5/5 80%
PASS ticket-triage::routes_a_real_ticket 1/1 100%
✓ 3/3 cases passed.
Abdeckung
$ connic test --coverage
┌───────────────┬──────┬───────────────┬──────────┐
│ Agent │ Type │ Tools covered │ Coverage │
├───────────────┼──────┼───────────────┼──────────┤
│ billing-desk │ llm │ no tests │ 0.0% │
│ ticket-triage │ llm │ 3/4 │ 75.0% │
└───────────────┴──────┴───────────────┴──────────┘
→ Uncovered tools:
ticket-triage: tickets.issue_credit
Overall coverage: 37.5% (2 agents)

Ein roter Test stoppt das Deployment.

Liegen Suites in tests/, führt jedes Deployment per CLI oder Git-Push zuerst alle Testfälle aus. Live geht es erst, wenn jeder einzelne besteht.

#e5b28c41Failede5b28c4
Pipeline
  1. Build imagedone
    1.2m
  2. Run tests1 failed
    48.6s
    • ticket-triage::pages_oncall_for_outage
      3/5 (80% to pass)

      expected_result failed: 'output.priority == "urgent"'

      #4c1e0b9a72d3#a83f5d10c6e2#19be7f4a0d58#e60d2c97b1a4#7b5a93e2f01c
    • ticket-triage::routes_a_real_ticket
      1/1 (100% to pass)
      #d2f8a61c4e07
    • ticket-triage::routes_billing_question
      1/1 (100% to pass)
      #0c94b7e35a1f
  3. Deploy to Productionskipped

Pull Requests vor dem Merge testen.

Mit PR Testing läuft die Suite für jeden Pull oder Merge Request auf den Branch eines Environments. Das Ergebnis steht als connic/pr-tests am Commit.

Funktioniert mit GitHub und GitLab ab dem Pro-Plan. Machst du den Check bei deinem Git-Anbieter zur Pflicht, blockiert er Merges, bis er besteht.

fix/outage-routingdevelop
  • c08e5d3Mention the order number in the reply
    pendingconnic/pr-testsTests running
  • a41f9c2Only page on-call for checkout errors
    successconnic/pr-testsAll tests passed
  • 7d03be1Page on-call for any checkout complaint
    failureconnic/pr-tests1 of 3 test(s) failed

Häufig gestellte Fragen

Setz runs und success_threshold im Testfall oder in den defaults der Datei. Mit runs: 5 und success_threshold: 80 läuft der Agent fünfmal, und der Testfall besteht, wenn mindestens vier Runs bestehen. Beide Felder nehmen Werte von 1 bis 100.

Ja. Konfigurierte Tools, Middleware, Hooks und Guardrails laufen, solange kein Mocks-Modul sie ersetzt. Automatische ausgehende Verbindungen bleiben stumm, und Aufrufe ausgehender Verbindungen aus Tools oder Middleware werden nur aufgezeichnet, nicht zugestellt. Für alle anderen externen Dienste hinterlegst du im Test-Environment Testzugangsdaten.

Standardmäßig in dem Environment, in das du deployst. Mit der Einstellung Test environment läuft die Suite stattdessen in einem anderen Environment mit eigenen Variablen, Verbindungen und Daten. connic test nimmt das Test-Environment des Standard-Environments, außer du gibst --env an.

Leg die Datei in tests/files/ ab und trag ihren Namen im Testfall unter files ein. Jede Datei wird Base64-codiert an den Payload gehängt. Der Upload darf bis zu 25 MB groß sein, alles außerhalb von tests/files/ muss in 5 MB passen.

Bei einem CLI-Deployment überspringt connic deploy --skip-tests das Gate. In einem mit Git verbundenen Projekt geht das für manuelle Deployments über Deploy & skip tests im Deploy-Menü der Deployments-Seite. Deployments per Push durchlaufen das Gate immer.

Tests prüfen feste Testfälle, bevor eine Version live geht, und entscheiden, ob sie ausgeliefert wird. Judges bewerten Runs im Nachhinein mit einem LLM, A/B-Tests vergleichen Varianten eines Agenten mit echtem Traffic.