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>
11 KiB
11 KiB
Core-AI Dual-Mode Architecture
Overview
Core-AI provides two AI endpoints with different complexity levels:
- Simple Mode - Direct LiteLLM (existing)
- ADK Mode - Full Google ADK with tool calling (new)
Core-API becomes a pure tools platform providing REST endpoints.
Architecture Diagram
┌─────────────────────────────────────────────────────────────┐
│ Core-AI │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Simple Endpoint │ │ ADK Endpoint │ │
│ │ /v1/chat/simple │ │ /v1/chat/adk │ │
│ │ │ │ │ │
│ │ SimpleLiteLLMAgent │ │ ADKAgent │ │
│ │ ↓ │ │ ↓ │ │
│ │ LiteLLM │ │ ADK Runtime │ │
│ │ ↓ │ │ ↓ │ │
│ │ [No Tools] │ │ Tool Registry │ │
│ └─────────────────────┘ │ ↓ │ │
│ │ REST Calls ───────┼─────┼─┐
│ └─────────────────────┘ │ │
└───────────────────────────────────────────────────────────┘ │
│
┌────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Core-API │
│ (Tools Platform) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ System │ │ Services │ │ Docker │ │
│ │ Tools │ │ Tools │ │ Tools │ │
│ │ /system/* │ │ /services/* │ │ /docker/* │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ [No AI Agent - Pure REST API] │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ External Systems │
│ (Portainer, Uptime Kuma, Ollama, etc.) │
└─────────────────────────────────────────────────────────────┘
API Routes
Core-AI Routes
| Endpoint | Mode | Agent | Tools | Use Case |
|---|---|---|---|---|
POST /v1/chat/simple |
Simple | SimpleLiteLLMAgent | None | Fast Q&A, text generation |
POST /v1/chat/adk |
ADK | ADKAgent | Full toolset | Complex tasks, orchestration |
GET /health |
N/A | N/A | N/A | Health check |
Core-API Routes (No Changes - Tools Only)
| Endpoint | Purpose |
|---|---|
GET /v1/system/status |
System status |
GET /v1/services/* |
Service management |
GET /v1/docker/* |
Docker operations |
POST /v1/tools/* |
Tool execution |
Request/Response Formats
Simple Mode
POST /v1/chat/simple
{
"messages": [
{"role": "user", "content": "What is 2+2?"}
],
"stream": false
}
Response:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "simple",
"choices": [{
"message": {"role": "assistant", "content": "4"},
"finish_reason": "stop"
}]
}
ADK Mode
POST /v1/chat/adk
{
"messages": [
{"role": "user", "content": "Check the system status and tell me if everything is ok"}
],
"stream": true
}
Response (streaming):
data: {"type": "tool_call", "tool": "get_system_status", ...}
data: {"type": "tool_result", "result": {...}}
data: {"type": "content", "content": "Everything looks good..."}
data: {"type": "content", "finish_reason": "stop"}
File Structure
services/core-ai/
├── main.py # HTTP server with both routes
├── src/
│ ├── __init__.py
│ ├── config.py # Configuration
│ ├── prompts.py # System prompts (simple + ADK)
│ ├── agents/
│ │ ├── __init__.py
│ │ ├── simple.py # SimpleLiteLLMAgent (existing)
│ │ └── adk_agent.py # ADKAgent (new)
│ └── tools/
│ ├── __init__.py
│ ├── registry.py # ADK tool registry
│ ├── system_tools.py # System tools (REST calls to core-api)
│ ├── service_tools.py # Service tools (REST calls to core-api)
│ └── knowledge_tools.py # Knowledge tools (web search, etc.)
├── diagnostics/
│ ├── check_ollama.py
│ ├── test_litellm_direct.py
│ └── test_adk_direct.py # New: Test ADK without HTTP
├── tests/
│ ├── test_01_environment.py # ✓ Existing
│ ├── test_02_litellm_raw.py # ✓ Existing
│ ├── test_03_message_format.py # ✓ Existing
│ ├── test_04_agent.py # ✓ Existing (simple agent)
│ ├── test_05_api.py # ✓ Existing (simple API)
│ ├── test_06_adk_setup.py # New: ADK initialization
│ ├── test_07_adk_tools.py # New: ADK tool registration
│ ├── test_08_adk_agent.py # New: ADK agent logic
│ ├── test_09_adk_tool_calling.py # New: ADK tool execution
│ ├── test_10_adk_api.py # New: ADK API endpoint
│ ├── run_all_tests.sh
│ └── README.md
└── README.md
Implementation Phases
Phase 1: ADK Agent Setup ✓
- Create
src/agents/adk_agent.py - Initialize ADK runtime
- Test basic ADK completion
- Create diagnostic:
diagnostics/test_adk_direct.py - Create test:
tests/test_06_adk_setup.py
Phase 2: Tool Integration
- Create tool registry with ADK FunctionTool format
- Implement REST-based tools (call core-api endpoints)
- Test tool registration
- Create test:
tests/test_07_adk_tools.py
Phase 3: ADK Agent with Tools
- Integrate tools into ADK agent
- Test tool calling flow
- Verify REST calls to core-api
- Create tests:
test_08_adk_agent.py,test_09_adk_tool_calling.py
Phase 4: API Routes
- Add
/v1/chat/adkendpoint - Rename existing to
/v1/chat/simple(keep/v1/chat/completionsas alias) - Test both endpoints
- Create test:
tests/test_10_adk_api.py
Phase 5: Documentation & Cleanup
- Update README.md
- Update test documentation
- Add architecture diagrams
- Document migration from core-api
Tool Design: REST-First
All tools in core-ai make REST calls to core-api:
# Example: System Status Tool
@log_tool_call
async def get_system_status() -> str:
"""Get current system status from core-api."""
async with httpx.AsyncClient() as client:
response = await client.get(f"{CORE_API_BASE_URL}/system/status")
data = response.json()
return json.dumps(data, indent=2)
Benefits:
- Clean separation: core-ai = AI, core-api = tools
- Tools can be used by both AI and direct API calls
- Easy to test tools independently
- No code duplication
Testing Strategy
Layer 1-5: Simple Mode (Existing)
Already tested and passing ✓
Layer 6: ADK Setup
# Test ADK runtime initialization
# Test ADK basic completion (no tools)
# Test ADK message handling
Layer 7: ADK Tools
# Test tool registration
# Test tool discovery
# Test REST connectivity to core-api
Layer 8: ADK Agent
# Test agent with tools
# Test prompt handling
# Test error handling
Layer 9: ADK Tool Calling
# Test tool invocation
# Test tool results
# Test multi-tool workflows
Layer 10: ADK API
# Test /v1/chat/adk endpoint
# Test streaming with tools
# Test non-streaming with tools
Configuration
Environment Variables
# Existing
OLLAMA_BASE_URL=http://ollama:11434
AGENT_MODEL=gemma2:9b-instruct-q5_K_M
SYSTEM_PROMPT_VARIANT=minimal_agent
HOST=0.0.0.0
PORT=8086
# New
CORE_API_BASE_URL=http://core-api:8083/v1 # For tool REST calls
ADK_ENABLED=true # Enable ADK endpoint
SIMPLE_ENABLED=true # Enable simple endpoint
ADK_SYSTEM_PROMPT_VARIANT=adk_agent # Different prompt for ADK
Prompts
PROMPTS = {
"minimal_agent": "You are a helpful assistant.", # Simple mode
"adk_agent": """You are a system management assistant with access to tools.
Use tools when needed to answer questions about system status, services, and docker."""
}
Migration Path (Core-API)
Later cleanup - not in this phase:
- Remove AI agent code from core-api
- Remove ADK dependencies from core-api
- Keep only REST endpoints
- Update core-api to be pure API
- Redirect any AI requests to core-ai
Backward Compatibility
/v1/chat/completions→ alias for/v1/chat/simple- Existing clients keep working
- New clients can choose mode
Performance Considerations
| Aspect | Simple Mode | ADK Mode |
|---|---|---|
| Latency | ~0.5-1s | ~1-3s (with tools) |
| Overhead | Minimal | ADK runtime |
| Memory | Low | Medium (tool registry) |
| Use Case | Fast Q&A | Complex tasks |
Next Steps
- ✅ Design architecture (this document)
- ⏳ Implement Phase 1: ADK Agent Setup
- ⏳ Implement Phase 2: Tool Integration
- ⏳ Implement Phase 3: ADK Agent with Tools
- ⏳ Implement Phase 4: API Routes
- ⏳ Implement Phase 5: Documentation
Let's start with Phase 1!