Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pa_data
frontend/.env
.claude
.claude
.DS_Store
2 changes: 1 addition & 1 deletion backend/.python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10
3.14
8 changes: 4 additions & 4 deletions backend/ai_system/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
'ContextManager',
'CodeExecutor',
'FileTools',
'TemplateAgentTools',
'ToolManager'
'TemplateAgentTools'
# 'ToolManager' # 已移除
]

def _import_core_components():
Expand All @@ -36,7 +36,7 @@ def _import_core_components():
from .core_handlers.llm_factory import LLMFactory
from .core_managers.stream_manager import StreamOutputManager
from .core_managers.context_manager import ContextManager
from .core_managers.tool_manager import ToolManager
# ToolManager 已移除,不再导入
from .core_tools.code_executor import CodeExecutor
from .core_tools.file_tools import FileTools
from .core_tools.template_tools import TemplateAgentTools
Expand All @@ -49,7 +49,7 @@ def _import_core_components():
'LLMFactory': LLMFactory,
'StreamOutputManager': StreamOutputManager,
'ContextManager': ContextManager,
'ToolManager': ToolManager,
# 'ToolManager': ToolManager, # 已移除
'CodeExecutor': CodeExecutor,
'FileTools': FileTools,
'TemplateAgentTools': TemplateAgentTools
Expand Down
53 changes: 46 additions & 7 deletions backend/ai_system/config/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@ class DatabaseConfigManager:
def __init__(self, db_session: Session):
self.db_session = db_session

def get_model_config(self, system_type: str, user_id: int = None):
"""获取指定系统类型的模型配置"""
def get_model_config(self, system_type: str, user_id: int = None, provider: str = None):
"""
获取指定系统类型的模型配置

Args:
system_type: 系统类型(brain, code, writing)
user_id: 用户ID(可选)
provider: AI提供商(可选,用于筛选特定提供商的配置)

Returns:
ModelConfig对象
"""
from models.models import ModelConfig

query = self.db_session.query(ModelConfig).filter(
Expand All @@ -31,26 +41,55 @@ def get_model_config(self, system_type: str, user_id: int = None):
if user_id is not None:
query = query.filter(ModelConfig.created_by == user_id)

# 如果指定了提供商,只获取该提供商的配置
if provider is not None:
query = query.filter(ModelConfig.provider == provider)

config = query.first()

if not config:
raise ValueError(f"未找到系统类型 {system_type} 的配置")
raise ValueError(f"未找到系统类型 {system_type} 的配置" +
(f",提供商: {provider}" if provider else ""))
return config

def get_api_key(self, system_type: str, user_id: int = None) -> str:
def get_api_key(self, system_type: str, user_id: int = None, provider: str = None) -> str:
"""获取指定系统类型的API密钥"""
config = self.get_model_config(system_type, user_id)
config = self.get_model_config(system_type, user_id, provider)
return config.api_key

def get_model_info(self, system_type: str, user_id: int = None) -> Dict[str, Any]:
def get_model_info(self, system_type: str, user_id: int = None, provider: str = None) -> Dict[str, Any]:
"""获取模型信息(不包含敏感信息)"""
config = self.get_model_config(system_type, user_id)
config = self.get_model_config(system_type, user_id, provider)
return {
"provider": getattr(config, 'provider', 'openai'),
"model_id": config.model_id,
"base_url": config.base_url,
"is_active": config.is_active
}

def get_available_providers(self, system_type: str, user_id: int = None) -> List[str]:
"""获取指定系统类型可用的AI提供商列表"""
from models.models import ModelConfig

query = self.db_session.query(ModelConfig.provider).filter(
ModelConfig.type == system_type,
ModelConfig.is_active == True
)

if user_id is not None:
query = query.filter(ModelConfig.created_by == user_id)

providers = [row.provider for row in query.distinct()]
return providers

def validate_provider_config(self, system_type: str, provider: str, user_id: int = None) -> bool:
"""验证指定提供商的配置是否有效"""
try:
config = self.get_model_config(system_type, user_id, provider)
return bool(config.api_key and config.model_id)
except ValueError:
return False


class AIEnvironmentManager:
"""AI环境管理器"""
Expand Down
7 changes: 3 additions & 4 deletions backend/ai_system/core_agents/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
"""
AI系统核心代理模块 - 重构版本
包含BaseAgent、MainAgent、CodeAgent等核心代理类
AI系统核心代理模块 - LangChain 重构版本
包含MainAgent、CodeAgent等核心代理类
"""

from .agent_base import BaseAgent, CodeAgent
from .main_agent import MainAgent

__all__ = ['BaseAgent', 'CodeAgent', 'MainAgent']
__all__ = ['MainAgent']
230 changes: 9 additions & 221 deletions backend/ai_system/core_agents/agent_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
from typing import List, Dict, Any, Callable, Optional
from abc import ABC, abstractmethod
from datetime import datetime
from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

from ..core_managers.tool_manager import ToolManager
from ..core_managers.context_manager import ContextManager

logger = logging.getLogger(__name__)
Expand All @@ -37,11 +38,10 @@ def __init__(self, llm_handler: 'LLMHandler', stream_manager: 'StreamOutputManag
self.work_id = work_id
self.workspace_dir = workspace_dir

# 初始化工具管理器
if workspace_dir:
self.tool_manager = ToolManager(workspace_dir, stream_manager)
else:
self.tool_manager = None
# 工具管理器已移除,BaseAgent 不再直接管理工具
# 子类可以自行实现工具管理逻辑
self.tool_manager = None
self.smolagent_manager = None

# 消息和工具管理
self.messages: List[Dict[str, Any]] = []
Expand All @@ -67,11 +67,8 @@ def _initialize(self):
"content": system_prompt
}]

# 设置工具
self._setup_tools()

# 注册工具函数
self._register_tool_functions()
# 工具设置由子类实现
self.tools = []

@abstractmethod
def get_system_prompt(self) -> str:
Expand Down Expand Up @@ -357,213 +354,4 @@ def get_execution_summary(self) -> Dict[str, Any]:
}


class CodeAgent(BaseAgent):
"""
代码生成和执行Agent,专注于代码相关任务
"""

def __init__(self, llm_handler: 'LLMHandler', stream_manager: 'StreamOutputManager', workspace_dir: str, work_id: Optional[str] = None):
"""
初始化CodeAgent

Args:
llm_handler: LLM处理器
stream_manager: 流式输出管理器
workspace_dir: 工作空间目录(必需)
work_id: 工作ID
"""
if not workspace_dir:
raise ValueError("CodeAgent必须提供workspace_dir参数")

super().__init__(llm_handler, stream_manager, workspace_dir, work_id)

def get_system_prompt(self) -> str:
"""获取CodeAgent的系统提示词"""
return (
"你是一个专业的代码生成和执行助手。**务必确保成功产出所需文件再交付**,工作完成之前一定要调用工具!重复执行直到成功。\n\n"
"你的工作流程:\n"
"1. 分析用户任务,生成相应的Python代码\n"
"2. 使用 save_and_execute 工具保存代码并立即执行\n"
"3. 仔细分析执行结果和错误信息\n"
"4. 如果代码有错误或需要优化,使用 edit_code_file 修改后重新执行\n"
"5. 重复修改和执行,直到得到正确结果\n\n"
"**重要策略:**\n"
"- 推荐使用 save_and_execute 工具,一次性完成保存和执行\n"
"- 代码执行失败时,仔细分析错误信息,然后修改代码重试\n"
"- 代码应该包含必要的导入语句和完整的逻辑\n"
"- 文件操作使用相对路径,例如:plt.savefig('outputs/filename.png')\n"
"- 必须要保证保存图片且图片名字含有时间戳,否则会覆盖之前的图片\n\n"
"**重复执行直到成功**"
)

def _setup_tools(self):
"""设置CodeAgent的工具定义"""
# 保存并执行代码工具
save_and_execute_tool = {
"type": "function",
"function": {
"name": "save_and_execute",
"description": "保存Python代码到文件并立即执行",
"parameters": {
"type": "object",
"properties": {
"code_content": {"type": "string", "description": "要保存和执行的Python代码内容"},
"filename": {"type": "string", "description": "文件名(不需要.py后缀)"}
},
"required": ["code_content", "filename"],
},
},
}

# 直接执行代码工具
execute_code_tool = {
"type": "function",
"function": {
"name": "execute_code",
"description": "直接执行Python代码内容,不保存到文件",
"parameters": {
"type": "object",
"properties": {
"code_content": {"type": "string", "description": "要执行的Python代码内容"}
},
"required": ["code_content"],
},
},
}

# 执行文件工具
execute_file_tool = {
"type": "function",
"function": {
"name": "execute_file",
"description": "执行指定的Python代码文件",
"parameters": {
"type": "object",
"properties": {
"file_path": {"type": "string", "description": "要执行的代码文件路径"}
},
"required": ["file_path"],
},
},
}

# 修改代码文件工具
edit_code_tool = {
"type": "function",
"function": {
"name": "edit_code_file",
"description": "修改已存在的Python代码文件",
"parameters": {
"type": "object",
"properties": {
"filename": {"type": "string", "description": "要修改的文件名(不需要.py后缀)"},
"new_code_content": {"type": "string", "description": "修复后的完整代码内容"}
},
"required": ["filename", "new_code_content"],
},
},
}

# 列出代码文件工具
list_files_tool = {
"type": "function",
"function": {
"name": "list_code_files",
"description": "列出工作空间中的所有代码文件",
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
},
}

# 注册工具定义
self.tools = [
save_and_execute_tool,
execute_code_tool,
execute_file_tool,
edit_code_tool,
list_files_tool
]

def _register_tool_functions(self):
"""注册CodeAgent的工具函数"""
if not self.tool_manager:
raise ValueError("CodeAgent需要工具管理器")

code_executor = self.tool_manager.code_executor()

self.available_functions = {
"save_and_execute": code_executor.save_and_execute,
"execute_code": code_executor.execute_code,
"execute_file": code_executor.execute_file,
"edit_code_file": code_executor.edit_code_file,
"list_code_files": code_executor.list_code_files
}

async def run(self, task_prompt: str) -> str:
"""执行代码生成和执行任务"""
logger.info(f"CodeAgent开始执行任务: {repr(task_prompt[:50])}...")

if self.stream_manager:
await self.stream_manager.send_json_block("code_agent_start", f"开始执行代码任务: {task_prompt[:100]}...")

self.add_user_message(task_prompt)

max_iterations = 10
iteration = 0
last_tool_result = None

while iteration < max_iterations:
iteration += 1
logger.info(f"CodeAgent第{iteration}次迭代")

# 调用LLM
assistant_message, tool_calls = await self.llm_handler.process_stream(self.messages, self.tools)
self.messages.append(assistant_message)

if not tool_calls:
# 任务完成
if last_tool_result:
result = f"任务完成!\n\n执行结果:\n{last_tool_result}\n\nLLM总结:{assistant_message.get('content', '')}"
else:
result = assistant_message.get("content", "代码任务完成。")

logger.info(f"CodeAgent在第{iteration}次迭代完成")
if self.stream_manager:
await self.stream_manager.send_json_block("code_agent_result", f"任务完成,最终结果: {result[:200]}...")
return result

# 执行工具调用 - 使用统一的执行方法
for tool_call in tool_calls:
function_name = tool_call["function"]["name"]
logger.info(f"CodeAgent执行工具调用: {function_name}")

try:
tool_result = await self._execute_tool_call(tool_call)
last_tool_result = tool_result

# 添加工具结果到消息历史
self.messages.append({
"role": "tool",
"tool_call_id": tool_call["id"],
"content": tool_result,
})

except Exception as e:
logger.error(f"工具 {function_name} 执行失败: {e}")
error_result = f"工具 {function_name} 执行失败: {str(e)}"
self.messages.append({
"role": "tool",
"tool_call_id": tool_call["id"],
"content": error_result,
})
last_tool_result = error_result

# 达到最大迭代次数
logger.warning(f"CodeAgent达到最大迭代次数({max_iterations}),强制结束")
if last_tool_result:
return f"任务完成(达到最大迭代次数)!\n\n最终执行结果:\n{last_tool_result}"
else:
return "代码任务完成(达到最大迭代次数),但未获得有效结果"
# CodeAgent 已移至独立的 code_agent.py 文件
Loading