db620d33df
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Blocked by required conditions
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / paths-filter (push) Waiting to run
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Blocked by required conditions
dotnet-build-and-test / dotnet-test-functions (push) Blocked by required conditions
dotnet-build-and-test / dotnet-build-and-test-check (push) Blocked by required conditions
dotnet-build-and-test / Integration Test Report (push) Blocked by required conditions
108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
"""Calling agents inside functional workflows.
|
|
|
|
Agent calls work inside @workflow as plain function calls — no decorator needed.
|
|
Just call the agent and use the result.
|
|
|
|
If you want per-step caching (so agent calls don't re-execute on HITL resume
|
|
or crash recovery), add @step. Since each agent call hits an LLM API (time +
|
|
money), @step is often worth it. But it's always opt-in.
|
|
|
|
This sample shows both approaches side-by-side so you can see the difference.
|
|
"""
|
|
|
|
import asyncio
|
|
|
|
from agent_framework import Agent, step, workflow
|
|
from agent_framework.foundry import FoundryChatClient
|
|
from azure.identity import AzureCliCredential
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Create agents
|
|
# ---------------------------------------------------------------------------
|
|
|
|
client = FoundryChatClient(credential=AzureCliCredential())
|
|
|
|
classifier_agent = Agent(
|
|
name="ClassifierAgent",
|
|
instructions=(
|
|
"Classify documents into one category: Technical, Legal, Marketing, or Scientific. "
|
|
"Reply with only the category name."
|
|
),
|
|
client=client,
|
|
)
|
|
|
|
writer_agent = Agent(
|
|
name="WriterAgent",
|
|
instructions="Summarize the given content in one sentence.",
|
|
client=client,
|
|
)
|
|
|
|
reviewer_agent = Agent(
|
|
name="ReviewerAgent",
|
|
instructions="Review the given summary in one sentence. Is it accurate and complete?",
|
|
client=client,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Simplest approach: call agents directly inside the workflow.
|
|
# No @step, no wrappers — just plain function calls.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@workflow
|
|
async def simple_pipeline(document: str) -> str:
|
|
"""Process a document — agents called inline, no @step."""
|
|
classification = (await classifier_agent.run(f"Classify this document: {document}")).text
|
|
summary = (await writer_agent.run(f"Summarize: {document}")).text
|
|
review = (await reviewer_agent.run(f"Review this summary: {summary}")).text
|
|
|
|
return f"Classification: {classification}\nSummary: {summary}\nReview: {review}"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# With @step: agent results are cached. On HITL resume or checkpoint
|
|
# recovery, completed steps return their saved result instead of calling
|
|
# the LLM again. Worth it for expensive operations.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@step
|
|
async def classify_document(doc: str) -> str:
|
|
return (await classifier_agent.run(f"Classify this document: {doc}")).text
|
|
|
|
|
|
@step
|
|
async def generate_summary(doc: str) -> str:
|
|
return (await writer_agent.run(f"Summarize: {doc}")).text
|
|
|
|
|
|
@step
|
|
async def review_summary(summary: str) -> str:
|
|
return (await reviewer_agent.run(f"Review this summary: {summary}")).text
|
|
|
|
|
|
@workflow
|
|
async def cached_pipeline(document: str) -> str:
|
|
"""Same pipeline, but @step caches each agent call."""
|
|
classification = await classify_document(document)
|
|
summary = await generate_summary(document)
|
|
review = await review_summary(summary)
|
|
|
|
return f"Classification: {classification}\nSummary: {summary}\nReview: {review}"
|
|
|
|
|
|
async def main():
|
|
# Simple version — agents called inline
|
|
result = await simple_pipeline.run("This is a technical document about machine learning...")
|
|
print(result.get_outputs()[0])
|
|
|
|
# Cached version — same result, but steps won't re-execute on resume
|
|
result = await cached_pipeline.run("This is a technical document about machine learning...")
|
|
print(f"\nCached: {result.get_outputs()[0]}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|