DEV Community

Cover image for Building a Multi-Agent AI for Company LinkedIn Pages - Part 6: Building the Brief Agent
Manav
Manav

Posted on

Building a Multi-Agent AI for Company LinkedIn Pages - Part 6: Building the Brief Agent

Our system can now classify the topic, do the research, back it with examples and identify weak assumptions, unsupported claims, and irrelevant examples before handing everything over to the writing agents. But handing all of that information directly to the writing agents forces them to make too many decisions at once.

That's why we built the Brief Agent.

The Brief Agent takes topic, research chunks, examples and critique points as input and structures them into a single content brief so the writing agents don't have to decide which example to use, which angle to take, which statistic to highlight, or what nuance should be acknowledged.

Topic
   │
Research Chunks
   │
Examples
   │
Critique Points
   │
   ▼
Brief Agent
   │
   ▼
Content Brief
Enter fullscreen mode Exit fullscreen mode

Before we start writing code, let's write the system prompt. I explicitly instructed the agent not to rewrite the research, examples or critique. Its job is to make decisions, organise the information, and return a structured JSON object.

SYSTEM_PROMPT = """
Create a structured content brief.

Choose:
- best angle
- strongest statistic
- best example
- important nuance
- suggested structure
- hook direction

Return valid JSON.
"""
Enter fullscreen mode Exit fullscreen mode

The production prompt is much longer, but I've shortened it here to highlight the core rules.

Until now agents were responsible for gathering information. The Brief Agent is the one responsible for planning what needs to be done with this information and structuring it well for the writing agents.

Since every downstream writing agent depends on this output, I wanted to guarantee that the structure is always consistent. That's where Pydantic comes in.

class ContentBrief(BaseModel):
    angle: str
    key_stat: str
    best_example: str
    nuance_to_acknowledge: str
    suggested_structure: str
    hook_direction: str
Enter fullscreen mode Exit fullscreen mode

Think of it like the contract between the Brief Agent and the Writing Agents.

user_message = (
        f"TOPIC: {cleaned_topic}\n\n"
        "RESEARCH_CHUNKS:\n"
        + "\n---\n".join(research_chunks)
        + "\n\nEXAMPLES:\n"
        + "\n---\n".join(example)
        + "\n\nCRITIQUE_POINTS:\n"
        + "\n---\n".join(critique)
    )
Enter fullscreen mode Exit fullscreen mode

The user message consists of the topic, research chunks, examples and critique points. Instead of every writing agent collecting this context again, the Brief Agent packages everything into a single input.

Topic
   │
Research
   │
Examples
   │
Critique Points
   │
   ▼
Build user_message
   │
   ▼
call_llm()
   │
   ▼
strip_json_fences()
   │
   ▼
json.loads()
   │
   ▼
Pydantic Validation
   │
   ▼
ContentBrief
Enter fullscreen mode Exit fullscreen mode

So, before we code the whole function, let's breakdown what exactly happens. The function first cleans the topic, builds a user message containing every previous agent's output, calls the LLM with the system prompt, strips markdown fences, parses the JSON, and finally validates it using the ContentBrief model before returning it.

def create_brief(topic:str, research_chunks: list[str], example: list[str], critique: list[str]) -> ContentBrief|None:
    cleaned_topic = clean_topic(topic)
    user_message = (
        f"TOPIC: {cleaned_topic}\n\n"
        "RESEARCH_CHUNKS:\n"
        + "\n---\n".join(research_chunks)
        + "\n\nEXAMPLES:\n"
        + "\n---\n".join(example)
        + "\n\nCRITIQUE_POINTS:\n"
        + "\n---\n".join(critique)
    )
    raw_response = call_llm(SYSTEM_PROMPT, user_message)
    refined_response = strip_json_fences(raw_response)
    try:
        parsed = json.loads(refined_response)
    except json.JSONDecodeError:
        print("LLM did not return valid JSON:")
        print(raw_response)
        return None
    try:
        return ContentBrief.model_validate(parsed)
    except ValidationError as e:
        print("LLM returned JSON but it doesn't match expected structure:")
        print(e)
        return None

Enter fullscreen mode Exit fullscreen mode

At this point, our system can understand a topic, gather supporting research, find real-world examples, critically evaluate everything and structure all of it in a brief before handing it over to writing agents.

In the next article, we'll build the Hook Agent responsible for generating multiple hook directions from the structured brief before the full post is written.

Github Repo: https://github.com/Manav-N4/linkedin-agent#linkedin-agent

Top comments (0)