Apresentação
🤖 AI Agents — Muito importante para esta vaga
Conceitos
Planeamento
Dividir tarefa em sub-tarefas. Planeamento antes de executar.
Uso de ferramentas
Agente chama ferramentas: search, calculator, API, DB.
Memória
Curto prazo (conversa), longo prazo (embeddings, vector store).
Ciclos de raciocínio
Observar → Pensar → Agir. ReAct pattern.
Como usar Tools — implementação prática
1. Definir a tool (schema)
O LLM escolhe tools pela descrição e parâmetros. Usa JSON Schema ou Pydantic.
# Exemplo: OpenAI function calling format
tools = [{
"type": "function",
"function": {
"name": "search_documents",
"description": "Pesquisa a base de conhecimento por documentos relevantes. Usa quando o utilizador pergunta sobre documentação da empresa.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Query de pesquisa"}
},
"required": ["query"]
}
}
}]
Regra: Descrição clara = LLM escolhe melhor. "Use when..." ajuda o modelo a decidir.
2. Fluxo de execução (loop)
1. Mensagem do utilizador → LLM (com tools no prompt)
2. LLM responde: texto OU tool_calls
3. Se tool_calls: parse args → executar função → resultado
4. Adicionar tool result às mensagens: role=assistant (tool_call), role=user (tool_result)
5. Voltar ao passo 1 (LLM vê o resultado e continua)
6. Se LLM responde texto final → devolver ao utilizador
3. Código do loop (pseudocódigo)
messages = [{"role": "user", "content": user_input}]
while True:
response = llm.chat(messages, tools=tools)
if response.content:
return response.content # Resposta final
for tool_call in response.tool_calls:
result = execute_tool(tool_call.name, tool_call.args)
messages.append({"role": "assistant", "content": None, "tool_calls": [tool_call]})
messages.append({"role": "tool", "content": str(result), "tool_call_id": tool_call.id})
4. LangChain / LangGraph — como definir tools
from langchain.tools import tool
@tool
def search_documents(query: str) -> str:
"""Pesquisa a base de conhecimento. Usa quando o utilizador pergunta sobre documentação."""
return vector_db.similarity_search(query)
# O decorator @tool extrai nome, descrição e schema automaticamente
agent = create_react_agent(llm, [search_documents, calculator_tool], prompt)
5. Erros comuns
- Tool não chamada: Descrição vaga — ser mais explícito "Use when user asks X"
- Args errados: Schema muito aberto — definir tipos e required
- Loop infinito: Max iterations, timeout, detetar tool repetida com mesmos args
Como criar Multi-Agent Conversation
Arquitetura: Router + Specialized Agents
User: "Pesquisa docs e faz um resumo"
↓
Router Agent: analisa intent → decide "search" + "summarize"
↓
Search Agent: chama search_documents → devolve chunks
↓
Summarizer Agent: recebe chunks → gera resumo
↓
Resposta ao User
1. Router Agent — como implementar
O router é um LLM que recebe a mensagem e decide para onde enviar.
# Router prompt
task = "Classifica a intenção do utilizador: pesquisar | calcular | resumir | geral"
router_response = router_llm.invoke([{"role": "user", "content": f"{task}\nUser: {user_msg}"}])
intent = parse_intent(router_response) # ex: "search"
# Encaminhar para o agente correto
agent = agents[intent]
result = agent.invoke(user_msg)
2. Passar mensagens entre agentes
Opção A — State partilhado: Todos os agentes leem/escrevem num dict de estado.
state = {"messages": [], "search_results": None, "final_answer": None}
# Agent 1 escreve em state["search_results"]
# Agent 2 lê state["search_results"] e escreve state["final_answer"]
Opção B — Encadeamento: Output do Agent 1 = input do Agent 2.
search_result = search_agent.invoke(user_msg)
final = summarizer_agent.invoke(f"Context: {search_result}\nResumir para o utilizador.")
3. LangGraph — multi-agent com state machine
from langgraph.graph import StateGraph, END
# Definir state
def add_messages(state, new_msg):
return {"messages": state["messages"] + [new_msg]}
# Nós = funções que processam
graph = StateGraph(AgentState)
graph.add_node("router", router_node)
graph.add_node("search_agent", search_node)
graph.add_node("summarizer", summarizer_node)
# Edges: quem chama quem
graph.add_conditional_edges("router", lambda s: s["intent"], {"search": "search_agent", "summarize": "summarizer"})
graph.add_edge("search_agent", "summarizer")
graph.add_edge("summarizer", END)
app = graph.compile()
result = app.invoke({"messages": [{"role": "user", "content": user_input}]})
4. Conversa entre agentes (debate, consenso)
Para agentes que "falam" entre si (ex: debate):
Agent A: "Acho que a resposta é X porque..."
Agent B: "Discordo, Y faz mais sentido porque..."
Agent A: "Concordo com Y, mas adiciono Z"
→ Consolidator: combina e devolve resposta final
Implementação: Cada agente recebe o histórico da conversa (mensagens dos outros agentes). O consolidator vê todo o debate e sintetiza.
5. Shared memory em multi-agent
- Conversation buffer: Últimas N mensagens em memória partilhada
- Vector store: Cada agente pode escrever/ler embeddings (ex: factos descobertos)
- Redis/DB: Estado persistente entre turns (ex: dados da sessão)
Multi-Agent Architecture (resumo)
User → Router Agent → Specialized Agents
Exemplos: search agent, coding agent, data agent, reasoning agent.
Coordenação: LangGraph (state graph), task planner (decompor tarefa), shared memory.
Chatbot com Tools — fluxo
User → LLM (com tools) → Tool selector (LLM decide) → API execution → Result → LLM (vê resultado) → Response
Tools: consulta à base de dados, pesquisa na web, calculator, APIs internas.
Frameworks
- LangGraph — state machines, nós=agentes, edges=transições.
add_node,add_edge,add_conditional_edges - LangChain —
create_react_agent, tools como list, prompt com ReAct template - AutoGen —
ConversableAgent,GroupChat,GroupChatManagerpara multi-agent - CrewAI —
Agent(role, goal, backstory),Task,Crew(orquestra) - Swarm — multi-agent (OpenAI)
- OpenAI Assistants — API managed, tools via API
Padrões
- ReAct — Raciocínio + Ação, intercalar pensamento e ações
- Planear-Executar — planeamento primeiro, depois execução
- Reflexão — criticar e melhorar output
Human-in-the-loop
Agentes que param e pedem confirmação antes de ações críticas (ex: enviar email, fazer compra). Evita erros custosos. Implementar: detectar "action" de alto risco → pedir confirmação ao user → executar só se aprovado.
Tool design — boas práticas
- Descrições claras: O LLM escolhe tools pela descrição. "search_documents(query: str) - Pesquisa a base de conhecimento por documentos relevantes. Usa quando o utilizador pergunta sobre documentação da empresa."
- Schemas estritos: Parâmetros bem definidos (Pydantic, JSON Schema). Reduz erros de parsing.
- Tool limitado: Não dar acesso a tudo. Princípio do menor privilégio.
- Um tool, uma responsabilidade: Evitar tools que fazem demasiado.
Observability em agentes
- Trace cada step: Pensamento, Ação, Observação. Langfuse, LangSmith.
- Métricas: tokens por step, latência por tool call, taxa de sucesso.
- Debug: Logs de qual tool foi chamado, com que argumentos, que resultado.
Zona de prática
Sem perguntas. Clica em Editar para adicionar.