Skip to content

Commit 7429074

Browse files
committed
Improve aggregator examples
1 parent 6dbe1a1 commit 7429074

3 files changed

Lines changed: 38 additions & 201 deletions

File tree

examples/workflow_aggregator_ranked.py

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Fan-out/fan-in with LLM-as-judge ranking aggregation.
22
33
Three creative agents with different personas (bold, minimalist,
4-
emotional) each propose a marketing slogan. A formatter collects the
5-
candidates, then a judge Agent scores and ranks them — letting the LLM
6-
evaluate creativity, memorability, and brand fit.
4+
emotional) each propose a marketing slogan. A ranker Executor collects
5+
the candidates, formats them, and uses an internal judge Agent to score
6+
and rank them — letting the LLM evaluate creativity, memorability, and
7+
brand fit.
78
89
Aggregation technique: LLM-as-judge (generate N candidates, rank the best).
910
@@ -16,11 +17,13 @@
1617
import os
1718
import sys
1819

19-
from agent_framework import Agent, AgentExecutorResponse, Executor, WorkflowBuilder, WorkflowContext, handler
20+
from typing import Never
21+
22+
from agent_framework import Agent, AgentExecutorResponse, Executor, Message, WorkflowBuilder, WorkflowContext, handler
2023
from agent_framework.openai import OpenAIChatClient
2124
from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider
2225
from dotenv import load_dotenv
23-
from typing_extensions import Never
26+
2427

2528
load_dotenv(override=True)
2629
API_HOST = os.getenv("API_HOST", "github")
@@ -55,22 +58,37 @@ async def dispatch(self, prompt: str, ctx: WorkflowContext[str]) -> None:
5558
await ctx.send_message(prompt)
5659

5760

58-
class FormatCandidates(Executor):
59-
"""Fan-in aggregator that formats candidate slogans for the judge."""
61+
class RankerExecutor(Executor):
62+
"""Fan-in aggregator that formats candidate slogans and ranks them via the LLM client directly."""
63+
64+
def __init__(self, *, client: OpenAIChatClient, id: str = "Ranker") -> None:
65+
super().__init__(id=id)
66+
self._client = client
6067

6168
@handler
62-
async def format(
69+
async def run(
6370
self,
6471
results: list[AgentExecutorResponse],
6572
ctx: WorkflowContext[Never, str],
6673
) -> None:
67-
"""Collect slogans into a labeled list for the judge Agent."""
74+
"""Collect slogans, format them, and ask the LLM to rank them."""
6875
lines = []
6976
for result in results:
7077
slogan = result.agent_response.text.strip().strip("\"'").split("\n")[0].strip().strip("\"'")
7178
lines.append(f"- [{result.executor_id}]: \"{slogan}\"")
72-
await ctx.send_message("Candidate slogans:\n" + "\n".join(lines))
7379

80+
messages = [
81+
Message(role="system", text=(
82+
"You are a senior creative director judging marketing slogans. "
83+
"Given a list of candidate slogans, rank them from best to worst. "
84+
"For each slogan, give a 1-10 score and a one-sentence justification "
85+
"evaluating creativity, memorability, clarity, and brand fit. "
86+
'Format: #1 (score X) [AgentName]: "slogan" — justification'
87+
)),
88+
Message(role="user", text="Candidate slogans:\n" + "\n".join(lines)),
89+
]
90+
response = await self._client.get_response(messages)
91+
await ctx.yield_output(response.text)
7492

7593
dispatcher = DispatchPrompt(id="dispatcher")
7694

@@ -104,30 +122,19 @@ async def format(
104122
),
105123
)
106124

107-
ranker = FormatCandidates(id="ranker")
108-
109-
judge = Agent(
110-
client=client,
111-
name="Judge",
112-
instructions=(
113-
"You are a senior creative director judging marketing slogans. "
114-
"Given a list of candidate slogans, rank them from best to worst. "
115-
"For each slogan, give a 1-10 score and a one-sentence justification "
116-
"evaluating creativity, memorability, clarity, and brand fit. "
117-
"Format: #1 (score X) [AgentName]: \"slogan\" — justification"
118-
),
119-
)
125+
# The ranker Executor calls the LLM client directly to handle fan-in —
126+
# it formats the collected slogans and has the LLM rank them.
127+
ranker = RankerExecutor(client=client)
120128

121129
workflow = (
122130
WorkflowBuilder(
123131
name="FanOutFanInRanked",
124132
description="Generate slogans in parallel, then LLM-judge ranks them.",
125133
start_executor=dispatcher,
126-
output_executors=[judge],
134+
output_executors=[ranker],
127135
)
128136
.add_fan_out_edges(dispatcher, [bold_writer, minimalist_writer, emotional_writer])
129137
.add_fan_in_edges([bold_writer, minimalist_writer, emotional_writer], ranker)
130-
.add_edge(ranker, judge)
131138
.build()
132139
)
133140

examples/workflow_aggregator_structured.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import os
1717
import sys
1818

19-
from agent_framework import Agent, AgentExecutorResponse, Executor, WorkflowBuilder, WorkflowContext, handler
19+
from agent_framework import Agent, AgentExecutorResponse, Executor, Message, WorkflowBuilder, WorkflowContext, handler
2020
from agent_framework.openai import OpenAIChatClient
2121
from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider
2222
from dotenv import load_dotenv
@@ -90,11 +90,11 @@ async def extract(
9090
sections.append(f"[{label}]\n{result.agent_response.text}")
9191
combined = "\n\n".join(sections)
9292

93-
prompt = (
94-
"You are a hiring committee reviewer. Based on the following interviewer assessments, "
95-
"produce a structured candidate review.\n\n" + combined
96-
)
97-
response = await self._client.get_response(prompt, options={"response_format": CandidateReview})
93+
messages = [
94+
Message(role="system", text="You are a hiring committee reviewer. Based on the following interviewer assessments, produce a structured candidate review."),
95+
Message(role="user", text=combined),
96+
]
97+
response = await self._client.get_response(messages, options={"response_format": CandidateReview})
9898
review: CandidateReview = response.value
9999
await ctx.yield_output(review)
100100

examples/workflow_aggregator_template.py

Lines changed: 0 additions & 170 deletions
This file was deleted.

0 commit comments

Comments
 (0)