← Back to list

Supercharge Your Local LLM: Web-Aware Chat with Spring AI, Ollama, and Jsoup

How I used Spring Boot, Ollama, and Jsoup to build a private chatbot that can actually browse the web.

Ferdous Ahmed · 2025-11-16 05:20 · 0 claps · 3.3 min read
#spring-ai #ollama #ollama-api #jsoup #local-llm
Open on Medium ↗
Wiki topics: LLM · Large Language Models

Supercharge Your Local LLM: Web-Aware Chat with Spring AI, Ollama, and Jsoup

How I used Spring Boot, Ollama, and Jsoup to build a private chatbot that can actually browse the web.

I love running LLMs locally. Setting up Ollama with a model like Llama 3 or Qwen is great — fast, private, and fully under your control. But like all local LLMs, there’s one annoying limitation: they don’t know what’s happening right now. Ask about a new library version or the latest news, and you get the usual: “My knowledge cutoff is…” Ugh.

I got tired of that limitation, so I thought: what if I could give my AI “eyes”? Let it check the live web without losing the privacy I get from running it locally.

Turns out, it’s easier than I expected. The trick? A bit of Spring Boot, the new Spring AI framework, and a trusty friend: Jsoup.

My Setup: 100% Local, 0% Cloud APIs

Here’s the setup — and the best part? You can run all of it yourself. No API keys, no pay-per-token — just your local machine doing the work.

  • Spring Boot (3.5.7): Our rock-solid API foundation.
  • Spring AI (1.1.0): It makes calling Ollama from Java really easy.
  • Jsoup (1.17.2): A super simple library for scraping web pages.

The whole idea follows a simple MCP (Model-Context-Prompt) pattern:

  • Model: The Ollama LLM you want to use (Llama 3, Qwen, etc.).
  • Context: Grab fresh data from the web with Jsoup.
  • Prompt: Combine that context with the user’s question and system instructions so the model can generate an answer.

By wiring these pieces together, a local LLM suddenly becomes more than a static chatbot. It can pull fresh data, summarize news, track GitHub activity, or answer questions about any page you point it to — all running privately on your own machine.

Step 1: Fetch Web Content

Use a WebContentService to grab either a specific page or top search results. Truncate content so it fits within the model’s token window.

// In WebContentService.java
public String fetchWebContent(String url) {
    try {
        Document doc = Jsoup.connect(url)
                .timeout(10000)
                .userAgent("Mozilla/5.0 (compatible; SpringAI-Bot/1.0)")
                .get();
        String title = doc.title();
        String bodyText = doc.body().text();
        // Truncate to keep context manageable
        if (bodyText.length() > 2000) {
            bodyText = bodyText.substring(0, 2000) + "...";
        }
        return String.format("Title: %s\n\nContent: %s", title, bodyText);
    } catch (IOException e) {
        return "Error: Unable to fetch content.";
    }
}

How do you do a web search without an API key? You scrape one! I used DuckDuckGo’s simple HTML version. It’s lightweight, easy to parse, and perfect for grabbing the top few results — title, snippet, and URL.

// In WebContentService.java
public String searchAndFetch(String query) {
    String searchUrl = "https://html.duckduckgo.com/html/?q=" + query.replace(" ", "+");

    // Connect and parse search results...
    Document doc = Jsoup.connect(searchUrl).get();
    // ... My logic to extract top 3 results ...
    return results.toString();
}

Step 2: Combine Context with User Query

This is where the magic happens. We use Spring AI’s OllamaChatModel, but we wrap it in our own WebEnhancedChatService. This service is the conductor. When I send it a request (like ‘summarize this URL’), it:

  • Calls my WebContentService to get the raw text.
  • Creates a SystemMessage to tell the AI how to behave ("You are an assistant... use this content...").
  • It literally just stuffs the web content and my question into one big prompt. It’s that simple.
// In WebEnhancedChatService.java
public String replyWithWebContext(String userQuery, String url) {
    // 1. Retrieve
    String webContent = webContentService.fetchWebContent(url);

    // 2. Set the rules
    SystemMessage systemMessage = new SystemMessage(
        "You are a helpful assistant. Use the provided web content to answer the user's question..."
    );

    // 3. Augment
    String enhancedQuery = String.format(
        "Web Content:\n%s\n\nUser Question: %s",
        webContent, userQuery
    );

    // 4. Generate
    UserMessage userMessage = new UserMessage(enhancedQuery);
    Prompt chatPrompt = new Prompt(List.of(systemMessage, userMessage));
    ChatResponse response = chatModel.call(chatPrompt);
    return response.getResult().getOutput().getText();
}

I use the exact same pattern for the web search, just changing the system prompt to “Synthesize these search results…”.

Step 3: Hooking it Up to an API

Last step, we just need to hook this logic up to an API so we can actually use it. A standard WebChatController does the trick.

@RestController
@RequestMapping("/api/web-chat")
@AllArgsConstructor
public class WebChatController {

    private final WebEnhancedChatService webEnhancedChatService;

    @GetMapping("/with-url")
    public String chatWithUrl(
            @RequestParam String message,
            @RequestParam String url) {
        return webEnhancedChatService.replyWithWebContext(message, url);
    }

    @GetMapping("/with-search")
    public String chatWithSearch(@RequestParam String query) {
        return webEnhancedChatService.replyWithWebSearch(query);
    }
}

And… That’s It! Now for the fun part. We can hit our API with curl and ask it about the real world.

Ask it to summarize a page:

curl -G "http://localhost:8080/api/web-chat/with-url" \
  --data-urlencode "message=Summarize the key points" \
  --data-urlencode "url=https://spring.io/projects/spring-ai"

Ask it a current question:

curl -G "http://localhost:8080/api/web-chat/with-search" \
  --data-urlencode "query=What are the latest features in Java 21?"

By combining Jsoup and Ollama with Spring AI, we’ve built something stronger than the sum of its parts. It’s not just a static chatbot — it’s a dynamic chat assistant. You could turn this into a personal news summarizer, a bot that watches GitHub repos, or anything else — all running privately on your own machine.

Project Source: The complete code for this project is available on GitHub: https://github.com/taninme/spring-boot-ollama-sample


메타데이터
post_id
86a0d522b1ee
slug
supercharge-your-local-llm-web-aware-chat-with-spring-ai-ollama-and-jsoup-86a0d522b1ee
url
https://medium.com/@aferdousahmed/supercharge-your-local-llm-web-aware-chat-with-spring-ai-ollama-and-jsoup-86a0d522b1ee
canonical_url
https://medium.com/@aferdousahmed/supercharge-your-local-llm-web-aware-chat-with-spring-ai-ollama-and-jsoup-86a0d522b1ee
author_url
https://medium.com/@aferdousahmed
status
ok
fetched_at
2026-07-15 08:22:34