Blazor和当地LMs的确定性声音形式 (中文 (Chinese Simplified))

Blazor和当地LMs的确定性声音形式

Monday, 05 January 2026

//

12 minute read

十诫 –集成建筑

在其中,我们建立了一个声音系统 -#to @-sform 这个系统不能给AI王国的钥匙

@.}(这里是关于语音界面的话题) 每个人都想要它们 , 没人相信它们

多数声音形式在模型错误读取日期或决定“"@helptime @"” 跳过前端. 你说:‘"’ May _12}#1984"和LLM摘录 {" May @MS K7 并前进到下一个字段,然后你才能更正它>._or worse : 它会给人信心带来幻觉 而自动□-}用错误的数据向您提交您的表格

当您让 LLM {"} 控制} "} 您的表单,} 你已将一个非@-} 确定性黑盒引入到可以预测的用户体验中 @.}

这是'的假设吗? . McDonald ' @s 运行 AI- @ power 驱动器@-_thru 订购 校对:Soup

但如果我们可以吃蛋糕 并把它也吃掉 为了方便的语音输入 确定性守则 对于所有真正重要的东西 ?

使用 Blazor Server@,当地耳语表达器的语音形式系统

适用十诫

本项目如下: LLM 使用的十诫. @ @ MSk0 @ t 如果您读到@ MS K1} 短版本@ I: @ LMs 是概率引擎 @ MPK4 @ 不是决定@ O- @ makeers @ MOK6# 它们翻译并分类 @ MASK7 @ 他们不' @ t控制 @ MCSK9 @

对于语音表格来说 , 相关命令是:

  • 让LLM自己立州 @- 国家机器的轨迹形成进步=%,}不是模型
  • 让LLM引起影响 它建议提取 ;
  • III. 与叙述分开的因果关系 @-LLM解释自己听到的#; 验证人决定它是否正确
  • 在概率可以接受的情况下使用LLMs @ - @ 从演讲中提取@ MS K1_ May @ I12 @ t"} 是模糊的 ;{ 字段订单不是

语音形式设计目标

除了命令之外 这个制度遵循具体的原则 :

  • 演讲是损失的输入 @- @ 一种填充字段的方法 @ , @ never the truth source
  • 确认是策略@- @% 驱动 “-”+“Config,”中的阈值,而不是LLM判决。
  • 用户总是可以推翻 @-@ 声音是方便的 @ ,# 不是强迫
  • 全部都是本地经营的 - Whisper和Ollama,没有云层依赖性
  • 失败是优雅的 当声音失声时 ,}打字仍然有效

这里#'}这在实践上如何看? 200)}:

flowchart LR
    A[User Speaks] --> B[Whisper STT]
    B --> C[Raw Transcript]
    C --> D[Ollama LLM]
    D --> E[Extracted Value]
    E --> F{Validation}
    F -->|Pass| G{Policy Check}
    F -->|Fail| H[Show Error]
    G -->|High Confidence| I[Auto-Confirm]
    G -->|Low Confidence| J[Ask User]
    J --> K{User Confirms?}
    K -->|Yes| L[State Machine: Next Field]
    K -->|No| M[Retry Recording]
    I --> L
    H --> M

    style D stroke:#f96,stroke-width:2px
    style F stroke:#6f6,stroke-width:2px
    style G stroke:#ff9,stroke-width:2px

这是做什么? '吗?

让'%s明白范围@: @

  • 没有自然对话 - 这里是' t a chatbot}. 1 phone field as a time@.
  • 不询问适应性提问 “-”形式是静态的“. ” LLM doesnZ't Jimprovise 跟随“MS K3cups @.}
  • 没有"助理 "个性 “LLM”提取了值“, ” 它确实“MS K2 ” 做了些小闲聊 .
  • 没有横跨字段的上下文 @- @ 每一次提取都是独立的@.}LLM does'}在询问电子邮件时都不记得你的名字 .

这些限制是特性@, 而非bugs. 它们使系统可以预测 @, 测试{, 和可信赖}MS K4

如果您想要一个对话代理@ , @ building a talance agent *\ .} 如果您想要正确的数据 < MS K2 > don\ MPK3t 假装交谈有助于\ I.}

项目结构

我们正在建造一个独立的 Blazor 服务器 App._Breaking a separity brazor server appMSK1}这里是'_Chis the struilitation :

Mostlylucid.VoiceForm/
├── Config/
│   └── VoiceFormConfig.cs         # Configuration binding
├── Models/
│   ├── FormSchema/                # Form definitions
│   ├── State/                     # Session state
│   └── Extraction/                # LLM input/output
├── Services/
│   ├── Stt/                       # Speech-to-text (Whisper)
│   ├── Extraction/                # Field extraction (Ollama)
│   ├── Validation/                # Type-based validators
│   ├── StateMachine/              # Form flow control
│   └── Orchestration/             # Coordinates everything
├── Components/
│   └── Pages/                     # Blazor UI
└── wwwroot/js/
    └── audio-recorder.js          # Web Audio API capture

扶养规则_: 服务只依赖于下面的抽象数据。 没有上游的人知道下游发生什么

建立基础设施

首先,你需要耳语和奥拉马在本地跑. 加上这些 devdeps-docker-compose.yml:

services:
  whisper:
    image: onerahmet/openai-whisper-asr-webservice:latest
    container_name: whisper-stt
    ports:
      - "9000:9000"
    environment:
      - ASR_MODEL=base.en
      - ASR_ENGINE=faster_whisper
    volumes:
      - whisper-models:/root/.cache/huggingface
    restart: unless-stopped

  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama-models:/root/.ollama
    restart: unless-stopped

volumes:
  whisper-models:
  ollama-models:

在旋转后“,”拉出一个Ollama:的模型

docker exec -it ollama ollama pull llama3.2:3b

为何本地@? @ 测试点:.}没有利率限制 , 没有网络变异性=.

注:: 缩略 base.en 对于英文来说,耳语模式是快速和准确的。 small.en 或 medium.en 提高准确性@. @%

表格SchemaQ:+Z 声明格式定义

表格在 JSON.中定义,这是关于哪些领域存在及其行为方式的唯一真相来源。

{
  "id": "customer-intake",
  "name": "Customer Intake Form",
  "fields": [
    {
      "id": "fullName",
      "label": "Full Name",
      "type": "Text",
      "prompt": "Please say your full name.",
      "required": true
    },
    {
      "id": "dateOfBirth",
      "label": "Date of Birth",
      "type": "Date",
      "prompt": "What is your date of birth?",
      "required": true,
      "confirmationPolicy": {
        "alwaysConfirm": true
      }
    },
    {
      "id": "email",
      "label": "Email Address",
      "type": "Email",
      "prompt": "What is your email address?",
      "required": true
    },
    {
      "id": "phone",
      "label": "Phone Number",
      "type": "Phone",
      "prompt": "What is your phone number?",
      "required": false
    },
    {
      "id": "notes",
      "label": "Additional Notes",
      "type": "Text",
      "prompt": "Any additional notes?",
      "required": false
    }
  ]
}

C# 代表此模式的模型{:

public record FormDefinition(
    string Id,
    string Name,
    List<FieldDefinition> Fields);

public record FieldDefinition(
    string Id,
    string Label,
    FieldType Type,
    string Prompt,
    bool Required = true,
    ConfirmationPolicy? ConfirmationPolicy = null);

public enum FieldType
{
    Text,
    Date,
    Email,
    Phone,
    Choice  // Constrained vocabulary - especially important for voice
}

public record ConfirmationPolicy(
    bool AlwaysConfirm = false,
    double ConfidenceThreshold = 0.85);

因为剧情是宣示性的 , 添加字段无需触摸状态机器. 在 JSON,中丢弃新的字段定义, 且表单自动包含有适当的流量控制@.

国家机器-:-决定形式流动

该州立机器明确禁止该“.”

国家机器使用 AY=.+# 依据明确的规则决定过渡的逻辑=.}

public class FormStateMachine : IFormStateMachine
{
    private FormSession _session = null!;
    private int _currentFieldIndex;

    public FormSession StartSession(FormDefinition form)
    {
        _session = new FormSession
        {
            Id = Guid.NewGuid().ToString(),
            Form = form,
            Status = FormStatus.InProgress,
            StartedAt = DateTime.UtcNow,
            FieldStates = form.Fields.ToDictionary(
                f => f.Id,
                f => new FieldState { FieldId = f.Id, Status = FieldStatus.Pending })
        };

        // First field starts in progress
        if (form.Fields.Count > 0)
        {
            _session.FieldStates[form.Fields[0].Id].Status = FieldStatus.InProgress;
        }

        return _session;
    }

    public FieldDefinition? GetCurrentField()
    {
        if (_currentFieldIndex >= _session.Form.Fields.Count)
            return null;

        return _session.Form.Fields[_currentFieldIndex];
    }
}

州过渡是明确和可测试的 :

public StateTransitionResult ProcessExtraction(
    ExtractionResponse extraction,
    ValidationResult validation)
{
    var currentField = GetCurrentField();
    if (currentField == null)
        return new StateTransitionResult(false, "No current field");

    var fieldState = _session.FieldStates[currentField.Id];
    fieldState.AttemptCount++;

    // Validation failed? Stay on current field
    if (!validation.IsValid)
    {
        return new StateTransitionResult(
            false,
            $"Validation failed: {validation.ErrorMessage}");
    }

    // Store the pending value
    fieldState.PendingValue = extraction.Value;
    fieldState.PendingConfidence = extraction.Confidence;

    // Check confirmation policy - this is rules, not AI
    var policy = currentField.ConfirmationPolicy
        ?? new ConfirmationPolicy();

    var needsConfirmation = policy.AlwaysConfirm
        || extraction.Confidence < policy.ConfidenceThreshold;

    if (needsConfirmation)
    {
        fieldState.Status = FieldStatus.AwaitingConfirmation;
        return new StateTransitionResult(
            true,
            "Please confirm this value",
            RequiresConfirmation: true);
    }

    // Auto-confirm high confidence values
    return ConfirmValue();
}

关键点@: 缩略 _currentFieldIndex 只有在确认后 president@, @ never on republic_.}这表示提取失败或拒绝确认将您保留在同一字段@ .# 用户继续控制\ . @

注意确认逻辑@: @ it'}一个简单的政策检查 ,}不是LLM推理.#高度信任 *{+}否 alwaysConfirm 低置信度或敏感域 @=问用户@.

LLM' 合同_: 只翻译

Ollama 提取器有一份工作: 把乱七八糟的人的演讲变成结构化的字段值."

如果您能写下这个界面, 而不感到尴尬 @,}LLM正在做太多的事情@:#

public interface IFieldExtractor
{
    Task<ExtractionResponse> ExtractAsync(
        ExtractionContext context,
        CancellationToken ct = default);
}

public record ExtractionContext(
    FieldDefinition Field,
    string Prompt,
    string Transcript);

public record ExtractionResponse(
    string FieldId,
    string? Value,
    double Confidence,
    bool NeedsConfirmation,  // Suggestion only - policy has final say
    string? Reason);

重要的: 提取器可能暗示 NeedsConfirmation: true但确认政策总是有最终的发言权。 LLM='=%s 意见是建议*,}不是权威 .

以及执行@:

public class OllamaFieldExtractor : IFieldExtractor
{
    private readonly HttpClient _httpClient;
    private readonly string _model;

    public async Task<ExtractionResponse> ExtractAsync(
        ExtractionContext context,
        CancellationToken ct = default)
    {
        var systemPrompt = BuildSystemPrompt(context.Field);
        var userPrompt = $"User said: \"{context.Transcript}\"";

        var request = new
        {
            model = _model,
            messages = new[]
            {
                new { role = "system", content = systemPrompt },
                new { role = "user", content = userPrompt }
            },
            format = "json",
            stream = false,
            options = new { temperature = 0.1 }  // Low = deterministic
        };

        var response = await _httpClient.PostAsJsonAsync(
            "/api/chat", request, ct);

        return ParseResponse(response, context.Field.Id);
    }
}

为什么温度会变温? 我们希望LLM是无聊的和可预测的"."鉴于相同的笔录 ,"它应该每次提取同样的值 "."温度"\0.1" 最大限度地减少创造性变异"\ -"我们想要的数据提取什么"MS K5"

系统即时功能明确显示LLM'}有限角色=:

private string BuildSystemPrompt(FieldDefinition field)
{
    return $"""
        You are a data extraction assistant. Extract the {field.Label}
        from the user's speech.

        Field type: {field.Type}

        Return JSON only:
        {{
          "fieldId": "{field.Id}",
          "value": "<extracted value or null>",
          "confidence": <0.0-1.0>,
          "needsConfirmation": <true/false>,
          "reason": "<brief explanation>"
        }}

        Rules:
        - For dates, output ISO format (YYYY-MM-DD)
        - For emails, output lowercase
        - For phones, output digits only
        - If you can't extract, set value to null
        - Be conservative with confidence scores

        DO NOT:
        - Ask follow-up questions
        - Suggest next steps
        - Make assumptions beyond the transcript
        """;
}

LLM 提取@,}验证类型格式 @,}并报告信任性 它决定了接下来会发生什么

WAV 的音频记录器@:浏览器

JavaScript 侧面捕捉麦克风音频并将其转换为 @ 16kHz 单 WAV:}

window.voiceFormAudio = (function () {
    let mediaRecorder = null;
    let audioChunks = [];
    let audioContext = null;
    let dotNetRef = null;

    async function startRecording() {
        const stream = await navigator.mediaDevices
            .getUserMedia({ audio: true });

        audioContext = new AudioContext();
        audioChunks = [];

        const options = { mimeType: 'audio/webm;codecs=opus' };
        mediaRecorder = new MediaRecorder(stream, options);

        mediaRecorder.ondataavailable = (event) => {
            if (event.data.size > 0) {
                audioChunks.push(event.data);
            }
        };

        mediaRecorder.onstop = async () => {
            stream.getTracks().forEach(track => track.stop());

            const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
            const wavBlob = await convertToWav(audioBlob);
            const wavBytes = await wavBlob.arrayBuffer();

            // Send to Blazor
            const uint8Array = new Uint8Array(wavBytes);
            await dotNetRef.invokeMethodAsync(
                'OnRecordingComplete',
                Array.from(uint8Array));
        };

        mediaRecorder.start(100);
    }

    return { initialize, startRecording, stopRecording };
})();

为什么WAV? Whisper接受关于“16kHz one WAV.”的培训。同样的音频在“MS K2”中也包含相同的字节。

缩略 convertToWav 函数重新标注@- @I'}可以节省您使用 WAV header bit @-_twidling{,},但是在 repoQ.}中它会='%s

Blazor UI:+2 -+Column布局

UI 显示左侧的当前字段 ,}所有字段都可见于右侧的边栏\ I.} 侧边栏不是化妆品@- @it_'}是信任边界 @. 用户可以随时看到进步@, state @,和意图}#.

graph LR
    subgraph "Left Panel"
        A[Current Field Prompt]
        B[Record Button]
        C[Transcript Display]
        D[Confirmation Dialog]
    end

    subgraph "Right Sidebar"
        E[Field 1: Full Name ✓]
        F[Field 2: DOB - Active]
        G[Field 3: Email - Pending]
        H[Field 4: Phone - Pending]
    end

    style F stroke:#36f,stroke-width:2px
    style E stroke:#6f6,stroke-width:2px

这是Blazor页面结构的:

@page "/voiceform/{FormId}"
@inject IFormOrchestrator Orchestrator
@rendermode InteractiveServer

<div class="top-bar">
    <h1>Voice Form</h1>
    <button class="theme-toggle" onclick="voiceFormTheme.toggle()">
        Dark Mode
    </button>
</div>

<main>
    <div class="voice-form-layout">
        <!-- Left: Active Field -->
        <div class="active-field-panel">
            @if (_currentField != null)
            {
                <div class="current-prompt">
                    <h2>@_currentField.Label</h2>
                    <p class="prompt-text">@_message</p>
                </div>

                <AudioRecorder OnAudioCaptured="HandleAudioCaptured"
                               IsRecording="_isRecording"
                               IsProcessing="_isProcessing" />

                @if (!string.IsNullOrEmpty(_transcript))
                {
                    <TranscriptDisplay Transcript="_transcript"
                                       Confidence="_transcriptConfidence" />
                }

                @if (_showConfirmation)
                {
                    <ConfirmationDialog ExtractedValue="_pendingValue"
                                        OnConfirm="HandleConfirm"
                                        OnReject="HandleReject" />
                }
            }
        </div>

        <!-- Right: Form Overview -->
        <div class="form-sidebar">
            <h3>@_session.Form.Name</h3>
            <div class="form-fields-list">
                @foreach (var field in _session.Form.Fields)
                {
                    var state = _session.GetFieldState(field.Id);
                    <div class="form-field-item @GetFieldClass(field, state)">
                        <div class="field-status-icon">
                            @GetStatusIcon(state.Status)
                        </div>
                        <div class="field-info">
                            <div class="field-name">@field.Label</div>
                            <div class="field-value">
                                @(state.Value ?? "Waiting")
                            </div>
                        </div>
                    </div>
                }
            </div>
        </div>
    </div>
</main>

编织者: 将它统领到一起

管弦乐队协调各服务... 本身没有分支逻辑@-it只是按顺序拨打服务电话,

public class FormOrchestrator : IFormOrchestrator
{
    private readonly ISttService _sttService;
    private readonly IFieldExtractor _extractor;
    private readonly IFormValidator _validator;
    private readonly IFormStateMachine _stateMachine;
    private readonly IFormEventLog _eventLog;

    public async Task<ProcessingResult> ProcessAudioAsync(byte[] audioData)
    {
        var currentField = _stateMachine.GetCurrentField();
        if (currentField == null)
            return ProcessingResult.Error("No current field");

        // Step 1: Speech to text
        var sttResult = await _sttService.TranscribeAsync(audioData);
        await _eventLog.LogAsync(new TranscriptReceivedEvent(
            currentField.Id, sttResult.Transcript, sttResult.Confidence));

        // Step 2: Extract structured value
        var context = new ExtractionContext(
            currentField, currentField.Prompt, sttResult.Transcript);
        var extraction = await _extractor.ExtractAsync(context);
        await _eventLog.LogAsync(new ExtractionAttemptEvent(
            currentField.Id, extraction));

        // Step 3: Validate
        var validation = _validator.Validate(currentField, extraction.Value);

        // Step 4: State machine decides next step
        var transition = _stateMachine.ProcessExtraction(extraction, validation);

        return new ProcessingResult(
            Success: transition.Success,
            Message: transition.Message,
            Session: _stateMachine.GetSession(),
            RequiresConfirmation: transition.RequiresConfirmation,
            PendingValue: extraction.Value);
    }
}

每一步都是独立和可测试的 . 国家机器 永不触动网络灵丹妙药 绝不触动国家.

胜利的黑暗模式@: CSS 变量

使用 CSS 自定义属性来执行暗模式@ :

:root {
    --bg-primary: #f8fafc;
    --bg-secondary: #ffffff;
    --text-primary: #1e293b;
    --accent-blue: #3b82f6;
    --accent-green: #22c55e;
}

[data-theme="dark"] {
    --bg-primary: #0f172a;
    --bg-secondary: #1e293b;
    --text-primary: #f1f5f9;
    --accent-blue: #60a5fa;
    --accent-green: #4ade80;
}

body {
    background: var(--bg-primary);
    color: var(--text-primary);
}

主题切换通过本地端Storage @:+#

window.voiceFormTheme = (function () {
    const THEME_KEY = 'voiceform-theme';

    function toggle() {
        const current = document.documentElement
            .getAttribute('data-theme') || 'light';
        const newTheme = current === 'dark' ? 'light' : 'dark';
        document.documentElement.setAttribute('data-theme', newTheme);
        localStorage.setItem(THEME_KEY, newTheme);
    }

    // Initialize from saved preference or system preference
    function init() {
        const saved = localStorage.getItem(THEME_KEY);
        const systemDark = window.matchMedia(
            '(prefers-color-scheme: dark)').matches;
        const theme = saved || (systemDark ? 'dark' : 'light');
        document.documentElement.setAttribute('data-theme', theme);
    }

    return { toggle, init };
})();

测试 :單位測試 {+}瀏覽器整合

确定性结构在测试中得到回报... .... Here'...

[Fact]
public void ProcessExtraction_HighConfidence_AutoConfirms()
{
    // Arrange
    var form = CreateTestForm();
    var stateMachine = new FormStateMachine();
    stateMachine.StartSession(form);

    var extraction = new ExtractionResponse(
        FieldId: "fullName",
        Value: "John Smith",
        Confidence: 0.95,  // High confidence
        NeedsConfirmation: false,
        Reason: "Clear speech");

    var validation = ValidationResult.Success();

    // Act
    var result = stateMachine.ProcessExtraction(extraction, validation);

    // Assert
    result.Success.Should().BeTrue();
    result.RequiresConfirmation.Should().BeFalse();

    var fieldState = stateMachine.GetSession()
        .GetFieldState("fullName");
    fieldState.Status.Should().Be(FieldStatus.Confirmed);
    fieldState.Value.Should().Be("John Smith");
}

而这里的' 测试为负数 部队 不论LLM建议什么 :

[Fact]
public void ProcessExtraction_LowConfidence_RequiresConfirmation()
{
    // Arrange
    var form = CreateTestForm();
    var stateMachine = new FormStateMachine();
    stateMachine.StartSession(form);

    var extraction = new ExtractionResponse(
        FieldId: "fullName",
        Value: "John Smith",
        Confidence: 0.65,  // Below threshold
        NeedsConfirmation: false,  // LLM says no, but policy overrides
        Reason: "Noisy audio");

    var validation = ValidationResult.Success();

    // Act
    var result = stateMachine.ProcessExtraction(extraction, validation);

    // Assert
    result.RequiresConfirmation.Should().BeTrue(
        "Policy threshold (0.85) should override LLM suggestion");

    var fieldState = stateMachine.GetSession()
        .GetFieldState("fullName");
    fieldState.Status.Should().Be(FieldStatus.AwaitingConfirmation);
}

以及一个 Putopieer Sharp 浏览器测试, 实际上点击东西@: @%

[Fact]
public async Task HomePage_ThemeToggle_ShouldSwitchTheme()
{
    await _page!.GoToAsync(BaseUrl);
    await _page.WaitForSelectorAsync(".theme-toggle");

    var initialTheme = await _page.EvaluateFunctionAsync<string?>(
        "() => document.documentElement.getAttribute('data-theme')");

    // Click toggle
    await _page.ClickAsync(".theme-toggle");
    await Task.Delay(100);

    var newTheme = await _page.EvaluateFunctionAsync<string?>(
        "() => document.documentElement.getAttribute('data-theme')");

    newTheme.Should().NotBe(initialTheme);
}

[Fact]
public async Task VoiceFormPage_Sidebar_ShouldShowAllFields()
{
    await _page!.GoToAsync($"{BaseUrl}/voiceform/customer-intake");
    await _page.WaitForSelectorAsync(".form-fields-list");

    var fieldItems = await _page.QuerySelectorAllAsync(".form-field-item");

    fieldItems.Should().HaveCount(5, "Customer intake form has 5 fields");
}

完整的测试套件运行“% 98” 测试“ MS K1” 单位测试,用于商业逻辑“ @ ,” 和“ MPK3” 浏览器集成检测UI.” 。

重要的是,不是测试本身 -it' 建筑使得它们成为可能

为什么这个建筑问题

让我们重温为什么我们这样建造它 : *

graph TD
    subgraph "Traditional Voice Form"
        A1[User Speaks] --> B1[LLM]
        B1 --> C1[LLM decides field]
        C1 --> D1[LLM validates]
        D1 --> E1[LLM confirms]
        E1 --> F1[LLM advances form]
    end

    subgraph "Ten Commandments Approach"
        A2[User Speaks] --> B2[Whisper STT]
        B2 --> C2[Ollama Extract]
        C2 --> D2[C# Validator]
        D2 --> E2[Policy Check]
        E2 --> F2[State Machine]
    end

    style B1 stroke:#f96,stroke-width:2px
    style C1 stroke:#f96,stroke-width:2px
    style D1 stroke:#f96,stroke-width:2px
    style E1 stroke:#f96,stroke-width:2px
    style F1 stroke:#f96,stroke-width:2px

    style C2 stroke:#f96,stroke-width:2px
    style D2 stroke:#6f6,stroke-width:2px
    style E2 stroke:#6f6,stroke-width:2px
    style F2 stroke:#6f6,stroke-width:2px

传统做法: 一切都是全能的,“. ”每个决定都是非“- 确定性”或“MS K2 ” 每个测试都是概率的“MSC3”

每个错误都是 @ " @ it just sometimes does that @ I"-# 无法复制和解释@ MS K2 @

在我们的做法中,LLM是 还有一件事: 将演讲翻译为结构化的值@. 其他一切都是确定性的 C# 您可以调试, 测试 @, 和追踪#.

这是动作中的 II,}IIIMS K1}和四号命令 “:LLM”翻译了“(no side -effects}),}州立機控管系統流 *{(causality

自己运行

  1. 开始依赖关系@:}
docker compose -f devdeps-docker-compose.yml up -d
docker exec -it ollama ollama pull llama3.2:3b
  1. 运行 App:
cd Mostlylucid.VoiceForm
dotnet run
  1. 导航至 http://localhost:5000

  2. 点击“"”+“海关收件”"然后开始说!

结论结论

语音界面@' @t 必须是黑盒子 @ .} 通过将演讲作为另一种输入方法来对待 ,}LMs 作为翻译{,}(译者) 并保持确定代码的流量控制>,你得到:}

  • 可预见行为 -}相同的投入 *,}同样的输出
  • 可检验逻辑 -单位商业规则测试
  • 可审计裁决 每个州都记录了过渡情况
  • 优减降解 @ - @ 语音失败@ MS K1_ type
  • 当地业务 - 核心功能无云依赖性

@"_Ten 命令@"}是'}关于反对-QAAI.的 将大赦国际置于适当位置“:”是一个强有力的工具,可以翻译人类的不便和计算机精确度之间 ”“,”不是为我们做决定的神器 ‘.

AI在减少模棱两可之处时赢得了自己的地位 -*not 当它取代责任的时候

现在去建造一些东西 在那里你-}而不是模型{-}决定下一步会发生什么

部分内容为 @2:#语音反馈@(_IVR%)}

现在该用户读到提示并说回应@.}但是如果这个系统可以呢? 回话@? @ part @ 2 @ 将添加文字@ MS K2 @to @ MPK3_ speech 回馈@ I, @ 将此转换成完整的 IVR @ MCK5# 交互式语音响应 @ MASK6 @ system+: @

  • 大声朗读提示 请说出你的全名 "
  • 确认提取 "- "" 我听见了"' 约翰・史密斯・史密斯•'." 这是正确的吗?
  • 音频提示 - @ sound for record start@ /_stop,}确认 , 错误
  • 手M-无限制操作 完整表格不看屏幕

此架构已准备好 @ : @ 国家机器发布事件@ MS K1 @ 管弦乐队坐标服务 @ I. @ 添加语音输出只是另一个倾听这些事件的服务 @ MPK3 @

进入了“3:”部分的政策执行

目前的验证是 @-BARBAR:}电子邮件看起来像是emails{,}日期被解析为date@.}但是关于商业规则 <?} "#出生日期必须至少是%18}几年前 *."{Q"Phone number 必须匹配所选区域}."}"}Notes字段不能包含 profanity=."}

部分 @3}将添加#:

  • 基于规则的 - 校验 “-” 计划中的声明政策
  • Crossó- 实地限制 “- " 如果国家是美国,, 电话必须是“10 位数 @"”
  • LLM- 辅助政策检查 使用这个模型来标出潜在问题@,,
  • 审计线索 “- 哪个政策触发了“ , 为什么失败” @, 用户接下来做了什么?

同样的原则... ...:... ...LLM建议...

继续阅读

完整源代码在 Mostlylucid.VoiceForm 在 repo. 中的项目

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.