fix: agent search uses smart_search for content queries
- Update system prompt to prioritize smart_search over find_file - Add source prefix ([OCR], [ASRX], [ASRX+OCR]) to exec_smart_search results - Users can now see chunk content with source indicators
This commit is contained in:
+13
-9
@@ -86,19 +86,23 @@ const SYSTEM_PROMPT: &str = r#"你是 Momentry 影片分析助手。回答用戶
|
|||||||
- 只有當多個搜尋工具都返回空、且問題明顯指向特定影片時,才問用戶
|
- 只有當多個搜尋工具都返回空、且問題明顯指向特定影片時,才問用戶
|
||||||
- 搜尋工具(find_file, list_files, smart_search, universal_search)的 file_uuid 參數可省略以搜尋全部
|
- 搜尋工具(find_file, list_files, smart_search, universal_search)的 file_uuid 參數可省略以搜尋全部
|
||||||
|
|
||||||
## 工具使用規則
|
## 工具使用規則(重要:優先使用 smart_search)
|
||||||
1. 人物問題優先使用 tkg_query
|
1. **內容/關鍵字問題優先使用 smart_search** — 可以找到影片內的具體文字內容(OCR、ASR)
|
||||||
2. 人物台詞/發言問題使用 identities_search(輸入人名→回傳台詞片段)
|
2. **如果 smart_search 找到結果,附帶顯示 chunk 文字內容**(包含 [OCR]、[ASRX] 標記)
|
||||||
3. 人物對話互動(誰跟誰說話)使用 tkg_query 的 speaker_interaction
|
3. find_file 僅用於搜尋片名,不適合搜尋內容關鍵字
|
||||||
4. 人物台詞內容使用 tkg_query 的 speaker_dialogue
|
4. 人物問題使用 tkg_query
|
||||||
5. 用文字反查人物使用 identity_text(輸入關鍵字→找出誰說/提到這段話)
|
5. 人物台詞/發言問題使用 identities_search(輸入人名→回傳台詞片段)
|
||||||
6. 語意/內容問題使用 smart_search 或 universal_search
|
6. 人物對話互動(誰跟誰說話)使用 tkg_query 的 speaker_interaction
|
||||||
7. 畫面分析使用 analyze_frame — 可以分析影片中的任何畫面內容(場景、人物表情、動作、物件等)
|
7. 人物台詞內容使用 tkg_query 的 speaker_dialogue
|
||||||
8. **可以同時呼叫多個工具,但需符合以下條件:**
|
8. 用文字反查人物使用 identity_text(輸入關鍵字→找出誰說/提到這段話)
|
||||||
|
9. 畫面分析使用 analyze_frame — 可以分析影片中的任何畫面內容(場景、人物表情、動作、物件等)
|
||||||
|
10. **可以同時呼叫多個工具,但需符合以下條件:**
|
||||||
- ✅ 查詢多部影片的相同資訊(如:3部影片的人物列表)
|
- ✅ 查詢多部影片的相同資訊(如:3部影片的人物列表)
|
||||||
- ✅ 需要組合多個來源的資訊才能回答(如:file_info + tkg_query)
|
- ✅ 需要組合多個來源的資訊才能回答(如:file_info + tkg_query)
|
||||||
- ❌ 不要為了「嘗試所有可能」而盲目並行呼叫
|
- ❌ 不要為了「嘗試所有可能」而盲目並行呼叫
|
||||||
- ❌ 如果單一工具已返回足夠答案,不需要額外呼叫
|
- ❌ 如果單一工具已返回足夠答案,不需要額外呼叫
|
||||||
|
- ❌ 如果 smart_search 已找到相關 chunk,不需要再呼叫 find_file
|
||||||
|
- ❌ 如果單一工具已返回足夠答案,不需要額外呼叫
|
||||||
|
|
||||||
## 回答規則
|
## 回答規則
|
||||||
- 回答長度依問題類型調整:
|
- 回答長度依問題類型調整:
|
||||||
|
|||||||
+71
-5
@@ -555,7 +555,7 @@ pub async fn exec_smart_search(
|
|||||||
|
|
||||||
let chunk_table = schema::table_name("chunk");
|
let chunk_table = schema::table_name("chunk");
|
||||||
let mut sql = format!(
|
let mut sql = format!(
|
||||||
"SELECT chunk_id, text_content, start_frame, end_frame, chunk_type \
|
"SELECT chunk_id, text_content, start_frame, end_frame, chunk_type, content \
|
||||||
FROM {} WHERE text_content ILIKE $1",
|
FROM {} WHERE text_content ILIKE $1",
|
||||||
chunk_table
|
chunk_table
|
||||||
);
|
);
|
||||||
@@ -566,21 +566,87 @@ pub async fn exec_smart_search(
|
|||||||
|
|
||||||
if let Some(fuid) = file_uuid {
|
if let Some(fuid) = file_uuid {
|
||||||
let like = format!("%{}%", query);
|
let like = format!("%{}%", query);
|
||||||
let rows: Vec<(String, Option<String>, i64, i64, String)> = sqlx::query_as(&sql)
|
let rows: Vec<(String, Option<String>, i64, i64, String, Option<serde_json::Value>)> = sqlx::query_as(&sql)
|
||||||
.bind(&like)
|
.bind(&like)
|
||||||
.bind(fuid)
|
.bind(fuid)
|
||||||
.fetch_all(pool)
|
.fetch_all(pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
Ok(serde_json::json!({"results": rows}).to_string())
|
|
||||||
|
let results: Vec<Vec<serde_json::Value>> = rows.into_iter().map(|(chunk_id, text_content, start_frame, end_frame, chunk_type, content)| {
|
||||||
|
let source_prefix = if let Some(ref content) = content {
|
||||||
|
let text = content.get("text").and_then(|t| t.as_str()).unwrap_or("");
|
||||||
|
let ocr_text = content.get("ocr_text").and_then(|t| t.as_str()).unwrap_or("");
|
||||||
|
|
||||||
|
let has_asrx = !text.trim().is_empty();
|
||||||
|
let has_ocr = !ocr_text.trim().is_empty();
|
||||||
|
|
||||||
|
if has_asrx && has_ocr {
|
||||||
|
"[ASRX+OCR] "
|
||||||
|
} else if has_asrx {
|
||||||
|
"[ASRX] "
|
||||||
|
} else if has_ocr {
|
||||||
|
"[OCR] "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
let prefixed_text = text_content.map(|t| format!("{}{}", source_prefix, t));
|
||||||
|
|
||||||
|
vec![
|
||||||
|
serde_json::json!(chunk_id),
|
||||||
|
serde_json::json!(prefixed_text),
|
||||||
|
serde_json::json!(start_frame),
|
||||||
|
serde_json::json!(end_frame),
|
||||||
|
serde_json::json!(chunk_type),
|
||||||
|
]
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
Ok(serde_json::json!({"results": results}).to_string())
|
||||||
} else {
|
} else {
|
||||||
let like = format!("%{}%", query);
|
let like = format!("%{}%", query);
|
||||||
let rows: Vec<(String, Option<String>, i64, i64, String)> = sqlx::query_as(&sql)
|
let rows: Vec<(String, Option<String>, i64, i64, String, Option<serde_json::Value>)> = sqlx::query_as(&sql)
|
||||||
.bind(&like)
|
.bind(&like)
|
||||||
.fetch_all(pool)
|
.fetch_all(pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
Ok(serde_json::json!({"results": rows}).to_string())
|
|
||||||
|
let results: Vec<Vec<serde_json::Value>> = rows.into_iter().map(|(chunk_id, text_content, start_frame, end_frame, chunk_type, content)| {
|
||||||
|
let source_prefix = if let Some(ref content) = content {
|
||||||
|
let text = content.get("text").and_then(|t| t.as_str()).unwrap_or("");
|
||||||
|
let ocr_text = content.get("ocr_text").and_then(|t| t.as_str()).unwrap_or("");
|
||||||
|
|
||||||
|
let has_asrx = !text.trim().is_empty();
|
||||||
|
let has_ocr = !ocr_text.trim().is_empty();
|
||||||
|
|
||||||
|
if has_asrx && has_ocr {
|
||||||
|
"[ASRX+OCR] "
|
||||||
|
} else if has_asrx {
|
||||||
|
"[ASRX] "
|
||||||
|
} else if has_ocr {
|
||||||
|
"[OCR] "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
let prefixed_text = text_content.map(|t| format!("{}{}", source_prefix, t));
|
||||||
|
|
||||||
|
vec![
|
||||||
|
serde_json::json!(chunk_id),
|
||||||
|
serde_json::json!(prefixed_text),
|
||||||
|
serde_json::json!(start_frame),
|
||||||
|
serde_json::json!(end_frame),
|
||||||
|
serde_json::json!(chunk_type),
|
||||||
|
]
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
Ok(serde_json::json!({"results": results}).to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user