diff --git a/python/samples/README.md b/python/samples/README.md index 65f77645f2..a477f10a30 100644 --- a/python/samples/README.md +++ b/python/samples/README.md @@ -320,12 +320,6 @@ This directory contains samples demonstrating the capabilities of Microsoft Agen | [`getting_started/workflows/human-in-the-loop/guessing_game_with_human_input.py`](./getting_started/workflows/human-in-the-loop/guessing_game_with_human_input.py) | Sample: Human in the loop guessing game | | [`getting_started/workflows/human-in-the-loop/agents_with_approval_requests.py`](./getting_started/workflows/human-in-the-loop/agents_with_approval_requests.py) | Sample: Agents with Approval Requests in Workflows | -### Observability - -| File | Description | -|------|-------------| -| [`getting_started/workflows/observability/tracing_basics.py`](./getting_started/workflows/observability/tracing_basics.py) | Basic tracing workflow sample | - ### Orchestration | File | Description | diff --git a/python/samples/getting_started/observability/workflow_observability.py b/python/samples/getting_started/observability/workflow_observability.py index 9b56def216..b8ef5d10e9 100644 --- a/python/samples/getting_started/observability/workflow_observability.py +++ b/python/samples/getting_started/observability/workflow_observability.py @@ -17,10 +17,25 @@ """ This sample shows the telemetry collected when running a Agent Framework workflow. +This simple workflow consists of two executors arranged sequentially: +1. An executor that converts input text to uppercase. +2. An executor that reverses the uppercase text. + +The workflow receives an initial string message, processes it through the two executors, +and yields the final result. + Telemetry data that the workflow system emits includes: - Overall workflow build & execution spans + - workflow.build (events: build.started, build.validation_completed, build.completed, edge_group.process) + - workflow.run (events: workflow.started, workflow.completed or workflow.error) - Individual executor processing spans + - executor.process (for each executor invocation) - Message publishing between executors + - message.send (for each outbound message) + +Prerequisites: +- Basic understanding of workflow executors, edges, and messages. +- Basic understanding of OpenTelemetry concepts like spans and traces. """ diff --git a/python/samples/getting_started/workflows/README.md b/python/samples/getting_started/workflows/README.md index ffbeedd751..ab6d4a10cc 100644 --- a/python/samples/getting_started/workflows/README.md +++ b/python/samples/getting_started/workflows/README.md @@ -82,9 +82,7 @@ Once comfortable with these, explore the rest of the samples below. ### observability -| Sample | File | Concepts | -|---|---|---| -| Tracing (Basics) | [observability/tracing_basics.py](./observability/tracing_basics.py) | Use basic tracing for workflow telemetry. Refer to this [directory](../observability/) to learn more about observability concepts. | +For observability samples in Agent Framework, see the [observability getting started samples](../observability/README.md). The [sample](../observability/workflow_observability.py) demonstrates integrating observability into workflows. ### orchestration diff --git a/python/samples/getting_started/workflows/observability/tracing_basics.py b/python/samples/getting_started/workflows/observability/tracing_basics.py deleted file mode 100644 index 6914ad4ce2..0000000000 --- a/python/samples/getting_started/workflows/observability/tracing_basics.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) Microsoft. All rights reserved. - -import asyncio - -from agent_framework import Executor, WorkflowBuilder, WorkflowContext, get_logger, handler -from agent_framework.observability import setup_observability - -"""Basic tracing workflow sample. - -Sample: Workflow Tracing basics - -A minimal two executor workflow demonstrates built in OpenTelemetry spans when diagnostics are enabled. -The sample raises an error if tracing is not configured. - -Purpose: -- Require diagnostics by checking ENABLE_OTEL and wiring a console exporter. -- Show the span categories produced by a simple graph: - - workflow.build (events: build.started, build.validation_completed, build.completed, edge_group.process) - - workflow.run (events: workflow.started, workflow.completed or workflow.error) - - executor.process (for each executor invocation) - - message.send (for each outbound message) -- Provide a tiny flow that is easy to run and reason about: uppercase then print. - -Prerequisites: -- No external services required for the workflow itself. -""" - -logger = get_logger() - - -class StartExecutor(Executor): - @handler # type: ignore[misc] - async def handle_input(self, message: str, ctx: WorkflowContext[str]) -> None: - # Transform and forward downstream. This produces executor.process and message.send spans. - await ctx.send_message(message.upper()) - - -class EndExecutor(Executor): - @handler # type: ignore[misc] - async def handle_final(self, message: str, ctx: WorkflowContext) -> None: - # Sink executor. The workflow completes when idle with no pending work. - print(f"Final result: {message}") - - -async def main() -> None: - # This will enable tracing and create the necessary tracing, logging and metrics providers - # based on environment variables. - setup_observability() - - # Build a two node graph: StartExecutor -> EndExecutor. The builder emits a workflow.build span. - workflow = ( - WorkflowBuilder() - .add_edge(StartExecutor(id="start"), EndExecutor(id="end")) - .set_start_executor("start") # set_start_executor accepts an executor id string or the instance - .build() - ) # workflow.build span emitted here - - # Run once with a simple payload. You should see workflow.run plus executor and message spans. - await workflow.run("hello tracing") # workflow.run + executor.process and message.send spans - - -if __name__ == "__main__": # pragma: no cover - asyncio.run(main())