Restore: Reverted ai_agent.py to last known stable commit (6cf2c30)
This commit is contained in:
97
ai_agent.py
97
ai_agent.py
@@ -5,11 +5,11 @@ import json
|
||||
from tools import AVAILABLE_TOOLS
|
||||
from config import get_config
|
||||
|
||||
def get_llm_response(prompt: str, provider: str, cfg: dict, temp: float = 0.7, ctx: int = 4096) -> str:
|
||||
def get_llm_response(prompt: str, provider: str, cfg: dict) -> str:
|
||||
"""Invoca o provedor de LLM configurado."""
|
||||
if provider == "gemini":
|
||||
api_key = cfg.get("gemini_api_key") or os.getenv("GEMINI_API_KEY")
|
||||
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}"
|
||||
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={api_key}"
|
||||
payload = {"contents": [{"parts": [{"text": prompt}]}]}
|
||||
res = requests.post(url, json=payload)
|
||||
if res.status_code == 200:
|
||||
@@ -21,11 +21,7 @@ def get_llm_response(prompt: str, provider: str, cfg: dict, temp: float = 0.7, c
|
||||
res = requests.post(f"{ollama_host}/api/generate", json={
|
||||
"model": os.getenv("OLLAMA_MODEL", "qwen2.5-coder:1.5b"),
|
||||
"prompt": prompt,
|
||||
"stream": False,
|
||||
"options": {
|
||||
"temperature": temp,
|
||||
"num_ctx": ctx
|
||||
}
|
||||
"stream": False
|
||||
})
|
||||
if res.status_code == 200:
|
||||
return res.json().get("response", "")
|
||||
@@ -34,13 +30,17 @@ def get_llm_response(prompt: str, provider: str, cfg: dict, temp: float = 0.7, c
|
||||
return "Provedor desconhecido."
|
||||
|
||||
def query_agent(prompt: str, override_provider: str = None, chat_history: list = None) -> str:
|
||||
# 1. Ajuste de Provedor e Configuração
|
||||
"""
|
||||
Motor Agente em Loop (ReAct): Pensamento -> Ação -> Observação -> Resposta Final.
|
||||
"""
|
||||
cfg = get_config()
|
||||
provider = override_provider or cfg.get("active_provider", "gemini")
|
||||
|
||||
# Contexto de Ferramentas para a IA
|
||||
tools_desc = "\n".join([f"- {k}: {v['description']}" for k,v in AVAILABLE_TOOLS.items()])
|
||||
|
||||
# 2. Prompt especializado (O manual de elite)
|
||||
system_prompt_base = """Você é o [Antigravity VPS Agent], SysAdmin de elite do Marcos.
|
||||
# Prompt especializado reformulado para evitar alucinações
|
||||
system_prompt_base = """Você é o [Antigravity VPS Agent], o SysAdmin de elite do Marcos.
|
||||
Você tem acesso root completo à VPS e deve agir de forma profissional e precisa.
|
||||
|
||||
### REGRAS DE OURO:
|
||||
@@ -48,59 +48,84 @@ Você tem acesso root completo à VPS e deve agir de forma profissional e precis
|
||||
2. Se o usuário pedir o status da VPS, SEMPRE use a ferramenta 'get_system_health'.
|
||||
3. Se o usuário pedir algo sobre containers, use 'get_docker_stats'.
|
||||
4. Antes de decidir que um arquivo não existe, use 'run_bash_command' com 'ls' para verificar o diretório.
|
||||
5. NUNCA invente links fictícios. Se localizar um arquivo, use `read_vps_file`.
|
||||
6. O disco da VPS está focado em `/host_root`. Use este caminho para buscar arquivos.
|
||||
7. Use [TOOL:nome] arg [/TOOL] para ações. Rode UMA por vez.
|
||||
5. NUCA invente que buscou por arquivos (como syslog.conf) se o usuário não pediu especificamente por eles.
|
||||
6. A seção <REFINED> deve conter apenas as informações solicitadas. Se não houver imagem relevante, não inclua tags de imagem.
|
||||
7. O disco da VPS está montado em `/host_root`. Os arquivos do Marcos ficam principalmente em `/host_root/root/VPS_Sync`. Use este caminho como ponto de partida se o `find` na raiz falhar ou demorar demais.
|
||||
|
||||
### FORMATO DE AÇÃO:
|
||||
Use: [TOOL:nome_da_ferramenta] argumento [/TOOL]
|
||||
Rode UMA ferramenta por vez. Aguarde a saída do SISTEMA antes de concluir.
|
||||
|
||||
### RESPOSTA FINAL:
|
||||
- Deve ter um resumo técnico e uma seção <REFINED> com Markdown.
|
||||
- Se localizou imagem, use  dentro do <REFINED>.
|
||||
Sua resposta terminada deve ter:
|
||||
- Um resumo técnico.
|
||||
- Uma seção <REFINED> ... </REFINED> com Markdown limpo.
|
||||
- **DICA**: Só use imagens em <REFINED> se o usuário pediu para ver um arquivo de imagem específico que você localizou. Use o caminho absoluto encontrado.
|
||||
|
||||
### FERRAMENTAS:
|
||||
{TOOLS_LIST}"""
|
||||
### FERRAMENTAS DISPONÍVEIS:
|
||||
{TOOLS_LIST}
|
||||
|
||||
### EXEMPLO DE SUCESSO:
|
||||
Usuário: qual o uso de ram agora?
|
||||
Agente: [TOOL:get_system_health] [/TOOL]
|
||||
SISTEMA: CPU: 5% | RAM Usada: 20% | Disco Usado: 40%
|
||||
Resposta: A memória RAM está operando com 20% de uso.
|
||||
<REFINED>
|
||||
### 📊 Memória e CPU
|
||||
- **RAM Utilizada**: 20%
|
||||
- **CPU**: 5%
|
||||
</REFINED>
|
||||
"""
|
||||
system_prompt = system_prompt_base.replace("{TOOLS_LIST}", tools_desc)
|
||||
|
||||
# 3. Contexto e Memória Otimizada
|
||||
num_context = 2048 if provider == "ollama" else 4096
|
||||
hist_list = chat_history[-4:] if chat_history else []
|
||||
hist_txt = "\n".join([f"U: {m['user']}\nA: {m['bot']}" for m in hist_list])
|
||||
# Constrói o histórico da conversa (memória de curto prazo)
|
||||
history_str = ""
|
||||
if chat_history:
|
||||
for msg in chat_history[-5:]: # Pega as últimas 5 interações
|
||||
history_str += f"\nUsuário: {msg['user']}\nAgente: {msg['bot']}\n"
|
||||
|
||||
execution_context = f"\n{hist_txt}\nU: {prompt}\nA:"
|
||||
current_reasoning = ""
|
||||
history_str += f"\nUsuário: {prompt}\n"
|
||||
|
||||
current_iteration_history = history_str
|
||||
max_loops = 12
|
||||
|
||||
print(f"--- INICIANDO AGENTE ({provider}) ---")
|
||||
|
||||
for i in range(max_loops):
|
||||
print(f"\n[LOOP {i+1}/{max_loops}]")
|
||||
|
||||
full_prompt = f"{system_prompt}\n{execution_context}\n{current_reasoning}\n"
|
||||
|
||||
# Injeta o num_ctx dinâmico no payload
|
||||
if provider == "ollama":
|
||||
response = get_llm_response(full_prompt, provider, cfg, temp=0.1, ctx=num_context)
|
||||
else:
|
||||
response = get_llm_response(full_prompt, provider, cfg)
|
||||
full_prompt = system_prompt + current_iteration_history
|
||||
response = get_llm_response(full_prompt, provider, cfg)
|
||||
|
||||
print(f"PENSAMENTO:\n{response}")
|
||||
|
||||
# Procura por chamadas de ferramentas na resposta
|
||||
match = re.search(r"\[TOOL:(.*?)\](.*?)\[/TOOL\]", response, re.IGNORECASE | re.DOTALL)
|
||||
|
||||
if match:
|
||||
# ... (lógica de ferramenta existente) ...
|
||||
tool_name = match.group(1).strip()
|
||||
arg = match.group(2).strip()
|
||||
print(f"EXECUTANDO: {tool_name}")
|
||||
|
||||
print(f"EXECUTANDO: {tool_name} | ARGS: {arg}")
|
||||
|
||||
if tool_name in AVAILABLE_TOOLS:
|
||||
func = AVAILABLE_TOOLS[tool_name]["func"]
|
||||
observation = func() if tool_name in ["get_system_health", "get_docker_stats"] else func(arg)
|
||||
# Caso a ferramenta não aceite argumentos (ex: get_system_health)
|
||||
if tool_name in ["get_system_health", "get_docker_stats"]:
|
||||
observation = func()
|
||||
else:
|
||||
observation = func(arg)
|
||||
|
||||
print(f"OBSERVAÇÃO (suprimida): {str(observation)[:200]}...")
|
||||
else:
|
||||
observation = f"Erro: Ferramenta '{tool_name}' não encontrada."
|
||||
print(f"ERRO: {observation}")
|
||||
|
||||
current_reasoning += f"\nAção: {response}\nSISTEMA: {observation}\n"
|
||||
# Adiciona ao histórico do loop atual
|
||||
current_iteration_history += f"\nAgente (Ação): {response}\nSISTEMA (Saída de {tool_name}): {observation}\n"
|
||||
else:
|
||||
# Se não tem comando, é a resposta final
|
||||
print("--- RESPOSTA FINAL ENCONTRADA ---")
|
||||
return response
|
||||
|
||||
return "O agente atingiu o limite de tentativas."
|
||||
print("!!! ERRO: LIMITE DE TENTATIVAS ATINGIDO !!!")
|
||||
return "O agente atingiu o limite de tentativas para esta tarefa."
|
||||
|
||||
Reference in New Issue
Block a user