Agents·7 min read

How to use NousResearch Hermes for structured tool calling

Hermes is NousResearch's open-source model family trained specifically for function calling and agentic workflows. This guide covers running Hermes locally, defining tools in JSON Schema, and building a basic tool-calling loop.

What makes Hermes special for agents

NousResearch Hermes models are fine-tuned on top of Llama and Mistral base models specifically for function calling, structured JSON output, and agentic reasoning. They follow the function-calling format precisely and are less likely to hallucinate tool names or arguments compared to general-purpose models.

Hermes 3 (based on Llama 3.1 70B) supports parallel tool calling, meaning it can request multiple tool executions in a single response turn — critical for efficient agent loops. It also supports the 'thought' field in tool call responses for chain-of-thought reasoning before function execution.

Run Hermes locally with Ollama

Pull the Hermes 3 8B model: `ollama pull hermes3:8b`. For better function-calling accuracy, use the larger 70B: `ollama pull hermes3:70b` (requires 40+ GB unified memory or VRAM).

Hermes supports the same OpenAI-compatible chat completion format that Ollama exposes at `/v1/chat/completions`. This means any OpenAI SDK client can drive it without code changes.

Define tools in JSON Schema

Tools are defined as JSON Schema objects passed in the `tools` field of the chat completion request. Each tool has a name, description, and parameters schema. The description is critical — write it as you would write a docstring for a senior developer. The model uses it to decide when to call the function.

Example tool definition in Python: pass a `tools` list to the SDK with entries like `{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}`.

Implement the tool-calling loop

The basic agentic loop has four steps: (1) send the user's message plus available tools to the model; (2) check if the response contains a `tool_calls` field; (3) execute each tool call with your actual implementation and collect results; (4) send the tool results back to the model as messages with role 'tool' and re-request a final response.

Repeat until the model returns a response with no tool calls — this is the final answer. Use a maximum iteration count (e.g. 10) as a safety limit to prevent infinite loops if the model gets stuck.

Example: a simple web search agent

Define two tools: `search_web(query: str) -> str` and `get_page_content(url: str) -> str`. In your implementation, `search_web` calls a search API (DuckDuckGo, SerpAPI) and returns a JSON list of results. `get_page_content` fetches a URL and returns the cleaned text.

Prompt the model: 'Find the current price of Bitcoin and summarise the most recent news about it.' Hermes will call `search_web`, receive results, call `get_page_content` on relevant URLs, then synthesise a final answer. This three-turn exchange takes around 3–5 seconds with the 8B model locally.

Structured output without tools

For tasks where you want structured JSON output without function calling, Hermes supports the `response_format: {type: 'json_object'}` option. Pair this with a system prompt that specifies the exact JSON schema you want. Hermes reliably produces valid JSON that matches the described schema.

This is useful for data extraction, classification, and parsing tasks where you need machine-readable output. Example: 'Extract all person names, company names, and dates from this text and return them as JSON with arrays for each entity type.'