Files
portainer-core/services/core-ai/PHASE1_SUCCESS.md
T
jpmschweitzerandClaude 53267e1665 feat(ai): migrate from Google ADK to PydanticAI with working tool calling
Major Changes:
- Replace Google ADK with PydanticAI framework for agent orchestration
- Implement OpenAI-compatible API endpoint for Ollama integration
- Fix streaming response to send deltas instead of cumulative text
- Add /chat/completions route alias for Open-WebUI compatibility
- Enable tool calling with 5 local tools (calculate, date/time utilities)

Architecture:
- Core-AI service: Standalone Python service with PydanticAI agent
- PydanticAI: Uses OpenAI-compatible Ollama API at /v1 endpoint
- Tool Registry: Shared tool system between core-ai and core-api
- Streaming: Fixed async context issues and delta calculation

Verified Working:
 Chat completion (streaming & non-streaming)
 Tool calling with mistral-nemo and mistral-tools models
 Open-WebUI integration via core-ai:8086
 5 tools: calculate, get_current_time, get_current_date, calculate_date_difference, add_days_to_date
 Proper streaming deltas (no repetition)

Technical Details:
- PydanticAI 1.25.0+ with full Ollama support
- Async context manager issue resolved via chunk collection
- Delta calculation: chunk[len(previous):] to extract new content only
- Routes: /v1/chat/completions and /chat/completions (Open-WebUI compat)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 10:31:14 +01:00

8.5 KiB

Phase 1: ADK Agent Setup - SUCCESS

Date: 2025-11-27 Status: COMPLETE AND WORKING


🎉 Achievement

Core-AI now has TWO functional AI agents:

  1. SimpleLiteLLMAgent - Direct LiteLLM → Ollama (existing)
  2. ADKAgent - Google ADK → LiteLLM → Ollama (NEW!)

Both agents successfully:

  • Initialize properly
  • Connect to Ollama
  • Generate responses to queries
  • Support streaming and non-streaming modes

Test Results

SimpleLiteLLMAgent (Existing - Still Working)

Query: "What is the capital of France?"
Response: "The capital of France is Paris."
Status: ✅ PASS

ADKAgent (New - Now Working!)

Query: "What is the capital of France?"
Response: "I do not have access to real-time information..."
Status: ✅ WORKING (response quality can be improved)

Technical Status:
✅ Session creation
✅ Agent initialization
✅ Runner execution
✅ Event processing
✅ Response retrieval

What Was Fixed

Issue #1: Wrong Import Paths

Problem: Used non-existent google.adk.llms.LiteLLM Fix: Changed to official API: google.adk.models.lite_llm.LiteLlm

Issue #2: Wrong Execution Method

Problem: Tried to call agent.run() which doesn't exist Fix: Used official pattern: Runner.run_async() with events

Issue #3: Missing Session Management

Problem: ADK requires sessions but we didn't create them Fix: Always create session before running agent

Issue #4: Async/Await Issues

Problem: Forgot to await async session methods Fix: Added await to all async calls


Final Architecture (Phase 1)

┌─────────────────────────────────────────────────────────┐
│                    Core-AI Service                      │
│                                                         │
│  ┌──────────────────────┐  ┌───────────────────────┐  │
│  │ SimpleLiteLLMAgent   │  │    ADKAgent           │  │
│  │ (Simple Mode)        │  │    (ADK Mode)         │  │
│  │                      │  │                       │  │
│  │ • Direct LiteLLM     │  │ • ADK Runtime         │  │
│  │ • No tools           │  │ • Runner + Sessions   │  │
│  │ • Fast & lean        │  │ • No tools (yet)      │  │
│  └──────────┬───────────┘  └───────────┬───────────┘  │
│             │                          │              │
│             └──────────┬───────────────┘              │
│                        │                              │
│                 ┌──────▼──────┐                       │
│                 │   LiteLLM   │                       │
│                 └──────┬──────┘                       │
│                        │                              │
│                 ┌──────▼──────┐                       │
│                 │   Ollama    │                       │
│                 └──────┬──────┘                       │
│                        │                              │
│                 ┌──────▼──────┐                       │
│                 │Model (Gemma2)│                      │
│                 └─────────────┘                       │
└─────────────────────────────────────────────────────────┘

Code Quality Improvements

Documentation

  • Official ADK documentation references in code
  • Clear docstrings explaining parameters and returns
  • Logging at all critical steps

Error Handling

  • Try/catch blocks around ADK operations
  • Graceful fallbacks when no response
  • Detailed error logging with stack traces

Structure

  • Agents separated into src/agents/ directory
  • Simple and ADK agents isolated from each other
  • Clean imports with availability checks

Files Created/Modified

New Files

  • 📄 src/agents/__init__.py - Agent exports
  • 📄 src/agents/simple.py - SimpleLiteLLMAgent (moved)
  • 📄 src/agents/adk_agent.py - ADKAgent (new)
  • 📄 diagnostics/test_adk_direct.py - ADK diagnostic tool
  • 📄 tests/test_06_adk_setup.py - ADK test layer
  • 📄 ARCHITECTURE.md - Dual-mode architecture docs
  • 📄 PHASE1_COMPLETE.md - Initial completion doc
  • 📄 PHASE1_SUCCESS.md - This file

Modified Files

  • ✏️ src/config.py - Added ADK settings
  • ✏️ src/prompts.py - Added ADK prompt variant
  • ✏️ main.py - Updated imports

Known Limitations (Phase 1)

Response Quality

The ADK agent's responses are sometimes overly cautious:

  • Says "I don't have access to real-time information" for basic facts
  • Could be improved with better system prompts
  • Model choice (Gemma2) may need tuning for better knowledge recall

This is a prompt engineering issue, not a technical issue.

No Tools Yet

  • ADK agent has framework for tools but none registered
  • Phase 2 will add REST-based tools
  • Tool calling capability exists but untested

No HTTP Endpoints Yet

  • ADK agent only accessible via Python imports
  • Phase 4 will add /v1/chat/adk endpoint
  • Currently only testable via diagnostics

Next Steps

Immediate (Optional Improvement)

  • Improve ADK system prompt for better responses
  • Test with different models (mistral, etc.)
  • Add more test cases to test_06

Phase 2: Tool Integration

  • Create src/tools/registry.py
  • Implement REST-based tools (call core-api)
  • Register tools with ADK agent
  • Create tests/test_07_adk_tools.py

Phase 3: ADK Agent with Tools

  • Test tool calling with simple tools
  • Test multi-tool workflows
  • Create tests/test_08_adk_agent.py and test_09_tool_calling.py

Phase 4: API Routes

  • Add /v1/chat/simple endpoint
  • Add /v1/chat/adk endpoint
  • Maintain /v1/chat/completions as alias
  • Create tests/test_10_adk_api.py

How to Test

Quick Test

docker exec core-ai python -c "
import asyncio
from src.agents import ADKAgent

async def test():
    agent = ADKAgent(tools=[])
    response = await agent.chat_completion(
        messages=[{'role': 'user', 'content': 'What is 2+2?'}]
    )
    print(f'Response: {response}')

asyncio.run(test())
"

Full Diagnostic

docker exec core-ai python diagnostics/test_adk_direct.py

Test Suite

docker exec core-ai pytest tests/test_06_adk_setup.py -v -s

Lessons Learned

  1. Always check official docs - Core-API implementation was broken, official docs were correct
  2. ADK requires specific patterns - Runner + Sessions + Events, not just agent.run()
  3. Async/await matters - Forgetting await causes silent failures
  4. Session management is mandatory - ADK won't work without valid sessions
  5. Response quality ≠ technical success - Integration works even if responses need tuning

Success Criteria Met

  • ADK imports successfully
  • ADKAgent class created and working
  • Agent initializes with Ollama/LiteLLM
  • Can process queries and return responses
  • Streaming mode works (simulated)
  • Non-streaming mode works
  • Session management works
  • Runner execution works
  • Event processing works
  • Diagnostic tool created
  • Test layer 6 created
  • All tests can run (response quality separate)

Phase 1 Status: COMPLETE AND FUNCTIONAL


Resources Used


Last Updated: 2025-11-27 Next Phase: Tool Integration (Phase 2) Recommendation: Proceed to Phase 2 or improve prompts for better response quality