import os
import subprocess
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
# ================= 核心安全配置 =================
SANDBOX_DIR = os.path.expanduser("~/vcmi_sandbox")
VCMI_TARGET_DIR = os.path.join(SANDBOX_DIR, "vcmi")
BUILD_DIR = os.path.join(VCMI_TARGET_DIR, "build")
os.makedirs(SANDBOX_DIR, exist_ok=True)
# ================= 安全工具定义 =================
@tool
def safe_read_file(file_path: str) -> str:
"""安全读取文件,仅限沙盒目录"""
abs_path = os.path.abspath(file_path)
if not abs_path.startswith(SANDBOX_DIR):
return f"[安全拒绝] 禁止访问系统目录: {abs_path}"
if not os.path.exists(abs_path):
return f"文件不存在: {abs_path}"
with open(abs_path, 'r', encoding='utf-8') as f:
return f.read()
@tool
def safe_write_file(file_path: str, content: str) -> str:
"""安全写入文件,仅限沙盒目录"""
abs_path = os.path.abspath(file_path)
if not abs_path.startswith(SANDBOX_DIR):
return f"[安全拒绝] 禁止写入系统目录: {abs_path}"
parent_dir = os.path.dirname(abs_path)
if not os.path.exists(parent_dir):
os.makedirs(parent_dir, exist_ok=True)
try:
with open(abs_path, 'w', encoding='utf-8') as f:
f.write(content)
return f"成功写入: {abs_path}"
except Exception as e:
return f"写入失败: {str(e)}"
@tool
def run_build_command(command: str) -> str:
"""
执行构建命令 (仅限 cmake, make, git clone)。
自动锁定工作目录为沙盒内的 VCMI 目录。
禁止执行任何包含 'rm', 'sudo', 'chmod' 等危险命令。
"""
# 1. 高危命令拦截
dangerous_keywords = ['rm', 'sudo', 'chmod', 'chown', 'dd', 'mkfs', 'rmdir']
for kw in dangerous_keywords:
if kw in command.lower():
return f"[安全拦截] 检测到高危命令: {kw}。操作被禁止。"
# 2. 锁定工作目录
target_cwd = VCMI_TARGET_DIR
os.makedirs(target_cwd, exist_ok=True)
try:
print(f"[执行构建] {command} (目录: {target_cwd})")
result = subprocess.run(
command,
shell=True,
cwd=target_cwd,
capture_output=True,
text=True,
timeout=300 # 5分钟超时
)
# 截断过长输出
out = result.stdout[:1500] + "..." if len(result.stdout) > 1500 else result.stdout
err = result.stderr[:1500] + "..." if len(result.stderr) > 1500 else result.stderr
return f"退出码: {result.returncode}\nStdout: {out}\nStderr: {err}"
except subprocess.TimeoutExpired:
return "错误:命令执行超时。"
# ================= Agent 初始化 (核心修正点) =================
def main():
# 1. 连接本地服务 (这里完全不需要模型路径!)
# 只要 server 已经启动,这里直接连接地址即可
llm = ChatOpenAI(
model_name="deepseek-coder-instruct-7b", # 名字随便填,只是标识
base_url="http://localhost:8000", # 关键:连接你的 llama server 地址
", # 占位符
temperature=0.01, # 低温,保证精准
max_tokens=2048
)
# 2. 工具列表
tools = [safe_read_file, safe_write_file, run_build_command]
# 3. 提示词
prompt = ChatPromptTemplate.from_messages([
("system", f"""
你是 VCMI 项目的构建专家。
所有操作严格限制在目录 {SANDBOX_DIR} 内,无法访问系统任何其他文件。
禁止使用 rm, sudo 等命令。
任务流程:
1. 克隆 VCMI 仓库到 {VCMI_TARGET_DIR}。
2. 进入 {BUILD_DIR}。
3. 运行 cmake .. -DCMAKE_BUILD_TYPE=Release。
4. 运行 make -j4。
遇到错误尝试修复,不要删除文件。
"""),
("user", "{input}"),
("agent_scratchpad", "{agent_scratchpad}")
])
# 4. 创建 Agent
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True,
max_iterations=20
)
print("=== 启动安全沙盒构建 Agent ===")
try:
agent_executor.invoke({"input": "请开始构建 VCMI 项目,请严格遵守安全规则。"})
print("\n任务结束。检查 ~/vcmi_sandbox/vcmi/build 目录。")
except Exception as e:
print(f"错误: {e}")
if __name__ == "__main__":
main()