Skip to main content

Multi-Agent Basics

A multi-agent program splits one workflow into named agents with separate roles and context boundaries. The goal is not to make things more complicated; it is to make responsibilities visible.

This tutorial builds a small writing workflow:

  1. Coordinator receives the user request.
  2. Researcher extracts facts.
  3. Writer drafts an answer.
  4. Reviewer checks the draft.
Multi-Agent Basics tutorial overview

Full source: ../../../tutorials/multi-agent.as

1. The Complete Program​

Create multi-agent.as, or open the repository copy at tutorials/multi-agent.as:

import llm Qwen from "ollama://localhost:11434/qwen3.6"

main agent Coordinator {
model Qwen
role "Coordinator"
description "Route a small writing task through specialist agents."

main func(input {
topic: string
audience: string
}) {
research = Researcher({
topic: input.topic
})

draft = Writer({
topic: input.topic,
audience: input.audience,
research: research
})

review = Reviewer({
topic: input.topic,
audience: input.audience,
draft: draft
})

{
research: research,
draft: draft,
review: review
}
}
}

agent Researcher {
model Qwen
role "Researcher"
description "Extract a few useful facts for a topic."

main func(input {
topic: string
}) {
use input.topic as "topic"

generate({ input: "List a few useful facts for this topic", max_output: 500 }) -> {
facts: list[string]
angle
}
}
}

agent Writer {
model Qwen
role "Writer"
description "Draft a short answer for a specific audience."

main func(input {
topic: string
audience: string
research: json
}) {
use input.topic as "topic"
use input.audience as "audience"
use input.research.facts max 1k as "research facts"

generate({ input: "Write a concise draft", max_output: 600 }) -> {
title
body
}
}
}

agent Reviewer {
model Qwen
role "Reviewer"
description "Review whether a draft fits the topic and audience."

main func(input {
topic: string
audience: string
draft: json
}) {
use input.topic as "topic"
use input.audience as "audience"
use input.draft as "draft"

generate({ input: "Review the draft and suggest improvements", max_output: 500 }) -> {
ok: boolean
notes: list[string]
}
}
}

2. Coordinator Calls Other Agents​

Agent calls look like function calls:

research = Researcher({
topic: input.topic
})

Researcher receives only the object passed to it. It does not automatically see the coordinator's local variables, prompt context, or previous agent calls.

3. Each Agent Has Its Own Role​

Researcher, Writer, and Reviewer each declare their own role and description. That means each model call gets a different identity, even though the program uses the same LLM provider.

This is the practical reason to split agents: the prompt identity and context boundary become explicit.

4. Context Does Not Automatically Cross Agents​

Writer receives research as input, but it still has to choose what to show the model:

use input.research.facts max 1k as "research facts"

Passing data between agents and exposing data to the model are two different steps.

5. Run It​

Run with mock output:

agentscript tutorials/multi-agent.as --mock --input '{"topic":"AgentScript context boundaries","audience":"new users"}'

Print the trace to see nested agent calls:

agentscript tutorials/multi-agent.as --mock --trace --input '{"topic":"AgentScript context boundaries","audience":"new users"}'

Next​

The next tutorial can use this structure for a real multi-agent application pattern, such as planner → implementer → reviewer or researcher → critic → writer.