mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Properly configure structured outputs based on new options dict (#3213)
* Properly configure structured outputs based on new options dict * Fix mypy
This commit is contained in:
committed by
GitHub
Unverified
parent
620da7a829
commit
15d0c34d9f
@@ -34,7 +34,7 @@ async def main() -> None:
|
||||
name="ProductMarketerAgent",
|
||||
instructions="Return launch briefs as structured JSON.",
|
||||
# Specify type to use as response
|
||||
response_format=ReleaseBrief,
|
||||
options={"response_format": ReleaseBrief},
|
||||
)
|
||||
|
||||
query = "Draft a launch brief for the Contoso Note app."
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ async def non_streaming_example() -> None:
|
||||
print(f"User: {query}")
|
||||
|
||||
# Get structured response from the agent using response_format parameter
|
||||
result = await agent.run(query, response_format=OutputStruct)
|
||||
result = await agent.run(query, options={"response_format": OutputStruct})
|
||||
|
||||
# Access the structured output directly from the response value
|
||||
if result.value:
|
||||
@@ -63,7 +63,7 @@ async def streaming_example() -> None:
|
||||
# Get structured response from streaming agent using AgentResponse.from_agent_response_generator
|
||||
# This method collects all streaming updates and combines them into a single AgentResponse
|
||||
result = await AgentResponse.from_agent_response_generator(
|
||||
agent.run_stream(query, response_format=OutputStruct),
|
||||
agent.run_stream(query, options={"response_format": OutputStruct}),
|
||||
output_format_type=OutputStruct,
|
||||
)
|
||||
|
||||
|
||||
+2
-2
@@ -99,7 +99,7 @@ def spam_detection_orchestration(context: DurableOrchestrationContext):
|
||||
spam_result_raw = yield spam_agent.run(
|
||||
messages=spam_prompt,
|
||||
thread=spam_thread,
|
||||
response_format=SpamDetectionResult,
|
||||
options={"response_format": SpamDetectionResult},
|
||||
)
|
||||
|
||||
spam_result = cast(SpamDetectionResult, spam_result_raw.value)
|
||||
@@ -120,7 +120,7 @@ def spam_detection_orchestration(context: DurableOrchestrationContext):
|
||||
email_result_raw = yield email_agent.run(
|
||||
messages=email_prompt,
|
||||
thread=email_thread,
|
||||
response_format=EmailResponse,
|
||||
options={"response_format": EmailResponse},
|
||||
)
|
||||
|
||||
email_result = cast(EmailResponse, email_result_raw.value)
|
||||
|
||||
+4
-8
@@ -98,7 +98,7 @@ def content_generation_hitl_orchestration(context: DurableOrchestrationContext):
|
||||
initial_raw = yield writer.run(
|
||||
messages=f"Write a short article about '{payload.topic}'.",
|
||||
thread=writer_thread,
|
||||
response_format=GeneratedContent,
|
||||
options={"response_format": GeneratedContent},
|
||||
)
|
||||
|
||||
content = initial_raw.value
|
||||
@@ -135,9 +135,7 @@ def content_generation_hitl_orchestration(context: DurableOrchestrationContext):
|
||||
)
|
||||
return {"content": content.content}
|
||||
|
||||
context.set_custom_status(
|
||||
"Content rejected by human reviewer. Incorporating feedback and regenerating..."
|
||||
)
|
||||
context.set_custom_status("Content rejected by human reviewer. Incorporating feedback and regenerating...")
|
||||
rewrite_prompt = (
|
||||
"The content was rejected by a human reviewer. Please rewrite the article incorporating their feedback.\n\n"
|
||||
f"Human Feedback: {approval_payload.feedback or 'No feedback provided.'}"
|
||||
@@ -145,7 +143,7 @@ def content_generation_hitl_orchestration(context: DurableOrchestrationContext):
|
||||
rewritten_raw = yield writer.run(
|
||||
messages=rewrite_prompt,
|
||||
thread=writer_thread,
|
||||
response_format=GeneratedContent,
|
||||
options={"response_format": GeneratedContent},
|
||||
)
|
||||
|
||||
rewritten_value = rewritten_raw.value
|
||||
@@ -157,9 +155,7 @@ def content_generation_hitl_orchestration(context: DurableOrchestrationContext):
|
||||
context.set_custom_status(
|
||||
f"Human approval timed out after {payload.approval_timeout_hours} hour(s). Treating as rejection."
|
||||
)
|
||||
raise TimeoutError(
|
||||
f"Human approval timed out after {payload.approval_timeout_hours} hour(s)."
|
||||
)
|
||||
raise TimeoutError(f"Human approval timed out after {payload.approval_timeout_hours} hour(s).")
|
||||
|
||||
raise RuntimeError(f"Content could not be approved after {payload.max_review_attempts} iteration(s).")
|
||||
|
||||
|
||||
@@ -41,13 +41,13 @@ async def main() -> None:
|
||||
print(f"User: {message}")
|
||||
if stream:
|
||||
response = await ChatResponse.from_chat_response_generator(
|
||||
client.get_streaming_response(message, tools=get_weather, response_format=OutputStruct),
|
||||
client.get_streaming_response(message, tools=get_weather, options={"response_format": OutputStruct}),
|
||||
output_format_type=OutputStruct,
|
||||
)
|
||||
print(f"Assistant: {response.value}")
|
||||
|
||||
else:
|
||||
response = await client.get_response(message, tools=get_weather, response_format=OutputStruct)
|
||||
response = await client.get_response(message, tools=get_weather, options={"response_format": OutputStruct})
|
||||
print(f"Assistant: {response.value}")
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class UserInfoMemory(ContextProvider):
|
||||
messages=request_messages, # type: ignore
|
||||
instructions="Extract the user's name and age from the message if present. "
|
||||
"If not present return nulls.",
|
||||
response_format=UserInfo,
|
||||
options={"response_format": UserInfo},
|
||||
)
|
||||
|
||||
# Update user info with extracted data
|
||||
|
||||
@@ -86,7 +86,7 @@ reviewer = chat_client.create_agent(
|
||||
"- feedback: concise, actionable feedback\n"
|
||||
"- clarity, completeness, accuracy, structure: individual scores (0-100)"
|
||||
),
|
||||
response_format=ReviewResult,
|
||||
default_options={"response_format": ReviewResult},
|
||||
)
|
||||
|
||||
# Create Editor agent - improves content based on feedback
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ class Reviewer(Executor):
|
||||
messages.append(ChatMessage(role=Role.USER, text="Please review the agent's responses."))
|
||||
|
||||
print("Reviewer: Sending review request to LLM...")
|
||||
response = await self._chat_client.get_response(messages=messages, response_format=_Response)
|
||||
response = await self._chat_client.get_response(messages=messages, options={"response_format": _Response})
|
||||
|
||||
parsed = _Response.model_validate_json(response.messages[-1].text)
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ def create_spam_detector_agent() -> ChatAgent:
|
||||
"Include the original email content in email_content."
|
||||
),
|
||||
name="spam_detection_agent",
|
||||
response_format=DetectionResult,
|
||||
default_options={"response_format": DetectionResult},
|
||||
)
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ def create_email_assistant_agent() -> ChatAgent:
|
||||
"Return JSON with a single field 'response' containing the drafted reply."
|
||||
),
|
||||
name="email_assistant_agent",
|
||||
response_format=EmailResponse,
|
||||
default_options={"response_format": EmailResponse},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ def create_email_analysis_agent() -> ChatAgent:
|
||||
"and 'reason' (string)."
|
||||
),
|
||||
name="email_analysis_agent",
|
||||
response_format=AnalysisResultAgent,
|
||||
default_options={"response_format": AnalysisResultAgent},
|
||||
)
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ def create_email_assistant_agent() -> ChatAgent:
|
||||
return AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent(
|
||||
instructions=("You are an email assistant that helps users draft responses to emails with professionalism."),
|
||||
name="email_assistant_agent",
|
||||
response_format=EmailResponse,
|
||||
default_options={"response_format": EmailResponse},
|
||||
)
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ def create_email_summary_agent() -> ChatAgent:
|
||||
return AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent(
|
||||
instructions=("You are an assistant that helps users summarize emails."),
|
||||
name="email_summary_agent",
|
||||
response_format=EmailSummaryModel,
|
||||
default_options={"response_format": EmailSummaryModel},
|
||||
)
|
||||
|
||||
|
||||
@@ -243,7 +243,8 @@ async def main() -> None:
|
||||
)
|
||||
|
||||
workflow = (
|
||||
workflow_builder.set_start_executor("store_email")
|
||||
workflow_builder
|
||||
.set_start_executor("store_email")
|
||||
.add_edge("store_email", "email_analysis_agent")
|
||||
.add_edge("email_analysis_agent", "to_analysis_result")
|
||||
.add_multi_selection_edge_group(
|
||||
|
||||
@@ -162,7 +162,7 @@ def create_spam_detection_agent() -> ChatAgent:
|
||||
"and 'reason' (string)."
|
||||
),
|
||||
name="spam_detection_agent",
|
||||
response_format=DetectionResultAgent,
|
||||
default_options={"response_format": DetectionResultAgent},
|
||||
)
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ def create_email_assistant_agent() -> ChatAgent:
|
||||
return AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent(
|
||||
instructions=("You are an email assistant that helps users draft responses to emails with professionalism."),
|
||||
name="email_assistant_agent",
|
||||
response_format=EmailResponse,
|
||||
default_options={"response_format": EmailResponse},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -171,28 +171,28 @@ async def main() -> None:
|
||||
self_service_agent = chat_client.create_agent(
|
||||
name="SelfServiceAgent",
|
||||
instructions=SELF_SERVICE_INSTRUCTIONS,
|
||||
response_format=SelfServiceResponse,
|
||||
default_options={"response_format": SelfServiceResponse},
|
||||
)
|
||||
|
||||
ticketing_agent = chat_client.create_agent(
|
||||
name="TicketingAgent",
|
||||
instructions=TICKETING_INSTRUCTIONS,
|
||||
tools=plugin.get_functions(),
|
||||
response_format=TicketingResponse,
|
||||
default_options={"response_format": TicketingResponse},
|
||||
)
|
||||
|
||||
routing_agent = chat_client.create_agent(
|
||||
name="TicketRoutingAgent",
|
||||
instructions=TICKET_ROUTING_INSTRUCTIONS,
|
||||
tools=[plugin.get_ticket],
|
||||
response_format=RoutingResponse,
|
||||
default_options={"response_format": RoutingResponse},
|
||||
)
|
||||
|
||||
windows_support_agent = chat_client.create_agent(
|
||||
name="WindowsSupportAgent",
|
||||
instructions=WINDOWS_SUPPORT_INSTRUCTIONS,
|
||||
tools=[plugin.get_ticket],
|
||||
response_format=SupportResponse,
|
||||
default_options={"response_format": SupportResponse},
|
||||
)
|
||||
|
||||
resolution_agent = chat_client.create_agent(
|
||||
@@ -205,7 +205,7 @@ async def main() -> None:
|
||||
name="TicketEscalationAgent",
|
||||
instructions=ESCALATION_INSTRUCTIONS,
|
||||
tools=[plugin.get_ticket, plugin.send_notification],
|
||||
response_format=EscalationResponse,
|
||||
default_options={"response_format": EscalationResponse},
|
||||
)
|
||||
|
||||
# Agent registry for lookup
|
||||
|
||||
@@ -139,7 +139,7 @@ async def main() -> None:
|
||||
manager_agent = chat_client.create_agent(
|
||||
name="ManagerAgent",
|
||||
instructions=MANAGER_INSTRUCTIONS,
|
||||
response_format=ManagerResponse,
|
||||
default_options={"response_format": ManagerResponse},
|
||||
)
|
||||
|
||||
summary_agent = chat_client.create_agent(
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ def create_guessing_agent() -> ChatAgent:
|
||||
"No explanations or additional text."
|
||||
),
|
||||
# response_format enforces that the model produces JSON compatible with GuessOutput.
|
||||
response_format=GuessOutput,
|
||||
default_options={"response_format": GuessOutput},
|
||||
)
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -162,7 +162,7 @@ def create_spam_detection_agent() -> ChatAgent:
|
||||
"You are a spam detection assistant that identifies spam emails. "
|
||||
"Always return JSON with fields is_spam (bool) and reason (string)."
|
||||
),
|
||||
response_format=DetectionResultAgent,
|
||||
default_options={"response_format": DetectionResultAgent},
|
||||
# response_format enforces structured JSON from each agent.
|
||||
name="spam_detection_agent",
|
||||
)
|
||||
@@ -176,7 +176,7 @@ def create_email_assistant_agent() -> ChatAgent:
|
||||
"Return JSON with a single field 'response' containing the drafted reply."
|
||||
),
|
||||
# response_format enforces structured JSON from each agent.
|
||||
response_format=EmailResponse,
|
||||
default_options={"response_format": EmailResponse},
|
||||
name="email_assistant_agent",
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ async def run_agent_framework() -> None:
|
||||
# AF forwards the same response_format payload at invocation time.
|
||||
reply = await chat_agent.run(
|
||||
"Draft a launch brief for the Contoso Note app.",
|
||||
response_format=ReleaseBrief,
|
||||
options={"response_format": ReleaseBrief},
|
||||
)
|
||||
print("[AF]", reply.text)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user