diff --git a/python/llm/agents/agent-mastery-course/backend/.env.example b/python/llm/agents/agent-mastery-course/backend/.env.example index 174b869..a9d464c 100644 --- a/python/llm/agents/agent-mastery-course/backend/.env.example +++ b/python/llm/agents/agent-mastery-course/backend/.env.example @@ -3,14 +3,16 @@ # Do not commit real secrets. # Choose ONE provider -OPENAI_API_KEY=your_openai_api_key_here +OPENAI_API_KEY=#your_openai_api_key_here # Or use OpenRouter (OpenAI-compatible) # OPENROUTER_API_KEY=your_openrouter_api_key_here # OPENROUTER_MODEL=openai/gpt-4o-mini +# Or use local model (Ollama) +# OLLAMA_MODEL=#your_ollama_model_identification # Observability with Arize (https://app.arize.com) -ARIZE_SPACE_ID=your_arize_space_id_here -ARIZE_API_KEY=your_arize_api_key_here +ARIZE_SPACE_ID=#your_arize_space_id_here +ARIZE_API_KEY=#your_arize_api_key_here # Optional: Deterministic dev mode (no external LLM calls) # TEST_MODE=1 diff --git a/python/llm/agents/agent-mastery-course/backend/main.py b/python/llm/agents/agent-mastery-course/backend/main.py index b741dde..5b92b92 100644 --- a/python/llm/agents/agent-mastery-course/backend/main.py +++ b/python/llm/agents/agent-mastery-course/backend/main.py @@ -35,6 +35,11 @@ def _noop(): from langchain_core.documents import Document from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_community.vectorstores import InMemoryVectorStore + +# Not using langchain_community.llms.ollama because the prompt/response format is too different from the others used +# Using ollama library directly fits better +from ollama import chat as OllamaInvoke ### WIP add ollama + import httpx # Make MCP import optional @@ -59,6 +64,35 @@ class TripResponse(BaseModel): tool_calls: List[Dict[str, Any]] = [] +class ChatOllama(): + model: str + tools=[] + + def __init__(self, model): + self.model = model + self.tools = [] # Not implemented + pass + + def invoke(self, messages): + # Ollama expects specific message format + ollamaMessages = [] + # Ollama only returns if user content. If only has system messages, will return empty response + for msg in messages: + ollamaMsg={ + "content": msg.content, + "role": 'user' + } + ollamaMessages.append(ollamaMsg) + # + # + # expected return is the message object + response = OllamaInvoke(model=self.model, messages=ollamaMessages, tools=self.tools) + return response.message + + def bind_tools(self, tools=[]): + # Not implemented + return self + def _init_llm(): # Simple, test-friendly LLM init class _Fake: @@ -74,7 +108,7 @@ class _Msg: if os.getenv("TEST_MODE"): return _Fake() - if os.getenv("OPENAI_API_KEY"): + elif os.getenv("OPENAI_API_KEY"): return ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7, max_tokens=1500) elif os.getenv("OPENROUTER_API_KEY"): # Use OpenRouter via OpenAI-compatible client @@ -84,9 +118,14 @@ class _Msg: model=os.getenv("OPENROUTER_MODEL", "openai/gpt-4o-mini"), temperature=0.7, ) + elif os.getenv("OLLAMA_MODEL"): + # Use Ollama local model + return ChatOllama( + model=os.getenv("OLLAMA_MODEL") + ) else: # Require a key unless running tests - raise ValueError("Please set OPENAI_API_KEY or OPENROUTER_API_KEY in your .env") + raise ValueError("Please set OPENAI_API_KEY or OPENROUTER_API_KEY or OLLAMA_MODEL in your .env") llm = _init_llm() diff --git a/python/llm/agents/agent-mastery-course/backend/requirements.txt b/python/llm/agents/agent-mastery-course/backend/requirements.txt index 0b4fd6a..c586609 100644 --- a/python/llm/agents/agent-mastery-course/backend/requirements.txt +++ b/python/llm/agents/agent-mastery-course/backend/requirements.txt @@ -20,3 +20,4 @@ litellm python-dotenv>=1.0.0 requests>=2.31.0 pandas>=2.0.0 +ollama>=0.6.1 \ No newline at end of file diff --git a/python/llm/agents/agent-mastery-course/frontend/index.html b/python/llm/agents/agent-mastery-course/frontend/index.html index 91bd39a..fce7243 100644 --- a/python/llm/agents/agent-mastery-course/frontend/index.html +++ b/python/llm/agents/agent-mastery-course/frontend/index.html @@ -320,7 +320,8 @@

Fill out the form t renderIcons(); try { - const resp = await fetch('/plan-trip', { + var url = 'http://localhost:8000/plan-trip' + const resp = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ destination, duration, budget, interests })