fix(skills): inject skill list into system prompt for LLM awareness

Problem: Agent could not invoke appropriate skills when user asked about
financial reports because LLM didn't know which skills were available.

Root causes:
1. System prompt lacked available skill list
2. SkillManifest struct missing 'triggers' field
3. SKILL.md loader not parsing triggers list
4. "财报" keyword not matching "财务报告" trigger

Changes:
- Add triggers field to SkillManifest struct
- Parse triggers list from SKILL.md frontmatter
- Inject skill list into system prompt in kernel.rs
- Add "财报", "财务数据", "盈利", "营收" triggers to finance-tracker
- Add "财报分析" trigger to analytics-reporter
- Document fix in troubleshooting.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-24 15:39:18 +08:00
parent 504d5746aa
commit 9981a4674e
6 changed files with 256 additions and 13 deletions

View File

@@ -123,6 +123,47 @@ impl Kernel {
tools
}
/// Build a system prompt with skill information injected
fn build_system_prompt_with_skills(&self, base_prompt: Option<&String>) -> String {
// Get skill list synchronously (we're in sync context)
let skills = futures::executor::block_on(self.skills.list());
let mut prompt = base_prompt
.map(|p| p.clone())
.unwrap_or_else(|| "You are a helpful AI assistant.".to_string());
// Inject skill information
if !skills.is_empty() {
prompt.push_str("\n\n## Available Skills\n\n");
prompt.push_str("You have access to the following skills that can help with specific tasks. ");
prompt.push_str("Use the `execute_skill` tool with the skill_id to invoke them:\n\n");
for skill in skills {
prompt.push_str(&format!(
"- **{}**: {}",
skill.id.as_str(),
skill.description
));
// Add trigger words if available
if !skill.triggers.is_empty() {
prompt.push_str(&format!(
" (Triggers: {})",
skill.triggers.join(", ")
));
}
prompt.push('\n');
}
prompt.push_str("\n### When to use skills:\n");
prompt.push_str("- When the user's request matches a skill's trigger words\n");
prompt.push_str("- When you need specialized expertise for a task\n");
prompt.push_str("- When the task would benefit from a structured workflow\n");
}
prompt
}
/// Spawn a new agent
pub async fn spawn_agent(&self, config: AgentConfig) -> Result<AgentId> {
let id = config.id;
@@ -197,12 +238,9 @@ impl Kernel {
.with_max_tokens(agent_config.max_tokens.unwrap_or_else(|| self.config.max_tokens()))
.with_temperature(agent_config.temperature.unwrap_or_else(|| self.config.temperature()));
// Add system prompt if configured
let loop_runner = if let Some(ref prompt) = agent_config.system_prompt {
loop_runner.with_system_prompt(prompt)
} else {
loop_runner
};
// Build system prompt with skill information injected
let system_prompt = self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref());
let loop_runner = loop_runner.with_system_prompt(&system_prompt);
// Run the loop
let result = loop_runner.run(session_id, message).await?;
@@ -243,12 +281,9 @@ impl Kernel {
.with_max_tokens(agent_config.max_tokens.unwrap_or_else(|| self.config.max_tokens()))
.with_temperature(agent_config.temperature.unwrap_or_else(|| self.config.temperature()));
// Add system prompt if configured
let loop_runner = if let Some(ref prompt) = agent_config.system_prompt {
loop_runner.with_system_prompt(prompt)
} else {
loop_runner
};
// Build system prompt with skill information injected
let system_prompt = self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref());
let loop_runner = loop_runner.with_system_prompt(&system_prompt);
// Run with streaming
loop_runner.run_streaming(session_id, message).await