"""Agent implementation using LangChain 1.x. The agent uses a simple tool‑based architecture. The LLM is a local `ChatOllama` model (llama3). Two tools are available: * ``search_local_kb`` – semantic search in Qdrant. * ``web_search`` – web search via Tavily. The system prompt instructs the LLM to decide which tool to use based on the question. The response always contains a marker indicating the source (`chromadb`/`tavily`). The marker is added by the LLM itself. """ from __future__ import annotations from typing import List from langchain_ollama import ChatOllama from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import Runnable from langchain_core.tools import BaseTool # Import tools without relative import to allow top‑level import import tools # --------------------------------------------------------------------------- # Helper: create a tool list # --------------------------------------------------------------------------- def get_tools() -> List[BaseTool]: """Return the list of tools used by the agent.""" return [tools.search_local_kb, tools.web_search] # --------------------------------------------------------------------------- # System prompt # --------------------------------------------------------------------------- SYSTEM_PROMPT = ( "You are an AI assistant that can answer questions using two sources: " "1) a local knowledge base (Qdrant) and 2) the web via Tavily. " "If the answer can be found in the local KB, use the `search_local_kb` tool. " "If the answer requires up‑to‑date information, use the `web_search` tool. " "Return the answer followed by a source marker on a new line: " "`Source: chromadb` or `Source: tavily`." ) # --------------------------------------------------------------------------- # Agent construction # --------------------------------------------------------------------------- def create_agent() -> Runnable: """Create a runnable agent. The agent is a simple chain: system prompt → user message → tool calls → LLM response. It uses the default tool‑calling behaviour of LangChain 1.x. """ llm = ChatOllama(model="llama3", temperature=0.0) # AgentExecutor can accept a system message via agent_kwargs from langchain.agents import AgentExecutor agent = AgentExecutor.from_llm_and_tools( llm=llm, tools=get_tools(), verbose=True, # Provide the system prompt so the LLM knows how to behave agent_kwargs={"system_message": SYSTEM_PROMPT}, ) return agent