-
-
Notifications
You must be signed in to change notification settings - Fork 23.6k
feat(analytics): add MLflow integration for MLOps provenance tracking #5673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(analytics): add MLflow integration for MLOps provenance tracking #5673
Conversation
- Add MLflowApi credential with support for Bearer token and Basic auth - Add MLflow analytic node for Flowise canvas - Add MLflowClient class using MLflow REST API for thread-safe tracking - Add MLflow to AnalyticHandler for chain/LLM/tool event tracking - Add MLflow to UI analytics providers - Add mlflow-tracing dependency Closes FlowiseAI#5669
Summary of ChangesHello @vellanki-santhosh, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances Flowise's MLOps capabilities by integrating MLflow Analytics. It provides a robust framework for monitoring, comparing, and reproducing LLM experiments by automatically tracking chain executions, inputs, outputs, and performance metrics. This integration streamlines the development and deployment lifecycle of AI applications within Flowise, offering better visibility and control over experimental results. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces MLflow integration for analytics, which is a valuable addition for MLOps provenance tracking. The implementation includes a new MLflowClient for direct communication with the MLflow REST API and its integration within the AnalyticHandler. The code is generally well-structured. However, I've identified a few issues that should be addressed: an unused dependency, a potential injection vulnerability in experiment name handling, an error handling improvement opportunity, and a bug in how metrics are counted. My review comments provide specific details and suggestions for these points.
packages/components/src/handler.ts
Outdated
| try { | ||
| // Try to get or create the experiment | ||
| const searchResult = await this.fetch('/experiments/search', 'POST', { | ||
| filter: `name = '${this.experimentName}'` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The experimentName is used directly in the filter string for searching experiments. If an experiment name contains a single quote ('), it will break the filter's SQL-like syntax, leading to API errors. This poses a minor injection risk. The experiment name should be properly escaped to prevent this.
| filter: `name = '${this.experimentName}'` | |
| filter: `name = '${this.experimentName.replace(/'/g, "''")}'` |
packages/components/package.json
Outdated
| "lunary": "^0.7.12", | ||
| "mammoth": "^1.5.1", | ||
| "meilisearch": "^0.41.0", | ||
| "mlflow-tracing": "^0.1.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } catch (err) { | ||
| if (process.env.DEBUG === 'true') console.error(`Error initializing MLflow experiment: ${err}`) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The catch block in the init method swallows errors, only logging them when in debug mode. If init fails to get or create an experiment, this.experimentId remains null, and subsequent operations like startRun will fail silently by returning null, obscuring the root cause. It's better to propagate the error from init so the caller can handle the initialization failure explicitly.
} catch (err) {
if (process.env.DEBUG === 'true') console.error(`Error initializing MLflow experiment: ${err}`)
throw err
}
packages/components/src/handler.ts
Outdated
|
|
||
| if (mlflow && chainRunId) { | ||
| // Log LLM call as a metric on the parent chain run | ||
| await mlflow.logMetric(chainRunId, 'llm_calls', 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The llm_calls metric is logged with a value of 1 for every LLM call. Since no step is provided to logMetric, it defaults to 0. This causes each new metric to overwrite the previous one within the same run. Consequently, llm_calls will always be 1 at the end of the run, regardless of the actual number of calls. To correctly count the calls, you should provide a unique or incremental step for each metric. Using Date.now() as the step is a simple way to record each call individually. This same issue applies to tool_calls.
await mlflow.logMetric(chainRunId, 'llm_calls', 1, Date.now())
packages/components/src/handler.ts
Outdated
|
|
||
| if (mlflow && chainRunId) { | ||
| // Log tool call as a metric on the parent chain run | ||
| await mlflow.logMetric(chainRunId, 'tool_calls', 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tool_calls metric is logged with a value of 1 for every tool call. Similar to llm_calls, the absence of a step argument causes each log to overwrite the previous one. To accurately track the number of tool calls, a unique step should be provided for each metric. Using Date.now() will ensure each call is recorded as a distinct data point.
await mlflow.logMetric(chainRunId, 'tool_calls', 1, Date.now())… improved metrics - Add tokenCount tracking to activeRuns Map for token usage metrics - Add logParams() and logMetrics() batch methods for efficiency - Add setTags() batch method - Add addTokenUsage() for tracking token usage during runs - Add logChainExecution() comprehensive logging helper - endRun() now automatically logs: latency_ms, token_usage (if tracked), success (0/1) - Updated comments to clarify thread-safety (per-instance headers, no global process.env) - onChainStart now logs chain_id, chain_name, session_id as params - Use standard mlflow.note.content tag for inputs
- Fix llm_calls and tool_calls metrics to use Date.now() as step for proper counting - Escape single quotes in experiment name to prevent filter injection - Propagate init errors instead of silently swallowing them - Remove unused mlflow-tracing dependency
…etrics Major improvements to MLflow integration: ## New Features - Token usage tracking: Extract promptTokens, completionTokens, totalTokens from LLM responses - Batch logging: logBatch() method reduces HTTP requests by combining metrics, params, tags - Enhanced run info: Track llmCalls and toolCalls counts per run - incrementLLMCalls() and incrementToolCalls() for accumulating call counts - getRunInfo() for accessing current run state ## Bug Fixes (from code review) - Data overwrite bug: Use Date.now() as step for llm_calls/tool_calls metrics - SQL injection: Escape single quotes in experiment name filter - Error handling: Propagate init() errors instead of swallowing them ## Metrics Logged Final batch at chain end includes: - latency_ms: Total execution time - success: 1 for FINISHED, 0 for FAILED - total_tokens, prompt_tokens, completion_tokens: Token usage for cost analysis - total_llm_calls, total_tool_calls: Final call counts Per-call metrics (with unique timestamps): - llm_calls: Each LLM invocation - tool_calls: Each tool invocation ## Thread-Safety - All state is per-instance (activeRuns Map, headers, experimentId) - No global process.env usage for configuration
MLflow Analytics for FlowiseThis integration allows you to log traces, metrics, and parameters from your Flowise chains directly to an MLflow tracking server. Features
Setup Guide
Troubleshooting
|
Summary
This PR adds MLflow Analytics integration to Flowise, enabling users to automatically log LLM chain executions, inputs/outputs, metrics, and latency to an MLflow tracking server.
Closes #5669
Changes
New Files
packages/components/credentials/MLflowApi.credential.ts- Credential definition supporting:packages/components/nodes/analytic/MLflow/MLflow.ts- Analytics node for the Flowise canvaspackages/components/nodes/analytic/MLflow/mlflow.svg- Node iconpackages/ui/src/assets/images/mlflow.svg- UI icon for analytics settingsModified Files
packages/components/package.json- Addedmlflow-tracingdependencypackages/components/src/handler.ts- Added:MLflowClientclass with REST API integrationAnalyticHandlerclasspackages/ui/src/ui-component/extended/AnalyseFlow.jsx- Added MLflow to analytics providersImplementation Details
This integration uses a custom
MLflowClientclass that communicates directly with the MLflow REST API. This approach:process.envpollution)duration_ms,success,llm_calls,tool_callschain_name,session_idHow to Test
1. Setup MLflow Server
pip install mlflow mlflow ui # Starts server at http://127.0.0.1:50002. Configure Flowise
3. Enable MLflow Analytics
http://127.0.0.1:5000my-flowise-experiment4. Verify
http://127.0.0.1:5000Checklist