Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ private static void ConfigureTraceExporter(TracerProviderBuilder tracing, Teleme
break;

case "zipkin":
#pragma warning disable CS0618 // OpenTelemetry deprecated Zipkin exporter; keep existing config support until migrated.
tracing.AddZipkinExporter(o =>
{
if (TryParseEndpoint(endpoint, out var uri))
o.Endpoint = uri;
});
#pragma warning restore CS0618
break;

default: // "console"
Expand Down
4 changes: 2 additions & 2 deletions tools/JD.AI.Workflows.Training/AiTrainingDataSynthesizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public sealed class AiTrainingDataSynthesizer : IDisposable
private readonly string _model;
private int _generated;

public AiTrainingDataSynthesizer(string model = "qwen3.5:9b")
public AiTrainingDataSynthesizer(string model = "qwen3.5:9b", string ollamaHost = "http://localhost:11434")
{
_ollama = new OllamaClient(model);
_ollama = new OllamaClient(model, ollamaHost);
_model = model;
}

Expand Down
74 changes: 74 additions & 0 deletions tools/JD.AI.Workflows.Training/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,86 @@ public static async Task<int> Main(string[] args)
? args[outputArgIdx + 1]
: "../../src/JD.AI.Workflows/Models/intent_classifier.zip";

var ollamaGenerateArgIdx = Array.IndexOf(args, "--ollama-generate");
int? ollamaGenerateCount = ollamaGenerateArgIdx >= 0 && ollamaGenerateArgIdx + 1 < args.Length
? int.Parse(args[ollamaGenerateArgIdx + 1], System.Globalization.CultureInfo.InvariantCulture)
: null;
var ollamaValidate = args.Contains("--ollama-validate");

if (benchmark)
{
RunBenchmark();
return 0;
}

// ── Ollama-synthesized training data generation ──────────────────
if (ollamaGenerateCount.HasValue)
{
var ollamaHost = Environment.GetEnvironmentVariable("OLLAMA_HOST") ?? "http://localhost:11434";
var dir = Path.GetDirectoryName(Path.GetFullPath(outputPath));
var jsonlPath = dir is not null
? Path.Combine(dir, "ollama_training_data.jsonl")
: "ollama_training_data.jsonl";

if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);

List<TrainingDataGenerator.LabeledPrompt> generated = [];
using (var synthesizer = new AiTrainingDataSynthesizer(ollamaHost: ollamaHost))
{
await AnsiConsole.Progress()
.StartAsync(async ctx =>
{
var task = ctx.AddTask("[green]Synthesizing training examples[/]",
maxValue: ollamaGenerateCount.Value);
generated = await synthesizer.GenerateAsync(
ollamaGenerateCount.Value,
(done, _) => task.Value = done);
});
}

TrainingDataGenerator.WriteCsv(generated, jsonlPath);
AnsiConsole.MarkupLine($"[green]Synthesized {generated.Count} examples → {jsonlPath}[/]");
return 0;
}

// ── Ollama-based validation ──────────────────────────────────────
if (ollamaValidate)
{
if (dataPath is null)
{
AnsiConsole.MarkupLine("[red]--ollama-validate requires --data <path>[/]");
return 1;
}

if (!File.Exists(dataPath))
{
AnsiConsole.MarkupLine($"[red]Data file not found: {dataPath}[/]");
return 1;
}

var ollamaHost = Environment.GetEnvironmentVariable("OLLAMA_HOST") ?? "http://localhost:11434";
var prompts = TrainingDataGenerator.ReadCsv(dataPath);

List<ValidationResult> discrepancies = [];
using (var synthesizer = new AiTrainingDataSynthesizer(ollamaHost: ollamaHost))
{
await AnsiConsole.Progress()
.StartAsync(async ctx =>
{
var task = ctx.AddTask("[green]Validating against Ollama[/]",
maxValue: prompts.Count);
discrepancies = await synthesizer.ValidateAsync(
prompts,
(done, _) => task.Value = done);
});
}

await File.WriteAllTextAsync("validate_summary.txt", discrepancies.Count.ToString());
AnsiConsole.MarkupLine($"[cyan]Validation complete — {discrepancies.Count}/{prompts.Count} disagreements[/]");
return 0;
}

if (generateOnly)
{
dataPath ??= Path.Combine(Path.GetTempPath(), "intent_training_data.csv");
Expand Down
Loading