95 lines
3.9 KiB
Python
95 lines
3.9 KiB
Python
import os
|
|
import re
|
|
import requests
|
|
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:
|
|
"""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}"
|
|
payload = {"contents": [{"parts": [{"text": prompt}]}]}
|
|
res = requests.post(url, json=payload)
|
|
if res.status_code == 200:
|
|
return res.json()["candidates"][0]["content"]["parts"][0]["text"]
|
|
return f"Erro Gemini: {res.text}"
|
|
|
|
elif provider == "ollama":
|
|
ollama_host = os.getenv("OLLAMA_HOST", "http://ollama-lw4s8g4gc8gss4gkc4gg0wk4:11434")
|
|
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
|
|
}
|
|
})
|
|
if res.status_code == 200:
|
|
return res.json().get("response", "")
|
|
return f"Erro Ollama: {res.text}"
|
|
|
|
return "Provedor desconhecido."
|
|
|
|
def query_agent(prompt: str, override_provider: str = None, chat_history: list = None) -> str:
|
|
"""
|
|
Motor Agente em Loop (ReAct): Pensamento -> Ação -> Observação -> Resposta Final.
|
|
"""
|
|
# Ajuste de Provedor e Contexto
|
|
cfg = get_config()
|
|
provider = override_provider or cfg.get("active_provider", "gemini")
|
|
|
|
# Prompt agressivo para o Ollama (obriga uso de ferramentas)
|
|
if provider == "ollama":
|
|
system_prompt = "Você é o [BotVPS], o SysAdmin do Marcos. Se ele pedir uma imagem ou arquivo, use OBRIGATORIAMENTE [TOOL:nome] arg [/TOOL] para agir na VPS. Não dê conselhos teóricos, aja agora. Responda em Português."
|
|
num_context = 2048
|
|
else:
|
|
system_prompt = system_prompt_base.replace("{TOOLS_LIST}", tools_desc)
|
|
num_context = 4096
|
|
|
|
# Limpeza de Contexto (Remove echos de 'U:' e 'A:')
|
|
hist_list = chat_history[-3:] if chat_history else []
|
|
hist_txt = "\n".join([f"Anteriores:\nU: {m['user']}\nA: {m['bot']}" for m in hist_list])
|
|
|
|
execution_context = f"{hist_txt}\n\nPERGUNTA ATUAL: {prompt}\nRESPOSTA DO AGENTE:"
|
|
current_reasoning = ""
|
|
|
|
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)
|
|
|
|
print(f"PENSAMENTO:\n{response}")
|
|
|
|
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}")
|
|
|
|
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)
|
|
else:
|
|
observation = f"Erro: Ferramenta '{tool_name}' não encontrada."
|
|
|
|
current_reasoning += f"\nAção: {response}\nSISTEMA: {observation}\n"
|
|
else:
|
|
print("--- RESPOSTA FINAL ENCONTRADA ---")
|
|
return response
|
|
|
|
return "O agente atingiu o limite de tentativas."
|