[{"data":1,"prerenderedAt":3811},["ShallowReactive",2],{"guides-index":3,"guide-cats":3809},[4,1211,2335,3306],{"id":5,"title":6,"body":7,"category":1197,"description":1198,"difficulty":1199,"extension":1200,"meta":1201,"navigation":117,"path":1202,"published":1203,"readTime":364,"seo":1204,"slug":1205,"stem":1206,"tags":1207,"updated":1203,"__hash__":1210},"guides\u002Fen\u002Fguides\u002Fhermes-agent-setup.md","Running a Hermes Agent Locally",{"type":8,"value":9,"toc":1186},"minimark",[10,15,19,22,43,46,50,69,72,125,128,182,184,188,204,207,232,235,252,254,258,261,666,669,686,688,692,695,896,898,902,905,922,1002,1004,1008,1011,1025,1092,1095,1097,1101,1144,1159,1161,1165,1182],[11,12,14],"h2",{"id":13},"what-is-hermes","What Is Hermes",[16,17,18],"p",{},"Hermes 3 (by Nous Research) is a fine-tune of Llama 3 trained specifically for function calling, structured outputs, and multi-turn agentic workflows. Unlike base Llama 3, Hermes follows a consistent tool-use format and rarely hallucinates tool names.",[16,20,21],{},"Key properties:",[23,24,25,29,37,40],"ul",{},[26,27,28],"li",{},"Supports OpenAI-compatible tool schemas (JSON schema format)",[26,30,31,32,36],{},"Deterministic ",[33,34,35],"code",{},"\u003Ctool_call>"," tag output — easy to parse",[26,38,39],{},"Runs entirely offline via Ollama",[26,41,42],{},"8B parameter variant fits in 8 GB VRAM \u002F 16 GB unified RAM",[44,45],"hr",{},[11,47,49],{"id":48},"prerequisites","Prerequisites",[23,51,52,63,66],{},[26,53,54,55,58,59,62],{},"Ollama installed and running (",[33,56,57],{},"ollama --version"," → ",[33,60,61],{},"0.3+",")",[26,64,65],{},"Python 3.11 or later",[26,67,68],{},"8 GB RAM minimum; 16 GB recommended for comfortable operation",[16,70,71],{},"Install Ollama if not present:",[73,74,79],"pre",{"className":75,"code":76,"language":77,"meta":78,"style":78},"language-bash shiki shiki-themes github-light github-dark","# macOS \u002F Linux\ncurl -fsSL https:\u002F\u002Follama.com\u002Finstall.sh | sh\n\n# Windows: download from https:\u002F\u002Follama.com\u002Fdownload\n","bash","",[33,80,81,90,112,119],{"__ignoreMap":78},[82,83,86],"span",{"class":84,"line":85},"line",1,[82,87,89],{"class":88},"sJ8bj","# macOS \u002F Linux\n",[82,91,93,97,101,105,109],{"class":84,"line":92},2,[82,94,96],{"class":95},"sScJk","curl",[82,98,100],{"class":99},"sj4cs"," -fsSL",[82,102,104],{"class":103},"sZZnC"," https:\u002F\u002Follama.com\u002Finstall.sh",[82,106,108],{"class":107},"szBVR"," |",[82,110,111],{"class":95}," sh\n",[82,113,115],{"class":84,"line":114},3,[82,116,118],{"emptyLinePlaceholder":117},true,"\n",[82,120,122],{"class":84,"line":121},4,[82,123,124],{"class":88},"# Windows: download from https:\u002F\u002Follama.com\u002Fdownload\n",[16,126,127],{},"Create a Python environment:",[73,129,131],{"className":75,"code":130,"language":77,"meta":78,"style":78},"python -m venv .venv\nsource .venv\u002Fbin\u002Factivate     # Linux\u002FmacOS\n# .venv\\Scripts\\activate      # Windows\n\npip install requests          # only stdlib + requests needed for the minimal agent\n",[33,132,133,147,158,163,167],{"__ignoreMap":78},[82,134,135,138,141,144],{"class":84,"line":85},[82,136,137],{"class":95},"python",[82,139,140],{"class":99}," -m",[82,142,143],{"class":103}," venv",[82,145,146],{"class":103}," .venv\n",[82,148,149,152,155],{"class":84,"line":92},[82,150,151],{"class":99},"source",[82,153,154],{"class":103}," .venv\u002Fbin\u002Factivate",[82,156,157],{"class":88},"     # Linux\u002FmacOS\n",[82,159,160],{"class":84,"line":114},[82,161,162],{"class":88},"# .venv\\Scripts\\activate      # Windows\n",[82,164,165],{"class":84,"line":121},[82,166,118],{"emptyLinePlaceholder":117},[82,168,170,173,176,179],{"class":84,"line":169},5,[82,171,172],{"class":95},"pip",[82,174,175],{"class":103}," install",[82,177,178],{"class":103}," requests",[82,180,181],{"class":88},"          # only stdlib + requests needed for the minimal agent\n",[44,183],{},[11,185,187],{"id":186},"pull-the-model","Pull the Model",[73,189,191],{"className":75,"code":190,"language":77,"meta":78,"style":78},"ollama pull hermes3:8b\n",[33,192,193],{"__ignoreMap":78},[82,194,195,198,201],{"class":84,"line":85},[82,196,197],{"class":95},"ollama",[82,199,200],{"class":103}," pull",[82,202,203],{"class":103}," hermes3:8b\n",[16,205,206],{},"Download size: ~5.1 GB (Q4_K_M quantization). After download, verify:",[73,208,210],{"className":75,"code":209,"language":77,"meta":78,"style":78},"ollama list | grep hermes\n# hermes3:8b    ...    5.1 GB\n",[33,211,212,227],{"__ignoreMap":78},[82,213,214,216,219,221,224],{"class":84,"line":85},[82,215,197],{"class":95},[82,217,218],{"class":103}," list",[82,220,108],{"class":107},[82,222,223],{"class":95}," grep",[82,225,226],{"class":103}," hermes\n",[82,228,229],{"class":84,"line":92},[82,230,231],{"class":88},"# hermes3:8b    ...    5.1 GB\n",[16,233,234],{},"For a smaller footprint on machines with 8 GB RAM:",[73,236,238],{"className":75,"code":237,"language":77,"meta":78,"style":78},"ollama pull hermes3:3b   # ~2.1 GB\n",[33,239,240],{"__ignoreMap":78},[82,241,242,244,246,249],{"class":84,"line":85},[82,243,197],{"class":95},[82,245,200],{"class":103},[82,247,248],{"class":103}," hermes3:3b",[82,250,251],{"class":88},"   # ~2.1 GB\n",[44,253],{},[11,255,257],{"id":256},"minimal-agent-script","Minimal Agent Script",[16,259,260],{},"The agent loop below handles tool dispatch manually. No LangChain required.",[73,262,265],{"className":263,"code":264,"language":137,"meta":78,"style":78},"language-python shiki shiki-themes github-light github-dark","# agent.py\nimport json\nimport re\nimport requests\n\nOLLAMA_URL = \"http:\u002F\u002Flocalhost:11434\u002Fapi\u002Fchat\"\nMODEL = \"hermes3:8b\"\n\nTOOLS = [\n    {\n        \"type\": \"function\",\n        \"function\": {\n            \"name\": \"get_weather\",\n            \"description\": \"Returns current weather for a city.\",\n            \"parameters\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"city\": {\"type\": \"string\", \"description\": \"City name\"}\n                },\n                \"required\": [\"city\"]\n            }\n        }\n    }\n]\n\ndef get_weather(city: str) -> str:\n    # Replace with a real API call in production\n    return json.dumps({\"city\": city, \"temp_c\": 18, \"condition\": \"cloudy\"})\n\nTOOL_REGISTRY = {\"get_weather\": get_weather}\n\ndef chat(messages: list, tools: list) -> dict:\n    response = requests.post(OLLAMA_URL, json={\n        \"model\": MODEL,\n        \"messages\": messages,\n        \"tools\": tools,\n        \"stream\": False\n    })\n    response.raise_for_status()\n    return response.json()[\"message\"]\n\ndef run_agent(user_input: str):\n    messages = [\n        {\"role\": \"system\", \"content\": \"You are a helpful assistant with access to tools.\"},\n        {\"role\": \"user\",   \"content\": user_input}\n    ]\n\n    while True:\n        reply = chat(messages, TOOLS)\n        messages.append(reply)\n\n        if reply.get(\"tool_calls\"):\n            for call in reply[\"tool_calls\"]:\n                fn_name = call[\"function\"][\"name\"]\n                fn_args = call[\"function\"][\"arguments\"]\n                if isinstance(fn_args, str):\n                    fn_args = json.loads(fn_args)\n\n                result = TOOL_REGISTRY[fn_name](**fn_args)\n                messages.append({\n                    \"role\": \"tool\",\n                    \"content\": result\n                })\n        else:\n            print(reply[\"content\"])\n            break\n\nif __name__ == \"__main__\":\n    run_agent(\"What is the weather in Kyiv?\")\n",[33,266,267,272,277,282,287,291,297,303,308,314,320,326,332,338,344,350,356,362,368,374,380,386,392,398,404,409,415,421,427,432,438,443,449,455,461,467,473,479,485,491,497,502,508,514,520,526,532,537,543,549,555,560,566,572,578,584,590,596,601,607,613,619,625,631,637,643,649,654,660],{"__ignoreMap":78},[82,268,269],{"class":84,"line":85},[82,270,271],{},"# agent.py\n",[82,273,274],{"class":84,"line":92},[82,275,276],{},"import json\n",[82,278,279],{"class":84,"line":114},[82,280,281],{},"import re\n",[82,283,284],{"class":84,"line":121},[82,285,286],{},"import requests\n",[82,288,289],{"class":84,"line":169},[82,290,118],{"emptyLinePlaceholder":117},[82,292,294],{"class":84,"line":293},6,[82,295,296],{},"OLLAMA_URL = \"http:\u002F\u002Flocalhost:11434\u002Fapi\u002Fchat\"\n",[82,298,300],{"class":84,"line":299},7,[82,301,302],{},"MODEL = \"hermes3:8b\"\n",[82,304,306],{"class":84,"line":305},8,[82,307,118],{"emptyLinePlaceholder":117},[82,309,311],{"class":84,"line":310},9,[82,312,313],{},"TOOLS = [\n",[82,315,317],{"class":84,"line":316},10,[82,318,319],{},"    {\n",[82,321,323],{"class":84,"line":322},11,[82,324,325],{},"        \"type\": \"function\",\n",[82,327,329],{"class":84,"line":328},12,[82,330,331],{},"        \"function\": {\n",[82,333,335],{"class":84,"line":334},13,[82,336,337],{},"            \"name\": \"get_weather\",\n",[82,339,341],{"class":84,"line":340},14,[82,342,343],{},"            \"description\": \"Returns current weather for a city.\",\n",[82,345,347],{"class":84,"line":346},15,[82,348,349],{},"            \"parameters\": {\n",[82,351,353],{"class":84,"line":352},16,[82,354,355],{},"                \"type\": \"object\",\n",[82,357,359],{"class":84,"line":358},17,[82,360,361],{},"                \"properties\": {\n",[82,363,365],{"class":84,"line":364},18,[82,366,367],{},"                    \"city\": {\"type\": \"string\", \"description\": \"City name\"}\n",[82,369,371],{"class":84,"line":370},19,[82,372,373],{},"                },\n",[82,375,377],{"class":84,"line":376},20,[82,378,379],{},"                \"required\": [\"city\"]\n",[82,381,383],{"class":84,"line":382},21,[82,384,385],{},"            }\n",[82,387,389],{"class":84,"line":388},22,[82,390,391],{},"        }\n",[82,393,395],{"class":84,"line":394},23,[82,396,397],{},"    }\n",[82,399,401],{"class":84,"line":400},24,[82,402,403],{},"]\n",[82,405,407],{"class":84,"line":406},25,[82,408,118],{"emptyLinePlaceholder":117},[82,410,412],{"class":84,"line":411},26,[82,413,414],{},"def get_weather(city: str) -> str:\n",[82,416,418],{"class":84,"line":417},27,[82,419,420],{},"    # Replace with a real API call in production\n",[82,422,424],{"class":84,"line":423},28,[82,425,426],{},"    return json.dumps({\"city\": city, \"temp_c\": 18, \"condition\": \"cloudy\"})\n",[82,428,430],{"class":84,"line":429},29,[82,431,118],{"emptyLinePlaceholder":117},[82,433,435],{"class":84,"line":434},30,[82,436,437],{},"TOOL_REGISTRY = {\"get_weather\": get_weather}\n",[82,439,441],{"class":84,"line":440},31,[82,442,118],{"emptyLinePlaceholder":117},[82,444,446],{"class":84,"line":445},32,[82,447,448],{},"def chat(messages: list, tools: list) -> dict:\n",[82,450,452],{"class":84,"line":451},33,[82,453,454],{},"    response = requests.post(OLLAMA_URL, json={\n",[82,456,458],{"class":84,"line":457},34,[82,459,460],{},"        \"model\": MODEL,\n",[82,462,464],{"class":84,"line":463},35,[82,465,466],{},"        \"messages\": messages,\n",[82,468,470],{"class":84,"line":469},36,[82,471,472],{},"        \"tools\": tools,\n",[82,474,476],{"class":84,"line":475},37,[82,477,478],{},"        \"stream\": False\n",[82,480,482],{"class":84,"line":481},38,[82,483,484],{},"    })\n",[82,486,488],{"class":84,"line":487},39,[82,489,490],{},"    response.raise_for_status()\n",[82,492,494],{"class":84,"line":493},40,[82,495,496],{},"    return response.json()[\"message\"]\n",[82,498,500],{"class":84,"line":499},41,[82,501,118],{"emptyLinePlaceholder":117},[82,503,505],{"class":84,"line":504},42,[82,506,507],{},"def run_agent(user_input: str):\n",[82,509,511],{"class":84,"line":510},43,[82,512,513],{},"    messages = [\n",[82,515,517],{"class":84,"line":516},44,[82,518,519],{},"        {\"role\": \"system\", \"content\": \"You are a helpful assistant with access to tools.\"},\n",[82,521,523],{"class":84,"line":522},45,[82,524,525],{},"        {\"role\": \"user\",   \"content\": user_input}\n",[82,527,529],{"class":84,"line":528},46,[82,530,531],{},"    ]\n",[82,533,535],{"class":84,"line":534},47,[82,536,118],{"emptyLinePlaceholder":117},[82,538,540],{"class":84,"line":539},48,[82,541,542],{},"    while True:\n",[82,544,546],{"class":84,"line":545},49,[82,547,548],{},"        reply = chat(messages, TOOLS)\n",[82,550,552],{"class":84,"line":551},50,[82,553,554],{},"        messages.append(reply)\n",[82,556,558],{"class":84,"line":557},51,[82,559,118],{"emptyLinePlaceholder":117},[82,561,563],{"class":84,"line":562},52,[82,564,565],{},"        if reply.get(\"tool_calls\"):\n",[82,567,569],{"class":84,"line":568},53,[82,570,571],{},"            for call in reply[\"tool_calls\"]:\n",[82,573,575],{"class":84,"line":574},54,[82,576,577],{},"                fn_name = call[\"function\"][\"name\"]\n",[82,579,581],{"class":84,"line":580},55,[82,582,583],{},"                fn_args = call[\"function\"][\"arguments\"]\n",[82,585,587],{"class":84,"line":586},56,[82,588,589],{},"                if isinstance(fn_args, str):\n",[82,591,593],{"class":84,"line":592},57,[82,594,595],{},"                    fn_args = json.loads(fn_args)\n",[82,597,599],{"class":84,"line":598},58,[82,600,118],{"emptyLinePlaceholder":117},[82,602,604],{"class":84,"line":603},59,[82,605,606],{},"                result = TOOL_REGISTRY[fn_name](**fn_args)\n",[82,608,610],{"class":84,"line":609},60,[82,611,612],{},"                messages.append({\n",[82,614,616],{"class":84,"line":615},61,[82,617,618],{},"                    \"role\": \"tool\",\n",[82,620,622],{"class":84,"line":621},62,[82,623,624],{},"                    \"content\": result\n",[82,626,628],{"class":84,"line":627},63,[82,629,630],{},"                })\n",[82,632,634],{"class":84,"line":633},64,[82,635,636],{},"        else:\n",[82,638,640],{"class":84,"line":639},65,[82,641,642],{},"            print(reply[\"content\"])\n",[82,644,646],{"class":84,"line":645},66,[82,647,648],{},"            break\n",[82,650,652],{"class":84,"line":651},67,[82,653,118],{"emptyLinePlaceholder":117},[82,655,657],{"class":84,"line":656},68,[82,658,659],{},"if __name__ == \"__main__\":\n",[82,661,663],{"class":84,"line":662},69,[82,664,665],{},"    run_agent(\"What is the weather in Kyiv?\")\n",[16,667,668],{},"Run it:",[73,670,672],{"className":75,"code":671,"language":77,"meta":78,"style":78},"python agent.py\n# The weather in Kyiv is 18°C and cloudy.\n",[33,673,674,681],{"__ignoreMap":78},[82,675,676,678],{"class":84,"line":85},[82,677,137],{"class":95},[82,679,680],{"class":103}," agent.py\n",[82,682,683],{"class":84,"line":92},[82,684,685],{"class":88},"# The weather in Kyiv is 18°C and cloudy.\n",[44,687],{},[11,689,691],{"id":690},"tool-registration-pattern","Tool Registration Pattern",[16,693,694],{},"For more than a handful of tools, use a decorator to auto-register:",[73,696,698],{"className":263,"code":697,"language":137,"meta":78,"style":78},"import inspect\nfrom typing import get_type_hints\n\nTOOLS = []\nTOOL_REGISTRY = {}\n\ndef tool(fn):\n    \"\"\"Register a function as an agent tool.\"\"\"\n    hints = get_type_hints(fn)\n    properties = {}\n    for name, hint in hints.items():\n        if name == \"return\":\n            continue\n        properties[name] = {\n            \"type\": \"string\" if hint == str else \"number\" if hint in (int, float) else \"object\"\n        }\n\n    TOOLS.append({\n        \"type\": \"function\",\n        \"function\": {\n            \"name\": fn.__name__,\n            \"description\": (fn.__doc__ or \"\").strip(),\n            \"parameters\": {\n                \"type\": \"object\",\n                \"properties\": properties,\n                \"required\": list(properties.keys())\n            }\n        }\n    })\n    TOOL_REGISTRY[fn.__name__] = fn\n    return fn\n\n@tool\ndef search_web(query: str) -> str:\n    \"\"\"Search the web for current information.\"\"\"\n    return f\"Results for: {query}\"\n\n@tool\ndef read_file(path: str) -> str:\n    \"\"\"Read content of a local file.\"\"\"\n    with open(path) as f:\n        return f.read()\n",[33,699,700,705,710,714,719,724,728,733,738,743,748,753,758,763,768,773,777,781,786,790,794,799,804,808,812,817,822,826,830,834,839,844,848,853,858,863,868,872,876,881,886,891],{"__ignoreMap":78},[82,701,702],{"class":84,"line":85},[82,703,704],{},"import inspect\n",[82,706,707],{"class":84,"line":92},[82,708,709],{},"from typing import get_type_hints\n",[82,711,712],{"class":84,"line":114},[82,713,118],{"emptyLinePlaceholder":117},[82,715,716],{"class":84,"line":121},[82,717,718],{},"TOOLS = []\n",[82,720,721],{"class":84,"line":169},[82,722,723],{},"TOOL_REGISTRY = {}\n",[82,725,726],{"class":84,"line":293},[82,727,118],{"emptyLinePlaceholder":117},[82,729,730],{"class":84,"line":299},[82,731,732],{},"def tool(fn):\n",[82,734,735],{"class":84,"line":305},[82,736,737],{},"    \"\"\"Register a function as an agent tool.\"\"\"\n",[82,739,740],{"class":84,"line":310},[82,741,742],{},"    hints = get_type_hints(fn)\n",[82,744,745],{"class":84,"line":316},[82,746,747],{},"    properties = {}\n",[82,749,750],{"class":84,"line":322},[82,751,752],{},"    for name, hint in hints.items():\n",[82,754,755],{"class":84,"line":328},[82,756,757],{},"        if name == \"return\":\n",[82,759,760],{"class":84,"line":334},[82,761,762],{},"            continue\n",[82,764,765],{"class":84,"line":340},[82,766,767],{},"        properties[name] = {\n",[82,769,770],{"class":84,"line":346},[82,771,772],{},"            \"type\": \"string\" if hint == str else \"number\" if hint in (int, float) else \"object\"\n",[82,774,775],{"class":84,"line":352},[82,776,391],{},[82,778,779],{"class":84,"line":358},[82,780,118],{"emptyLinePlaceholder":117},[82,782,783],{"class":84,"line":364},[82,784,785],{},"    TOOLS.append({\n",[82,787,788],{"class":84,"line":370},[82,789,325],{},[82,791,792],{"class":84,"line":376},[82,793,331],{},[82,795,796],{"class":84,"line":382},[82,797,798],{},"            \"name\": fn.__name__,\n",[82,800,801],{"class":84,"line":388},[82,802,803],{},"            \"description\": (fn.__doc__ or \"\").strip(),\n",[82,805,806],{"class":84,"line":394},[82,807,349],{},[82,809,810],{"class":84,"line":400},[82,811,355],{},[82,813,814],{"class":84,"line":406},[82,815,816],{},"                \"properties\": properties,\n",[82,818,819],{"class":84,"line":411},[82,820,821],{},"                \"required\": list(properties.keys())\n",[82,823,824],{"class":84,"line":417},[82,825,385],{},[82,827,828],{"class":84,"line":423},[82,829,391],{},[82,831,832],{"class":84,"line":429},[82,833,484],{},[82,835,836],{"class":84,"line":434},[82,837,838],{},"    TOOL_REGISTRY[fn.__name__] = fn\n",[82,840,841],{"class":84,"line":440},[82,842,843],{},"    return fn\n",[82,845,846],{"class":84,"line":445},[82,847,118],{"emptyLinePlaceholder":117},[82,849,850],{"class":84,"line":451},[82,851,852],{},"@tool\n",[82,854,855],{"class":84,"line":457},[82,856,857],{},"def search_web(query: str) -> str:\n",[82,859,860],{"class":84,"line":463},[82,861,862],{},"    \"\"\"Search the web for current information.\"\"\"\n",[82,864,865],{"class":84,"line":469},[82,866,867],{},"    return f\"Results for: {query}\"\n",[82,869,870],{"class":84,"line":475},[82,871,118],{"emptyLinePlaceholder":117},[82,873,874],{"class":84,"line":481},[82,875,852],{},[82,877,878],{"class":84,"line":487},[82,879,880],{},"def read_file(path: str) -> str:\n",[82,882,883],{"class":84,"line":493},[82,884,885],{},"    \"\"\"Read content of a local file.\"\"\"\n",[82,887,888],{"class":84,"line":499},[82,889,890],{},"    with open(path) as f:\n",[82,892,893],{"class":84,"line":504},[82,894,895],{},"        return f.read()\n",[44,897],{},[11,899,901],{"id":900},"optional-langgraph-orchestration","Optional: LangGraph Orchestration",[16,903,904],{},"For complex multi-step workflows with conditional branching, LangGraph adds minimal overhead:",[73,906,908],{"className":75,"code":907,"language":77,"meta":78,"style":78},"pip install langgraph langchain-ollama\n",[33,909,910],{"__ignoreMap":78},[82,911,912,914,916,919],{"class":84,"line":85},[82,913,172],{"class":95},[82,915,175],{"class":103},[82,917,918],{"class":103}," langgraph",[82,920,921],{"class":103}," langchain-ollama\n",[73,923,925],{"className":263,"code":924,"language":137,"meta":78,"style":78},"from langchain_ollama import ChatOllama\nfrom langgraph.prebuilt import create_react_agent\n\nllm = ChatOllama(model=\"hermes3:8b\")\n\n# define tools as LangChain Tool objects\nfrom langchain_core.tools import tool as lc_tool\n\n@lc_tool\ndef get_weather(city: str) -> str:\n    \"\"\"Returns weather for a city.\"\"\"\n    return f\"18°C, cloudy in {city}\"\n\nagent = create_react_agent(llm, tools=[get_weather])\nresult = agent.invoke({\"messages\": [(\"user\", \"Weather in Berlin?\")]})\nprint(result[\"messages\"][-1].content)\n",[33,926,927,932,937,941,946,950,955,960,964,969,973,978,983,987,992,997],{"__ignoreMap":78},[82,928,929],{"class":84,"line":85},[82,930,931],{},"from langchain_ollama import ChatOllama\n",[82,933,934],{"class":84,"line":92},[82,935,936],{},"from langgraph.prebuilt import create_react_agent\n",[82,938,939],{"class":84,"line":114},[82,940,118],{"emptyLinePlaceholder":117},[82,942,943],{"class":84,"line":121},[82,944,945],{},"llm = ChatOllama(model=\"hermes3:8b\")\n",[82,947,948],{"class":84,"line":169},[82,949,118],{"emptyLinePlaceholder":117},[82,951,952],{"class":84,"line":293},[82,953,954],{},"# define tools as LangChain Tool objects\n",[82,956,957],{"class":84,"line":299},[82,958,959],{},"from langchain_core.tools import tool as lc_tool\n",[82,961,962],{"class":84,"line":305},[82,963,118],{"emptyLinePlaceholder":117},[82,965,966],{"class":84,"line":310},[82,967,968],{},"@lc_tool\n",[82,970,971],{"class":84,"line":316},[82,972,414],{},[82,974,975],{"class":84,"line":322},[82,976,977],{},"    \"\"\"Returns weather for a city.\"\"\"\n",[82,979,980],{"class":84,"line":328},[82,981,982],{},"    return f\"18°C, cloudy in {city}\"\n",[82,984,985],{"class":84,"line":334},[82,986,118],{"emptyLinePlaceholder":117},[82,988,989],{"class":84,"line":340},[82,990,991],{},"agent = create_react_agent(llm, tools=[get_weather])\n",[82,993,994],{"class":84,"line":346},[82,995,996],{},"result = agent.invoke({\"messages\": [(\"user\", \"Weather in Berlin?\")]})\n",[82,998,999],{"class":84,"line":352},[82,1000,1001],{},"print(result[\"messages\"][-1].content)\n",[44,1003],{},[11,1005,1007],{"id":1006},"optional-chromadb-memory-backend","Optional: ChromaDB Memory Backend",[16,1009,1010],{},"Add persistent conversation memory in one install:",[73,1012,1014],{"className":75,"code":1013,"language":77,"meta":78,"style":78},"pip install chromadb\n",[33,1015,1016],{"__ignoreMap":78},[82,1017,1018,1020,1022],{"class":84,"line":85},[82,1019,172],{"class":95},[82,1021,175],{"class":103},[82,1023,1024],{"class":103}," chromadb\n",[73,1026,1028],{"className":263,"code":1027,"language":137,"meta":78,"style":78},"import chromadb\nfrom chromadb.utils import embedding_functions\n\nclient = chromadb.PersistentClient(path=\".agent_memory\")\nef = embedding_functions.DefaultEmbeddingFunction()\ncollection = client.get_or_create_collection(\"conversations\", embedding_function=ef)\n\ndef remember(text: str, doc_id: str):\n    collection.upsert(documents=[text], ids=[doc_id])\n\ndef recall(query: str, n: int = 3) -> list[str]:\n    results = collection.query(query_texts=[query], n_results=n)\n    return results[\"documents\"][0]\n",[33,1029,1030,1035,1040,1044,1049,1054,1059,1063,1068,1073,1077,1082,1087],{"__ignoreMap":78},[82,1031,1032],{"class":84,"line":85},[82,1033,1034],{},"import chromadb\n",[82,1036,1037],{"class":84,"line":92},[82,1038,1039],{},"from chromadb.utils import embedding_functions\n",[82,1041,1042],{"class":84,"line":114},[82,1043,118],{"emptyLinePlaceholder":117},[82,1045,1046],{"class":84,"line":121},[82,1047,1048],{},"client = chromadb.PersistentClient(path=\".agent_memory\")\n",[82,1050,1051],{"class":84,"line":169},[82,1052,1053],{},"ef = embedding_functions.DefaultEmbeddingFunction()\n",[82,1055,1056],{"class":84,"line":293},[82,1057,1058],{},"collection = client.get_or_create_collection(\"conversations\", embedding_function=ef)\n",[82,1060,1061],{"class":84,"line":299},[82,1062,118],{"emptyLinePlaceholder":117},[82,1064,1065],{"class":84,"line":305},[82,1066,1067],{},"def remember(text: str, doc_id: str):\n",[82,1069,1070],{"class":84,"line":310},[82,1071,1072],{},"    collection.upsert(documents=[text], ids=[doc_id])\n",[82,1074,1075],{"class":84,"line":316},[82,1076,118],{"emptyLinePlaceholder":117},[82,1078,1079],{"class":84,"line":322},[82,1080,1081],{},"def recall(query: str, n: int = 3) -> list[str]:\n",[82,1083,1084],{"class":84,"line":328},[82,1085,1086],{},"    results = collection.query(query_texts=[query], n_results=n)\n",[82,1088,1089],{"class":84,"line":334},[82,1090,1091],{},"    return results[\"documents\"][0]\n",[16,1093,1094],{},"Pass recalled context into the system message before each agent run.",[44,1096],{},[11,1098,1100],{"id":1099},"cost","Cost",[1102,1103,1104,1116],"table",{},[1105,1106,1107],"thead",{},[1108,1109,1110,1114],"tr",{},[1111,1112,1113],"th",{},"Option",[1111,1115,1100],{},[1117,1118,1119,1128,1136],"tbody",{},[1108,1120,1121,1125],{},[1122,1123,1124],"td",{},"hermes3:8b via Ollama",[1122,1126,1127],{},"$0 (local)",[1108,1129,1130,1133],{},[1122,1131,1132],{},"hermes3:8b via Groq",[1122,1134,1135],{},"Free tier: 14,400 req\u002Fday",[1108,1137,1138,1141],{},[1122,1139,1140],{},"hermes3:70b via Groq",[1122,1142,1143],{},"Free tier with rate limits",[16,1145,1146,1147,1150,1151,1154,1155,1158],{},"Groq API uses the same OpenAI-compatible endpoint — swap ",[33,1148,1149],{},"OLLAMA_URL"," for ",[33,1152,1153],{},"https:\u002F\u002Fapi.groq.com\u002Fopenai\u002Fv1\u002Fchat\u002Fcompletions"," and add an ",[33,1156,1157],{},"Authorization: Bearer \u003Ckey>"," header.",[44,1160],{},[11,1162,1164],{"id":1163},"see-also","See Also",[23,1166,1167,1175],{},[26,1168,1169,1174],{},[1170,1171,1173],"a",{"href":1172},"\u002Fen\u002Ftools","AI Agents tools directory"," — filter by AI Agents category",[26,1176,1177,1181],{},[1170,1178,1180],{"href":1179},"\u002Fen\u002Ftier-list\u002Ftext","Text model tier list"," — compare Hermes against GPT-4o, Claude, and others",[1183,1184,1185],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":78,"searchDepth":92,"depth":114,"links":1187},[1188,1189,1190,1191,1192,1193,1194,1195,1196],{"id":13,"depth":92,"text":14},{"id":48,"depth":92,"text":49},{"id":186,"depth":92,"text":187},{"id":256,"depth":92,"text":257},{"id":690,"depth":92,"text":691},{"id":900,"depth":92,"text":901},{"id":1006,"depth":92,"text":1007},{"id":1099,"depth":92,"text":1100},{"id":1163,"depth":92,"text":1164},"ai-agents","Set up a function-calling Hermes agent with tool registration and optional memory backend in under 20 minutes.","intermediate","md",{},"\u002Fen\u002Fguides\u002Fhermes-agent-setup","2026-05-30",{"title":6,"description":1198},"hermes-agent-setup","en\u002Fguides\u002Fhermes-agent-setup",[1208,1197,197,1209,137],"hermes","function-calling","e1XmAE0eY6yYF7ODeSmKYNvgaatBNRKkQJq7aQBDE44",{"id":1212,"title":1213,"body":1214,"category":2322,"description":2323,"difficulty":2324,"extension":1200,"meta":2325,"navigation":117,"path":2326,"published":1203,"readTime":406,"seo":2327,"slug":2328,"stem":2329,"tags":2330,"updated":1203,"__hash__":2334},"guides\u002Fen\u002Fguides\u002Fhetzner-vps-setup.md","Hetzner VPS Setup for AI Workloads",{"type":8,"value":1215,"toc":2306},[1216,1220,1223,1229,1246,1248,1252,1279,1281,1285,1359,1364,1375,1382,1384,1388,1391,1409,1416,1419,1446,1453,1455,1459,1490,1493,1538,1540,1544,1547,1604,1607,1638,1640,1644,1651,1666,1669,1677,1680,1698,1700,1704,1841,1844,1846,1850,1853,1965,1967,1971,2010,2013,2032,2035,2050,2052,2056,2059,2070,2120,2123,2186,2188,2192,2195,2201,2204,2225,2227,2231,2280,2283,2285,2289,2303],[11,1217,1219],{"id":1218},"overview","Overview",[16,1221,1222],{},"Hetzner Cloud offers the best price-per-core ratio in Europe for AI inference workloads. This guide gets you from zero to a hardened, Docker-ready server in under 30 minutes.",[16,1224,1225],{},[1226,1227,1228],"strong",{},"What you will have at the end:",[23,1230,1231,1234,1237,1240,1243],{},[26,1232,1233],{},"Non-root user with sudo",[26,1235,1236],{},"UFW firewall (only ports 22, 80, 443 open)",[26,1238,1239],{},"fail2ban blocking brute-force SSH",[26,1241,1242],{},"Docker + Docker Compose installed",[26,1244,1245],{},"Automated snapshot schedule",[44,1247],{},[11,1249,1251],{"id":1250},"_1-create-a-project","1. Create a Project",[1253,1254,1255,1265,1276],"ol",{},[26,1256,1257,1258,1264],{},"Sign up at ",[1170,1259,1263],{"href":1260,"rel":1261},"https:\u002F\u002Fconsole.hetzner.cloud",[1262],"nofollow","console.hetzner.cloud",".",[26,1266,1267,1268,1271,1272,1275],{},"Click ",[1226,1269,1270],{},"New Project"," → name it (e.g., ",[33,1273,1274],{},"ai-infra",").",[26,1277,1278],{},"Stay in the project — all resources below are created inside it.",[44,1280],{},[11,1282,1284],{"id":1283},"_2-choose-a-server-type","2. Choose a Server Type",[1102,1286,1287,1306],{},[1105,1288,1289],{},[1108,1290,1291,1294,1297,1300,1303],{},[1111,1292,1293],{},"Type",[1111,1295,1296],{},"vCPU",[1111,1298,1299],{},"RAM",[1111,1301,1302],{},"Disk",[1111,1304,1305],{},"Price\u002Fmo",[1117,1307,1308,1325,1342],{},[1108,1309,1310,1313,1316,1319,1322],{},[1122,1311,1312],{},"CX22",[1122,1314,1315],{},"2",[1122,1317,1318],{},"4 GB",[1122,1320,1321],{},"40 GB NVMe",[1122,1323,1324],{},"€4.51",[1108,1326,1327,1330,1333,1336,1339],{},[1122,1328,1329],{},"CPX31",[1122,1331,1332],{},"4",[1122,1334,1335],{},"8 GB",[1122,1337,1338],{},"160 GB NVMe",[1122,1340,1341],{},"€13.49",[1108,1343,1344,1347,1350,1353,1356],{},[1122,1345,1346],{},"CPX41",[1122,1348,1349],{},"8",[1122,1351,1352],{},"16 GB",[1122,1354,1355],{},"240 GB NVMe",[1122,1357,1358],{},"€26.49",[16,1360,1361],{},[1226,1362,1363],{},"Rule of thumb:",[23,1365,1366,1369,1372],{},[26,1367,1368],{},"CX22 → API proxy, lightweight agents, small Ollama models (≤3B).",[26,1370,1371],{},"CPX31 → Ollama with 7–8B models, self-hosted inference gateway.",[26,1373,1374],{},"CPX41 → Multiple models, vector DB, full agent stack.",[16,1376,1377,1378,1381],{},"Select ",[1226,1379,1380],{},"Ubuntu 24.04"," as the OS image.",[44,1383],{},[11,1385,1387],{"id":1386},"_3-upload-your-ssh-key","3. Upload Your SSH Key",[16,1389,1390],{},"Before creating the server, add your public key:",[73,1392,1394],{"className":75,"code":1393,"language":77,"meta":78,"style":78},"# on your local machine\ncat ~\u002F.ssh\u002Fid_ed25519.pub\n",[33,1395,1396,1401],{"__ignoreMap":78},[82,1397,1398],{"class":84,"line":85},[82,1399,1400],{"class":88},"# on your local machine\n",[82,1402,1403,1406],{"class":84,"line":92},[82,1404,1405],{"class":95},"cat",[82,1407,1408],{"class":103}," ~\u002F.ssh\u002Fid_ed25519.pub\n",[16,1410,1411,1412,1415],{},"Copy the output. In Hetzner console: ",[1226,1413,1414],{},"SSH Keys → Add SSH Key"," → paste → save.",[16,1417,1418],{},"If you do not have a key yet:",[73,1420,1422],{"className":75,"code":1421,"language":77,"meta":78,"style":78},"ssh-keygen -t ed25519 -C \"hetzner-ai\"\n# press Enter twice for no passphrase (or set one)\n",[33,1423,1424,1441],{"__ignoreMap":78},[82,1425,1426,1429,1432,1435,1438],{"class":84,"line":85},[82,1427,1428],{"class":95},"ssh-keygen",[82,1430,1431],{"class":99}," -t",[82,1433,1434],{"class":103}," ed25519",[82,1436,1437],{"class":99}," -C",[82,1439,1440],{"class":103}," \"hetzner-ai\"\n",[82,1442,1443],{"class":84,"line":92},[82,1444,1445],{"class":88},"# press Enter twice for no passphrase (or set one)\n",[16,1447,1448,1449,1452],{},"Select your key during server creation. Hetzner injects it into ",[33,1450,1451],{},"\u002Froot\u002F.ssh\u002Fauthorized_keys"," automatically.",[44,1454],{},[11,1456,1458],{"id":1457},"_4-first-login","4. First Login",[73,1460,1462],{"className":75,"code":1461,"language":77,"meta":78,"style":78},"ssh root@\u003CSERVER_IP>\n# confirm the fingerprint on first connect\n",[33,1463,1464,1485],{"__ignoreMap":78},[82,1465,1466,1469,1472,1475,1478,1482],{"class":84,"line":85},[82,1467,1468],{"class":95},"ssh",[82,1470,1471],{"class":103}," root@",[82,1473,1474],{"class":107},"\u003C",[82,1476,1477],{"class":103},"SERVER_I",[82,1479,1481],{"class":1480},"sVt8B","P",[82,1483,1484],{"class":107},">\n",[82,1486,1487],{"class":84,"line":92},[82,1488,1489],{"class":88},"# confirm the fingerprint on first connect\n",[16,1491,1492],{},"Update packages immediately:",[73,1494,1496],{"className":75,"code":1495,"language":77,"meta":78,"style":78},"apt update && apt upgrade -y\napt install -y curl wget git unzip\n",[33,1497,1498,1517],{"__ignoreMap":78},[82,1499,1500,1503,1506,1509,1511,1514],{"class":84,"line":85},[82,1501,1502],{"class":95},"apt",[82,1504,1505],{"class":103}," update",[82,1507,1508],{"class":1480}," && ",[82,1510,1502],{"class":95},[82,1512,1513],{"class":103}," upgrade",[82,1515,1516],{"class":99}," -y\n",[82,1518,1519,1521,1523,1526,1529,1532,1535],{"class":84,"line":92},[82,1520,1502],{"class":95},[82,1522,175],{"class":103},[82,1524,1525],{"class":99}," -y",[82,1527,1528],{"class":103}," curl",[82,1530,1531],{"class":103}," wget",[82,1533,1534],{"class":103}," git",[82,1536,1537],{"class":103}," unzip\n",[44,1539],{},[11,1541,1543],{"id":1542},"_5-create-a-non-root-user","5. Create a Non-Root User",[16,1545,1546],{},"Never run production workloads as root.",[73,1548,1550],{"className":75,"code":1549,"language":77,"meta":78,"style":78},"adduser deploy\n# enter a password, skip the other prompts\nusermod -aG sudo deploy\n\n# copy SSH key to the new user\nrsync --archive --chown=deploy:deploy ~\u002F.ssh \u002Fhome\u002Fdeploy\n",[33,1551,1552,1560,1565,1578,1582,1587],{"__ignoreMap":78},[82,1553,1554,1557],{"class":84,"line":85},[82,1555,1556],{"class":95},"adduser",[82,1558,1559],{"class":103}," deploy\n",[82,1561,1562],{"class":84,"line":92},[82,1563,1564],{"class":88},"# enter a password, skip the other prompts\n",[82,1566,1567,1570,1573,1576],{"class":84,"line":114},[82,1568,1569],{"class":95},"usermod",[82,1571,1572],{"class":99}," -aG",[82,1574,1575],{"class":103}," sudo",[82,1577,1559],{"class":103},[82,1579,1580],{"class":84,"line":121},[82,1581,118],{"emptyLinePlaceholder":117},[82,1583,1584],{"class":84,"line":169},[82,1585,1586],{"class":88},"# copy SSH key to the new user\n",[82,1588,1589,1592,1595,1598,1601],{"class":84,"line":293},[82,1590,1591],{"class":95},"rsync",[82,1593,1594],{"class":99}," --archive",[82,1596,1597],{"class":99}," --chown=deploy:deploy",[82,1599,1600],{"class":103}," ~\u002F.ssh",[82,1602,1603],{"class":103}," \u002Fhome\u002Fdeploy\n",[16,1605,1606],{},"Test the new user in a second terminal before closing root session:",[73,1608,1610],{"className":75,"code":1609,"language":77,"meta":78,"style":78},"ssh deploy@\u003CSERVER_IP>\nsudo whoami   # should return: root\n",[33,1611,1612,1627],{"__ignoreMap":78},[82,1613,1614,1616,1619,1621,1623,1625],{"class":84,"line":85},[82,1615,1468],{"class":95},[82,1617,1618],{"class":103}," deploy@",[82,1620,1474],{"class":107},[82,1622,1477],{"class":103},[82,1624,1481],{"class":1480},[82,1626,1484],{"class":107},[82,1628,1629,1632,1635],{"class":84,"line":92},[82,1630,1631],{"class":95},"sudo",[82,1633,1634],{"class":103}," whoami",[82,1636,1637],{"class":88},"   # should return: root\n",[44,1639],{},[11,1641,1643],{"id":1642},"_6-harden-ssh","6. Harden SSH",[16,1645,1646,1647,1650],{},"Edit ",[33,1648,1649],{},"\u002Fetc\u002Fssh\u002Fsshd_config",":",[73,1652,1654],{"className":75,"code":1653,"language":77,"meta":78,"style":78},"sudo nano \u002Fetc\u002Fssh\u002Fsshd_config\n",[33,1655,1656],{"__ignoreMap":78},[82,1657,1658,1660,1663],{"class":84,"line":85},[82,1659,1631],{"class":95},[82,1661,1662],{"class":103}," nano",[82,1664,1665],{"class":103}," \u002Fetc\u002Fssh\u002Fsshd_config\n",[16,1667,1668],{},"Set these values (add or uncomment):",[73,1670,1675],{"className":1671,"code":1673,"language":1674},[1672],"language-text","PermitRootLogin no\nPasswordAuthentication no\nPubkeyAuthentication yes\nPort 22\n","text",[33,1676,1673],{"__ignoreMap":78},[16,1678,1679],{},"Reload:",[73,1681,1683],{"className":75,"code":1682,"language":77,"meta":78,"style":78},"sudo systemctl reload ssh\n",[33,1684,1685],{"__ignoreMap":78},[82,1686,1687,1689,1692,1695],{"class":84,"line":85},[82,1688,1631],{"class":95},[82,1690,1691],{"class":103}," systemctl",[82,1693,1694],{"class":103}," reload",[82,1696,1697],{"class":103}," ssh\n",[44,1699],{},[11,1701,1703],{"id":1702},"_7-configure-ufw-firewall","7. Configure UFW Firewall",[73,1705,1707],{"className":75,"code":1706,"language":77,"meta":78,"style":78},"sudo apt install -y ufw\n\n# default: deny incoming, allow outgoing\nsudo ufw default deny incoming\nsudo ufw default allow outgoing\n\n# allow your access\nsudo ufw allow 22\u002Ftcp   # SSH\nsudo ufw allow 80\u002Ftcp   # HTTP\nsudo ufw allow 443\u002Ftcp  # HTTPS\n\nsudo ufw --force enable\nsudo ufw status verbose\n",[33,1708,1709,1723,1727,1732,1748,1762,1766,1771,1785,1799,1813,1817,1829],{"__ignoreMap":78},[82,1710,1711,1713,1716,1718,1720],{"class":84,"line":85},[82,1712,1631],{"class":95},[82,1714,1715],{"class":103}," apt",[82,1717,175],{"class":103},[82,1719,1525],{"class":99},[82,1721,1722],{"class":103}," ufw\n",[82,1724,1725],{"class":84,"line":92},[82,1726,118],{"emptyLinePlaceholder":117},[82,1728,1729],{"class":84,"line":114},[82,1730,1731],{"class":88},"# default: deny incoming, allow outgoing\n",[82,1733,1734,1736,1739,1742,1745],{"class":84,"line":121},[82,1735,1631],{"class":95},[82,1737,1738],{"class":103}," ufw",[82,1740,1741],{"class":103}," default",[82,1743,1744],{"class":103}," deny",[82,1746,1747],{"class":103}," incoming\n",[82,1749,1750,1752,1754,1756,1759],{"class":84,"line":169},[82,1751,1631],{"class":95},[82,1753,1738],{"class":103},[82,1755,1741],{"class":103},[82,1757,1758],{"class":103}," allow",[82,1760,1761],{"class":103}," outgoing\n",[82,1763,1764],{"class":84,"line":293},[82,1765,118],{"emptyLinePlaceholder":117},[82,1767,1768],{"class":84,"line":299},[82,1769,1770],{"class":88},"# allow your access\n",[82,1772,1773,1775,1777,1779,1782],{"class":84,"line":305},[82,1774,1631],{"class":95},[82,1776,1738],{"class":103},[82,1778,1758],{"class":103},[82,1780,1781],{"class":103}," 22\u002Ftcp",[82,1783,1784],{"class":88},"   # SSH\n",[82,1786,1787,1789,1791,1793,1796],{"class":84,"line":310},[82,1788,1631],{"class":95},[82,1790,1738],{"class":103},[82,1792,1758],{"class":103},[82,1794,1795],{"class":103}," 80\u002Ftcp",[82,1797,1798],{"class":88},"   # HTTP\n",[82,1800,1801,1803,1805,1807,1810],{"class":84,"line":316},[82,1802,1631],{"class":95},[82,1804,1738],{"class":103},[82,1806,1758],{"class":103},[82,1808,1809],{"class":103}," 443\u002Ftcp",[82,1811,1812],{"class":88},"  # HTTPS\n",[82,1814,1815],{"class":84,"line":322},[82,1816,118],{"emptyLinePlaceholder":117},[82,1818,1819,1821,1823,1826],{"class":84,"line":328},[82,1820,1631],{"class":95},[82,1822,1738],{"class":103},[82,1824,1825],{"class":99}," --force",[82,1827,1828],{"class":103}," enable\n",[82,1830,1831,1833,1835,1838],{"class":84,"line":334},[82,1832,1631],{"class":95},[82,1834,1738],{"class":103},[82,1836,1837],{"class":103}," status",[82,1839,1840],{"class":103}," verbose\n",[16,1842,1843],{},"Output should show three ALLOW rules and status: active.",[44,1845],{},[11,1847,1849],{"id":1848},"_8-install-fail2ban","8. Install fail2ban",[16,1851,1852],{},"fail2ban bans IPs after repeated failed SSH attempts.",[73,1854,1856],{"className":75,"code":1855,"language":77,"meta":78,"style":78},"sudo apt install -y fail2ban\n\nsudo tee \u002Fetc\u002Ffail2ban\u002Fjail.local \u003C\u003C'EOF'\n[DEFAULT]\nbantime  = 10m\nfindtime = 10m\nmaxretry = 5\n\n[sshd]\nenabled = true\nport    = 22\nEOF\n\nsudo systemctl enable --now fail2ban\nsudo fail2ban-client status sshd\n",[33,1857,1858,1871,1875,1891,1896,1901,1906,1911,1915,1920,1925,1930,1935,1939,1953],{"__ignoreMap":78},[82,1859,1860,1862,1864,1866,1868],{"class":84,"line":85},[82,1861,1631],{"class":95},[82,1863,1715],{"class":103},[82,1865,175],{"class":103},[82,1867,1525],{"class":99},[82,1869,1870],{"class":103}," fail2ban\n",[82,1872,1873],{"class":84,"line":92},[82,1874,118],{"emptyLinePlaceholder":117},[82,1876,1877,1879,1882,1885,1888],{"class":84,"line":114},[82,1878,1631],{"class":95},[82,1880,1881],{"class":103}," tee",[82,1883,1884],{"class":103}," \u002Fetc\u002Ffail2ban\u002Fjail.local",[82,1886,1887],{"class":107}," \u003C\u003C",[82,1889,1890],{"class":103},"'EOF'\n",[82,1892,1893],{"class":84,"line":121},[82,1894,1895],{"class":103},"[DEFAULT]\n",[82,1897,1898],{"class":84,"line":169},[82,1899,1900],{"class":103},"bantime  = 10m\n",[82,1902,1903],{"class":84,"line":293},[82,1904,1905],{"class":103},"findtime = 10m\n",[82,1907,1908],{"class":84,"line":299},[82,1909,1910],{"class":103},"maxretry = 5\n",[82,1912,1913],{"class":84,"line":305},[82,1914,118],{"emptyLinePlaceholder":117},[82,1916,1917],{"class":84,"line":310},[82,1918,1919],{"class":103},"[sshd]\n",[82,1921,1922],{"class":84,"line":316},[82,1923,1924],{"class":103},"enabled = true\n",[82,1926,1927],{"class":84,"line":322},[82,1928,1929],{"class":103},"port    = 22\n",[82,1931,1932],{"class":84,"line":328},[82,1933,1934],{"class":103},"EOF\n",[82,1936,1937],{"class":84,"line":334},[82,1938,118],{"emptyLinePlaceholder":117},[82,1940,1941,1943,1945,1948,1951],{"class":84,"line":340},[82,1942,1631],{"class":95},[82,1944,1691],{"class":103},[82,1946,1947],{"class":103}," enable",[82,1949,1950],{"class":99}," --now",[82,1952,1870],{"class":103},[82,1954,1955,1957,1960,1962],{"class":84,"line":346},[82,1956,1631],{"class":95},[82,1958,1959],{"class":103}," fail2ban-client",[82,1961,1837],{"class":103},[82,1963,1964],{"class":103}," sshd\n",[44,1966],{},[11,1968,1970],{"id":1969},"_9-install-docker","9. Install Docker",[73,1972,1974],{"className":75,"code":1973,"language":77,"meta":78,"style":78},"curl -fsSL https:\u002F\u002Fget.docker.com | sudo sh\nsudo usermod -aG docker deploy\n# log out and back in for group to take effect\n",[33,1975,1976,1991,2005],{"__ignoreMap":78},[82,1977,1978,1980,1982,1985,1987,1989],{"class":84,"line":85},[82,1979,96],{"class":95},[82,1981,100],{"class":99},[82,1983,1984],{"class":103}," https:\u002F\u002Fget.docker.com",[82,1986,108],{"class":107},[82,1988,1575],{"class":95},[82,1990,111],{"class":103},[82,1992,1993,1995,1998,2000,2003],{"class":84,"line":92},[82,1994,1631],{"class":95},[82,1996,1997],{"class":103}," usermod",[82,1999,1572],{"class":99},[82,2001,2002],{"class":103}," docker",[82,2004,1559],{"class":103},[82,2006,2007],{"class":84,"line":114},[82,2008,2009],{"class":88},"# log out and back in for group to take effect\n",[16,2011,2012],{},"Verify:",[73,2014,2016],{"className":75,"code":2015,"language":77,"meta":78,"style":78},"docker run --rm hello-world\n",[33,2017,2018],{"__ignoreMap":78},[82,2019,2020,2023,2026,2029],{"class":84,"line":85},[82,2021,2022],{"class":95},"docker",[82,2024,2025],{"class":103}," run",[82,2027,2028],{"class":99}," --rm",[82,2030,2031],{"class":103}," hello-world\n",[16,2033,2034],{},"Install Docker Compose plugin (included since Docker 24, but confirm):",[73,2036,2038],{"className":75,"code":2037,"language":77,"meta":78,"style":78},"docker compose version\n",[33,2039,2040],{"__ignoreMap":78},[82,2041,2042,2044,2047],{"class":84,"line":85},[82,2043,2022],{"class":95},[82,2045,2046],{"class":103}," compose",[82,2048,2049],{"class":103}," version\n",[44,2051],{},[11,2053,2055],{"id":2054},"_10-set-up-automated-snapshots","10. Set Up Automated Snapshots",[16,2057,2058],{},"Hetzner charges €0.0119\u002FGB\u002Fmonth for snapshots. For a CX22 (40 GB, typically 5–10 GB compressed), that is ~€0.06–0.12\u002Fmo.",[16,2060,2061,2062,2065,2066,2069],{},"In Hetzner console: ",[1226,2063,2064],{},"Server → Backups"," → enable (adds 20% to server cost) ",[1226,2067,2068],{},"or"," use snapshots manually before upgrades:",[73,2071,2073],{"className":75,"code":2072,"language":77,"meta":78,"style":78},"# via hcloud CLI (optional)\nhcloud server create-image \u003CSERVER_ID> --type snapshot --description \"pre-upgrade-$(date +%Y%m%d)\"\n",[33,2074,2075,2080],{"__ignoreMap":78},[82,2076,2077],{"class":84,"line":85},[82,2078,2079],{"class":88},"# via hcloud CLI (optional)\n",[82,2081,2082,2085,2088,2091,2094,2096,2099,2102,2105,2108,2111,2114,2117],{"class":84,"line":92},[82,2083,2084],{"class":95},"hcloud",[82,2086,2087],{"class":103}," server",[82,2089,2090],{"class":103}," create-image",[82,2092,2093],{"class":107}," \u003C",[82,2095,1477],{"class":103},[82,2097,2098],{"class":1480},"D",[82,2100,2101],{"class":107},">",[82,2103,2104],{"class":99}," --type",[82,2106,2107],{"class":103}," snapshot",[82,2109,2110],{"class":99}," --description",[82,2112,2113],{"class":103}," \"pre-upgrade-$(",[82,2115,2116],{"class":95},"date",[82,2118,2119],{"class":103}," +%Y%m%d)\"\n",[16,2121,2122],{},"For CLI access:",[73,2124,2126],{"className":75,"code":2125,"language":77,"meta":78,"style":78},"# install hcloud on your local machine\ncurl -Lo hcloud.tar.gz https:\u002F\u002Fgithub.com\u002Fhetznercloud\u002Fcli\u002Freleases\u002Flatest\u002Fdownload\u002Fhcloud-linux-amd64.tar.gz\ntar -xzf hcloud.tar.gz\nsudo mv hcloud \u002Fusr\u002Flocal\u002Fbin\u002F\nhcloud context create ai-infra   # paste API token from console\n",[33,2127,2128,2133,2146,2157,2170],{"__ignoreMap":78},[82,2129,2130],{"class":84,"line":85},[82,2131,2132],{"class":88},"# install hcloud on your local machine\n",[82,2134,2135,2137,2140,2143],{"class":84,"line":92},[82,2136,96],{"class":95},[82,2138,2139],{"class":99}," -Lo",[82,2141,2142],{"class":103}," hcloud.tar.gz",[82,2144,2145],{"class":103}," https:\u002F\u002Fgithub.com\u002Fhetznercloud\u002Fcli\u002Freleases\u002Flatest\u002Fdownload\u002Fhcloud-linux-amd64.tar.gz\n",[82,2147,2148,2151,2154],{"class":84,"line":114},[82,2149,2150],{"class":95},"tar",[82,2152,2153],{"class":99}," -xzf",[82,2155,2156],{"class":103}," hcloud.tar.gz\n",[82,2158,2159,2161,2164,2167],{"class":84,"line":121},[82,2160,1631],{"class":95},[82,2162,2163],{"class":103}," mv",[82,2165,2166],{"class":103}," hcloud",[82,2168,2169],{"class":103}," \u002Fusr\u002Flocal\u002Fbin\u002F\n",[82,2171,2172,2174,2177,2180,2183],{"class":84,"line":169},[82,2173,2084],{"class":95},[82,2175,2176],{"class":103}," context",[82,2178,2179],{"class":103}," create",[82,2181,2182],{"class":103}," ai-infra",[82,2184,2185],{"class":88},"   # paste API token from console\n",[44,2187],{},[11,2189,2191],{"id":2190},"_11-point-a-dns-record","11. Point a DNS Record",[16,2193,2194],{},"In your DNS provider, add an A record:",[73,2196,2199],{"className":2197,"code":2198,"language":1674},[1672],"A   ai.yourdomain.com   \u003CSERVER_IP>   TTL 300\n",[33,2200,2198],{"__ignoreMap":78},[16,2202,2203],{},"Verify propagation:",[73,2205,2207],{"className":75,"code":2206,"language":77,"meta":78,"style":78},"dig +short ai.yourdomain.com\n# should return your server IP within 5 minutes\n",[33,2208,2209,2220],{"__ignoreMap":78},[82,2210,2211,2214,2217],{"class":84,"line":85},[82,2212,2213],{"class":95},"dig",[82,2215,2216],{"class":103}," +short",[82,2218,2219],{"class":103}," ai.yourdomain.com\n",[82,2221,2222],{"class":84,"line":92},[82,2223,2224],{"class":88},"# should return your server IP within 5 minutes\n",[44,2226],{},[11,2228,2230],{"id":2229},"_12-cost-summary","12. Cost Summary",[1102,2232,2233,2246],{},[1105,2234,2235],{},[1108,2236,2237,2240,2243],{},[1111,2238,2239],{},"Config",[1111,2241,2242],{},"Use Case",[1111,2244,2245],{},"Monthly Cost",[1117,2247,2248,2258,2269],{},[1108,2249,2250,2252,2255],{},[1122,2251,1312],{},[1122,2253,2254],{},"API proxy, small agents",[1122,2256,2257],{},"~€4.51",[1108,2259,2260,2263,2266],{},[1122,2261,2262],{},"CPX31 + snapshots",[1122,2264,2265],{},"7B models, agent stack",[1122,2267,2268],{},"~€14–16",[1108,2270,2271,2274,2277],{},[1122,2272,2273],{},"CPX31 + IPv4 + backups",[1122,2275,2276],{},"Production inference",[1122,2278,2279],{},"~€16–18",[16,2281,2282],{},"IPv4 addresses cost an additional €0.50\u002Fmo. IPv6 is free and works for most setups.",[44,2284],{},[11,2286,2288],{"id":2287},"next-steps","Next Steps",[23,2290,2291,2297,2300],{},[26,2292,2293,2294],{},"Install Ollama on the server: ",[33,2295,2296],{},"curl -fsSL https:\u002F\u002Follama.com\u002Finstall.sh | sh",[26,2298,2299],{},"Set up Nginx as a reverse proxy with Let's Encrypt",[26,2301,2302],{},"Deploy an OpenAI-compatible inference gateway (LiteLLM, llama.cpp server)",[1183,2304,2305],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":78,"searchDepth":92,"depth":114,"links":2307},[2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321],{"id":1218,"depth":92,"text":1219},{"id":1250,"depth":92,"text":1251},{"id":1283,"depth":92,"text":1284},{"id":1386,"depth":92,"text":1387},{"id":1457,"depth":92,"text":1458},{"id":1542,"depth":92,"text":1543},{"id":1642,"depth":92,"text":1643},{"id":1702,"depth":92,"text":1703},{"id":1848,"depth":92,"text":1849},{"id":1969,"depth":92,"text":1970},{"id":2054,"depth":92,"text":2055},{"id":2190,"depth":92,"text":2191},{"id":2229,"depth":92,"text":2230},{"id":2287,"depth":92,"text":2288},"vps","Rent and harden a Hetzner Cloud VPS for running local LLMs, agents, or a private inference gateway.","beginner",{},"\u002Fen\u002Fguides\u002Fhetzner-vps-setup",{"title":1213,"description":2323},"hetzner-vps-setup","en\u002Fguides\u002Fhetzner-vps-setup",[2331,2322,2332,1468,2333],"hetzner","devops","ufw","wtVDW9ODhnfcAfvRElGAmFdkdznRukpDNw5bp3AbzU0",{"id":2336,"title":2337,"body":2338,"category":3294,"description":3295,"difficulty":1199,"extension":1200,"meta":3296,"navigation":117,"path":3297,"published":1203,"readTime":388,"seo":3298,"slug":3299,"stem":3300,"tags":3301,"updated":1203,"__hash__":3305},"guides\u002Fen\u002Fguides\u002Flocal-llm-mac.md","Run Local LLMs on Mac (Apple Silicon)",{"type":8,"value":2339,"toc":3274},[2340,2344,2347,2352,2410,2416,2422,2428,2431,2433,2437,2440,2455,2458,2475,2478,2495,2498,2515,2517,2521,2535,2538,2541,2574,2585,2587,2591,2594,2699,2705,2708,2722,2724,2728,2733,2774,2778,2831,2835,2876,2878,2882,2885,2888,2908,2911,2914,2949,2951,2955,2958,2962,2965,3037,3045,3049,3055,3059,3079,3082,3084,3088,3095,3157,3159,3163,3241,3248,3254,3256,3258,3271],[11,2341,2343],{"id":2342},"hardware-requirements","Hardware Requirements",[16,2345,2346],{},"Apple Silicon Macs use unified memory — the same physical RAM serves both CPU and GPU. This means a 16 GB M2 Mac can run a 7–9B model with acceptable speed, because the GPU does not need a separate VRAM pool.",[16,2348,2349],{},[1226,2350,2351],{},"Minimum requirements:",[1102,2353,2354,2367],{},[1105,2355,2356],{},[1108,2357,2358,2361,2364],{},[1111,2359,2360],{},"Spec",[1111,2362,2363],{},"Minimum",[1111,2365,2366],{},"Recommended",[1117,2368,2369,2380,2388,2399],{},[1108,2370,2371,2374,2377],{},[1122,2372,2373],{},"Chip",[1122,2375,2376],{},"M1",[1122,2378,2379],{},"M2 \u002F M3",[1108,2381,2382,2384,2386],{},[1122,2383,1299],{},[1122,2385,1335],{},[1122,2387,1352],{},[1108,2389,2390,2393,2396],{},[1122,2391,2392],{},"Storage",[1122,2394,2395],{},"50 GB free",[1122,2397,2398],{},"100 GB free",[1108,2400,2401,2404,2407],{},[1122,2402,2403],{},"macOS",[1122,2405,2406],{},"13 Ventura",[1122,2408,2409],{},"14 Sonoma+",[16,2411,2412,2415],{},[1226,2413,2414],{},"8 GB RAM reality check:"," You can run 3B–7B models at Q4_K_M quantization. macOS keeps ~2–3 GB for the OS. That leaves ~5–6 GB usable. Expect slower token generation and potential swapping.",[16,2417,2418,2421],{},[1226,2419,2420],{},"16 GB:"," Run 7B–13B models comfortably. The sweet spot for most users.",[16,2423,2424,2427],{},[1226,2425,2426],{},"32 GB+:"," Run 30B+ models (Llama 3.3 70B at Q2_K fits in 35 GB).",[16,2429,2430],{},"Intel Macs (pre-2020) are not supported — Ollama requires Apple Silicon for Metal acceleration.",[44,2432],{},[11,2434,2436],{"id":2435},"install-ollama","Install Ollama",[16,2438,2439],{},"Homebrew is the simplest path:",[73,2441,2443],{"className":75,"code":2442,"language":77,"meta":78,"style":78},"brew install ollama\n",[33,2444,2445],{"__ignoreMap":78},[82,2446,2447,2450,2452],{"class":84,"line":85},[82,2448,2449],{"class":95},"brew",[82,2451,175],{"class":103},[82,2453,2454],{"class":103}," ollama\n",[16,2456,2457],{},"Or use the official installer (no Homebrew required):",[73,2459,2461],{"className":75,"code":2460,"language":77,"meta":78,"style":78},"curl -fsSL https:\u002F\u002Follama.com\u002Finstall.sh | sh\n",[33,2462,2463],{"__ignoreMap":78},[82,2464,2465,2467,2469,2471,2473],{"class":84,"line":85},[82,2466,96],{"class":95},[82,2468,100],{"class":99},[82,2470,104],{"class":103},[82,2472,108],{"class":107},[82,2474,111],{"class":95},[16,2476,2477],{},"Verify installation:",[73,2479,2481],{"className":75,"code":2480,"language":77,"meta":78,"style":78},"ollama --version\n# ollama version 0.3.x\n",[33,2482,2483,2490],{"__ignoreMap":78},[82,2484,2485,2487],{"class":84,"line":85},[82,2486,197],{"class":95},[82,2488,2489],{"class":99}," --version\n",[82,2491,2492],{"class":84,"line":92},[82,2493,2494],{"class":88},"# ollama version 0.3.x\n",[16,2496,2497],{},"Start the Ollama server (runs automatically as a background service after install, but you can also start it manually):",[73,2499,2501],{"className":75,"code":2500,"language":77,"meta":78,"style":78},"ollama serve\n# Listening on 127.0.0.1:11434\n",[33,2502,2503,2510],{"__ignoreMap":78},[82,2504,2505,2507],{"class":84,"line":85},[82,2506,197],{"class":95},[82,2508,2509],{"class":103}," serve\n",[82,2511,2512],{"class":84,"line":92},[82,2513,2514],{"class":88},"# Listening on 127.0.0.1:11434\n",[44,2516],{},[11,2518,2520],{"id":2519},"pull-your-first-model","Pull Your First Model",[73,2522,2524],{"className":75,"code":2523,"language":77,"meta":78,"style":78},"ollama pull llama3.2:3b\n",[33,2525,2526],{"__ignoreMap":78},[82,2527,2528,2530,2532],{"class":84,"line":85},[82,2529,197],{"class":95},[82,2531,200],{"class":103},[82,2533,2534],{"class":103}," llama3.2:3b\n",[16,2536,2537],{},"This downloads a 3B parameter Llama 3.2 model (Q4_K_M, ~2 GB). Fast download, very fast on M2.",[16,2539,2540],{},"Run it immediately in the terminal:",[73,2542,2544],{"className":75,"code":2543,"language":77,"meta":78,"style":78},"ollama run llama3.2:3b\n>>> Tell me about Apple Silicon.\n",[33,2545,2546,2554],{"__ignoreMap":78},[82,2547,2548,2550,2552],{"class":84,"line":85},[82,2549,197],{"class":95},[82,2551,2025],{"class":103},[82,2553,2534],{"class":103},[82,2555,2556,2559,2562,2565,2568,2571],{"class":84,"line":92},[82,2557,2558],{"class":1480},">>> ",[82,2560,2561],{"class":95},"Tell",[82,2563,2564],{"class":103}," me",[82,2566,2567],{"class":103}," about",[82,2569,2570],{"class":103}," Apple",[82,2572,2573],{"class":103}," Silicon.\n",[16,2575,2576,2577,2580,2581,2584],{},"Press ",[33,2578,2579],{},"Ctrl+D"," or type ",[33,2582,2583],{},"\u002Fbye"," to exit the interactive session.",[44,2586],{},[11,2588,2590],{"id":2589},"quantization-tradeoffs","Quantization Tradeoffs",[16,2592,2593],{},"GGUF quantization reduces model size at the cost of slight quality degradation. Ollama uses llama.cpp under the hood and pulls pre-quantized models from the Ollama library.",[1102,2595,2596,2615],{},[1105,2597,2598],{},[1108,2599,2600,2603,2606,2609,2612],{},[1111,2601,2602],{},"Format",[1111,2604,2605],{},"Size (7B model)",[1111,2607,2608],{},"Quality",[1111,2610,2611],{},"RAM needed",[1111,2613,2614],{},"Speed (M2)",[1117,2616,2617,2634,2651,2667,2684],{},[1108,2618,2619,2622,2625,2628,2631],{},[1122,2620,2621],{},"F16",[1122,2623,2624],{},"~14 GB",[1122,2626,2627],{},"Best",[1122,2629,2630],{},"18+ GB",[1122,2632,2633],{},"Slow",[1108,2635,2636,2639,2642,2645,2648],{},[1122,2637,2638],{},"Q8_0",[1122,2640,2641],{},"~7 GB",[1122,2643,2644],{},"Excellent",[1122,2646,2647],{},"10 GB",[1122,2649,2650],{},"Good",[1108,2652,2653,2656,2659,2661,2664],{},[1122,2654,2655],{},"Q4_K_M",[1122,2657,2658],{},"~4 GB",[1122,2660,2650],{},[1122,2662,2663],{},"6 GB",[1122,2665,2666],{},"Fast",[1108,2668,2669,2672,2675,2678,2681],{},[1122,2670,2671],{},"Q3_K_M",[1122,2673,2674],{},"~3.3 GB",[1122,2676,2677],{},"Fair",[1122,2679,2680],{},"5 GB",[1122,2682,2683],{},"Very fast",[1108,2685,2686,2689,2692,2695,2697],{},[1122,2687,2688],{},"Q2_K",[1122,2690,2691],{},"~2.5 GB",[1122,2693,2694],{},"Acceptable",[1122,2696,1318],{},[1122,2698,2683],{},[16,2700,2701,2704],{},[1226,2702,2703],{},"Recommendation:"," Use Q4_K_M by default. It is the best tradeoff for most workloads. Q8_0 if you have 16+ GB and need higher accuracy.",[16,2706,2707],{},"Ollama automatically selects Q4_K_M when you pull without specifying a tag. Specify explicitly with a colon:",[73,2709,2711],{"className":75,"code":2710,"language":77,"meta":78,"style":78},"ollama pull llama3.2:8b-instruct-q8_0\n",[33,2712,2713],{"__ignoreMap":78},[82,2714,2715,2717,2719],{"class":84,"line":85},[82,2716,197],{"class":95},[82,2718,200],{"class":103},[82,2720,2721],{"class":103}," llama3.2:8b-instruct-q8_0\n",[44,2723],{},[11,2725,2727],{"id":2726},"model-recommendations-by-ram","Model Recommendations by RAM",[2729,2730,2732],"h3",{"id":2731},"_8-gb-ram","8 GB RAM",[73,2734,2736],{"className":75,"code":2735,"language":77,"meta":78,"style":78},"ollama pull llama3.2:3b       # general purpose, fast\nollama pull phi4-mini         # Microsoft Phi-4 Mini, strong at coding\nollama pull gemma3:4b         # Google Gemma 3, good instruction following\n",[33,2737,2738,2750,2762],{"__ignoreMap":78},[82,2739,2740,2742,2744,2747],{"class":84,"line":85},[82,2741,197],{"class":95},[82,2743,200],{"class":103},[82,2745,2746],{"class":103}," llama3.2:3b",[82,2748,2749],{"class":88},"       # general purpose, fast\n",[82,2751,2752,2754,2756,2759],{"class":84,"line":92},[82,2753,197],{"class":95},[82,2755,200],{"class":103},[82,2757,2758],{"class":103}," phi4-mini",[82,2760,2761],{"class":88},"         # Microsoft Phi-4 Mini, strong at coding\n",[82,2763,2764,2766,2768,2771],{"class":84,"line":114},[82,2765,197],{"class":95},[82,2767,200],{"class":103},[82,2769,2770],{"class":103}," gemma3:4b",[82,2772,2773],{"class":88},"         # Google Gemma 3, good instruction following\n",[2729,2775,2777],{"id":2776},"_16-gb-ram","16 GB RAM",[73,2779,2781],{"className":75,"code":2780,"language":77,"meta":78,"style":78},"ollama pull llama3.3:8b       # best general-purpose 8B model (Q4_K_M)\nollama pull qwen2.5:7b        # strong multilingual and coding\nollama pull mistral-nemo:12b  # Mistral NeMo 12B, excellent for instruction\nollama pull deepseek-r1:8b    # reasoning-focused, CoT outputs\n",[33,2782,2783,2795,2807,2819],{"__ignoreMap":78},[82,2784,2785,2787,2789,2792],{"class":84,"line":85},[82,2786,197],{"class":95},[82,2788,200],{"class":103},[82,2790,2791],{"class":103}," llama3.3:8b",[82,2793,2794],{"class":88},"       # best general-purpose 8B model (Q4_K_M)\n",[82,2796,2797,2799,2801,2804],{"class":84,"line":92},[82,2798,197],{"class":95},[82,2800,200],{"class":103},[82,2802,2803],{"class":103}," qwen2.5:7b",[82,2805,2806],{"class":88},"        # strong multilingual and coding\n",[82,2808,2809,2811,2813,2816],{"class":84,"line":114},[82,2810,197],{"class":95},[82,2812,200],{"class":103},[82,2814,2815],{"class":103}," mistral-nemo:12b",[82,2817,2818],{"class":88},"  # Mistral NeMo 12B, excellent for instruction\n",[82,2820,2821,2823,2825,2828],{"class":84,"line":121},[82,2822,197],{"class":95},[82,2824,200],{"class":103},[82,2826,2827],{"class":103}," deepseek-r1:8b",[82,2829,2830],{"class":88},"    # reasoning-focused, CoT outputs\n",[2729,2832,2834],{"id":2833},"_32-gb-ram","32 GB RAM",[73,2836,2838],{"className":75,"code":2837,"language":77,"meta":78,"style":78},"ollama pull llama3.3:70b      # Llama 3.3 70B at Q2_K\nollama pull qwen2.5:32b       # excellent coding model\nollama pull deepseek-r1:32b   # reasoning, competitive with GPT-4o on benchmarks\n",[33,2839,2840,2852,2864],{"__ignoreMap":78},[82,2841,2842,2844,2846,2849],{"class":84,"line":85},[82,2843,197],{"class":95},[82,2845,200],{"class":103},[82,2847,2848],{"class":103}," llama3.3:70b",[82,2850,2851],{"class":88},"      # Llama 3.3 70B at Q2_K\n",[82,2853,2854,2856,2858,2861],{"class":84,"line":92},[82,2855,197],{"class":95},[82,2857,200],{"class":103},[82,2859,2860],{"class":103}," qwen2.5:32b",[82,2862,2863],{"class":88},"       # excellent coding model\n",[82,2865,2866,2868,2870,2873],{"class":84,"line":114},[82,2867,197],{"class":95},[82,2869,200],{"class":103},[82,2871,2872],{"class":103}," deepseek-r1:32b",[82,2874,2875],{"class":88},"   # reasoning, competitive with GPT-4o on benchmarks\n",[44,2877],{},[11,2879,2881],{"id":2880},"metal-mps-acceleration","Metal \u002F MPS Acceleration",[16,2883,2884],{},"Ollama uses Metal Performance Shaders (MPS) automatically on Apple Silicon. No configuration needed.",[16,2886,2887],{},"To confirm Metal is active, check the Ollama server log:",[73,2889,2891],{"className":75,"code":2890,"language":77,"meta":78,"style":78},"# In the Ollama server terminal, look for:\n# llm_load_tensors: offloading 32 repeating layers to GPU\n# llm_load_tensors: offloaded 33\u002F33 layers to GPU\n",[33,2892,2893,2898,2903],{"__ignoreMap":78},[82,2894,2895],{"class":84,"line":85},[82,2896,2897],{"class":88},"# In the Ollama server terminal, look for:\n",[82,2899,2900],{"class":84,"line":92},[82,2901,2902],{"class":88},"# llm_load_tensors: offloading 32 repeating layers to GPU\n",[82,2904,2905],{"class":84,"line":114},[82,2906,2907],{"class":88},"# llm_load_tensors: offloaded 33\u002F33 layers to GPU\n",[16,2909,2910],{},"When all layers are offloaded to GPU, inference is fastest. If only partial offload occurs (due to RAM pressure), performance drops significantly.",[16,2912,2913],{},"Force full GPU offload by ensuring no other memory-heavy apps are running:",[73,2915,2917],{"className":75,"code":2916,"language":77,"meta":78,"style":78},"# check what's using RAM\ntop -l 1 -s 0 | head -20\n",[33,2918,2919,2924],{"__ignoreMap":78},[82,2920,2921],{"class":84,"line":85},[82,2922,2923],{"class":88},"# check what's using RAM\n",[82,2925,2926,2929,2932,2935,2938,2941,2943,2946],{"class":84,"line":92},[82,2927,2928],{"class":95},"top",[82,2930,2931],{"class":99}," -l",[82,2933,2934],{"class":99}," 1",[82,2936,2937],{"class":99}," -s",[82,2939,2940],{"class":99}," 0",[82,2942,108],{"class":107},[82,2944,2945],{"class":95}," head",[82,2947,2948],{"class":99}," -20\n",[44,2950],{},[11,2952,2954],{"id":2953},"open-webui","Open WebUI",[16,2956,2957],{},"Open WebUI provides a ChatGPT-like interface for Ollama running locally.",[2729,2959,2961],{"id":2960},"install-with-docker","Install with Docker",[16,2963,2964],{},"Ensure Docker Desktop for Mac is installed and running, then:",[73,2966,2968],{"className":75,"code":2967,"language":77,"meta":78,"style":78},"docker run -d \\\n  --name open-webui \\\n  -p 3000:8080 \\\n  -v open-webui:\u002Fapp\u002Fbackend\u002Fdata \\\n  -e OLLAMA_BASE_URL=http:\u002F\u002Fhost.docker.internal:11434 \\\n  --restart always \\\n  ghcr.io\u002Fopen-webui\u002Fopen-webui:main\n",[33,2969,2970,2982,2992,3002,3012,3022,3032],{"__ignoreMap":78},[82,2971,2972,2974,2976,2979],{"class":84,"line":85},[82,2973,2022],{"class":95},[82,2975,2025],{"class":103},[82,2977,2978],{"class":99}," -d",[82,2980,2981],{"class":99}," \\\n",[82,2983,2984,2987,2990],{"class":84,"line":92},[82,2985,2986],{"class":99},"  --name",[82,2988,2989],{"class":103}," open-webui",[82,2991,2981],{"class":99},[82,2993,2994,2997,3000],{"class":84,"line":114},[82,2995,2996],{"class":99},"  -p",[82,2998,2999],{"class":103}," 3000:8080",[82,3001,2981],{"class":99},[82,3003,3004,3007,3010],{"class":84,"line":121},[82,3005,3006],{"class":99},"  -v",[82,3008,3009],{"class":103}," open-webui:\u002Fapp\u002Fbackend\u002Fdata",[82,3011,2981],{"class":99},[82,3013,3014,3017,3020],{"class":84,"line":169},[82,3015,3016],{"class":99},"  -e",[82,3018,3019],{"class":103}," OLLAMA_BASE_URL=http:\u002F\u002Fhost.docker.internal:11434",[82,3021,2981],{"class":99},[82,3023,3024,3027,3030],{"class":84,"line":293},[82,3025,3026],{"class":99},"  --restart",[82,3028,3029],{"class":103}," always",[82,3031,2981],{"class":99},[82,3033,3034],{"class":84,"line":299},[82,3035,3036],{"class":103},"  ghcr.io\u002Fopen-webui\u002Fopen-webui:main\n",[16,3038,3039,3040,3044],{},"Open ",[1170,3041,3042],{"href":3042,"rel":3043},"http:\u002F\u002Flocalhost:3000",[1262]," in your browser. First run will prompt you to create an admin account (local only, no external registration).",[2729,3046,3048],{"id":3047},"select-a-model","Select a Model",[16,3050,3051,3052,1275],{},"In Open WebUI: click the model dropdown at the top → select any model you have pulled in Ollama. If you do not see models, verify Ollama is running (",[33,3053,3054],{},"ollama list",[2729,3056,3058],{"id":3057},"install-without-docker","Install Without Docker",[73,3060,3062],{"className":75,"code":3061,"language":77,"meta":78,"style":78},"pip install open-webui\nopen-webui serve\n",[33,3063,3064,3073],{"__ignoreMap":78},[82,3065,3066,3068,3070],{"class":84,"line":85},[82,3067,172],{"class":95},[82,3069,175],{"class":103},[82,3071,3072],{"class":103}," open-webui\n",[82,3074,3075,3077],{"class":84,"line":92},[82,3076,2953],{"class":95},[82,3078,2509],{"class":103},[16,3080,3081],{},"This is simpler but requires Python 3.11+.",[44,3083],{},[11,3085,3087],{"id":3086},"api-access","API Access",[16,3089,3090,3091,3094],{},"Ollama exposes an OpenAI-compatible API at ",[33,3092,3093],{},"http:\u002F\u002Flocalhost:11434\u002Fv1",". Any OpenAI SDK or tool that supports a custom base URL works:",[73,3096,3098],{"className":263,"code":3097,"language":137,"meta":78,"style":78},"from openai import OpenAI\n\nclient = OpenAI(\n    base_url=\"http:\u002F\u002Flocalhost:11434\u002Fv1\",\n    api_key=\"ollama\"   # required by the SDK, value is ignored\n)\n\nresponse = client.chat.completions.create(\n    model=\"llama3.2:3b\",\n    messages=[{\"role\": \"user\", \"content\": \"What is 2 + 2?\"}]\n)\nprint(response.choices[0].message.content)\n",[33,3099,3100,3105,3109,3114,3119,3124,3129,3133,3138,3143,3148,3152],{"__ignoreMap":78},[82,3101,3102],{"class":84,"line":85},[82,3103,3104],{},"from openai import OpenAI\n",[82,3106,3107],{"class":84,"line":92},[82,3108,118],{"emptyLinePlaceholder":117},[82,3110,3111],{"class":84,"line":114},[82,3112,3113],{},"client = OpenAI(\n",[82,3115,3116],{"class":84,"line":121},[82,3117,3118],{},"    base_url=\"http:\u002F\u002Flocalhost:11434\u002Fv1\",\n",[82,3120,3121],{"class":84,"line":169},[82,3122,3123],{},"    api_key=\"ollama\"   # required by the SDK, value is ignored\n",[82,3125,3126],{"class":84,"line":293},[82,3127,3128],{},")\n",[82,3130,3131],{"class":84,"line":299},[82,3132,118],{"emptyLinePlaceholder":117},[82,3134,3135],{"class":84,"line":305},[82,3136,3137],{},"response = client.chat.completions.create(\n",[82,3139,3140],{"class":84,"line":310},[82,3141,3142],{},"    model=\"llama3.2:3b\",\n",[82,3144,3145],{"class":84,"line":316},[82,3146,3147],{},"    messages=[{\"role\": \"user\", \"content\": \"What is 2 + 2?\"}]\n",[82,3149,3150],{"class":84,"line":322},[82,3151,3128],{},[82,3153,3154],{"class":84,"line":328},[82,3155,3156],{},"print(response.choices[0].message.content)\n",[44,3158],{},[11,3160,3162],{"id":3161},"managing-models","Managing Models",[73,3164,3166],{"className":75,"code":3165,"language":77,"meta":78,"style":78},"# list downloaded models\nollama list\n\n# remove a model (frees disk space)\nollama rm llama3.2:3b\n\n# show model details\nollama show llama3.3:8b\n\n# copy\u002Fcreate a custom model variant\nollama create my-model -f Modelfile\n",[33,3167,3168,3173,3180,3184,3189,3198,3202,3207,3217,3221,3226],{"__ignoreMap":78},[82,3169,3170],{"class":84,"line":85},[82,3171,3172],{"class":88},"# list downloaded models\n",[82,3174,3175,3177],{"class":84,"line":92},[82,3176,197],{"class":95},[82,3178,3179],{"class":103}," list\n",[82,3181,3182],{"class":84,"line":114},[82,3183,118],{"emptyLinePlaceholder":117},[82,3185,3186],{"class":84,"line":121},[82,3187,3188],{"class":88},"# remove a model (frees disk space)\n",[82,3190,3191,3193,3196],{"class":84,"line":169},[82,3192,197],{"class":95},[82,3194,3195],{"class":103}," rm",[82,3197,2534],{"class":103},[82,3199,3200],{"class":84,"line":293},[82,3201,118],{"emptyLinePlaceholder":117},[82,3203,3204],{"class":84,"line":299},[82,3205,3206],{"class":88},"# show model details\n",[82,3208,3209,3211,3214],{"class":84,"line":305},[82,3210,197],{"class":95},[82,3212,3213],{"class":103}," show",[82,3215,3216],{"class":103}," llama3.3:8b\n",[82,3218,3219],{"class":84,"line":310},[82,3220,118],{"emptyLinePlaceholder":117},[82,3222,3223],{"class":84,"line":316},[82,3224,3225],{"class":88},"# copy\u002Fcreate a custom model variant\n",[82,3227,3228,3230,3232,3235,3238],{"class":84,"line":322},[82,3229,197],{"class":95},[82,3231,2179],{"class":103},[82,3233,3234],{"class":103}," my-model",[82,3236,3237],{"class":99}," -f",[82,3239,3240],{"class":103}," Modelfile\n",[16,3242,3243,3244,3247],{},"A minimal ",[33,3245,3246],{},"Modelfile"," for customizing system prompt:",[73,3249,3252],{"className":3250,"code":3251,"language":1674},[1672],"FROM llama3.3:8b\nSYSTEM \"You are a concise assistant. Answer in under 3 sentences.\"\nPARAMETER temperature 0.7\n",[33,3253,3251],{"__ignoreMap":78},[44,3255],{},[11,3257,1164],{"id":1163},[23,3259,3260,3265],{},[26,3261,3262,3264],{},[1170,3263,1180],{"href":1179}," — ranked comparisons of local and cloud models",[26,3266,3267,3270],{},[1170,3268,3269],{"href":1172},"Tools directory"," — GUI apps and integrations for local LLMs",[1183,3272,3273],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":78,"searchDepth":92,"depth":114,"links":3275},[3276,3277,3278,3279,3280,3285,3286,3291,3292,3293],{"id":2342,"depth":92,"text":2343},{"id":2435,"depth":92,"text":2436},{"id":2519,"depth":92,"text":2520},{"id":2589,"depth":92,"text":2590},{"id":2726,"depth":92,"text":2727,"children":3281},[3282,3283,3284],{"id":2731,"depth":114,"text":2732},{"id":2776,"depth":114,"text":2777},{"id":2833,"depth":114,"text":2834},{"id":2880,"depth":92,"text":2881},{"id":2953,"depth":92,"text":2954,"children":3287},[3288,3289,3290],{"id":2960,"depth":114,"text":2961},{"id":3047,"depth":114,"text":3048},{"id":3057,"depth":114,"text":3058},{"id":3086,"depth":92,"text":3087},{"id":3161,"depth":92,"text":3162},{"id":1163,"depth":92,"text":1164},"local-llm","Use Ollama and Open WebUI to run quantized language models locally on M1\u002FM2\u002FM3 Macs with Metal acceleration.",{},"\u002Fen\u002Fguides\u002Flocal-llm-mac",{"title":2337,"description":3295},"local-llm-mac","en\u002Fguides\u002Flocal-llm-mac",[197,3302,3303,3294,2953,3304],"mac","apple-silicon","gguf","9n60mek5RY42Tn79I5lmt6n6azqSIQK432BBY3xh2L8",{"id":3307,"title":3308,"body":3309,"category":3796,"description":3797,"difficulty":2324,"extension":1200,"meta":3798,"navigation":117,"path":3799,"published":1203,"readTime":340,"seo":3800,"slug":3801,"stem":3802,"tags":3803,"updated":1203,"__hash__":3808},"guides\u002Fen\u002Fguides\u002Fnotebooklm-guide.md","NotebookLM: From Zero to Useful in 15 Minutes",{"type":8,"value":3310,"toc":3777},[3311,3315,3318,3321,3323,3327,3330,3348,3351,3353,3357,3360,3452,3458,3460,3464,3467,3481,3484,3486,3490,3494,3504,3510,3516,3522,3526,3540,3542,3546,3549,3552,3566,3569,3575,3577,3581,3584,3604,3607,3609,3613,3617,3632,3636,3647,3652,3654,3658,3739,3745,3751,3753,3757,3760,3766,3768,3772],[11,3312,3314],{"id":3313},"what-is-notebooklm","What Is NotebookLM",[16,3316,3317],{},"NotebookLM is Google's document-grounded AI assistant. Unlike general chatbots, it confines its answers to sources you provide — PDFs, Google Docs, URLs, YouTube transcripts, or pasted text.",[16,3319,3320],{},"It uses Gemini under the hood with Retrieval-Augmented Generation (RAG). Every answer includes inline citations pointing to the exact source passage. This makes it practical for research, legal review, and technical documentation work where hallucination risk matters.",[44,3322],{},[11,3324,3326],{"id":3325},"account-setup","Account Setup",[16,3328,3329],{},"NotebookLM requires a Google account. No paid tier is required for most features.",[1253,3331,3332,3340,3343],{},[26,3333,3334,3335],{},"Go to ",[1170,3336,3339],{"href":3337,"rel":3338},"https:\u002F\u002Fnotebooklm.google.com",[1262],"notebooklm.google.com",[26,3341,3342],{},"Sign in with any Google account",[26,3344,1267,3345],{},[1226,3346,3347],{},"New Notebook",[16,3349,3350],{},"That is the entire setup. No installation, no API keys, no configuration.",[44,3352],{},[11,3354,3356],{"id":3355},"source-types","Source Types",[16,3358,3359],{},"NotebookLM accepts these source formats:",[1102,3361,3362,3375],{},[1105,3363,3364],{},[1108,3365,3366,3369,3372],{},[1111,3367,3368],{},"Source Type",[1111,3370,3371],{},"Max Size",[1111,3373,3374],{},"Notes",[1117,3376,3377,3388,3399,3409,3420,3430,3441],{},[1108,3378,3379,3382,3385],{},[1122,3380,3381],{},"PDF",[1122,3383,3384],{},"500 MB per file",[1122,3386,3387],{},"Text PDFs work best; scanned PDFs need OCR",[1108,3389,3390,3393,3396],{},[1122,3391,3392],{},"Google Docs",[1122,3394,3395],{},"No limit",[1122,3397,3398],{},"Auto-synced when source is updated",[1108,3400,3401,3404,3406],{},[1122,3402,3403],{},"Google Slides",[1122,3405,3395],{},[1122,3407,3408],{},"Extracts text from slides",[1108,3410,3411,3414,3417],{},[1122,3412,3413],{},"Web URL",[1122,3415,3416],{},"—",[1122,3418,3419],{},"Fetches page content at upload time",[1108,3421,3422,3425,3427],{},[1122,3423,3424],{},"YouTube URL",[1122,3426,3416],{},[1122,3428,3429],{},"Uses auto-generated captions",[1108,3431,3432,3435,3438],{},[1122,3433,3434],{},"Plain text",[1122,3436,3437],{},"500,000 characters",[1122,3439,3440],{},"Paste directly",[1108,3442,3443,3446,3449],{},[1122,3444,3445],{},"Audio file",[1122,3447,3448],{},"8 hours",[1122,3450,3451],{},"MP3, WAV, M4A",[16,3453,3454,3457],{},[1226,3455,3456],{},"Practical limit per notebook:"," 50 sources, 25 MB text per source (roughly 25,000 pages).",[44,3459],{},[11,3461,3463],{"id":3462},"notebook-structure","Notebook Structure",[16,3465,3466],{},"A notebook has two panels:",[23,3468,3469,3475],{},[26,3470,3471,3474],{},[1226,3472,3473],{},"Sources panel (left):"," All uploaded documents. Click any source to view it inline. Click the checkbox to include\u002Fexclude it from queries.",[26,3476,3477,3480],{},[1226,3478,3479],{},"Notes panel (right):"," AI-generated or manual notes. These persist between sessions and can be exported.",[16,3482,3483],{},"The chat interface sits at the bottom. Queries run against all checked sources simultaneously.",[44,3485],{},[11,3487,3489],{"id":3488},"asking-effective-questions","Asking Effective Questions",[2729,3491,3493],{"id":3492},"cite-mode-vs-summary-mode","Cite Mode vs Summary Mode",[16,3495,3496,3499,3500,3503],{},[1226,3497,3498],{},"Cite mode (default):"," Ask specific questions. Answers include ",[33,3501,3502],{},"[1]"," inline citations.",[73,3505,3508],{"className":3506,"code":3507,"language":1674},[1672],"What are the exact system requirements from the installation manual?\nWhat does Section 4.2 say about data retention?\n",[33,3509,3507],{"__ignoreMap":78},[16,3511,3512,3515],{},[1226,3513,3514],{},"Summary mode:"," Ask for overviews. Fewer citations, more synthesis.",[73,3517,3520],{"className":3518,"code":3519,"language":1674},[1672],"Summarize the key findings across all three reports.\nWhat are the main arguments the author makes?\n",[33,3521,3519],{"__ignoreMap":78},[2729,3523,3525],{"id":3524},"tips","Tips",[23,3527,3528,3531,3534,3537],{},[26,3529,3530],{},"Start with a broad question, then narrow: \"What topics does this cover?\" → \"Tell me more about X.\"",[26,3532,3533],{},"Ask for comparisons: \"How does the 2024 report differ from the 2023 one?\"",[26,3535,3536],{},"Ask for gaps: \"What is not addressed in these documents?\"",[26,3538,3539],{},"Quote specific text to ground your question: \"The doc says 'X'. What does it mean?\"",[44,3541],{},[11,3543,3545],{"id":3544},"audio-overview-feature","Audio Overview Feature",[16,3547,3548],{},"NotebookLM can generate a podcast-style audio overview of your sources. Two AI voices discuss the material in a conversational format.",[16,3550,3551],{},"To generate:",[1253,3553,3554,3560,3563],{},[26,3555,1267,3556,3559],{},[1226,3557,3558],{},"Audio Overview"," in the toolbar",[26,3561,3562],{},"Wait 1–2 minutes",[26,3564,3565],{},"Download as MP3 or listen in-browser",[16,3567,3568],{},"Audio overviews are ~10–15 minutes. They do not replace a full read but work well for quick orientation to unfamiliar material.",[16,3570,3571,3574],{},[1226,3572,3573],{},"Limitation:"," Audio overviews cannot be regenerated with different voices or styles. If you add new sources, you need to generate a new one.",[44,3576],{},[11,3578,3580],{"id":3579},"exporting-notes","Exporting Notes",[16,3582,3583],{},"Notes created in the notebook can be exported:",[23,3585,3586,3592,3598],{},[26,3587,3588,3591],{},[1226,3589,3590],{},"Copy to clipboard:"," Markdown-formatted text",[26,3593,3594,3597],{},[1226,3595,3596],{},"Download as .txt:"," Plain text with note titles",[26,3599,3600,3603],{},[1226,3601,3602],{},"Save to Google Docs:"," Creates a new Doc in your Drive",[16,3605,3606],{},"Chat history is not exportable. Copy important answers into notes immediately.",[44,3608],{},[11,3610,3612],{"id":3611},"privacy-considerations","Privacy Considerations",[2729,3614,3616],{"id":3615},"consumer-accounts-personal-google","Consumer accounts (personal Google)",[23,3618,3619,3626,3629],{},[26,3620,3621,3622,3625],{},"Google states NotebookLM content is ",[1226,3623,3624],{},"not"," used to train models",[26,3627,3628],{},"Data is retained per Google's standard privacy policy",[26,3630,3631],{},"Content is accessible to Google's infrastructure",[2729,3633,3635],{"id":3634},"google-workspace-accounts-workschool","Google Workspace accounts (work\u002Fschool)",[23,3637,3638,3641,3644],{},[26,3639,3640],{},"Data handling follows your organization's Workspace agreement",[26,3642,3643],{},"If your organization has disabled NotebookLM, you will not see the option",[26,3645,3646],{},"Check with your IT admin before uploading confidential material",[16,3648,3649,3651],{},[1226,3650,1363],{}," Do not upload client contracts, personal health information, or unreleased product details to the consumer tier. Use a local RAG solution for sensitive documents.",[44,3653],{},[11,3655,3657],{"id":3656},"notebooklm-vs-local-rag","NotebookLM vs Local RAG",[1102,3659,3660,3673],{},[1105,3661,3662],{},[1108,3663,3664,3667,3670],{},[1111,3665,3666],{},"Factor",[1111,3668,3669],{},"NotebookLM",[1111,3671,3672],{},"Local RAG",[1117,3674,3675,3686,3697,3707,3717,3728],{},[1108,3676,3677,3680,3683],{},[1122,3678,3679],{},"Setup time",[1122,3681,3682],{},"2 minutes",[1122,3684,3685],{},"1–4 hours",[1108,3687,3688,3691,3694],{},[1122,3689,3690],{},"Privacy",[1122,3692,3693],{},"Data on Google servers",[1122,3695,3696],{},"Data stays on device",[1108,3698,3699,3701,3704],{},[1122,3700,1100],{},[1122,3702,3703],{},"Free (consumer)",[1122,3705,3706],{},"Hardware cost only",[1108,3708,3709,3711,3714],{},[1122,3710,2608],{},[1122,3712,3713],{},"Gemini 1.5 \u002F 2.0",[1122,3715,3716],{},"Depends on model",[1108,3718,3719,3722,3725],{},[1122,3720,3721],{},"Source limits",[1122,3723,3724],{},"50 sources \u002F notebook",[1122,3726,3727],{},"Unlimited",[1108,3729,3730,3733,3736],{},[1122,3731,3732],{},"Offline use",[1122,3734,3735],{},"No",[1122,3737,3738],{},"Yes",[16,3740,3741,3744],{},[1226,3742,3743],{},"When to use NotebookLM:"," Non-sensitive documents, shared research, quick analysis, Audio Overview.",[16,3746,3747,3750],{},[1226,3748,3749],{},"When to use local RAG:"," Confidential data, air-gapped environments, custom embeddings, high-volume processing.",[44,3752],{},[11,3754,3756],{"id":3755},"practical-workflow","Practical Workflow",[16,3758,3759],{},"For a research project with 10 PDFs:",[73,3761,3764],{"className":3762,"code":3763,"language":1674},[1672],"1. Create notebook: \"Project Alpha Research\"\n2. Upload all PDFs (drag and drop supported)\n3. Generate Audio Overview → listen during commute\n4. Ask: \"What are the main claims in each paper?\"\n5. Ask: \"What evidence supports claim X?\"\n6. Save key passages to Notes\n7. Export Notes → Google Doc → share with team\n",[33,3765,3763],{"__ignoreMap":78},[44,3767],{},[11,3769,3771],{"id":3770},"next-step","Next Step",[16,3773,3774,3775],{},"For sensitive documents that cannot leave your machine, try the local RAG setup on Mac:\n",[1170,3776,2337],{"href":3297},{"title":78,"searchDepth":92,"depth":114,"links":3778},[3779,3780,3781,3782,3783,3787,3788,3789,3793,3794,3795],{"id":3313,"depth":92,"text":3314},{"id":3325,"depth":92,"text":3326},{"id":3355,"depth":92,"text":3356},{"id":3462,"depth":92,"text":3463},{"id":3488,"depth":92,"text":3489,"children":3784},[3785,3786],{"id":3492,"depth":114,"text":3493},{"id":3524,"depth":114,"text":3525},{"id":3544,"depth":92,"text":3545},{"id":3579,"depth":92,"text":3580},{"id":3611,"depth":92,"text":3612,"children":3790},[3791,3792],{"id":3615,"depth":114,"text":3616},{"id":3634,"depth":114,"text":3635},{"id":3656,"depth":92,"text":3657},{"id":3755,"depth":92,"text":3756},{"id":3770,"depth":92,"text":3771},"notebooklm","Load your documents into NotebookLM and start getting answers, summaries, and audio overviews immediately.",{},"\u002Fen\u002Fguides\u002Fnotebooklm-guide",{"title":3308,"description":3797},"notebooklm-guide","en\u002Fguides\u002Fnotebooklm-guide",[3796,3804,3805,3806,3807],"google","rag","productivity","research","TChWLLAETZ22pNF-ULySgKZFgLVJuQ7H3QwZIEp2ZsQ",["Map",3810,121,1197,85,2322,85,3294,85,3796,85],"all",1781557609815]