diff --git a/README.md b/README.md index 436f51d..4218b26 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ Whether you're a novice eager to learn or an expert ready to share your knowledg - 🛠️ Practical, ready-to-use agent implementations - 🌟 Regular updates with the latest advancements in GenAI - 🤝 Share your own agent creations with the community +- 🔌 Multi-provider LLM support — switch between OpenAI, [MiniMax](https://www.minimaxi.com/), and other OpenAI-compatible providers via `utils/llm_provider.py` ## GenAI Agent Implementations @@ -140,6 +141,7 @@ Below is a comprehensive overview of our GenAI agent implementations, organized | 43 | 🔍 **QA** | [EU Green Deal Bot](all_agents_tutorials/EU_Green_Compliance_FAQ_Bot.ipynb) | LangGraph | Regulatory compliance, FAQ system | | 44 | 🔍 **QA** | [Systematic Review](all_agents_tutorials/systematic_review_of_scientific_articles.ipynb) | LangGraph | Academic paper processing, draft generation | | 45 | 🌟 **Advanced** | [Controllable RAG Agent](https://github.com/NirDiamant/Controllable-RAG-Agent) | Custom | Complex question answering, deterministic graph | +| 46 | 🔧 **Framework** | [Multi-Provider Agent (MiniMax)](all_agents_tutorials/multi_provider_conversational_agent.ipynb) | LangChain | Multi-provider LLM support, OpenAI/MiniMax switching, env-based config | Explore our extensive list of GenAI agent implementations, sorted by categories: @@ -199,9 +201,17 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: - **[Official MCP Documentation](https://modelcontextprotocol.io/introduction)** - **[MCP GitHub Repository](https://github.com/modelcontextprotocol)** +6. **[Multi-Provider Conversational Agent with MiniMax Support](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/multi_provider_conversational_agent.ipynb)** + + #### Overview 🔎 + Demonstrates how to build a conversational agent that works with **multiple LLM providers** through a unified interface. Shows how to use [MiniMax](https://www.minimaxi.com/) M2.7 (204K context window, OpenAI-compatible API) alongside OpenAI, switching providers with a single parameter change. + + #### Implementation 🛠️ + Introduces a shared `utils/llm_provider.py` module with a provider registry and `get_llm()` helper. Any tutorial notebook can import it to switch between OpenAI and MiniMax without changing agent logic. Includes environment-driven provider selection for production use. + ### 🎓 Educational and Research Agents -6. **[ATLAS: Academic Task and Learning Agent System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/Academic_Task_Learning_Agent_LangGraph.ipynb)** +7. **[ATLAS: Academic Task and Learning Agent System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/Academic_Task_Learning_Agent_LangGraph.ipynb)** #### Overview 🔎 ATLAS demonstrates how to build an intelligent multi-agent system that transforms academic support through AI-powered assistance. The system leverages LangGraph's workflow framework to coordinate multiple specialized agents that provide personalized academic planning, note-taking, and advisory support. @@ -213,7 +223,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: - **[YouTube Explanation](https://www.youtube.com/watch?v=yxowMLL2dDI)** - **[Blog Post](https://open.substack.com/pub/diamantai/p/atlas-when-artificial-intelligence?r=336pe4&utm_campaign=post&utm_medium=web&showWelcomeOnShare=false)** -7. **[Scientific Paper Agent - Literature Review](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/scientific_paper_agent_langgraph.ipynb)** +8. **[Scientific Paper Agent - Literature Review](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/scientific_paper_agent_langgraph.ipynb)** #### Overview 🔎 An intelligent research assistant that helps users navigate, understand, and analyze scientific literature through an orchestrated workflow. The system combines academic APIs with sophisticated paper processing techniques to automate literature review tasks, enabling researchers to efficiently extract insights from academic papers while maintaining research rigor and quality control. @@ -225,7 +235,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: - **[YouTube Explanation](https://youtu.be/Bc4YtpHY6Ws)** - **[Blog Post](https://open.substack.com/pub/diamantai/p/nexus-ai-the-revolutionary-research?r=336pe4&utm_campaign=post&utm_medium=web&showWelcomeOnShare=false)** -8. **[Chiron - A Feynman-Enhanced Learning Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/chiron_learning_agent_langgraph.ipynb)** +9. **[Chiron - A Feynman-Enhanced Learning Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/chiron_learning_agent_langgraph.ipynb)** #### Overview 🔎 An adaptive learning agent that guides users through educational content using a structured checkpoint system and Feynman-style teaching. The system processes learning materials (either user-provided or web-retrieved), verifies understanding through interactive checkpoints, and provides simplified explanations when needed, creating a personalized learning experience that mimics one-on-one tutoring. @@ -238,7 +248,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 💼 Business and Professional Agents -9. **[Customer Support Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/customer_support_agent_langgraph.ipynb)** +10. **[Customer Support Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/customer_support_agent_langgraph.ipynb)** #### Overview 🔎 An intelligent customer support agent using LangGraph categorizes queries, analyzes sentiment, and provides appropriate responses or escalates issues. @@ -246,7 +256,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Utilizes LangGraph to create a workflow combining state management, query categorization, sentiment analysis, and response generation. -10. **[Essay Grading Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/essay_grading_system_langgraph.ipynb)** +11. **[Essay Grading Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/essay_grading_system_langgraph.ipynb)** #### Overview 🔎 An automated essay grading system using LangGraph and an LLM model evaluates essays based on relevance, grammar, structure, and depth of analysis. @@ -254,7 +264,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Utilizes a state graph to define the grading workflow, incorporating separate grading functions for each criterion. -11. **[Travel Planning Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/simple_travel_planner_langgraph.ipynb)** +12. **[Travel Planning Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/simple_travel_planner_langgraph.ipynb)** #### Overview 🔎 A Travel Planner using LangGraph demonstrates how to build a stateful, multi-step conversational AI application that collects user input and generates personalized travel itineraries. @@ -262,7 +272,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Utilizes StateGraph to define the application flow, incorporates custom PlannerState for process management. -12. **[GenAI Career Assistant Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/agent_hackathon_genAI_career_assistant.ipynb)** +13. **[GenAI Career Assistant Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/agent_hackathon_genAI_career_assistant.ipynb)** #### Overview 🔎 The GenAI Career Assistant demonstrates how to create a multi-agent system that provides personalized guidance for careers in Generative AI. Using LangGraph and Gemini LLM, the system delivers customized learning paths, resume assistance, interview preparation, and job search support. @@ -273,7 +283,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=IcKh0ltXO_8)** -13. **[Project Manager Assistant Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/project_manager_assistant_agent.ipynb)** +14. **[Project Manager Assistant Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/project_manager_assistant_agent.ipynb)** #### Overview 🔎 An AI agent designed to assist in project management tasks by automating the process of creating actionable tasks from project descriptions, identifying dependencies, scheduling work, and assigning tasks to team members based on expertise. The system includes risk assessment and self-reflection capabilities to optimize project plans through multiple iterations, aiming to minimize overall project risk. @@ -284,7 +294,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=R7YWjzg3LpI)** -14. **[Contract Analysis Assistant (ClauseAI)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ClauseAI.ipynb)** +15. **[Contract Analysis Assistant (ClauseAI)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ClauseAI.ipynb)** #### Overview 🔎 ClauseAI demonstrates how to build an AI-powered contract analysis system using a multi-agent approach. The system employs specialized AI agents for different aspects of contract review, from clause analysis to compliance checking, and leverages LangGraph for workflow orchestration and Pinecone for efficient clause retrieval and comparison. @@ -295,7 +305,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=rP8uv_tXuSI)** -15. **[E2E Testing Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/e2e_testing_agent.ipynb)** +16. **[E2E Testing Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/e2e_testing_agent.ipynb)** #### Overview 🔎 The E2E Testing Agent demonstrates how to build an AI-powered system that converts natural language test instructions into executable end-to-end web tests. Using LangGraph for workflow orchestration and Playwright for browser automation, the system enables users to specify test cases in plain English while handling the complexity of test generation and execution. @@ -308,7 +318,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 🎨 Creative and Content Generation Agents -16. **[GIF Animation Generator Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/gif_animation_generator_langgraph.ipynb)** +17. **[GIF Animation Generator Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/gif_animation_generator_langgraph.ipynb)** #### Overview 🔎 A GIF animation generator that integrates LangGraph for workflow management, GPT-4 for text generation, and DALL-E for image creation, producing custom animations from user prompts. @@ -316,7 +326,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Utilizes LangGraph to orchestrate a workflow that generates character descriptions, plots, and image prompts using GPT-4, creates images with DALL-E 3, and assembles them into GIFs using PIL. Employs asynchronous programming for efficient parallel processing. -17. **[TTS Poem Generator Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/tts_poem_generator_agent_langgraph.ipynb)** +18. **[TTS Poem Generator Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/tts_poem_generator_agent_langgraph.ipynb)** #### Overview 🔎 An advanced text-to-speech (TTS) agent using LangGraph and OpenAI's APIs classifies input text, processes it based on content type, and generates corresponding speech output. @@ -324,7 +334,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Utilizes LangGraph to orchestrate a workflow that classifies input text using GPT models, applies content-specific processing, and converts the processed text to speech using OpenAI's TTS API. The system adapts its output based on the identified content type (general, poem, news, or joke). -18. **[Music Compositor Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/music_compositor_agent_langgraph.ipynb)** +19. **[Music Compositor Agent (LangGraph)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/music_compositor_agent_langgraph.ipynb)** #### Overview 🔎 An AI Music Compositor using LangGraph and OpenAI's language models generates custom musical compositions based on user input. The system processes the input through specialized components, each contributing to the final musical piece, which is then converted to a playable MIDI file. @@ -332,7 +342,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ LangGraph orchestrates a workflow that transforms user input into a musical composition, using ChatOpenAI (GPT-4) to generate melody, harmony, and rhythm, which are then style-adapted. The final AI-generated composition is converted to a MIDI file using music21 and can be played back using pygame. -19. **[Content Intelligence: Multi-Platform Content Generation Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ContentIntelligence.ipynb)** +20. **[Content Intelligence: Multi-Platform Content Generation Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ContentIntelligence.ipynb)** #### Overview 🔎 Content Intelligence demonstrates how to build an advanced content generation system that transforms input text into platform-optimized content across multiple social media channels. The system employs LangGraph for workflow orchestration to analyze content, conduct research, and generate tailored content while maintaining brand consistency across different platforms. @@ -343,7 +353,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=DPMtPbKmWnU)** -20. **[Business Meme Generator Using LangGraph and Memegen.link](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/business_meme_generator.ipynb)** +21. **[Business Meme Generator Using LangGraph and Memegen.link](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/business_meme_generator.ipynb)** #### Overview 🔎 The Business Meme Generator demonstrates how to create an AI-powered system that generates contextually relevant memes based on company website analysis. Using LangGraph for workflow orchestration, the system combines Groq's Llama model for text analysis and the Memegen.link API to automatically produce brand-aligned memes for digital marketing. @@ -354,7 +364,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://youtu.be/lsdDaGmkSCw?si=oF3CGfhbRqz1_Vm8)** -21. **[Murder Mystery Game with LLM Agents](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/murder_mystery_agent_langgraph.ipynb)** +22. **[Murder Mystery Game with LLM Agents](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/murder_mystery_agent_langgraph.ipynb)** #### Overview 🔎 A text-based detective game that utilizes autonomous LLM agents as interactive characters in a procedurally generated murder mystery. Drawing inspiration from the UNBOUNDED paper, the system creates unique scenarios each time, with players taking on the role of Sherlock Holmes to solve the case through character interviews and deductive reasoning. @@ -368,7 +378,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 📊 Analysis and Information Processing Agents -22. **[Memory-Enhanced Conversational Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/memory_enhanced_conversational_agent.ipynb)** +23. **[Memory-Enhanced Conversational Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/memory_enhanced_conversational_agent.ipynb)** #### Overview 🔎 A memory-enhanced conversational AI agent incorporates short-term and long-term memory systems to maintain context within conversations and across multiple sessions, improving interaction quality and personalization. @@ -376,7 +386,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Integrates a language model with separate short-term and long-term memory stores, utilizes a prompt template incorporating both memory types, and employs a memory manager for storage and retrieval. The system includes an interaction loop that updates and utilizes memories for each response. -23. **[Multi-Agent Collaboration System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/multi_agent_collaboration_system.ipynb)** +24. **[Multi-Agent Collaboration System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/multi_agent_collaboration_system.ipynb)** #### Overview 🔎 A multi-agent collaboration system combining historical research with data analysis, leveraging large language models to simulate specialized agents working together to answer complex historical questions. @@ -384,7 +394,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Utilizes a base Agent class to create specialized HistoryResearchAgent and DataAnalysisAgent, orchestrated by a HistoryDataCollaborationSystem. The system follows a five-step process: historical context provision, data needs identification, historical data provision, data analysis, and final synthesis. -24. **[Self-Improving Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/self_improving_agent.ipynb)** +25. **[Self-Improving Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/self_improving_agent.ipynb)** #### Overview 🔎 A Self-Improving Agent using LangChain engages in conversations, learns from interactions, and continuously improves its performance over time through reflection and adaptation. @@ -392,7 +402,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Integrates a language model with chat history management, response generation, and a reflection mechanism. The system employs a learning system that incorporates insights from reflection to enhance future performance, creating a continuous improvement loop. -25. **[Task-Oriented Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/task_oriented_agent.ipynb)** +26. **[Task-Oriented Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/task_oriented_agent.ipynb)** #### Overview 🔎 A language model application using LangChain that summarizes text and translates the summary to Spanish, combining custom functions, structured tools, and an agent for efficient text processing. @@ -400,7 +410,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Utilizes custom functions for summarization and translation, wrapped as structured tools. Employs a prompt template to guide the agent, which orchestrates the use of tools. An agent executor manages the process, taking input text and producing both an English summary and its Spanish translation. -26. **[Internet Search and Summarize Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/search_the_internet_and_summarize.ipynb)** +27. **[Internet Search and Summarize Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/search_the_internet_and_summarize.ipynb)** #### Overview 🔎 An intelligent web research assistant that combines web search capabilities with AI-powered summarization, automating the process of gathering information from the internet and distilling it into concise, relevant summaries. @@ -409,7 +419,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: Integrates a web search module using DuckDuckGo's API, a result parser, and a text summarization engine leveraging OpenAI's language models. The system performs site-specific or general searches, extracts relevant content, generates concise summaries, and compiles attributed results for efficient information retrieval and synthesis. -27. **[Multi agent research team - Autogen](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/research_team_autogen.ipynb)** +28. **[Multi agent research team - Autogen](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/research_team_autogen.ipynb)** #### Overview 🔎 This technique explores a multi-agent system for collaborative research using the AutoGen library. It employs agents to solve tasks collaboratively, focusing on efficient execution and quality assurance. The system enhances research by distributing tasks among specialized agents. @@ -422,7 +432,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: - **[Blogpost](https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/build-your-dream-team-with-autogen/ba-p/4157961)** -28. **[Sales Call Analyzer](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/sales_call_analyzer_agent.ipynb)** +29. **[Sales Call Analyzer](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/sales_call_analyzer_agent.ipynb)** #### Overview 🔎 An intelligent system that automates the analysis of sales call recordings by combining audio transcription with advanced natural language processing. The analyzer transcribes audio using OpenAI's Whisper, processes the text using NLP techniques, and generates comprehensive reports including sentiment analysis, key phrases, pain points, and actionable recommendations to improve sales performance. @@ -433,7 +443,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=SKAt_PvznDw)** -29. **[Weather Emergency & Response System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/Weather_Disaster_Management_AI_AGENT.ipynb)** +30. **[Weather Emergency & Response System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/Weather_Disaster_Management_AI_AGENT.ipynb)** #### Overview 🔎 A comprehensive system demonstrating two agent graph implementations for weather emergency response: a real-time graph processing live weather data, and a hybrid graph combining real and simulated data for testing high-severity scenarios. The system handles complete workflow from data gathering through emergency plan generation, with automated notifications and human verification steps. @@ -444,7 +454,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=AgiOAJl_apw)** -30. **[Self-Healing Codebase System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/self_healing_code.ipynb)** +31. **[Self-Healing Codebase System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/self_healing_code.ipynb)** #### Overview 🔎 An intelligent system that automatically detects, diagnoses, and fixes runtime code errors using LangGraph workflow orchestration and ChromaDB vector storage. The system maintains a memory of encountered bugs and their fixes through vector embeddings, enabling pattern recognition for similar errors across the codebase. @@ -455,7 +465,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=ga7ShvIXOvE)** -31. **[DataScribe: AI-Powered Schema Explorer](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/database_discovery_fleet.ipynb)** +32. **[DataScribe: AI-Powered Schema Explorer](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/database_discovery_fleet.ipynb)** #### Overview 🔎 An intelligent agent system that enables intuitive exploration and querying of relational databases through natural language interactions. The system utilizes a fleet of specialized agents, coordinated by a stateful Supervisor, to handle schema discovery, query planning, and data analysis tasks while maintaining contextual understanding through vector-based relationship graphs. @@ -463,7 +473,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Implementation 🛠️ Leverages LangGraph for orchestrating a multi-agent workflow including discovery, inference, and planning agents, with NetworkX for relationship graph visualization and management. The system incorporates dynamic state management through TypedDict classes, maintains database context between sessions using a db_graph attribute, and includes safety measures to prevent unauthorized database modifications. -32. **[Memory-Enhanced Email Agent (LangGraph & LangMem)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/memory-agent-tutorial.ipynb)** +33. **[Memory-Enhanced Email Agent (LangGraph & LangMem)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/memory-agent-tutorial.ipynb)** #### Overview 🔎 An intelligent email assistant that combines three types of memory (semantic, episodic, and procedural) to create a system that improves over time. The agent can triage incoming emails, draft contextually appropriate responses using stored knowledge, and enhance its performance based on user feedback. @@ -476,7 +486,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 📰 News and Information Agents -33. **[News TL;DR using LangGraph](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/news_tldr_langgraph.ipynb)** +34. **[News TL;DR using LangGraph](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/news_tldr_langgraph.ipynb)** #### Overview 🔎 A news summarization system that generates concise TL;DR summaries of current events based on user queries. The system leverages large language models for decision making and summarization while integrating with news APIs to access up-to-date content, allowing users to quickly catch up on topics of interest through generated bullet-point summaries. @@ -488,7 +498,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: - **[YouTube Explanation](https://www.youtube.com/watch?v=0fRxW6miybI)** - **[Blog Post](https://open.substack.com/pub/diamantai/p/stop-reading-start-understanding?r=336pe4&utm_campaign=post&utm_medium=web&showWelcomeOnShare=false)** -34. **[AInsight: AI/ML Weekly News Reporter](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ainsight_langgraph.ipynb)** +35. **[AInsight: AI/ML Weekly News Reporter](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ainsight_langgraph.ipynb)** #### Overview 🔎 AInsight demonstrates how to build an intelligent news aggregation and summarization system using a multi-agent architecture. The system employs three specialized agents (NewsSearcher, Summarizer, Publisher) to automatically collect, process and summarize AI/ML news for general audiences through LangGraph-based workflow orchestration. @@ -499,7 +509,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=kH5S1is2D_0)** -35. **[Journalism-Focused AI Assistant](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/journalism_focused_ai_assistant_langgraph.ipynb)** +36. **[Journalism-Focused AI Assistant](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/journalism_focused_ai_assistant_langgraph.ipynb)** #### Overview 🔎 A specialized AI assistant that helps journalists tackle modern journalistic challenges like misinformation, bias, and information overload. The system integrates fact-checking, tone analysis, summarization, and grammar review tools to enhance the accuracy and efficiency of journalistic work while maintaining ethical reporting standards. @@ -508,7 +518,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: Leverages LangGraph to orchestrate a workflow of specialized components including language models for analysis and generation, web search integration via DuckDuckGo's API, document parsing tools like PyMuPDFLoader and WebBaseLoader, text splitting with RecursiveCharacterTextSplitter, and structured JSON outputs. Each component works together through a unified workflow to analyze content, verify facts, detect bias, extract quotes, and generate comprehensive reports. -36. **[Blog Writer (Open AI Swarm)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/blog_writer_swarm.ipynb)** +37. **[Blog Writer (Open AI Swarm)](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/blog_writer_swarm.ipynb)** #### Overview 🔎 A multi-agent system for collaborative blog post creation using OpenAI's Swarm package. It leverages specialized agents to perform research, planning, writing, and editing tasks efficiently. @@ -519,7 +529,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[Swarm Repo](https://github.com/openai/swarm)** -37. **[Podcast Internet Search and Generate Agent 🎙️](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/generate_podcast_agent_langgraph.ipynb)** +38. **[Podcast Internet Search and Generate Agent 🎙️](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/generate_podcast_agent_langgraph.ipynb)** #### Overview 🔎 A two step agent that first searches the internet for a given topic and then generates a podcast on the topic found. The search step uses a search agent and search function to find the most relevant information. The second step uses a podcast generation agent and generation function to create a podcast on the topic found. @@ -530,7 +540,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 🛍️ Shopping and Product Analysis Agents -38. **[ShopGenie - Redefining Online Shopping Customer Experience](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ShopGenie.ipynb)** +39. **[ShopGenie - Redefining Online Shopping Customer Experience](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/ShopGenie.ipynb)** #### Overview 🔎 An AI-powered shopping assistant that helps customers make informed purchasing decisions even without domain expertise. The system analyzes product information from multiple sources, compares specifications and reviews, identifies the best option based on user needs, and delivers recommendations through email with supporting video reviews, creating a comprehensive shopping experience. @@ -541,7 +551,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=Js0sK0u53dQ)** -39. **[Car Buyer AI Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/car_buyer_agent_langgraph.ipynb)** +40. **[Car Buyer AI Agent](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/car_buyer_agent_langgraph.ipynb)** #### Overview 🔎 The Smart Product Buyer AI Agent demonstrates how to build an intelligent system that assists users in making informed purchasing decisions. Using LangGraph and LLM-based intelligence, the system processes user requirements, scrapes product listings from websites like AutoTrader, and provides detailed analysis and recommendations for car purchases. @@ -554,7 +564,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 🎯 Task Management and Productivity Agents -40. **[Taskifier - Intelligent Task Allocation & Management](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/taskifier.ipynb)** +41. **[Taskifier - Intelligent Task Allocation & Management](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/taskifier.ipynb)** #### Overview 🔎 An intelligent task management system that analyzes user work styles and creates personalized task breakdown strategies, born from the observation that procrastination often stems from task ambiguity among students and early-career professionals. The system evaluates historical work patterns, gathers relevant task information through web search, and generates customized step-by-step approaches to optimize productivity and reduce workflow paralysis. @@ -565,7 +575,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=1W_p_RVi9KE&t=25s)** -41. **[Grocery Management Agents System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/grocery_management_agents_system.ipynb)** +42. **[Grocery Management Agents System](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/grocery_management_agents_system.ipynb)** #### Overview 🔎 A multi-agent system built with CrewAI that automates grocery management tasks including receipt interpretation, expiration date tracking, inventory management, and recipe recommendations. The system uses specialized agents to extract data from receipts, estimate product shelf life, track consumption, and suggest recipes to minimize food waste. @@ -578,7 +588,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 🔍 Quality Assurance and Testing Agents -42. **[LangGraph-Based Systems Inspector](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/graph_inspector_system_langgraph.ipynb)** +43. **[LangGraph-Based Systems Inspector](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/graph_inspector_system_langgraph.ipynb)** #### Overview 🔎 A comprehensive testing and validation tool for LangGraph-based applications that automatically analyzes system architecture, generates test cases, and identifies potential vulnerabilities through multi-agent inspection. The inspector employs specialized AI testers to evaluate different aspects of the system, from basic functionality to security concerns and edge cases. @@ -590,7 +600,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: - **[YouTube Explanation](https://www.youtube.com/watch?v=fQd6lXc-Y9A)** - **[Blog Post](https://open.substack.com/pub/diamantai/p/langgraph-systems-inspector-an-ai?r=336pe4&utm_campaign=post&utm_medium=web&showWelcomeOnShare=false)** -43. **[EU Green Deal FAQ Bot](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/EU_Green_Compliance_FAQ_Bot.ipynb)** +44. **[EU Green Deal FAQ Bot](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/EU_Green_Compliance_FAQ_Bot.ipynb)** #### Overview 🔎 The EU Green Deal FAQ Bot demonstrates how to build a RAG-based AI agent that helps businesses understand EU green deal policies. The system processes complex regulatory documents into manageable chunks and provides instant, accurate answers to common questions about environmental compliance, emissions reporting, and waste management requirements. @@ -601,7 +611,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: #### Additional Resources 📚 - **[YouTube Explanation](https://www.youtube.com/watch?v=Av0kBQjwU-Y)** -44. **[Systematic Review Automation System + Paper Draft Creation](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/systematic_review_of_scientific_articles.ipynb)** +45. **[Systematic Review Automation System + Paper Draft Creation](https://github.com/NirDiamant/GenAI_Agents/blob/main/all_agents_tutorials/systematic_review_of_scientific_articles.ipynb)** #### Overview 🔎 A comprehensive system for automating academic systematic reviews using a directed graph architecture and LangChain components. The system generates complete, publication-ready systematic review papers, automatically processing everything from literature search through final draft generation with multiple revision cycles. @@ -614,7 +624,7 @@ Explore our extensive list of GenAI agent implementations, sorted by categories: ### 🌟 Special Advanced Technique 🌟 -45. **[Sophisticated Controllable Agent for Complex RAG Tasks 🤖](https://github.com/NirDiamant/Controllable-RAG-Agent)** +46. **[Sophisticated Controllable Agent for Complex RAG Tasks 🤖](https://github.com/NirDiamant/Controllable-RAG-Agent)** #### Overview 🔎 An advanced RAG solution designed to tackle complex questions that simple semantic similarity-based retrieval cannot solve. This approach uses a sophisticated deterministic graph as the "brain" 🧠 of a highly controllable autonomous agent, capable of answering non-trivial questions from your own data. diff --git a/all_agents_tutorials/multi_provider_conversational_agent.ipynb b/all_agents_tutorials/multi_provider_conversational_agent.ipynb new file mode 100644 index 0000000..373fab5 --- /dev/null +++ b/all_agents_tutorials/multi_provider_conversational_agent.ipynb @@ -0,0 +1,333 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-Provider Conversational Agent with MiniMax Support\n", + "\n", + "## Overview\n", + "This tutorial demonstrates how to build a conversational agent that can work with **multiple LLM providers** through a single, unified interface. In addition to OpenAI, we show how to use [MiniMax](https://www.minimaxi.com/) (M2.7 / M2.5 / M2.5-highspeed) as an alternative LLM backend.\n", + "\n", + "## Motivation\n", + "Most GenAI agent tutorials are hard-wired to a single provider (typically OpenAI). In production you often need to:\n", + "- **Switch providers** without rewriting agent code.\n", + "- **Reduce costs** by routing certain workloads to cheaper models.\n", + "- **Improve resilience** by falling back to a secondary provider when the primary is unavailable.\n", + "\n", + "MiniMax M2.7 is the latest high-capability model with a **204K token context window** and an OpenAI-compatible API, making it a practical alternative.\n", + "\n", + "## Key Components\n", + "1. **`utils/llm_provider.py`** – shared helper that returns a LangChain `ChatOpenAI` instance for any registered provider.\n", + "2. **Provider registry** – a dictionary mapping provider names to their configuration (base URL, API-key env var, default model).\n", + "3. **Conversational chain** – LangChain prompt + LLM + message history, identical regardless of which provider is active.\n", + "\n", + "## Method Details\n", + "\n", + "### Architecture\n", + "```\n", + "User Input\n", + " │\n", + " ▼\n", + "Prompt Template ────▶ get_llm(provider) ────▶ LLM Response\n", + " ▲ │\n", + " │ ┌────┴────┐\n", + "History Store │ OpenAI │\n", + " │ MiniMax │\n", + " │ ... │\n", + " └─────────┘\n", + "```\n", + "\n", + "The `get_llm()` function reads the provider configuration and returns the right `ChatOpenAI` object. The rest of the agent code never touches provider-specific details." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "### Install required packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install -q langchain langchain_openai openai python-dotenv" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Configure environment variables\n", + "\n", + "Create a `.env` file in the repository root (or export the variables in your shell):\n", + "\n", + "```bash\n", + "# Required for OpenAI provider\n", + "OPENAI_API_KEY=sk-...\n", + "\n", + "# Required for MiniMax provider (get yours at https://www.minimaxi.com/)\n", + "MINIMAX_API_KEY=sk-...\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import the multi-provider helper and LangChain components" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "import sys, os\n\n# Ensure the repository root is on the Python path so we can import utils/\nsys.path.insert(0, os.path.join(os.getcwd(), \"..\"))\n\nfrom utils.llm_provider import get_llm, list_providers\nfrom langchain_core.runnables.history import RunnableWithMessageHistory\nfrom langchain_community.chat_message_histories import ChatMessageHistory\nfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### List available providers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Available LLM providers:\", list_providers())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 1 – Conversational Agent with OpenAI (baseline)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Initialize the LLM via the unified helper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "llm_openai = get_llm(provider=\"openai\", model=\"gpt-4o-mini\", temperature=0)\n", + "print(f\"Provider: OpenAI | Model: {llm_openai.model_name}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Build the conversational chain (provider-agnostic)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def build_agent(llm):\n", + " \"\"\"Build a conversational agent chain for any LangChain-compatible LLM.\"\"\"\n", + " prompt = ChatPromptTemplate.from_messages([\n", + " (\"system\", \"You are a helpful AI assistant. Keep answers concise.\"),\n", + " MessagesPlaceholder(variable_name=\"history\"),\n", + " (\"human\", \"{input}\"),\n", + " ])\n", + "\n", + " store: dict = {}\n", + "\n", + " def get_history(session_id: str):\n", + " if session_id not in store:\n", + " store[session_id] = ChatMessageHistory()\n", + " return store[session_id]\n", + "\n", + " chain = prompt | llm\n", + " return RunnableWithMessageHistory(\n", + " chain,\n", + " get_history,\n", + " input_messages_key=\"input\",\n", + " history_messages_key=\"history\",\n", + " ), store" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "agent_openai, history_openai = build_agent(llm_openai)\n", + "\n", + "config = {\"configurable\": {\"session_id\": \"demo_openai\"}}\n", + "\n", + "r1 = agent_openai.invoke({\"input\": \"Hello! My name is Alice.\"}, config=config)\n", + "print(\"OpenAI:\", r1.content)\n", + "\n", + "r2 = agent_openai.invoke({\"input\": \"What is my name?\"}, config=config)\n", + "print(\"OpenAI:\", r2.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 2 – Switch to MiniMax M2.7\n", + "\n", + "Switching providers is a one-line change. The rest of the agent code stays exactly the same." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "llm_minimax = get_llm(provider=\"minimax\") # defaults to MiniMax-M2.7\n", + "print(f\"Provider: MiniMax | Model: {llm_minimax.model_name}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "agent_minimax, history_minimax = build_agent(llm_minimax)\n", + "\n", + "config = {\"configurable\": {\"session_id\": \"demo_minimax\"}}\n", + "\n", + "r1 = agent_minimax.invoke({\"input\": \"Hello! My name is Alice.\"}, config=config)\n", + "print(\"MiniMax:\", r1.content)\n", + "\n", + "r2 = agent_minimax.invoke({\"input\": \"What is my name?\"}, config=config)\n", + "print(\"MiniMax:\", r2.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Use the high-speed variant for lower latency" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "llm_fast = get_llm(provider=\"minimax\", model=\"MiniMax-M2.5-highspeed\")\n", + "agent_fast, _ = build_agent(llm_fast)\n", + "\n", + "config = {\"configurable\": {\"session_id\": \"demo_fast\"}}\n", + "r = agent_fast.invoke({\"input\": \"Explain quantum computing in two sentences.\"}, config=config)\n", + "print(\"MiniMax (highspeed):\", r.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 3 – Compare providers side-by-side\n", + "\n", + "Run the same prompt through both providers and compare outputs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prompt_text = \"What are the three most important factors when choosing a cloud LLM provider?\"\n", + "\n", + "for name, llm in [(\"OpenAI\", llm_openai), (\"MiniMax\", llm_minimax)]:\n", + " agent, _ = build_agent(llm)\n", + " config = {\"configurable\": {\"session_id\": f\"compare_{name}\"}}\n", + " resp = agent.invoke({\"input\": prompt_text}, config=config)\n", + " print(f\"\\n--- {name} ---\")\n", + " print(resp.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 4 – Environment-driven provider selection\n", + "\n", + "In production, you often want the provider to be controlled by an environment variable rather than hard-coded." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "# Set via environment (e.g. LLM_PROVIDER=minimax python app.py)\n", + "provider_name = os.getenv(\"LLM_PROVIDER\", \"minimax\")\n", + "llm_env = get_llm(provider=provider_name)\n", + "\n", + "agent_env, _ = build_agent(llm_env)\n", + "config = {\"configurable\": {\"session_id\": \"env_demo\"}}\n", + "r = agent_env.invoke({\"input\": \"Summarize the benefits of multi-provider LLM setups.\"}, config=config)\n", + "print(f\"[{provider_name}]:\", r.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "By introducing a thin **provider abstraction** (`utils/llm_provider.py`), all tutorials in this repository can:\n", + "\n", + "- Support **OpenAI** and **MiniMax** (and any future OpenAI-compatible provider) without code changes.\n", + "- Switch providers via a single parameter or environment variable.\n", + "- Share the same agent logic regardless of the underlying LLM.\n", + "\n", + "### Next steps\n", + "- Explore more complex agents in this repository using the `get_llm()` helper.\n", + "- Add additional providers by extending `PROVIDERS` in `utils/llm_provider.py`.\n", + "- Try MiniMax-M2.5-highspeed for latency-sensitive workloads, or MiniMax-M2.7 for the latest capabilities.\n", + "\n", + "### References\n", + "- [MiniMax Platform](https://www.minimaxi.com/)\n", + "- [MiniMax API Documentation](https://www.minimaxi.com/document/introduction)\n", + "- [LangChain OpenAI Integration](https://python.langchain.com/docs/integrations/chat/openai/)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_llm_provider.py b/tests/test_llm_provider.py new file mode 100644 index 0000000..2c3d495 --- /dev/null +++ b/tests/test_llm_provider.py @@ -0,0 +1,190 @@ +"""Unit tests for utils.llm_provider.""" + +import os +import unittest +from unittest.mock import patch, MagicMock + +import sys + +# Ensure the repo root is on the path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) + +from utils.llm_provider import ( + PROVIDERS, + get_llm, + get_provider_info, + list_providers, +) + + +class TestListProviders(unittest.TestCase): + """Tests for list_providers().""" + + def test_returns_list(self): + result = list_providers() + self.assertIsInstance(result, list) + + def test_contains_openai(self): + self.assertIn("openai", list_providers()) + + def test_contains_minimax(self): + self.assertIn("minimax", list_providers()) + + def test_at_least_two_providers(self): + self.assertGreaterEqual(len(list_providers()), 2) + + +class TestGetProviderInfo(unittest.TestCase): + """Tests for get_provider_info().""" + + def test_openai_config(self): + info = get_provider_info("openai") + self.assertIsNone(info["base_url"]) + self.assertEqual(info["api_key_env"], "OPENAI_API_KEY") + self.assertEqual(info["default_model"], "gpt-4o-mini") + + def test_minimax_config(self): + info = get_provider_info("minimax") + self.assertEqual(info["base_url"], "https://api.minimax.io/v1") + self.assertEqual(info["api_key_env"], "MINIMAX_API_KEY") + self.assertEqual(info["default_model"], "MiniMax-M2.7") + + def test_unknown_provider_raises(self): + with self.assertRaises(ValueError) as ctx: + get_provider_info("nonexistent") + self.assertIn("nonexistent", str(ctx.exception)) + + def test_returns_copy(self): + info = get_provider_info("minimax") + info["base_url"] = "modified" + self.assertEqual( + PROVIDERS["minimax"]["base_url"], + "https://api.minimax.io/v1", + ) + + +class TestGetLlm(unittest.TestCase): + """Tests for get_llm().""" + + @patch.dict(os.environ, {"OPENAI_API_KEY": "test-openai-key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_openai_default(self, mock_cls): + mock_cls.return_value = MagicMock() + llm = get_llm(provider="openai") + mock_cls.assert_called_once() + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["model"], "gpt-4o-mini") + self.assertEqual(call_kwargs["api_key"], "test-openai-key") + self.assertNotIn("base_url", call_kwargs) + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-minimax-key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_minimax_default(self, mock_cls): + mock_cls.return_value = MagicMock() + llm = get_llm(provider="minimax") + mock_cls.assert_called_once() + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["model"], "MiniMax-M2.7") + self.assertEqual(call_kwargs["api_key"], "test-minimax-key") + self.assertEqual(call_kwargs["base_url"], "https://api.minimax.io/v1") + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-minimax-key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_minimax_custom_model(self, mock_cls): + mock_cls.return_value = MagicMock() + get_llm(provider="minimax", model="MiniMax-M2.5-highspeed") + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["model"], "MiniMax-M2.5-highspeed") + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-minimax-key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_minimax_temperature_clamping_zero(self, mock_cls): + mock_cls.return_value = MagicMock() + get_llm(provider="minimax", temperature=0) + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["temperature"], 0.01) + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-minimax-key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_minimax_temperature_negative_clamped(self, mock_cls): + mock_cls.return_value = MagicMock() + get_llm(provider="minimax", temperature=-0.5) + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["temperature"], 0.01) + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-minimax-key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_minimax_temperature_positive_preserved(self, mock_cls): + mock_cls.return_value = MagicMock() + get_llm(provider="minimax", temperature=0.5) + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["temperature"], 0.5) + + @patch.dict(os.environ, {"OPENAI_API_KEY": "key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_openai_temperature_zero_not_clamped(self, mock_cls): + mock_cls.return_value = MagicMock() + get_llm(provider="openai", temperature=0) + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["temperature"], 0) + + @patch.dict(os.environ, {"OPENAI_API_KEY": "key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_max_tokens_forwarded(self, mock_cls): + mock_cls.return_value = MagicMock() + get_llm(provider="openai", max_tokens=2048) + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["max_tokens"], 2048) + + @patch.dict(os.environ, {"OPENAI_API_KEY": "key"}) + @patch("utils.llm_provider.ChatOpenAI") + def test_extra_kwargs_forwarded(self, mock_cls): + mock_cls.return_value = MagicMock() + get_llm(provider="openai", top_p=0.9) + call_kwargs = mock_cls.call_args[1] + self.assertEqual(call_kwargs["top_p"], 0.9) + + def test_unknown_provider_raises(self): + with self.assertRaises(ValueError): + get_llm(provider="nonexistent") + + @patch.dict(os.environ, {}, clear=True) + def test_missing_api_key_raises(self): + # Remove all env vars to trigger the error + for key in ("OPENAI_API_KEY", "MINIMAX_API_KEY"): + os.environ.pop(key, None) + with self.assertRaises(EnvironmentError) as ctx: + get_llm(provider="openai") + self.assertIn("OPENAI_API_KEY", str(ctx.exception)) + + @patch.dict(os.environ, {}, clear=True) + def test_missing_minimax_key_raises(self): + for key in ("OPENAI_API_KEY", "MINIMAX_API_KEY"): + os.environ.pop(key, None) + with self.assertRaises(EnvironmentError) as ctx: + get_llm(provider="minimax") + self.assertIn("MINIMAX_API_KEY", str(ctx.exception)) + + +class TestProviderRegistry(unittest.TestCase): + """Tests for the PROVIDERS registry itself.""" + + def test_all_providers_have_required_keys(self): + required = {"base_url", "api_key_env", "default_model"} + for name, config in PROVIDERS.items(): + self.assertTrue( + required.issubset(config.keys()), + f"Provider {name!r} is missing keys: {required - config.keys()}", + ) + + def test_minimax_base_url_is_https(self): + self.assertTrue( + PROVIDERS["minimax"]["base_url"].startswith("https://") + ) + + def test_openai_has_no_base_url(self): + self.assertIsNone(PROVIDERS["openai"]["base_url"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_minimax_integration.py b/tests/test_minimax_integration.py new file mode 100644 index 0000000..7615ba2 --- /dev/null +++ b/tests/test_minimax_integration.py @@ -0,0 +1,108 @@ +"""Integration tests for MiniMax provider via utils.llm_provider. + +These tests make real API calls and require a valid MINIMAX_API_KEY +environment variable. Skip automatically when the key is absent. +""" + +import os +import sys +import unittest + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) + +MINIMAX_API_KEY = os.getenv("MINIMAX_API_KEY") +SKIP_REASON = "MINIMAX_API_KEY not set" + + +@unittest.skipUnless(MINIMAX_API_KEY, SKIP_REASON) +class TestMiniMaxIntegration(unittest.TestCase): + """Live integration tests against the MiniMax API.""" + + def _get_llm(self, **kwargs): + from utils.llm_provider import get_llm + return get_llm(provider="minimax", **kwargs) + + # ------------------------------------------------------------------ + # Basic connectivity + # ------------------------------------------------------------------ + + def test_simple_prompt(self): + llm = self._get_llm(temperature=0.1) + resp = llm.invoke("Say hello in one sentence.") + self.assertTrue(len(resp.content) > 0) + + def test_response_is_string(self): + llm = self._get_llm(temperature=0.1) + resp = llm.invoke("What is 1+1?") + self.assertIsInstance(resp.content, str) + + # ------------------------------------------------------------------ + # Model variants + # ------------------------------------------------------------------ + + def test_default_model(self): + llm = self._get_llm(temperature=0.1) + resp = llm.invoke("Reply with the word 'ok'.") + self.assertIn("ok", resp.content.lower()) + + def test_m27_model(self): + llm = self._get_llm(model="MiniMax-M2.7", temperature=0.1) + resp = llm.invoke("Reply with the word 'ok'.") + self.assertIn("ok", resp.content.lower()) + + def test_highspeed_model(self): + llm = self._get_llm(model="MiniMax-M2.5-highspeed", temperature=0.1) + resp = llm.invoke("Reply with the word 'ok'.") + self.assertIn("ok", resp.content.lower()) + + # ------------------------------------------------------------------ + # Temperature handling + # ------------------------------------------------------------------ + + def test_temperature_clamped(self): + """Temperature=0 should be auto-clamped; the API should not reject it.""" + llm = self._get_llm(temperature=0) + resp = llm.invoke("What is 2+2?") + self.assertIn("4", resp.content) + + +@unittest.skipUnless(MINIMAX_API_KEY, SKIP_REASON) +class TestMiniMaxConversation(unittest.TestCase): + """Test multi-turn conversation with MiniMax.""" + + def test_context_retention(self): + from utils.llm_provider import get_llm + from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder + from langchain_core.runnables.history import RunnableWithMessageHistory + from langchain_community.chat_message_histories import ChatMessageHistory + + llm = get_llm(provider="minimax", temperature=0.1) + prompt = ChatPromptTemplate.from_messages([ + ("system", "You are a helpful assistant. Keep answers concise."), + MessagesPlaceholder(variable_name="history"), + ("human", "{input}"), + ]) + store = {} + + def get_history(session_id): + if session_id not in store: + store[session_id] = ChatMessageHistory() + return store[session_id] + + chain = RunnableWithMessageHistory( + prompt | llm, + get_history, + input_messages_key="input", + history_messages_key="history", + ) + config = {"configurable": {"session_id": "integration_test"}} + + r1 = chain.invoke({"input": "My favorite color is blue."}, config=config) + self.assertTrue(len(r1.content) > 0) + + r2 = chain.invoke({"input": "What is my favorite color?"}, config=config) + self.assertIn("blue", r2.content.lower()) + + +if __name__ == "__main__": + unittest.main() diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..73491c5 --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1 @@ +# GenAI Agents - Shared Utilities diff --git a/utils/llm_provider.py b/utils/llm_provider.py new file mode 100644 index 0000000..082b5d6 --- /dev/null +++ b/utils/llm_provider.py @@ -0,0 +1,133 @@ +"""Multi-provider LLM configuration for GenAI Agents tutorials. + +Provides a unified ``get_llm()`` helper that returns a LangChain +``ChatOpenAI`` instance wired to the requested provider. Every +OpenAI-compatible provider (including MiniMax) is supported through +the same interface. + +Supported providers +------------------- +- **openai** - OpenAI GPT models (default) +- **minimax** - MiniMax M2.7 / M2.5 / M2.5-highspeed (204K context, OpenAI-compatible) + +Usage:: + + from utils.llm_provider import get_llm + + # Default - OpenAI + llm = get_llm() + + # MiniMax M2.7 (default MiniMax model) + llm = get_llm(provider="minimax") + + # MiniMax M2.5 + llm = get_llm(provider="minimax", model="MiniMax-M2.5") + + # MiniMax high-speed variant + llm = get_llm(provider="minimax", model="MiniMax-M2.5-highspeed") + +Environment variables +--------------------- +Set the API key for the provider you want to use: + +- ``OPENAI_API_KEY`` - for OpenAI +- ``MINIMAX_API_KEY`` - for MiniMax (obtain at https://www.minimaxi.com/) +""" + +from __future__ import annotations + +import os +from typing import Any + +from dotenv import load_dotenv +from langchain_openai import ChatOpenAI + +# --------------------------------------------------------------------------- +# Provider registry +# --------------------------------------------------------------------------- + +PROVIDERS: dict[str, dict[str, Any]] = { + "openai": { + "base_url": None, + "api_key_env": "OPENAI_API_KEY", + "default_model": "gpt-4o-mini", + }, + "minimax": { + "base_url": "https://api.minimax.io/v1", + "api_key_env": "MINIMAX_API_KEY", + "default_model": "MiniMax-M2.7", + }, +} + + +def list_providers() -> list[str]: + """Return the names of all registered providers.""" + return list(PROVIDERS.keys()) + + +def get_provider_info(provider: str) -> dict[str, Any]: + """Return configuration metadata for *provider*. + + Raises ``ValueError`` if the provider is unknown. + """ + if provider not in PROVIDERS: + raise ValueError( + f"Unknown provider: {provider!r}. " + f"Available providers: {list_providers()}" + ) + return dict(PROVIDERS[provider]) + + +def get_llm( + provider: str = "openai", + model: str | None = None, + temperature: float = 0.7, + max_tokens: int = 1000, + **kwargs: Any, +) -> ChatOpenAI: + """Return a :class:`ChatOpenAI` instance configured for *provider*. + + Parameters + ---------- + provider: + Name of the provider (see :data:`PROVIDERS`). + model: + Model identifier. Falls back to the provider's default model when + ``None``. + temperature: + Sampling temperature. Automatically clamped to ``0.01`` for MiniMax, + whose API rejects ``0``. + max_tokens: + Maximum number of tokens to generate. + **kwargs: + Extra keyword arguments forwarded to :class:`ChatOpenAI`. + """ + load_dotenv() + + config = get_provider_info(provider) # raises on bad name + + api_key = os.getenv(config["api_key_env"]) + if not api_key: + raise EnvironmentError( + f"Missing API key: please set the {config['api_key_env']!r} " + f"environment variable." + ) + + resolved_model = model or config["default_model"] + base_url = config["base_url"] + + # MiniMax rejects temperature == 0; clamp to a near-zero value. + if provider == "minimax" and temperature <= 0: + temperature = 0.01 + + params: dict[str, Any] = { + "model": resolved_model, + "temperature": temperature, + "max_tokens": max_tokens, + "api_key": api_key, + } + if base_url is not None: + params["base_url"] = base_url + params.update(kwargs) + + return ChatOpenAI(**params)