Skip to main content

QA Agent

A Q&A assistant with tool calling capabilities.

Difficulty: Intermediate

What You'll Learn​

  • LangGraph bind_tools() for tool calling
  • ReAct pattern (reason then act)
  • Tool policy enforcement
  • Multiple HTTP endpoints

Available Tools​

ToolDescriptionHTTP Access
get_current_timeCurrent UTC timeNone (local)
calculateMath expressionsNone (local)
lookup_factWikipedia lookupWikipedia API

Setup​

agentvisor template create langgraph/qa-agent
cd qa-agent
docker compose up -d
agentvisor serve .

The template's LLM calls go through Ollama at a loopback address, which the proxy's SSRF guard blocks by default — the shipped agentvisor.yaml allowlists it; see Egress Controls for how proxy.ssrf_allowed_cidrs works.

Test It​

THREAD=$(curl -sX POST http://localhost:8090/threads | jq -r '.thread_id')

# Time query (uses tool)
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "What time is it?"}]}}'

# Calculator (uses tool)
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Calculate sqrt(144) + 10"}]}}'

# Wikipedia (HTTP call through proxy)
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Tell me about Python programming"}]}}'

Key Code​

Tool Binding​

from langchain_core.tools import tool

@tool
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression."""
# ... implementation

llm = ChatOllama(...)
llm_with_tools = llm.bind_tools([get_current_time, calculate, lookup_fact])

ReAct Graph​

builder.add_node("assistant", assistant)
builder.add_node("tools", ToolNode(ALL_TOOLS))

builder.add_conditional_edges(
"assistant",
should_continue,
{"tools": "tools", "end": END}
)
builder.add_edge("tools", "assistant")

Policy Highlights​

# Tool allowlist
annotations:
- name: "allowed_tools"
value:
- "get_current_time"
- "calculate"
- "lookup_fact"

# HTTP patterns - Ollama and Wikipedia allowed, internal networks blocked
annotations:
- name: "allowed_patterns"
value:
- "^ollama(:\\d+)?(/.*)?$"
- "^localhost:11434(/.*)?$"
- "^127\\.0\\.0\\.1:11434(/.*)?$"
- "^en\\.wikipedia\\.org(/.*)?$"
- name: "blocked_patterns"
value:
- "^localhost(?!:11434).*"
- "^127\\..*(?<!:11434).*"
- "^10\\..*"
- "^192\\.168\\..*"
- "^172\\.(1[6-9]|2[0-9]|3[0-1])\\..*"

Next Steps​