$ show langchain-ai/local-deep-researcher
This is a LangGraph-based web research assistant that runs fully locally. It accepts a research topic, then enters a loop: an LLM (Ollama or LMStudio) generates a web search query, a configurable search API (DuckDuckGo, Tavily, Perplexity, or SearXNG) fetches results, the same LLM summarizes the findings and reflects on knowledge gaps to generate follow-up queries. After a configurable number of iterations, it produces a final markdown summary with deduplicated source citations. The architecture is a clean state graph with six nodes and conditional routing, all orchestrated via LangGraph's compile and run mechanism. It is deployed as a LangGraph dev server or via Docker. The codebase demonstrates solid LangGraph patterns, proper separation of concerns (configuration, state, utilities, prompts, graph definition), and a smart abstraction for switching between JSON mode and tool calling for structured LLM output. Notable craft includes the `generate_search_query_with_structured_output` helper that cleanly handles fallback and the `ChatLMStudio` adapter for LMStudio's OpenAI-compatible API.
The LLM identified 2 files worth highlighting for reuse:
A standalone ChatLMStudio class that extends ChatOpenAI to support LMStudio's OpenAI-compatible API. It adds a `format` field to optionally request JSON output, and in `_generate` it sets `response_format` to `{"type": "json_object"}` when JSON mode is requested. It also implements a cleanup heuristic that extracts the first JSON block from the raw response text, falling back gracefully to the original text if JSON extraction fails. This class is a reusable pattern for adapting any OpenAI-compatible API endpoint (LMStudio, vLLM, TGI, etc.) into LangChain's ChatModel interface.
The `deduplicate_and_format_sources` function takes a heterogeneous search response (dict with 'results' key or list of dicts), deduplicates by URL, and formats it into a structured string with source metadata and optional truncated raw content. It handles edge cases like missing `raw_content` and malformed results with informative warnings. This function is a reusable data-cleaning utility for any project that aggregates search results from multiple APIs and needs a consistent, deduped textual representation for LLM consumption.