集成技能功能到系统提示词框架

- 在 AgentLoop 中添加 SkillsLoader 支持\n- 在系统提示词构建中集成技能提示\n- 更新 Session 以传递 SkillsLoader\n- 修复所有编译错误和测试问题
This commit is contained in:
xiaoxixi 2026-04-27 23:04:24 +08:00
parent 8226e8429d
commit 1abac85034
3 changed files with 30 additions and 5 deletions

View File

@ -6,6 +6,7 @@ use crate::observability::{
truncate_args, Observer, ObserverEvent, ToolExecutionOutcome,
};
use crate::providers::{create_provider, LLMProvider, ChatCompletionRequest, Message, ToolCall};
use crate::skills::SkillsLoader;
use crate::tools::ToolRegistry;
use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
@ -226,6 +227,7 @@ pub struct AgentLoop {
max_iterations: usize,
workspace_dir: PathBuf,
model_name: String,
skills_loader: Arc<SkillsLoader>,
}
#[derive(Debug, Clone)]
@ -236,7 +238,7 @@ pub struct AgentProcessResult {
impl AgentLoop {
/// Create a new AgentLoop with a provider created from config.
pub fn new(provider_config: LLMProviderConfig) -> Result<Self, AgentError> {
pub fn new(provider_config: LLMProviderConfig, skills_loader: Arc<SkillsLoader>) -> Result<Self, AgentError> {
let max_iterations = provider_config.max_tool_iterations;
let model_name = provider_config.model_id.clone();
let workspace_dir = provider_config.workspace_dir.clone();
@ -250,11 +252,12 @@ impl AgentLoop {
max_iterations,
workspace_dir,
model_name,
skills_loader,
})
}
/// Create a new AgentLoop with provider created from config and given tools.
pub fn with_tools(provider_config: LLMProviderConfig, tools: Arc<ToolRegistry>) -> Result<Self, AgentError> {
pub fn with_tools(provider_config: LLMProviderConfig, tools: Arc<ToolRegistry>, skills_loader: Arc<SkillsLoader>) -> Result<Self, AgentError> {
let max_iterations = provider_config.max_tool_iterations;
let model_name = provider_config.model_id.clone();
let workspace_dir = provider_config.workspace_dir.clone();
@ -268,11 +271,12 @@ impl AgentLoop {
max_iterations,
workspace_dir,
model_name,
skills_loader,
})
}
/// Create a new AgentLoop with an existing shared provider.
pub fn with_provider(provider: Arc<dyn LLMProvider>, max_iterations: usize, model_name: String, workspace_dir: PathBuf) -> Self {
pub fn with_provider(provider: Arc<dyn LLMProvider>, max_iterations: usize, model_name: String, workspace_dir: PathBuf, skills_loader: Arc<SkillsLoader>) -> Self {
Self {
provider,
tools: Arc::new(ToolRegistry::new()),
@ -280,6 +284,7 @@ impl AgentLoop {
max_iterations,
workspace_dir,
model_name,
skills_loader,
}
}
@ -290,6 +295,7 @@ impl AgentLoop {
max_iterations: usize,
model_name: String,
workspace_dir: PathBuf,
skills_loader: Arc<SkillsLoader>,
) -> Self {
Self {
provider,
@ -298,6 +304,7 @@ impl AgentLoop {
max_iterations,
workspace_dir,
model_name,
skills_loader,
}
}
@ -331,7 +338,17 @@ impl AgentLoop {
// Build and inject system prompt if not present
let has_system = messages.first().map_or(false, |m| m.role == "system");
if !has_system {
let system_prompt = build_system_prompt(&self.workspace_dir, &self.model_name, &self.tools);
let mut system_prompt = build_system_prompt(&self.workspace_dir, &self.model_name, &self.tools);
// Add skills prompt if there are skills
let skills_prompt = self.skills_loader.build_skills_prompt();
if !skills_prompt.is_empty() {
if !system_prompt.is_empty() {
system_prompt.push_str("\n\n");
}
system_prompt.push_str(&skills_prompt);
}
#[cfg(debug_assertions)]
tracing::debug!("System prompt injected:\n{}", system_prompt);
messages.insert(0, ChatMessage::system(system_prompt));

View File

@ -12,7 +12,7 @@ use tokio::sync::{broadcast, RwLock};
use crate::bus::{MessageBus, MediaItem, OutboundMessage};
use crate::channels::base::{Channel, ChannelError};
use crate::config::{FeishuChannelConfig, LLMProviderConfig};
use crate::config::FeishuChannelConfig;
const FEISHU_API_BASE: &str = "https://open.feishu.cn/open-apis";
const FEISHU_WS_BASE: &str = "https://open.feishu.cn";

View File

@ -36,6 +36,7 @@ pub struct Session {
tools: Arc<ToolRegistry>,
compressor: ContextCompressor,
store: Arc<SessionStore>,
skills_loader: Arc<SkillsLoader>,
}
impl Session {
@ -45,6 +46,7 @@ impl Session {
user_tx: mpsc::Sender<WsOutbound>,
tools: Arc<ToolRegistry>,
store: Arc<SessionStore>,
skills_loader: Arc<SkillsLoader>,
) -> Result<Self, AgentError> {
let provider_box = create_provider(provider_config.clone())
.map_err(|e| AgentError::Other(format!("provider creation error: {}", e)))?;
@ -64,6 +66,7 @@ impl Session {
tools,
compressor: ContextCompressor::with_config(provider.clone(), provider_config.token_limit, compressor_config),
store,
skills_loader,
})
}
@ -178,6 +181,7 @@ impl Session {
self.provider_config.max_tool_iterations,
self.provider_config.model_id.clone(),
self.provider_config.workspace_dir.clone(),
self.skills_loader.clone(),
))
}
}
@ -389,6 +393,7 @@ impl SessionManager {
user_tx,
self.tools.clone(),
self.store.clone(),
self.skills_loader.clone(),
).await?;
let arc = Arc::new(Mutex::new(session));
@ -416,6 +421,7 @@ impl SessionManager {
user_tx,
self.tools.clone(),
self.store.clone(),
self.skills_loader.clone(),
).await?;
let arc = Arc::new(Mutex::new(session));
@ -431,6 +437,7 @@ impl SessionManager {
user_tx,
self.tools.clone(),
self.store.clone(),
self.skills_loader.clone(),
).await?;
let arc = Arc::new(Mutex::new(session));
@ -648,6 +655,7 @@ mod tests {
model_extra: HashMap::new(),
max_tool_iterations: 1,
token_limit: 4096,
workspace_dir: std::path::PathBuf::from("/tmp/test-workspace"),
}
}
}