昨天我們完成了歷史會議記錄的載入與管理功能,但是當使用者的指令不夠明確時,系統沒辦法主動確認意圖,以及使用者無法針對已完成的會議記錄進行補充提問,因為它缺乏「對話脈絡」的概念。
因此今天的目標是建立智慧澄清對話機制,讓 AI 在指令不明確時主動向使用者確認意圖,並且實作會議脈絡問答功能,允許使用者針對歷史會議進行後續的補充提問。
這個功能的核心是讓 AI 「記住」我們正在談論哪一場會議。當我們在介面上點選了一筆歷史紀錄,系統就必須將該紀錄的完整內容載入到一個暫存的「對話狀態」中,接下來的所有問答都將圍繞這個狀態展開。
meeting_history.py
新增脈絡生成功能為了讓 AI 能快速理解一場會議的重點,我在 meeting_history.py
中新增了一個輔助函式 create_context_summary
。它的作用是將一筆完整的會議紀錄,打包成一份結構清晰、適合 AI 閱讀的文字摘要。
在原有的程式碼裡的,新增以下兩個函式
# 儲存完整會議記錄以供脈絡使用
def get_full_record_by_session(self, session_id: str) -> dict | None:
"""根據 Session ID 取得最完整的單筆紀錄"""
records = self.get_all_records()
for record in records:
if record.get("session_id") == session_id:
return record
return None
# 建立脈絡摘要
def create_context_summary(self, session_id: str) -> dict | None:
"""為指定的 session_id 建立 AI 可讀的上下文摘要"""
record = self.get_full_record_by_session(session_id)
if not record:
return None
# 將紀錄打包成一個字典格式的 context
context = {
"session_id": session_id,
"timestamp": record.get("timestamp", "未知"),
"project_name": record.get("project_name", "未指定"),
"meeting_type": record.get("meeting_type", "未分類"),
"summary": record.get("summary", "無摘要"),
"tasks": record.get("tasks", "無任務"),
"participants": record.get("participants", []),
"deadline_date": record.get("deadline_date", "未設定")
}
return context
create_context_summary
:它會接收一個 session_id
,並找到對應的完整會議紀錄,然後將其中最重要的資訊(像是專案名稱、摘要、行動任務等)整理成一個乾淨的 dict
物件,這個物件就是我們接下來要餵給 AI 的「對話脈絡」。app.py
串接脈絡問答流程接下來,我在 app.py
中進行了較大幅度的修改,以支援新的問答介面。
app.py
中新增與修改的關鍵內容
# 新增一個專門用於上下文問答的 Prompt
def build_context_qa_prompt(context):
return f"""你是一個精確的會議問答助理。你的任務是根據下方提供的「會議脈絡」,準確回答使用者的提問。
[會議脈絡]
- 專案名稱:{context.get('project_name')}
- 會議類型:{context.get('meeting_type')}
- 會議時間:{context.get('timestamp')}
- 參與者:{', '.join(context.get('participants')) if context.get('participants') else '未記錄'}
- 完成期限:{context.get('deadline_date')}
[會議摘要]
{context.get('summary')}
[行動任務]
{context.get('tasks')}
[你的規則]
1. 嚴格根據上方提供的「會議脈絡」、「摘要」和「任務」來回答問題。
2. 絕對不可以編造或提供脈絡以外的資訊。
3. 如果問題的答案在脈絡中找不到,請明確回答「根據目前提供的會議內容,我無法回答這個問題。」
4. 回答盡量簡潔、直接。
"""
# 新增一個專門處理上下文問答的 API 呼叫函式
def answer_with_context(question, context):
system_prompt = build_context_qa_prompt(context)
return call_lm_studio_api(system_prompt, question, temperature=0.3)
# ...
# 處理歷史會議問答的主要邏輯
def process_history_qa(question: str, context_state: dict, chat_history: list):
# ... (省略錯誤處理)
try:
# 呼叫新的問答函式
answer = answer_with_context(question, context_state)
# ... (處理 API 回傳結果)
bot_message = answer.get("content", "抱歉,我無法處理您的請求。")
except Exception as e:
# ... (錯誤處理)
chat_history.append((question, bot_message))
return "", chat_history
# 載入歷史會議紀錄的函式
def load_history_record(evt: gr.SelectData):
try:
row_index = evt.index[^0]
# ... (從 history_manager 取得紀錄)
record = all_records[row_index]
session_id = record.get("session_id")
# 使用剛才建立的函式來生成上下文
context_summary = history_manager.create_context_summary(session_id)
# ... (產生要在介面上顯示的 Markdown 內容)
# 建立一個初始對話,引導使用者開始提問
initial_chat = [
(None, f"已為您載入 {record.get('project_name', '該')} 會議的紀錄,請問有什麼想了解的嗎?")
]
# 將上下文存入 gr.State,並更新對話視窗
return output_markdown, row_index, context_summary, initial_chat
except Exception as e:
# ... (錯誤處理)
# ... (Gradio 介面佈局)
# 將 UI 事件與後端函式綁定
history_table.select(
fn=load_history_record,
inputs=None,
outputs=[history_output, selected_record_index, context_state, history_qa_chatbot]
)
history_qa_submit.click(
fn=process_history_qa,
inputs=[history_qa_input, context_state, history_qa_chatbot],
outputs=[history_qa_input, history_qa_chatbot]
)
# ...
build_context_qa_prompt
:我設計了一個新的 Prompt,明確指示 AI 扮演「會議問答助理」,並將會議的詳細資料作為上下文提供給它,同時設立嚴格規則,防止 AI 亂答。load_history_record
:這個函式與「歷史會議記錄」表格的 select
事件綁定。當使用者點選一筆紀錄時,它會觸發,並呼叫 history_manager.create_context_summary
來準備好「對話脈絡」。這個脈絡被儲存在一個名為 context_state
的 gr.State
元件中,它就像一個隱藏的記憶體,專門存放當前對話的上下文。process_history_qa
:當使用者在歷史問答框中輸入問題並送出時,此函式會被觸發。它會從 context_state
中讀取先前儲存的會議脈絡,連同使用者的問題一起傳遞給 answer_with_context
函式,最後將 AI 的回答更新到對話視窗上。這個機制改變了 AI 處理任務的流程,從「接收指令 → 執行」變成了「接收指令 → 理解與確認 → 執行」。
要讓 AI 學會「提問」,關鍵在於要設計一個能夠分析指令清晰度的 Prompt。
在 app.py
中新增意圖分析 Prompt
def build_intent_analysis_prompt():
return """你是一個專業的指令分析專家。你的任務是分析使用者的會議處理指令,判斷意圖是否明確,並決定是否需要進一步澄清。
[指令分析標準]
1. **明確指令的特徵**:
- 明確指出要執行的動作(摘要、任務提取、參與者辨識等)
- 提及需要特別注意的重點(時間、人員、專案等)
- 指令完整且無歧義
2. **需要澄清的情況**:
- 指令過於簡短或模糊(如「處理一下」、「分析」)
- 缺少關鍵資訊(如未說明要提取什麼)
- 包含多個動作但未明確優先順序
- 使用模糊的詞彙(如「大概」、「可能」、「差不多」)
[分析步驟]
1. **識別動作**:使用者想要執行什麼動作
2. **評估完整性**:執行該動作需要的資訊是否充足
3. **判斷明確度**:指令是否清晰無歧義
[輸出格式]
請嚴格按照以下 JSON 格式回傳:
如果指令明確,回傳:
{
"is_clear": true,
"intent": "使用者的明確意圖描述",
"actions": ["動作1", "動作2"],
"proceed": true
}
如果需要澄清,回傳:
{
"is_clear": false,
"unclear_points": ["不明確的地方1", "不明確的地方2"],
"clarification_question": "請問您希望我執行以下哪些動作?",
"suggestions": [
"選項1:生成會議摘要與提取任務",
"選項2:只提取行動任務",
"選項3:完整分析包含摘要、任務、參與者與時間"
],
"proceed": false
}"""
proceed
這個布林值欄位,程式邏輯可以輕易地判斷下一步該執行任務還是該提問。clarification_question
和 suggestions
則直接提供了與使用者互動所需的內容。app.py
的主處理流程我重構了 process_new_meeting
函式,將意圖分析作為第一道關卡
# 新增一個全域變數來管理澄清對話的狀態
clarification_context = {
"is_in_clarification": False,
"original_instruction": None,
"last_suggestions": []
}
def process_new_meeting(audio_filepath, command_text, chat_history, progress=gr.Progress(track_tqdm=True)):
global clarification_context
# ... (省略初步的輸入檢查)
# 如果目前不是在澄清模式中
if not clarification_context["is_in_clarification"]:
# 儲存原始指令
clarification_context["original_instruction"] = command_text
# 步驟 1: 進行意圖分析
intent_result = analyze_intent(command_text)
# 如果分析結果是清晰的 (proceed: true)
if intent_result.get("proceed", False):
# 直接執行會議處理流程
return execute_meeting_processing(audio_filepath, command_text, chat_history, progress)
# 如果分析結果是模糊的 (proceed: false)
else:
# 進入澄清模式
clarification_context["is_in_clarification"] = True
clarification_context["last_suggestions"] = intent_result.get("suggestions", [])
# 從 AI 的分析結果中取得問題和建議選項
clarification_msg = intent_result.get("clarification_question", "我不太確定您的意思,可以說得更詳細一點嗎?")
suggestions = intent_result.get("suggestions", [])
if suggestions:
clarification_msg += "\n\n您可以試著這樣說,或直接回覆數字:\n"
for i, suggestion in enumerate(suggestions, 1):
clarification_msg += f"{i}. {suggestion}\n"
chat_history.append((command_text, clarification_msg))
return "", chat_history, gr.DataFrame(value=get_recent_records_for_display(limit=5))
# 如果目前已經在澄清模式中
else:
# 使用者的回覆 + 原始指令 = 完整的指令
mapped_instruction = map_option_to_instruction(command_text, clarification_context["last_suggestions"])
full_instruction = f"{clarification_context['original_instruction']},補充說明:{mapped_instruction}"
# 步驟 2: 再次進行意圖分析
intent_result = analyze_intent(full_instruction)
# 如果這次指令清晰了
if intent_result.get("proceed", False):
# 結束澄清模式並執行任務
clarification_context["is_in_clarification"] = False
return execute_meeting_processing(clarification_context.get("audio_filepath"), full_instruction, chat_history, progress)
# 如果指令還是不清楚
else:
# 繼續提問... (邏輯同上)
dict
clarification_context
來作為澄清模式的狀態管理器,記錄當前是否在提問、以及原始的指令是什麼。process_new_meeting
會先呼叫 analyze_intent
。"proceed"
是 false
,系統就進入澄清模式。它會將 AI 生成的 clarification_question
和 suggestions
顯示在聊天視窗,然後等待使用者回覆。clarification_context["is_in_clarification"]
是 True
,程式會進入 else
區塊,將使用者的補充說明與原始指令結合,再次進行意圖分析。這個過程會一直循環,直到 AI 認為指令足夠清晰為止。現在來測試新實作的功能。
python app.py
測試模糊指令:
指令:幫我處理一下
指令:3
測試明確指令:
載入歷史會議:
測試提問:
提問:這個會議主要在討論什麼事情?
提問:這場會議有誰出席?
提問:你可以更具體說明任務1該怎麼做嗎?
✅ 完成項目
build_context_qa_prompt
,確保 AI 回答的準確性build_intent_analysis_prompt
意圖分析專用 Prompt,作為澄清機制的判斷核心終於打破了「人說,AI 做」的單向模式,我成功賦予了 AI 「提問」與「記憶」的能力,整個系統從一個被動的執行工具,轉變為一個能與使用者進行有效溝通的「智慧助理」。
我體會到好的互動體驗來自於對「不確定性」的管理,現在透過「意圖分析 → 澄清 → 執行」這個新流程,可以將不確定性轉化為一個確認的機會,不僅大幅提升了任務執行的成功率,也讓使用者感覺 AI 變得更「聰明」、更「體貼」了。
同時,脈絡問答功能的加入,也讓儲存下來的會議記錄不再是冰冷的文字,而是一份可以隨時查閱、探勘的動態知識庫,極大地提升了實用的價值。
🎯 明天計劃
強化對話體驗,實作多輪澄清對話、增加明確的脈絡視覺提示,並精煉核心 Prompt,讓 AI 的理解與互動能力更上一層樓。