惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
爱范儿
爱范儿
Martin Fowler
Martin Fowler
T
The Blog of Author Tim Ferriss
B
Blog RSS Feed
博客园 - 聂微东
G
GRAHAM CLULEY
Engineering at Meta
Engineering at Meta
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
WordPress大学
WordPress大学
Scott Helme
Scott Helme
AI
AI
S
Security Affairs
T
Threat Research - Cisco Blogs
M
MIT News - Artificial intelligence
T
Troy Hunt's Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
AWS News Blog
AWS News Blog
T
Threatpost
Cyberwarzone
Cyberwarzone
www.infosecurity-magazine.com
www.infosecurity-magazine.com
U
Unit 42
V
Vulnerabilities – Threatpost
J
Java Code Geeks
博客园 - Franky
月光博客
月光博客
Blog — PlanetScale
Blog — PlanetScale
NISL@THU
NISL@THU
D
Docker
小众软件
小众软件
N
News and Events Feed by Topic
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
A
Arctic Wolf
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
Forbes - Security
Forbes - Security
量子位
PCI Perspectives
PCI Perspectives
美团技术团队
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
I
InfoQ
Security Archives - TechRepublic
Security Archives - TechRepublic
有赞技术团队
有赞技术团队
腾讯CDC
P
Proofpoint News Feed
S
Security @ Cisco Blogs
G
Google Developers Blog
C
Cisco Blogs

ISE Developer Blog

From Noisy Queries to Precise Frames: Query Decomposition for Media Asset Search Passing Context Between Agents in Multi-Agent A2A Systems - ISE Developer Blog Separating Deterministic Extraction from AI Inference in Industrial Summarization - ISE Developer Blog Orchestration Patterns for Multi-Agent Systems: Performance and Trade-offs How we Decide Between Keyword and Hybrid Search: 5 Enterprise Evaluation Criteria Verification-driven tooling prompts for fast-moving codebases Coordinating AI-Assisted Development with AGENTS.md and Skills WebAssembly Data Processing at the Edge with Azure IoT Operations SQL query generation from natural language Propagating SharePoint Document Permissions to AI Search and RAG Pipelines Lessons Learned from Building a Well-Matching Intelligence Layer Discoverable - Observable MCP Server - ISE Developer Blog Building Search-Enabled Agents with Azure AI Foundry and Semantic Kernel and A2A From Azure IoT Operations Data Processor Pipelines to Dataflows Using Agents to Setup Experiments Building a Secure MCP Server with OAuth 2.1 and Azure AD: Lessons from the Field Using Codes to Increase Adherence to Prompts Minimal GitOps for Edge Applications with Azure IoT Operations and Azure DevOps Bridging Local Development and Cloud Evaluation: Using Microsoft Devtunnels with Azure Machine Learning Evaluate Small Language Model Function Calling using the Azure AI Evaluation SDK Introducing the Copilot Studio + Azure AI Search Solution Agent Onboarding Process for Agentic Systems: Maintain accuracy at scale
Enabling MLflow OpenAI Autolog on PySpark Workers - ISE Developer Blog
Jaya Kumar · 2026-07-03 · via ISE Developer Blog

Context

In a recent engagement, the team built an LLM-based contract intelligence pipeline on Azure Databricks. The goal was to extract entitlements from a large corpus of inconsistently formatted service-contract PDFs — what is covered, on which equipment, and under which terms — so downstream systems can tell what is in scope and what is billable.

Rules or template-based extraction were not a realistic option given the variability in layout and wording across contracts, which made an LLM a good fit: it can absorb that variability, reason about context across a document, and emit structured output in a single pass.

To parallelize the extraction, the pipeline fans those per-document LLM calls out across Spark workers. Per-call visibility into token spend, latency, and prompt/response quality becomes essential to keep cost and output quality from drifting unnoticed.

The natural tool for that is mlflow.openai.autolog(). The catch: getting it to reliably emit traces in this setup takes more than the docs suggest. If you are running instrumented LLM calls across PySpark workers, the patterns below are what finally made tracing work end-to-end.

Problem

The pipeline distributes OpenAI API calls across Spark workers using mapInPandas to process documents in parallel, with mlflow.openai.autolog() enabled for tracing. Traces from the driver looked exactly as expected; the workers produced none. The Databricks autologging docs flag that autologging must be called explicitly on workers, but following that guidance alone was not enough. Three separate issues had to be solved before traces appeared reliably.

Solution

Issue 1: Workers Need Full MLflow Context

Calling mlflow.openai.autolog() on workers is necessary but not sufficient. Workers also need the MLflow tracking URI and experiment name – neither is inherited from the driver.

# Capture on the driver before mapInPandas
_tracking_uri = mlflow.get_tracking_uri()
_experiment_name = "/Shared/my-experiment"

def process_partition(batch_iter):
    import mlflow

    # All three are required on workers
    mlflow.set_tracking_uri(_tracking_uri)
    mlflow.set_experiment(_experiment_name)
    mlflow.openai.autolog()

    # ... LLM calls here

Without set_tracking_uri and set_experiment, autolog silently discards traces. The tracking URI defaults to an empty local path on workers, and without an experiment, traces have nowhere to go. On Unity Catalog-enabled workspaces, workers also need access to the experiment path — permissions don’t carry over from the driver. The failure mode is the same: a silent drop.

Since Spark can reuse worker processes across partitions, a module-level flag avoids redundant setup:

_worker_initialized = False

def process_partition(batch_iter):
    global _worker_initialized
    if not _worker_initialized:
        os.environ["MLFLOW_ENABLE_ASYNC_TRACE_LOGGING"] = "false"
        mlflow.set_tracking_uri(_tracking_uri)
        mlflow.set_experiment(_experiment_name)
        mlflow.openai.autolog()
        _worker_initialized = True
    # ... LLM calls

Issue 2: Span Artifacts Lost Due to Async Export

After fixing the context propagation, traces appeared in the experiment list with metadata (inputs, outputs, token counts), but the “detailed trace view” in the MLflow UI was broken for most traces. Investigation revealed that 5 out of 6 trace span artifacts were missing from storage.

The root cause: MLflow’s AsyncTraceExportQueue writes span artifacts via a background daemon thread, relying on atexit to flush on shutdown. When running as a Databricks job task, the Python process exits shortly after the pipeline completes. The daemon thread races against process termination, and atexit hooks may not complete in time.

The fix is to disable async logging on workers:

import os
os.environ["MLFLOW_ENABLE_ASYNC_TRACE_LOGGING"] = "false"
mlflow.openai.autolog()

This forces synchronous trace export. The overhead is approximately 100-500ms per trace, negligible compared to 5-20 second LLM call latency. Alternatively, this can be set as a cluster or job environment variable so it applies to all workers without code changes.

Issue 3: No Parent-Child Trace Linking

Each chat.completions.create() call produces an independent trace. The MLflow autolog implementation uses start_span_no_context() in mlflow/openai/autolog.py, which creates root spans without checking for a parent context. There is currently no mechanism to group worker traces under a single parent span.

Processing 6 documents produces 6 disconnected traces. Correlation is possible by timestamp and experiment, but no trace hierarchy exists in the UI. A feature request has been filed with the MLflow team. Realistic workarounds include:

  • Tagging traces with a shared batch_id via mlflow.set_span_attribute()
  • Dropping autolog and using mlflow.start_trace() manually for full hierarchy control, at the cost of losing autolog’s structured ChatCompletion parsing

Complete Pattern

_tracking_uri = mlflow.get_tracking_uri()
_experiment_name = "/Shared/my-experiment"

def process_partition(batch_iter):
    import os, mlflow
    os.environ["MLFLOW_ENABLE_ASYNC_TRACE_LOGGING"] = "false"
    mlflow.set_tracking_uri(_tracking_uri)
    mlflow.set_experiment(_experiment_name)
    mlflow.openai.autolog()

    client = DatabricksOpenAI(workspace_client=WorkspaceClient(
        host=_host, token=_token))
    for batch_df in batch_iter:
        for _, row in batch_df.iterrows():
            client.chat.completions.create(
                model="endpoint", messages=[...])
        yield batch_df

input_df.mapInPandas(process_partition, schema=schema).collect()

Results

After applying the fixes, every LLM call across all pipeline stages produces a structured trace with model details, system/user messages, full response, and token usage. Key learnings:

  • MLflow autolog on workers requires three things: tracking URI, experiment name, and the autolog call itself. Missing any one quietly produces zero traces.
  • Async trace export is unsafe in job tasks: the daemon thread flush races against process termination. Disable it with MLFLOW_ENABLE_ASYNC_TRACE_LOGGING=false.
  • Observability reveals hidden costs: once per-call tracing was working, the team discovered that some pipeline stages were re-executing LLM calls multiple times without warning due to Spark lazy evaluation. This cost multiplier had been invisible without autolog and was straightforward to fix once measured.

Conclusion

Enabling mlflow.openai.autolog() on PySpark workers is straightforward once the pitfalls are known, but discovering them requires reading MLflow internals. The silent failure modes (e.g., no errors, no warnings, just missing traces) make these issues particularly difficult to diagnose. Investing in per-call observability early paid off not only for tracing but also for uncovering hidden cost multipliers in the pipeline.

Attribution

Featured image created by copilot.