feat: 发给无头 Claude 的需求统一包一层「一次性完成」自动化前置说明
无头 claude -p 单次运行没有多轮兜底,模型中途提问/给半成品这一轮就废了。新增 coding_agent::autonomous_prompt(task):把真实需求包进目标驱动(/goal 式)的自动化指令—— 要求先定目标与完成标准、自主连续执行到彻底完成、不提问、不给计划/半成品、长任务也在本次跑完、 只回最终结果。语音 Agent 改用它构造 prompt。 验证:autonomous_prompt 单测过 / cargo check 0 error
This commit is contained in:
1 parent
e9e7ba50c4
commit
ff918ece31
2 files changed
+43
-3
No files matched your search
@@ -27,6 +27,26 @@ pub use args::{build_claude_args, CodingAgentPermissionMode, CodingAgentRequest}
|
||||
pub use detect::McpServerStatus;
|
||||
pub use stream::{parse_stream_json_line, CodingAgentEvent};
|
||||
|
||||
/// 无头 Claude 的「自动化前置说明」。
|
||||
///
|
||||
/// 无头 `claude -p` 是单次运行、没有多轮对话兜底:模型若中途提问、只给计划 / 半成品,
|
||||
/// 这一轮就废了。所以在把用户的真实需求交给它之前,统一包一层目标驱动(/goal 式)的
|
||||
/// 自动化指令,要求它一口气把任务彻底做完、只回最终结果。所有走 [`run_claude_agent`]
|
||||
/// 的「让 Claude 干活」入口都应该用它来构造 prompt。
|
||||
pub fn autonomous_prompt(task: &str) -> String {
|
||||
format!(
|
||||
"【自动化任务 · 一次性完成】这是一次无人值守的单次无头运行,没有多轮对话机会,\
|
||||
你无法事后追问或补充。请把下面的需求当成一个必须在本次运行内彻底达成的目标(等价于先 /goal \
|
||||
设定目标与完成标准,再自主执行直到达成):\n\
|
||||
- 先想清楚目标和「完成」的判定标准,再开始动手;\n\
|
||||
- 自主、连续地一口气执行到完全完成,不要中途停下来提问或等待确认;遇到歧义按最合理的方式继续;\n\
|
||||
- 不要只给计划、思路或半成品,也不要留「后续步骤」给别人——要交付最终可用的结果;\n\
|
||||
- 任务较长也要想办法在这一次运行内拆解并跑完;\n\
|
||||
- 全部完成后,只输出最终结果本身,不要解释过程、不要前后缀、不要引号。\n\n\
|
||||
需求:\n{task}"
|
||||
)
|
||||
}
|
||||
|
||||
/// 运行器把事件投递到这个 sink(coordinator / 命令层再转成 Tauri event)。
|
||||
pub type CodingAgentEventSink = tokio::sync::mpsc::UnboundedSender<CodingAgentEvent>;
|
||||
|
||||
@@ -242,3 +262,24 @@ pub async fn run_claude_agent(
|
||||
|
||||
outcome
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn autonomous_prompt_wraps_task_with_oneshot_directive() {
|
||||
let p = autonomous_prompt("把这段话翻译成英文:你好");
|
||||
// 原始需求必须原样带上。
|
||||
assert!(p.contains("把这段话翻译成英文:你好"));
|
||||
// 必含「一次性完成 / 单次无头运行 / 不要提问 / 只输出最终结果」这些核心约束。
|
||||
assert!(p.contains("一次性完成"));
|
||||
assert!(p.contains("无头"));
|
||||
assert!(p.contains("不要中途停下来提问"));
|
||||
assert!(p.contains("只输出最终结果"));
|
||||
// 需求要排在自动化说明之后(前置说明在前)。
|
||||
let directive_idx = p.find("自动化任务").unwrap();
|
||||
let task_idx = p.find("把这段话翻译成英文").unwrap();
|
||||
assert!(directive_idx < task_idx, "自动化前置说明必须在需求之前");
|
||||
}
|
||||
}
|
||||
@@ -602,9 +602,8 @@ async fn run_voice_agent_transcript(
|
||||
);
|
||||
|
||||
let prefs = inner.prefs.get();
|
||||
let prompt = format!(
|
||||
"下面是用户的语音指令,请直接完成它并只返回结果文本(不要解释、不要前后缀、不要引号):\n\n{transcript}"
|
||||
);
|
||||
// 无头单次运行没有多轮兜底:包一层目标驱动的自动化前置说明,逼 Claude 一口气做完。
|
||||
let prompt = crate::coding_agent::autonomous_prompt(&transcript);
|
||||
let mut req = crate::coding_agent::CodingAgentRequest::new("voice-agent", prompt);
|
||||
req.model = prefs
|
||||
.coding_agent_model
|
||||
|
||||
Reference in new issue
Block a user