iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0

目標先講清楚:
把 Day 2 的即時語音助理升級為「能看圖、會看鏡頭」的 Vision Agent。
Input:語音/文字/圖片/視訊;Output:文字/語音。
仍然要能即時互動(real-time)


今日改動總覽(在 Day 2 基礎上)

  • 維持原本語音管線(Deepgram STT → GPT → Cartesia TTS),再加兩件事

    1. 圖片資料流處理(byte stream handler)
    2. 視訊軌道處理(WebRTC Track,擷取最新幀)
  • 整合對話生命週期:在使用者說完一句話(turn completed)時,自動把當下鏡頭畫面附加到該輪訊息,讓 LLM 能「同時看與聽」。


三段式落地:從 Agent → Session → Room

助手代理定義

class Assistant(Agent):
    def __init__(self) -> None:
        super().__init__(instructions="You are a helpful voice AI assistant.")
  • 繼承 LiveKit Agent
  • 定義助理角色與行為說明(instructions)

主要會話邏輯(語音處理鏈路不變)

async def entrypoint(ctx: agents.JobContext):
    session = AgentSession(...)

語音處理鏈路

  1. 語音輸入deepgram.STT(Nova-3,多語)
  2. 語言理解Azure OpenAI GPT-4.1-mini
  3. 語音輸出cartesia.TTS(Sonic-2)

智能語音控制

vad = ctx.proc.userdata["vad"]          # 語音活動偵測
turn_detection = MultilingualModel()    # 多語言轉場偵測
  • 精準判斷使用者何時開始/停止說話
  • 多語環境下轉場更穩定

房間配置與啟動

await session.start(
    room=ctx.room,
    agent=Assistant(),
    room_input_options=RoomInputOptions(
        noise_cancellation=noise_cancellation.BVC(),
    ),
)
  • 啟動 LiveKit 房間會話
  • 開啟 BVC(Bidirectional Voice Cancellation)噪音消除
  • 注意:BVC 僅適用於 LiveKit Cloud

應用程式啟動

cli.run_app(WorkerOptions(
    entrypoint_fnc=entrypoint, 
    initialize_process_timeout=60,
    prewarm_fnc=prewarm
))
  • 使用 LiveKit CLI 運行
  • 初始化逾時 60 秒
  • prewarm 預熱關鍵元件,加速啟動

深入理解 LiveKit 房間機制

room=ctx.room 是一個 rtc.Room,由 JobContext.connect() 連上 LiveKit 伺服器,負責完整 WebRTC 連線與媒體傳輸。LiveKit agents 在底層提供了自動對話循環,讓互動自然順暢。

房間機制示意


升級版本:加入「視覺」能力

在不動既有語音管線的前提下,透過擴充 Agent 行為加入圖片與視訊:
(Livekit提供以下3種的固定function,去達成)

1) on_enter:註冊圖片資料流(byte stream handler)

async def on_enter(self):
    room = get_job_context().room

    # 接收前端上傳的圖片("images" 通道)
    def image_received_handler(reader, participant_identity):
        task = asyncio.create_task(
            self._image_received(reader, participant_identity)
        )
        self._tasks.append(task)
        task.add_done_callback(lambda t: self._tasks.remove(t))

    # 前端傳送示例:
    # await room.localParticipant.publishData(uint8Array, "images")
    room.register_byte_stream_handler("images", image_received_handler)

重點

  • on_enter固定生命週期方法:Agent 進房時自動觸發
  • 在此註冊接收圖片的處理器;圖片以分塊傳輸、後端重組後加入對話上下文

2) 監聽視訊軌道,建立串流並擷取最新幀

# 當有新視訊軌道被訂閱時觸發
@room.on("track_subscribed")
def on_track_subscribed(track: rtc.Track, publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
    if track.kind == rtc.TrackKind.KIND_VIDEO:
        self._create_video_stream(track)

重點

  • 這是 WebRTC Track 的事件機制,不需要用 byte stream
  • _create_video_stream(track) 內部持續讀取畫面,緩存到 self._latest_frame

3) 對話收束:把當下畫面附加到該輪訊息

async def on_user_turn_completed(self, turn_ctx: ChatContext, new_message: dict) -> None:
    # 如果有最新視訊幀,把它加到使用者該輪訊息內容中
    if self._latest_frame:
        if isinstance(new_message.content, list):
            new_message.content.append(ImageContent(image=self._latest_frame))
        else:
            new_message.content = [new_message.content, ImageContent(image=self._latest_frame)]
        self._latest_frame = None

效果

  • 使用者說話結束(VAD 判定)→ 自動把當下鏡頭畫面一併送進 LLM
  • 助理就能根據「你剛才說的話 + 你鏡頭中的畫面」回覆

小結:今天我們完成了什麼?

  • 保持 Day 2 的即時語音體驗,新增:

    • 圖片上傳通道(byte stream handler)
    • 視訊軌處理(WebRTC Track,持續擷取最新幀)
    • 對話生命週期整合(turn 完成時附加畫面)
  • 互動從「會聽、會說」升級為 「會聽、會說、也會看」


下一步(Day 4 預告)

Default(4/5)—— 將 Agent 邏輯替換為 LangGraph,把多步驟流程(工具呼叫、記憶、檢索等)圖形化與模組化,便於擴充與維運。


參考資源


上一篇
Day 2|使用 LiveKit 開始打造(2/5)
下一篇
Day 4|將langGraph接上Livekit(4/5)
系列文
從讀書筆記到可落地 AI:LangChain、LangSmith 與 Agent 工具 30 講4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言