近期AI热点009|LiveKit Agents 1.7:语音 Agent 开始有情绪,也开始处理隐私

主要信息源:LiveKit Agents 1.7.0 Release、Expressive Mode 官方文档与博客、PII Redaction 官方说明
关键词:LiveKit Agents、语音 Agent、Expressive Mode、PII Redaction、TTS、STT、隐私脱敏、Python

官方资料(建议先打开)

2026 年 8 月 20 日,LiveKit 发布 Agents 1.7.0。这个版本有两项看起来不太相关、实际都在解决生产问题的更新:语音可以根据对话内容改变情绪和节奏,进入日志与录音的姓名、电话、地址等个人信息则可以在保存前被脱敏。

前者叫 Expressive Mode,解决的是“回答正确,但听起来像客服录音”;后者叫 PII Redaction,解决的是“为了排查 Agent 问题,结果把用户隐私完整保存了下来”。

它们并不是两个打开即用的本地开关。Expressive Mode 对语音管线和 TTS Provider 有要求,PII Redaction 则属于 LiveKit Cloud 的 Agent Observability 功能。下面从普通开发者真正会遇到的问题开始拆解。

先看结论:哪些能直接用,哪些有条件

功能使用位置必要条件主要限制
Expressive ModeAgentSessionSTT–LLM–TTS 管线、LiveKit Inference、受支持的 TTS不适用于 Speech-to-Speech Realtime 模型
PII RedactionLiveKit Cloud 项目设置Agent Observability、Agents SDK 1.7.0不是开源 SDK 自带的本地脱敏器

截至官方文档发布时,Expressive Mode 支持的 TTS 包括:

  • Fish Audio s2.1-pro;
  • Inworld inworld-tts-2;
  • Cartesia Sonic 系列;
  • xAI tts-1,但不提供用于前端情绪显示的 lk.expression Mood。

如果换成不支持标记方言的 TTS,expressive=True 不会凭空给声音添加情绪,官方文档称该开关会保持不生效。

一条语音是怎样生成的

传统语音 Agent 通常由五个部分组成:

用户说话
   ↓
VAD:判断用户是否开始或停止说话
   ↓
STT:把音频转换成文字
   ↓
LLM:理解上下文并生成回答
   ↓
TTS:把回答转换成音频
   ↓
WebRTC:把音频实时传给用户

此外还要处理 Turn Detection 和 Interruption。VAD 只判断“有没有人在说话”,Turn Detection 还要判断“用户是不是说完了”;Interruption 则决定用户插话时,Agent 是否立即停止当前播报。

Expressive Mode 插入在 LLM 与 TTS 之间。它不是另起一个“情绪识别模型”给用户贴标签,而是把当前 TTS 支持的表达标记说明注入 LLM Prompt,让 LLM 根据完整对话,在回答中生成内联标记。

概念上,LLM 可能生成:

<expr type="expression" label="excited" />太好了,这次部署已经成功。
<expr type="sound" label="laughing" />日志终于不再报错了。

LiveKit 随后会:

  1. 把标记转换成当前 TTS Provider 能理解的方言;
  2. 修正常见的标记格式错误;
  3. 将多句话组成较大的合成块,保持一个 Turn 内的情绪连续;
  4. 把带标记文本送给 TTS;
  5. 从用户可见的 Transcript 中移除标记。

因此,聊天界面里看到的仍是干净文字,TTS 收到的却包含说话方式。这里的“情绪”首先是一种语音控制信号,不是对用户心理状态的医学或心理学判断。

用 Python 跑起来

官方 Quickstart 要求 Python 3.10 及以上,示例使用 uv 管理依赖。最省事的路径是先安装 LiveKit CLI,然后创建模板项目。

Windows 可以使用:

winget install LiveKit.LiveKitCLI
lk cloud auth
lk agent init my-voice-agent --template agent-starter-python
cd my-voice-agent
uv sync
lk agent dev

lk cloud auth 会打开浏览器,把 CLI 与 LiveKit Cloud 项目关联;lk agent init 会创建模板并生成包含项目凭证的 .env.local。这个文件不应提交到 Git 仓库。

创建完成后,在 Agent 文件的 AgentSession 中加入 expressive=True:

from dotenv import load_dotenv
from livekit import agents
from livekit.agents import (
    Agent,
    AgentServer,
    AgentSession,
    TurnHandlingOptions,
    inference,
)


load_dotenv(".env.local")


class Assistant(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions=(
                "你是一名语音技术支持助手。回答简短、准确。"
                "当用户遇到故障时保持平静,不要用过度兴奋的语气。"
            )
        )


server = AgentServer()


@server.rtc_session(agent_name="my-voice-agent")
async def run_agent(ctx: agents.JobContext):
    session = AgentSession(
        stt=inference.STT(
            model="deepgram/nova-3",
            language="multi",
        ),
        llm=inference.LLM(
            model="google/gemma-4-31b-it",
        ),
        tts=inference.TTS(
            model="inworld/inworld-tts-2",
            voice="Ashley",
        ),
        expressive=True,
        turn_handling=TurnHandlingOptions(
            turn_detection=inference.TurnDetector(),
        ),
    )

    await session.start(
        room=ctx.room,
        agent=Assistant(),
    )

    await session.generate_reply(
        instructions="向用户问好,并询问需要处理什么问题。"
    )


if __name__ == "__main__":
    agents.cli.run_app(server)

这段代码基于 LiveKit 1.7 官方用法整理。实际运行还需要有效的 LiveKit Cloud 项目凭证,以及所选 Inference 模型在当前账户和地区可用。

不想让 Agent 随便笑,可以限制表达范围

客服、医疗咨询和故障处理并不适合频繁出现笑声、叹息或口头停顿。Expressive Mode 可以传入配置,而不只是布尔值:

session = AgentSession(
    # stt、llm、tts 与前文相同
    expressive={
        "speech_steering": {
            "disfluencies": False,
            "nonverbal_sounds": {
                "laughing": False,
                "crying": False,
                "mouth_sounds": False,
            },
            "pace": "normal",
        }
    },
)

官方文档列出的可控非语言声音包括 Laughing、Breathing、Sighing、Crying、Vocalizing、Mouth Sounds 和 Reflex Sounds。具体能否合成,仍取决于 TTS Provider。

还可以通过 tts_instructions_append 补充规则,或用 tts_instructions_template 替换默认标记说明。生产环境不建议一开始就完全替换模板,因为一旦遗漏 Provider 的标记格式,可能导致标签被读出来,或者 TTS 忽略控制信号。

情绪标签能不能拿给前端使用

可以,但不能假设它是固定枚举。

LiveKit 在清理 Transcript 中的表达标记时,会把开头的表达信息作为 lk.expression 属性发布。前端可以据此改变头像颜色或动画。

问题在于,不同 Provider 的输出格式并不统一:有的使用有限的单词集合,有的返回自由文本,例如 soft, with genuine care。因此,代码不应直接写成:

if (expression === "happy") {
  // 只处理一个固定字符串,切换 Provider 后很容易失效
}

官方建议使用 Agents UI 中的 useAgentExpression Hook,把 Provider 的原始标签归一化成较稳定的 Mood。即便如此,前端也应该保留默认状态,避免遇到未知标签时界面报错。

情绪化 TTS 会增加多少延迟

官方没有给出一个可以适用于所有模型和网络环境的固定毫秒数。

Expressive Mode 会增加两类工作:LLM 需要输出额外标记,框架会把句子组成更大的 Chunk,再交给 TTS。LiveKit 官方博客表示,这种较大的合成块没有带来“有意义的延迟增加”,并提到其 Gemma 4 31B 配置可以达到亚秒级响应。但这是官方配置与体验结论,不能直接推导为所有 Provider、语言和地区都能稳定低于一秒。

真实端到端延迟至少由下面几部分组成:

用户停顿检测
+ STT 最终结果
+ LLM 首个有效文本块
+ 表达标记与句子分块
+ TTS 首段音频
+ 网络传输与客户端播放缓冲

测试时不要只记录“用户说完到 Agent 开口”的总时间,还应分别记录 STT、LLM 首 Token、TTS 首 Audio Frame 和完整 Turn 时长。建议用同一组录音做 A/B 测试:模型、语音、网络区域和提示词保持不变,只切换 expressive。

至少应记录:

session_id
expressive_enabled
stt_final_ms
llm_first_text_ms
tts_first_audio_ms
end_to_end_ms
interruption_success
provider
language

情绪更自然但首音频明显变慢,是否值得使用,要看业务:游戏 NPC 可以接受稍长的戏剧性停顿,电话客服通常更在意快速确认用户已经被听见。

PII Redaction 到底在哪里发生

PII 是 Personally Identifiable Information,即可以识别或关联个人的信息。语音 Agent 中常见的 PII 包括:

  • 姓名、生日和年龄;
  • 电话、邮箱和住址;
  • 用户名与密码;
  • 银行账户、银行卡号和 CVV;
  • IP 地址、证件号和地理坐标。

LiveKit 官方说明,1.7.0 的 PII Redaction 面向 LiveKit Cloud Agent Observability。开启路径是:

LiveKit Cloud
→ Project Settings
→ Observability
→ 开启 Agent Observability
→ 开启 PII Redaction
→ 选择需要脱敏的类别

它不是在 AgentSession 里写一个 pii_redaction=True,也不是把原始音频先写入 Observability 存储再异步修改。

官方描述的处理链路是:Agent 先把未脱敏的 Transcript、Recording 和观测数据发送到安全 Ingestion Service;该服务执行脱敏,再把最终结果写入 Agent Observability 存储。官方还称其 Runtime Stack 采用 Zero Data Retention 策略,而进入 Observability 的脱敏记录保留 30 天后自动删除。

这仍然意味着原始数据会在 Ingestion 处理阶段出现。对金融、医疗或其他受监管业务,不能只看到“脱敏”两个字就默认满足合规要求,还需要核对数据区域、处理协议、访问权限和自身适用的法规。

为什么音频不能只把几个词静音

文字脱敏相对直接:检测到手机号后,可以替换成类似 [phone_number] 的标记,同时保留周围语境。

音频更麻烦。用户可能把号码拆成几句话,中途纠正;不同 STT 的词级时间戳也并不总是准确。如果只静音估算出来的几百毫秒,很可能漏掉一个数字。

LiveKit 采用了更保守的策略:只要某个 Turn 检测到 PII,就从存储录音中移除整个 Turn,用柔和提示音代替原始语音。这样会损失更多录音内容,但比误保留半个卡号更安全。

此外,可能包含敏感信息的 Trace 和 Log 字段会被直接丢弃。这里也有一个工程提醒:应用自己的日志、第三方 APM、模型 Provider 日志和业务数据库不一定经过 LiveKit Observability 的脱敏链路,仍需分别治理。

41 类 PII 不等于零漏检

官方称目前支持 10 组、41 类 PII,并使用 LLM 结合对话上下文识别,而不是只靠正则表达式。这样可以处理口述拼写、跨 Turn 信息和中途纠正等情况。

但基于模型的识别仍存在误报和漏报:

  • “小王”可能是姓名,也可能是店铺简称;
  • 一串数字可能是订单号,也可能是银行卡号;
  • 用户使用方言、噪声环境或识别错误时,PII 可能没有进入正确 Transcript;
  • 业务特有编号不一定属于默认类别。

因此,生产环境还应遵循数据最小化原则:不需要录音就不要录音,不需要保存完整 Transcript 就缩短保留时间,不要把密码或 CVV 设计成语音 Agent 的必填输入。

客服、陪练和游戏 NPC 是否适合

场景Expressive ModePII Redaction需要特别注意
客服适合克制使用建议开启禁止在投诉或故障场景中过度兴奋
语言陪练比较适合涉及录音时建议开启情绪不能掩盖发音和语法反馈
游戏 NPC很适合视是否采集真实身份而定更关注角色一致性和响应延迟
医疗咨询谨慎强烈建议,并需额外合规评估不应把语气自然等同于专业判断
金融电话谨慎强烈建议不应通过语音收集密码和 CVV

Expressive Mode 的目标应该是“符合当前场景”,不是让每一句话都更有戏。真正好的语音 Agent 在用户焦虑时会降低语速,在好消息出现时适度明亮,也会在不确定时避免用过于肯定的语气。

这次更新给开发者的实际信号

语音 Agent 的竞争点正在从“能不能听懂和回答”转向两件更难的事:交互是否自然,运行数据是否可安全观察。

LiveKit 1.7 的实现也说明,二者都不是单模型能力。表达效果由 Prompt、LLM 标签、Provider 方言、分块策略和 TTS 共同决定;隐私保护则涉及 Transcript、音频、日志、Trace、存储和保留周期。只换一个更好的语音模型,解决不了整条链路的问题。

现阶段需要保留几个边界:

  • Expressive Mode 不适用于 Realtime Speech-to-Speech 模型;
  • 受支持的 TTS Provider 和表达能力并不完全一致;
  • 官方没有公布可通用于所有配置的额外延迟数据;
  • PII Redaction 是 LiveKit Cloud Observability 功能,不是本地 SDK 的通用脱敏库;
  • 41 类识别范围不代表可以保证零漏检;
  • LiveKit 的脱敏不会自动覆盖应用自己的数据库和第三方日志。

对于准备上线的团队,合理的实施顺序是:先建立可重复的语音延迟测试,再小范围开启 Expressive Mode;先盘点数据流向和保留位置,再决定 PII 类别和录音策略。声音更像人之后,数据治理反而更不能像 Demo。

参考资料

  • LiveKit Agents 1.7.0 Release,2026-08-20
    https://github.com/livekit/agents/releases/tag/livekit-agents%401.7.0
  • LiveKit Docs:Expressive Mode
    https://docs.livekit.io/agents/models/tts/expressive/
  • LiveKit:Making voice agents sound human with expressive mode,2026-08-12
    https://livekit.com/blog/making-voice-agents-sound-human-with-expressive-mode
  • LiveKit:Introducing PII Redaction for LiveKit Observability,2026-08-20
    https://livekit.com/blog/introducing-pii-redaction-for-livekit-observability
  • LiveKit Docs:Voice AI Quickstart
    https://docs.livekit.io/agents/start/voice-ai/
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐