feat: 重写默认提示词和工具调用指南,整合 21 个工具为完整操作手册
- DEFAULT_SYSTEM_PROMPT:从 10 行简略说明扩展为完整操作手册 包含:两层工具体系说明、21 个工具分类一览、7 步决策树、工作流程、7 条关键规则 - build_capability_guide:重构为 6 大分类(高德/天气/备忘录/定时任务/联网/基础) 每类含工具一览表、参数详解、使用提示和谨慎事项 - format_spec → format_spec_detail:参数显示改为逐行格式,标注必填/可选
This commit is contained in:
+83
-13
@@ -450,16 +450,86 @@ impl ChatHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_SYSTEM_PROMPT: &str = "You are a concise and helpful assistant replying in Chinese. \
|
||||
Keep replies practical and natural. \
|
||||
Unless the user asks for detail, keep most replies under 120 Chinese characters. \
|
||||
\
|
||||
可用的核心工具:query_capabilities(查看所有可用工具及优先级)、call_capability(按名调用工具)。\
|
||||
可使用 read_memories / write_memory 管理用户长期记忆,read_summaries 查看历史摘要。\
|
||||
\
|
||||
工具选择优先级(重要):\
|
||||
1. 🗺️ 旅游/路线/地点查询 → amap_* 系列(amap_poi_search, amap_route_plan, amap_travel_plan 等)\
|
||||
2. 🌤️ 天气查询 → query_weather\
|
||||
3. 🔍 以上都不匹配 → web_search(Tavily 联网搜索)\
|
||||
\
|
||||
调用工具前先用 query_capabilities 确认有哪些工具及其参数格式。";
|
||||
pub const DEFAULT_SYSTEM_PROMPT: &str = "\
|
||||
你是一个运行在 iAs 智能助手系统中的 AI 助手,通过微信与用户交流。你的回复应简洁、自然、实用,\
|
||||
除非用户明确要求详细说明,否则回复控制在 120 汉字以内。\
|
||||
\
|
||||
════════════════════════════════════════════════════════════\
|
||||
## 🔧 工具体系说明(核心)\
|
||||
\
|
||||
你拥有两层工具架构来访问外部能力:\
|
||||
\
|
||||
### 第一层:元工具(直接在你的 function calling 列表中)\
|
||||
| 工具名 | 用途 |\
|
||||
|--------|------|\
|
||||
| query_capabilities | 列出所有 21 个能力工具的详细说明、参数、使用示例 |\
|
||||
| call_capability | 按名称调用任意一个能力工具,传 JSON 参数 |\
|
||||
| read_memories | 读取当前用户的长期记忆(偏好、习惯、重要信息)|\
|
||||
| write_memory | 记录一条长期记忆(用户喜好、重要决定等)|\
|
||||
| delete_memory | 删除指定 id 的长期记忆 |\
|
||||
| update_memory | 更新指定 id 的长期记忆内容 |\
|
||||
| read_summaries | 查看历史会话摘要,了解之前的对话背景 |\
|
||||
\
|
||||
### 第二层:能力工具(通过 call_capability 调用)\
|
||||
共 21 个,分为 6 大类:\
|
||||
\
|
||||
🏙️ 高德地图系列(6个)— 出行/地点/路线/旅游一站式服务\
|
||||
amap_poi_search → 搜索地点(餐饮/景点/酒店/加油站等)\
|
||||
amap_geocode → 地址转坐标(如'天安门' → 116.397,39.908)\
|
||||
amap_reverse_geocode → 坐标转地址(如 116.397,39.908 → '北京市东城区...')\
|
||||
amap_route_plan → 路径规划(驾车/公交/步行/骑行/电动车)\
|
||||
amap_travel_plan → 智能旅游规划(自动搜景点+规划路线)\
|
||||
amap_map_link → 生成高德地图可视化链接(POI/路线展示)\
|
||||
\
|
||||
🌤️ 天气系列(3个)— 实时/预报/逐时\
|
||||
weather_now → 当前天气(温度/体感/风向/湿度/气压/能见度)\
|
||||
weather_forecast → 未来N天预报(高低温/白天夜间天气/紫外线)\
|
||||
weather_hourly → 未来逐小时预报(温度/天气/风力/降水概率)\
|
||||
\
|
||||
📝 备忘录系列(4个)— 个人便签管理\
|
||||
memos_list → 列出所有备忘录\
|
||||
memos_add → 添加备忘录\
|
||||
memos_get → 查看指定备忘录详情\
|
||||
memos_delete → 删除指定备忘录\
|
||||
\
|
||||
⏰ 定时任务系列(5个)— 周期执行的自动化脚本\
|
||||
scheduled_task_list → 列出所有定时任务及运行状态\
|
||||
scheduled_task_add → 添加定时任务(名称/用户/命令/间隔)\
|
||||
scheduled_task_update → 修改定时任务字段\
|
||||
scheduled_task_delete → 删除定时任务(系统任务不可删)\
|
||||
scheduled_task_toggle → 启用/禁用定时任务\
|
||||
\
|
||||
🌐 联网工具(2个)— 搜索与网页抓取\
|
||||
web_search → Tavily 联网搜索(含AI摘要/新闻/财经/多过滤)\
|
||||
fetch_page → 抓取网页并提取正文(自动过滤广告导航)\
|
||||
\
|
||||
🕐 基础工具(1个)\
|
||||
get_current_datetime → 获取当前北京时间\
|
||||
\
|
||||
════════════════════════════════════════════════════════════\
|
||||
## 🎯 工具选择决策树(每次必看)\
|
||||
\
|
||||
收到用户请求后,按以下顺序判断:\
|
||||
\
|
||||
1. 📍 涉及地点/路线/旅游/导航?\
|
||||
→ 高德地图系列。先用 amap_geocode 转地址为坐标,再路由到对应工具\
|
||||
\n2. 🌤️ 查询天气?\
|
||||
→ weather_now(当前)/ weather_forecast(未来几天)/ weather_hourly(逐时)\
|
||||
\n3. 📝 需要记录/查看/删除备忘录?\
|
||||
→ memos_add / memos_list / memos_get / memos_delete\
|
||||
\n4. ⏰ 需要设置/管理定时任务?\
|
||||
→ scheduled_task_* 系列。先 list 确认现状,再 add/update/delete/toggle\
|
||||
\n5. 🌐 需要最新信息/事实查询/抓取网页?\
|
||||
→ web_search(搜索)/ fetch_page(抓取具体URL)\
|
||||
\n6. 🕐 需要当前时间?\
|
||||
→ get_current_datetime\
|
||||
\n7. 以上都不匹配\
|
||||
→ web_search 搜索相关信息\
|
||||
\n════════════════════════════════════════════════════════════\
|
||||
## 📐 工作流程\
|
||||
\n1. 收到用户消息后,首先调用 query_capabilities 获取最新工具列表(含参数格式)\
|
||||
2. 按决策树判断需要哪个工具\
|
||||
3. 用 call_capability 调用:参数格式为 {\"name\": \"工具名\", \"prompt\": \"{\\\"参数键\\\": \\\"参数值\\\"}\"}\n4. 获取结果后,整理成自然语言回复用户\
|
||||
\n提示:对复杂任务,可组合多个工具。例如:\
|
||||
'北京三日游' → amap_travel_plan\
|
||||
'明天去上海穿什么' → weather_forecast(location='上海')\n '附近有什么好吃的' → amap_poi_search(keywords='美食', ...)\n '帮我记下:下周二开会' → memos_add(content='下周二开会')\n '每天8点提醒我喝水' → scheduled_task_add(name='喝水提醒', command='echo 喝水', interval=86400)\n\n════════════════════════════════════════════════════════════\n## ⚠️ 关键规则\n\n1. 先查后调:调用任何能力工具前,先用 query_capabilities 确认参数格式\n2. 只能调一个:call_capability 一次只调用一个工具,不支持批量\n3. 坐标格式:高德地图的坐标参数格式为'经度,纬度'(注意顺序)\n4. 系统任务保护:scheduled_task 中标记为 [系统] 的不可修改/删除/禁用\n5. 主动记忆:当用户透露偏好、习惯、重要信息时,主动用 write_memory 记录\n6. 回忆历史:对话开始时可调用 read_summaries 了解历史背景\n7. 回复简洁:工具返回的原始数据用自然语言概括,不要逐字复述\n\n你是一个乐于助人、主动思考的助手。在给出最终答案前,先想清楚是否需要调用工具。\n";
|
||||
|
||||
+122
-33
@@ -300,69 +300,158 @@ pub fn is_builtin(name: &str) -> bool {
|
||||
/// 返回给 LLM 的工具列表 + 使用建议
|
||||
pub fn build_capability_guide(specs: &[SkillSpec]) -> String {
|
||||
let mut lines = vec![
|
||||
"📋 可用工具及调用优先级指南:".to_string(),
|
||||
"📋 iAs 能力工具全览(共 {} 个):".to_string(),
|
||||
String::new(),
|
||||
"调用方式:call_capability({ name: \"工具名\", prompt: \"{...参数...}\" })".to_string(),
|
||||
"提示:先查看参数格式,再构造调用。所有参数按下面列出的格式传递。".to_string(),
|
||||
String::new(),
|
||||
"## 🗺️ 高德地图工具(amap_*)— 旅游、路线、地点查询优先使用:".to_string(),
|
||||
];
|
||||
|
||||
// 先列出 amap 工具
|
||||
// ════════════════════════════════════════
|
||||
// 分类 1: 高德地图
|
||||
// ════════════════════════════════════════
|
||||
let amap_specs: Vec<&SkillSpec> = specs.iter().filter(|s| s.name.starts_with("amap_")).collect();
|
||||
if amap_specs.is_empty() {
|
||||
lines.push(" (未配置高德 API Key,暂不可用)".to_string());
|
||||
lines.push("## 🗺️ 高德地图(未配置 API Key,暂不可用)".to_string());
|
||||
} else {
|
||||
lines.push("## 🗺️ 高德地图 — 出行/路线/地点/旅游一站式服务".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 📍 amap_geocode → 地址 → 坐标(如:address='天安门', city='北京')".to_string());
|
||||
lines.push(" 📍 amap_reverse_geocode → 坐标 → 地址(如:location='116.397,39.908')".to_string());
|
||||
lines.push(" 🔍 amap_poi_search → 搜索地点(如:keywords='咖啡厅', city='上海', radius=1000)".to_string());
|
||||
lines.push(" 🚗 amap_route_plan → 路径规划(origin/destination 为坐标,type 可选 driving/walking/riding/electrobike/transit)".to_string());
|
||||
lines.push(" 🎯 amap_travel_plan → 智能旅游规划(city 城市名, interests 兴趣词数组, route_type 路线类型)".to_string());
|
||||
lines.push(" 🖼️ amap_map_link → 生成地图可视化链接".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 💡 使用提示:旅游/路径规划前,先用 amap_geocode 把地名转坐标".to_string());
|
||||
for spec in &amap_specs {
|
||||
format_spec(&mut lines, spec);
|
||||
format_spec_detail(&mut lines, spec);
|
||||
}
|
||||
}
|
||||
lines.push(String::new());
|
||||
lines.push(" ▸ 旅游规划、路径规划、地点/周边搜索、地理编码 → 优先使用 amap_* 系列工具".to_string());
|
||||
|
||||
lines.push(String::new());
|
||||
lines.push("## 🌤️ 天气工具 — 天气相关查询:".to_string());
|
||||
// ════════════════════════════════════════
|
||||
// 分类 2: 天气
|
||||
// ════════════════════════════════════════
|
||||
lines.push("".to_string());
|
||||
lines.push("## 🌤️ 天气 — 实时/预报/逐时".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" ☀️ weather_now → 实时天气(location='北京')".to_string());
|
||||
lines.push(" 📅 weather_forecast → 未来N天预报(location='上海', days=7)".to_string());
|
||||
lines.push(" 🕐 weather_hourly → 逐小时预报(location='深圳', hours=48)".to_string());
|
||||
for spec in specs.iter().filter(|s| s.name.starts_with("weather_")) {
|
||||
format_spec(&mut lines, spec);
|
||||
}
|
||||
lines.push(String::new());
|
||||
lines.push(" ▸ 实时天气 → weather_now | 每日预报 → weather_forecast | 逐时预报 → weather_hourly".to_string());
|
||||
|
||||
lines.push(String::new());
|
||||
lines.push("## 🔍 其他工具:".to_string());
|
||||
for spec in specs.iter().filter(|s| !s.name.starts_with("amap_") && !s.name.starts_with("weather_")) {
|
||||
format_spec(&mut lines, spec);
|
||||
format_spec_detail(&mut lines, spec);
|
||||
}
|
||||
|
||||
lines.push(String::new());
|
||||
lines.push("## ⚡ 工具选择优先级:".to_string());
|
||||
lines.push(" 1. 旅游/路线/地点/地址查询 → amap_* 系列".to_string());
|
||||
lines.push(" 2. 天气查询 → weather_now / weather_forecast / weather_hourly".to_string());
|
||||
lines.push(" 3. 联网搜索/网页抓取 → web_search / fetch_page".to_string());
|
||||
lines.push(" 4. 以上都不匹配的需求 → web_search 搜索最新信息".to_string());
|
||||
lines.push(String::new());
|
||||
lines.push("📌 注意:每次调用工具前请确认它确实是当前最合适的工具。".to_string());
|
||||
// ════════════════════════════════════════
|
||||
// 分类 3: 备忘录
|
||||
// ════════════════════════════════════════
|
||||
lines.push("".to_string());
|
||||
lines.push("## 📝 备忘录 — 个人便签管理".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 📋 memos_list → 查看所有备忘录".to_string());
|
||||
lines.push(" ➕ memos_add → 添加(content='明天下午2点开会')".to_string());
|
||||
lines.push(" 🔍 memos_get → 查看详情(id=1)".to_string());
|
||||
lines.push(" 🗑️ memos_delete → 删除(id=1)".to_string());
|
||||
for spec in specs.iter().filter(|s| s.name.starts_with("memos_")) {
|
||||
format_spec_detail(&mut lines, spec);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════
|
||||
// 分类 4: 定时任务
|
||||
// ════════════════════════════════════════
|
||||
lines.push("".to_string());
|
||||
lines.push("## ⏰ 定时任务 — 周期执行的自动化脚本".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 📋 scheduled_task_list → 列出所有任务及状态(系统任务标记 [系统])".to_string());
|
||||
lines.push(" ➕ scheduled_task_add → 添加(name/command/interval 必填,如: 每天早上8点发送天气)".to_string());
|
||||
lines.push(" ✏️ scheduled_task_update → 修改字段(id 必填,只改传入的字段)".to_string());
|
||||
lines.push(" 🗑️ scheduled_task_delete → 删除(系统任务不可删)".to_string());
|
||||
lines.push(" 🔄 scheduled_task_toggle → 启用/禁用切换".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 💡 使用提示:添加定时任务前先 list 查看现有任务,避免重复".to_string());
|
||||
lines.push(" ⚠️ 系统任务(标记 [系统])不可修改、删除或切换状态".to_string());
|
||||
for spec in specs.iter().filter(|s| s.name.starts_with("scheduled_")) {
|
||||
format_spec_detail(&mut lines, spec);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════
|
||||
// 分类 5: 联网
|
||||
// ════════════════════════════════════════
|
||||
lines.push("".to_string());
|
||||
lines.push("## 🌐 联网工具 — 搜索与网页抓取".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 🔍 web_search → Tavily 联网搜索(支持 AI 摘要/新闻/财经/国家过滤/时间范围)".to_string());
|
||||
lines.push(" 📄 fetch_page → 抓取网页并提取正文(自动过滤广告/导航/页脚)".to_string());
|
||||
for spec in specs.iter().filter(|s| s.name == "web_search" || s.name == "fetch_page") {
|
||||
format_spec_detail(&mut lines, spec);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════
|
||||
// 分类 6: 基础
|
||||
// ════════════════════════════════════════
|
||||
lines.push("".to_string());
|
||||
lines.push("## 🕐 基础工具".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 🕐 get_current_datetime → 获取当前北京时间(无参数)".to_string());
|
||||
for spec in specs.iter().filter(|s| s.name == "get_current_datetime") {
|
||||
format_spec_detail(&mut lines, spec);
|
||||
}
|
||||
|
||||
lines.push("".to_string());
|
||||
lines.push("═══════════════════════════════════════════════════".to_string());
|
||||
lines.push("## ⚡ 工具选择优先级(必读)".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push(" 1. 📍 地点/路线/旅游/导航 → amap_* 系列".to_string());
|
||||
lines.push(" 2. 🌤️ 天气 → weather_now / weather_forecast / weather_hourly".to_string());
|
||||
lines.push(" 3. 📝 备忘录 → memos_* 系列".to_string());
|
||||
lines.push(" 4. ⏰ 定时任务 → scheduled_task_* 系列".to_string());
|
||||
lines.push(" 5. 🌐 最新信息/网页 → web_search / fetch_page".to_string());
|
||||
lines.push(" 6. 🕐 当前时间 → get_current_datetime".to_string());
|
||||
lines.push(" 7. 以上都不匹配 → web_search 搜索相关信息".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push("📌 组合示例:".to_string());
|
||||
lines.push(" • '北京三日游怎么安排' → amap_travel_plan(city='北京')".to_string());
|
||||
lines.push(" • '明天去杭州穿什么' → weather_forecast(location='杭州', days=1)".to_string());
|
||||
lines.push(" • '附近有什么好吃的' → amap_poi_search(keywords='美食', ...)".to_string());
|
||||
lines.push(" • '帮我记下下周二开会' → memos_add(content='下周二开会')".to_string());
|
||||
lines.push(" • '每天8点推送天气预报' → scheduled_task_add(name='天气推送', ...)".to_string());
|
||||
lines.push("".to_string());
|
||||
lines.push("📌 每次调用前确认参数格式正确,坐标格式为'经度,纬度'".to_string());
|
||||
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
fn format_spec(lines: &mut Vec<String>, spec: &SkillSpec) {
|
||||
fn format_spec_detail(lines: &mut Vec<String>, spec: &SkillSpec) {
|
||||
let risk = if spec.risk_level == crate::tools::types::RiskLevel::High {
|
||||
" ⚠️需确认"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
lines.push(format!(
|
||||
"\n🔹 {} {} — {}",
|
||||
spec.name, risk, spec.description
|
||||
"\n🔹 {} ({}){}",
|
||||
spec.name, spec.timeout_secs, risk
|
||||
));
|
||||
lines.push(format!(" 描述: {}", spec.description));
|
||||
if !spec
|
||||
.parameters
|
||||
.get("properties")
|
||||
.and_then(|v| v.as_object())
|
||||
.is_none_or(|o| o.is_empty())
|
||||
{
|
||||
lines.push(format!(
|
||||
" 参数: {}",
|
||||
serde_json::to_string(&spec.parameters).unwrap_or_default()
|
||||
));
|
||||
// 精简参数显示
|
||||
if let Some(props) = spec.parameters.get("properties").and_then(|v| v.as_object()) {
|
||||
let required: Vec<&str> = spec
|
||||
.parameters
|
||||
.get("required")
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|arr| arr.iter().filter_map(|v| v.as_str()).collect())
|
||||
.unwrap_or_default();
|
||||
for (name, info) in props {
|
||||
let desc = info.get("description").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let req = if required.contains(&name.as_str()) { "*必填" } else { "可选" };
|
||||
lines.push(format!(" - {} ({}) {}", name, req, desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user