refactor(agent): 将智能体相关的名称参数更改为ID,优化智能体管理逻辑
This commit is contained in:
parent
9d9101a3e5
commit
9d58ebc13c
@ -36,7 +36,7 @@ async def get_default_agent(current_user: User = Depends(get_required_user)):
|
||||
if not default_agent_id:
|
||||
agents = await agent_manager.get_agents_info()
|
||||
if agents:
|
||||
default_agent_id = agents[0].get("name", "")
|
||||
default_agent_id = agents[0].get("id", "")
|
||||
|
||||
return {"default_agent_id": default_agent_id}
|
||||
except Exception as e:
|
||||
@ -49,7 +49,7 @@ async def set_default_agent(agent_id: str = Body(..., embed=True), current_user
|
||||
try:
|
||||
# 验证智能体是否存在
|
||||
agents = await agent_manager.get_agents_info()
|
||||
agent_ids = [agent.get("name", "") for agent in agents]
|
||||
agent_ids = [agent.get("id", "") for agent in agents]
|
||||
|
||||
if agent_id not in agent_ids:
|
||||
raise HTTPException(status_code=404, detail=f"智能体 {agent_id} 不存在")
|
||||
@ -96,8 +96,8 @@ async def get_agent(current_user: User = Depends(get_required_user)):
|
||||
# logger.debug(f"agents: {agents}")
|
||||
return {"agents": agents}
|
||||
|
||||
@chat.post("/agent/{agent_name}")
|
||||
async def chat_agent(agent_name: str,
|
||||
@chat.post("/agent/{agent_id}")
|
||||
async def chat_agent(agent_id: str,
|
||||
query: str = Body(...),
|
||||
config: dict = Body({}),
|
||||
meta: dict = Body({}),
|
||||
@ -106,8 +106,8 @@ async def chat_agent(agent_name: str,
|
||||
|
||||
meta.update({
|
||||
"query": query,
|
||||
"agent_name": agent_name,
|
||||
"server_model_name": config.get("model", agent_name),
|
||||
"agent_id": agent_id,
|
||||
"server_model_name": config.get("model", agent_id),
|
||||
"thread_id": config.get("thread_id"),
|
||||
"user_id": current_user.id
|
||||
})
|
||||
@ -127,10 +127,10 @@ async def chat_agent(agent_name: str,
|
||||
yield make_chunk(status="init", meta=meta, msg=HumanMessage(content=query).model_dump())
|
||||
|
||||
try:
|
||||
agent = agent_manager.get_agent(agent_name)
|
||||
agent = agent_manager.get_agent(agent_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting agent {agent_name}: {e}, {traceback.format_exc()}")
|
||||
yield make_chunk(message=f"Error getting agent {agent_name}: {e}", status="error")
|
||||
logger.error(f"Error getting agent {agent_id}: {e}, {traceback.format_exc()}")
|
||||
yield make_chunk(message=f"Error getting agent {agent_id}: {e}", status="error")
|
||||
return
|
||||
|
||||
messages = [{"role": "user", "content": query}]
|
||||
@ -185,25 +185,25 @@ async def get_tools(current_user: User = Depends(get_admin_user)):
|
||||
"""获取所有可用工具(需要登录)"""
|
||||
return {"tools": list(get_all_tools().keys())}
|
||||
|
||||
@chat.post("/agent/{agent_name}/config")
|
||||
@chat.post("/agent/{agent_id}/config")
|
||||
async def save_agent_config(
|
||||
agent_name: str,
|
||||
agent_id: str,
|
||||
config: dict = Body(...),
|
||||
current_user: User = Depends(get_admin_user)
|
||||
):
|
||||
"""保存智能体配置到YAML文件(需要管理员权限)"""
|
||||
try:
|
||||
# 获取Agent实例和配置类
|
||||
agent = agent_manager.get_agent(agent_name)
|
||||
agent = agent_manager.get_agent(agent_id)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail=f"智能体 {agent_name} 不存在")
|
||||
raise HTTPException(status_code=404, detail=f"智能体 {agent_id} 不存在")
|
||||
|
||||
# 使用配置类的save_to_file方法保存配置
|
||||
config_cls = agent.config_schema
|
||||
result = config_cls.save_to_file(config, agent_name)
|
||||
result = config_cls.save_to_file(config, agent.module_name)
|
||||
|
||||
if result:
|
||||
return {"success": True, "message": f"智能体 {agent_name} 配置已保存"}
|
||||
return {"success": True, "message": f"智能体 {agent.name} 配置已保存"}
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail="保存智能体配置失败")
|
||||
|
||||
@ -211,18 +211,18 @@ async def save_agent_config(
|
||||
logger.error(f"保存智能体配置出错: {e}, {traceback.format_exc()}")
|
||||
raise HTTPException(status_code=500, detail=f"保存智能体配置出错: {str(e)}")
|
||||
|
||||
@chat.get("/agent/{agent_name}/history")
|
||||
@chat.get("/agent/{agent_id}/history")
|
||||
async def get_agent_history(
|
||||
agent_name: str,
|
||||
agent_id: str,
|
||||
thread_id: str,
|
||||
current_user: User = Depends(get_required_user)
|
||||
):
|
||||
"""获取智能体历史消息(需要登录)"""
|
||||
try:
|
||||
# 获取Agent实例和配置类
|
||||
agent = agent_manager.get_agent(agent_name)
|
||||
agent = agent_manager.get_agent(agent_id)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail=f"智能体 {agent_name} 不存在")
|
||||
raise HTTPException(status_code=404, detail=f"智能体 {agent_id} 不存在")
|
||||
|
||||
# 获取历史消息
|
||||
history = await agent.get_history(user_id=str(current_user.id), thread_id=thread_id)
|
||||
@ -232,18 +232,18 @@ async def get_agent_history(
|
||||
logger.error(f"获取智能体历史消息出错: {e}, {traceback.format_exc()}")
|
||||
raise HTTPException(status_code=500, detail=f"获取智能体历史消息出错: {str(e)}")
|
||||
|
||||
@chat.get("/agent/{agent_name}/config")
|
||||
@chat.get("/agent/{agent_id}/config")
|
||||
async def get_agent_config(
|
||||
agent_name: str,
|
||||
agent_id: str,
|
||||
current_user: User = Depends(get_required_user)
|
||||
):
|
||||
"""从YAML文件加载智能体配置(需要登录)"""
|
||||
try:
|
||||
# 检查智能体是否存在
|
||||
if not (agent := agent_manager.get_agent(agent_name)):
|
||||
raise HTTPException(status_code=404, detail=f"智能体 {agent_name} 不存在")
|
||||
if not (agent := agent_manager.get_agent(agent_id)):
|
||||
raise HTTPException(status_code=404, detail=f"智能体 {agent_id} 不存在")
|
||||
|
||||
config = agent.config_schema.from_runnable_config(config={}, agent_name=agent_name)
|
||||
config = agent.config_schema.from_runnable_config(config={}, module_name=agent.module_name)
|
||||
return {"success": True, "config": config}
|
||||
|
||||
except Exception as e:
|
||||
|
||||
@ -10,19 +10,19 @@ class AgentManager:
|
||||
self._instances = {} # 存储已创建的 agent 实例
|
||||
|
||||
def register_agent(self, agent_class):
|
||||
self._classes[agent_class.name] = agent_class
|
||||
self._classes[agent_class.__name__] = agent_class
|
||||
|
||||
def init_all_agents(self):
|
||||
for agent_class in self._classes.values():
|
||||
self.get_agent(agent_class.name)
|
||||
for agent_id in self._classes.keys():
|
||||
self.get_agent(agent_id)
|
||||
|
||||
def get_agent(self, agent_name, **kwargs):
|
||||
def get_agent(self, agent_id, **kwargs):
|
||||
# 检查是否已经创建了该 agent 的实例
|
||||
if agent_name not in self._instances:
|
||||
agent_class = self._classes[agent_name]
|
||||
self._instances[agent_name] = agent_class()
|
||||
if agent_id not in self._instances:
|
||||
agent_class = self._classes[agent_id]
|
||||
self._instances[agent_id] = agent_class()
|
||||
|
||||
return self._instances[agent_name]
|
||||
return self._instances[agent_id]
|
||||
|
||||
def get_agents(self):
|
||||
return list(self._instances.values())
|
||||
|
||||
@ -26,7 +26,7 @@ class ChatbotAgent(BaseAgent):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.graph = None
|
||||
self.workdir = Path(sys_config.save_dir) / "agents" / self.name
|
||||
self.workdir = Path(sys_config.save_dir) / "agents" / self.id
|
||||
self.workdir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _get_tools(self, tools: list[str]):
|
||||
@ -47,7 +47,7 @@ class ChatbotAgent(BaseAgent):
|
||||
|
||||
async def llm_call(self, state: State, config: RunnableConfig = None) -> dict[str, Any]:
|
||||
"""调用 llm 模型 - 异步版本以支持异步工具"""
|
||||
conf = self.config_schema.from_runnable_config(config, agent_name=self.name)
|
||||
conf = self.config_schema.from_runnable_config(config, module_name=self.module_name)
|
||||
|
||||
system_prompt = f"{conf.system_prompt} Now is {get_cur_time_with_utc()}"
|
||||
model = load_chat_model(conf.model)
|
||||
|
||||
@ -51,13 +51,13 @@ class Configuration(dict):
|
||||
|
||||
@classmethod
|
||||
def from_runnable_config(
|
||||
cls, config: RunnableConfig | None = None, agent_name: str | None = None
|
||||
cls, config: RunnableConfig | None = None, module_name: str | None = None
|
||||
) -> Configuration:
|
||||
"""Create a Configuration instance from a RunnableConfig object.
|
||||
|
||||
Args:
|
||||
config: RunnableConfig object with highest priority
|
||||
agent_name: Name of the agent to load config file for
|
||||
module_name: Name of the agent to load config file for
|
||||
|
||||
Returns:
|
||||
Configuration instance with merged config values
|
||||
@ -68,8 +68,8 @@ class Configuration(dict):
|
||||
|
||||
# 尝试加载文件配置(中等优先级)
|
||||
file_config = {}
|
||||
if agent_name:
|
||||
file_config = cls.from_file(agent_name)
|
||||
if module_name:
|
||||
file_config = cls.from_file(module_name)
|
||||
|
||||
# 获取运行时配置(最高优先级)
|
||||
configurable = (config.get("configurable") or {}) if config else {}
|
||||
@ -94,39 +94,39 @@ class Configuration(dict):
|
||||
return cls(**merged_config)
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, agent_name: str) -> Configuration:
|
||||
def from_file(cls, module_name: str) -> Configuration:
|
||||
"""从文件加载配置"""
|
||||
config_file_path = Path(f"src/agents/{agent_name}/config.private.yaml")
|
||||
config_file_path = Path(f"src/agents/{module_name}/config.private.yaml")
|
||||
file_config = {}
|
||||
if os.path.exists(config_file_path):
|
||||
try:
|
||||
with open(config_file_path, encoding='utf-8') as f:
|
||||
file_config = yaml.safe_load(f) or {}
|
||||
# logger.info(f"从文件加载智能体 {agent_name} 配置: {file_config}")
|
||||
# logger.info(f"从文件加载智能体 {module_name} 配置: {file_config}")
|
||||
except Exception as e:
|
||||
logger.error(f"加载智能体配置文件出错: {e}")
|
||||
|
||||
return file_config
|
||||
|
||||
@classmethod
|
||||
def save_to_file(cls, config: dict, agent_name: str) -> bool:
|
||||
def save_to_file(cls, config: dict, module_name: str) -> bool:
|
||||
"""Save configuration to a YAML file
|
||||
|
||||
Args:
|
||||
config: Configuration dictionary to save
|
||||
agent_name: Name of the agent to save config for
|
||||
module_name: Name of the agent to save config for
|
||||
|
||||
Returns:
|
||||
True if saving was successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
config_file_path = Path(f"src/agents/{agent_name}/config.private.yaml")
|
||||
config_file_path = Path(f"src/agents/{module_name}/config.private.yaml")
|
||||
# 确保目录存在
|
||||
os.makedirs(os.path.dirname(config_file_path), exist_ok=True)
|
||||
with open(config_file_path, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(config, f, indent=2, allow_unicode=True)
|
||||
|
||||
# logger.info(f"智能体 {agent_name} 配置已保存到 {config_file_path}")
|
||||
# logger.info(f"智能体 {module_name} 配置已保存到 {config_file_path}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"保存智能体配置文件出错: {e}")
|
||||
@ -183,7 +183,7 @@ class BaseModelConfiguration(BaseModel):
|
||||
def from_runnable_config(
|
||||
cls,
|
||||
config: Optional["RunnableConfig"] = None,
|
||||
agent_name: Optional[str] = None,
|
||||
module_name: Optional[str] = None,
|
||||
) -> "BaseModelConfiguration":
|
||||
"""
|
||||
从 RunnableConfig 和 YAML 文件中构建 Configuration 实例
|
||||
@ -193,7 +193,7 @@ class BaseModelConfiguration(BaseModel):
|
||||
default_values = default_instance.dict()
|
||||
|
||||
# 文件配置
|
||||
file_config = cls.from_file(agent_name) if agent_name else {}
|
||||
file_config = cls.from_file(module_name) if module_name else {}
|
||||
|
||||
# 运行时配置(最高优先级)
|
||||
runtime_config = config.get("configurable") if config else {}
|
||||
@ -207,11 +207,11 @@ class BaseModelConfiguration(BaseModel):
|
||||
return cls(**merged_config)
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, agent_name: str) -> dict[str, Any]:
|
||||
def from_file(cls, module_name: str) -> dict[str, Any]:
|
||||
"""
|
||||
从 YAML 文件加载配置
|
||||
"""
|
||||
config_file_path = Path(f"src/agents/{agent_name}/config.private.yaml")
|
||||
config_file_path = Path(f"src/agents/{module_name}/config.private.yaml")
|
||||
if os.path.exists(config_file_path):
|
||||
try:
|
||||
with open(config_file_path, encoding="utf-8") as f:
|
||||
@ -221,12 +221,12 @@ class BaseModelConfiguration(BaseModel):
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
def save_to_file(cls, config: dict, agent_name: str) -> bool:
|
||||
def save_to_file(cls, config: dict, module_name: str) -> bool:
|
||||
"""
|
||||
保存配置到 YAML 文件
|
||||
"""
|
||||
try:
|
||||
config_file_path = Path(f"src/agents/{agent_name}/config.private.yaml")
|
||||
config_file_path = Path(f"src/agents/{module_name}/config.private.yaml")
|
||||
os.makedirs(config_file_path.parent, exist_ok=True)
|
||||
with open(config_file_path, "w", encoding="utf-8") as f:
|
||||
yaml.dump(config, f, indent=2, allow_unicode=True)
|
||||
@ -290,8 +290,19 @@ class BaseAgent:
|
||||
def __init__(self, **kwargs):
|
||||
self.check_requirements()
|
||||
|
||||
@property
|
||||
def module_name(self) -> str:
|
||||
"""Get the module name of the agent class."""
|
||||
return self.__class__.__module__.split('.')[-2]
|
||||
|
||||
@property
|
||||
def id(self) -> str:
|
||||
"""Get the agent's class name."""
|
||||
return self.__class__.__name__
|
||||
|
||||
async def get_info(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name if hasattr(self, "name") else "Unknown",
|
||||
"description": self.description if hasattr(self, "description") else "Unknown",
|
||||
"config_schema": self.config_schema.to_dict(),
|
||||
|
||||
@ -92,7 +92,7 @@ export const chatApi = {
|
||||
* @param {string} threadId - 会话ID
|
||||
* @returns {Promise} - 历史消息
|
||||
*/
|
||||
getAgentHistory: (agentName, threadId) => apiGet(`/api/chat/agent/${agentName}/history?thread_id=${threadId}`, {}, true),
|
||||
getAgentHistory: (agentId, threadId) => apiGet(`/api/chat/agent/${agentId}/history?thread_id=${threadId}`, {}, true),
|
||||
|
||||
/**
|
||||
* 获取可用工具列表
|
||||
|
||||
@ -1014,7 +1014,7 @@ const fetchAgents = async () => {
|
||||
const data = await chatApi.getAgents();
|
||||
// 将数组转换为对象
|
||||
agents.value = data.agents.reduce((acc, agent) => {
|
||||
acc[agent.name] = agent;
|
||||
acc[agent.id] = agent;
|
||||
return acc;
|
||||
}, {});
|
||||
console.log("agents", agents.value);
|
||||
|
||||
@ -15,13 +15,13 @@
|
||||
@change="selectAgent"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(agent, name) in agents"
|
||||
:key="name"
|
||||
:value="name"
|
||||
v-for="(agent, id) in agents"
|
||||
:key="id"
|
||||
:value="id"
|
||||
>
|
||||
<div class="agent-option">
|
||||
<div class="agent-option-content">
|
||||
<p class="agent-option-name">{{ agent.name }} <StarFilled v-if="name === defaultAgentId" class="default-icon" /></p>
|
||||
<p class="agent-option-name">{{ agent.name }} <StarFilled v-if="id === defaultAgentId" class="default-icon" /></p>
|
||||
<p class="agent-option-description">{{ agent.description }}</p>
|
||||
</div>
|
||||
|
||||
@ -338,7 +338,7 @@ const fetchAgents = async () => {
|
||||
const data = await chatApi.getAgents();
|
||||
// 将数组转换为对象
|
||||
agents.value = data.agents.reduce((acc, agent) => {
|
||||
acc[agent.name] = agent;
|
||||
acc[agent.id] = agent;
|
||||
return acc;
|
||||
}, {});
|
||||
// console.log("agents", agents.value);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user