reorganize: consolidate all documentation into readmes/
- Moved 20 root-level markdown files to readmes/ - Includes COMMANDS.md, CONFIG_README.md, all UNO docs, all completion reports - Added new: MEMORY_EDITOR_FEATURE.md, MEMORY_EDITOR_ESCAPING_FIX.md, CONFIG_SOURCES_ANALYSIS.md, MCP_TOOL_CALLING_ANALYSIS.md, and others - Root directory is now clean of documentation clutter
This commit is contained in:
532
readmes/MCP_TOOL_CALLING_ANALYSIS.md
Normal file
532
readmes/MCP_TOOL_CALLING_ANALYSIS.md
Normal file
@@ -0,0 +1,532 @@
|
||||
# MCP Tool Calling Analysis: Jaison-core vs Miku Bot
|
||||
|
||||
## Executive Summary
|
||||
|
||||
After analyzing both your Miku bot's autonomous system and jaison-core's MCP tool calling approach, here's my evaluation:
|
||||
|
||||
**Verdict: Your current system is MORE SUITABLE for Miku's autonomous personality than MCP tool calling.**
|
||||
|
||||
However, MCP could be **complementary** for extending Miku's capabilities in specific scenarios.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Comparison
|
||||
|
||||
### Your Current System (Miku Bot)
|
||||
|
||||
**Philosophy**: Rule-based autonomous decision engine with personality-driven behavior
|
||||
|
||||
**Decision Making**:
|
||||
```
|
||||
Context Signals → Heuristic Rules → Action Selection → LLM for Content
|
||||
```
|
||||
|
||||
**Key Components**:
|
||||
1. **AutonomousEngine** (`autonomous_engine.py`):
|
||||
- Tracks lightweight context signals (message frequency, user presence, mood)
|
||||
- Makes decisions using **deterministic heuristics** + **mood-based probabilities**
|
||||
- No LLM needed for WHEN to act
|
||||
- Actions: `join_conversation`, `engage_user`, `share_tweet`, `general`, `change_profile_picture`
|
||||
|
||||
2. **Personality-Driven**:
|
||||
- Mood profiles define energy, sociability, impulsiveness (0-1 scales)
|
||||
- 14 different moods: bubbly, sleepy, curious, shy, flirty, angry, etc.
|
||||
- Each mood adjusts decision thresholds dynamically
|
||||
|
||||
3. **Context Awareness**:
|
||||
- Message momentum tracking (5min/1hr windows)
|
||||
- FOMO detection (feeling left out)
|
||||
- Activity-based triggers (users playing games, status changes)
|
||||
- Time-based patterns (hour of day, weekend)
|
||||
|
||||
**Strengths**:
|
||||
- ✅ Fast decisions (no LLM latency for decision-making)
|
||||
- ✅ Consistent personality (mood-driven behavior)
|
||||
- ✅ Predictable resource usage
|
||||
- ✅ True autonomy (doesn't need constant prompting)
|
||||
- ✅ Works perfectly for social interaction scenarios
|
||||
|
||||
**Limitations**:
|
||||
- ❌ Cannot dynamically discover new actions
|
||||
- ❌ Limited to predefined action types
|
||||
- ❌ Cannot interact with external services autonomously
|
||||
|
||||
---
|
||||
|
||||
### Jaison-core MCP System
|
||||
|
||||
**Philosophy**: LLM-driven tool discovery and execution with Model Context Protocol
|
||||
|
||||
**Decision Making**:
|
||||
```
|
||||
User Input → LLM analyzes context → LLM suggests tools → Execute tools → LLM responds with enriched context
|
||||
```
|
||||
|
||||
**Key Components**:
|
||||
1. **MCPManager** (`mcp/manager.py`):
|
||||
- Manages MCP servers (external tool providers)
|
||||
- Servers expose tools, resources, and URI templates
|
||||
- LLM receives tool descriptions and decides which to call
|
||||
|
||||
2. **Tool Calling Flow**:
|
||||
```python
|
||||
# 1. LLM is given system prompt with all available tools
|
||||
tooling_prompt = self.mcp_manager.get_tooling_prompt()
|
||||
|
||||
# 2. LLM decides which tools to call (separate MCP-role LLM)
|
||||
mcp_response = await llm_call(tooling_prompt, user_context)
|
||||
|
||||
# 3. Parse tool calls from LLM response
|
||||
tool_calls = parse_tool_calls(mcp_response) # e.g., "<internet> name='Limit'"
|
||||
|
||||
# 4. Execute tools via MCP servers
|
||||
results = await mcp_manager.use(tool_calls)
|
||||
|
||||
# 5. Inject results into conversation context
|
||||
prompter.add_mcp_results(results)
|
||||
|
||||
# 6. Main LLM generates final response with enriched context
|
||||
response = await main_llm_call(system_prompt, conversation + tool_results)
|
||||
```
|
||||
|
||||
3. **Tool Format**:
|
||||
- MCP servers expose tools with JSON schemas
|
||||
- Example tools: web search, memory retrieval, calendar access, file operations
|
||||
- LLM receives descriptions like: `"<internet> Search the internet for information"`
|
||||
|
||||
**Strengths**:
|
||||
- ✅ Dynamic tool discovery (add new capabilities without code changes)
|
||||
- ✅ Flexible external integrations
|
||||
- ✅ Rich ecosystem of MCP servers
|
||||
- ✅ Good for task-oriented interactions (research, data retrieval)
|
||||
|
||||
**Limitations**:
|
||||
- ❌ Requires LLM call for EVERY decision (slower, more expensive)
|
||||
- ❌ Tool selection depends on LLM reasoning quality
|
||||
- ❌ Not designed for autonomous social interaction
|
||||
- ❌ Personality consistency depends on prompt engineering
|
||||
- ❌ Cannot make mood-driven decisions without complex prompting
|
||||
|
||||
---
|
||||
|
||||
## Detailed Comparison
|
||||
|
||||
### 1. Decision-Making Speed
|
||||
|
||||
**Miku Bot**:
|
||||
```python
|
||||
# Instant decision (no LLM)
|
||||
action_type = autonomous_engine.should_take_action(guild_id)
|
||||
# → Returns "join_conversation" in <1ms
|
||||
|
||||
# LLM only called AFTER decision made
|
||||
if action_type == "join_conversation":
|
||||
response = await llm_call(...) # Generate WHAT to say
|
||||
```
|
||||
|
||||
**Jaison-core MCP**:
|
||||
```python
|
||||
# Must call LLM to decide which tools to use
|
||||
tooling_response = await mcp_llm_call(context) # ~500ms-2s
|
||||
tool_results = await execute_tools(tooling_response) # Variable
|
||||
final_response = await main_llm_call(context + results) # ~500ms-2s
|
||||
# Total: 1-5+ seconds per decision
|
||||
```
|
||||
|
||||
**Winner**: Miku Bot (for real-time social interaction)
|
||||
|
||||
---
|
||||
|
||||
### 2. Personality Consistency
|
||||
|
||||
**Miku Bot**:
|
||||
```python
|
||||
# Mood directly controls decision thresholds
|
||||
mood = "sleepy"
|
||||
profile = {"energy": 0.2, "sociability": 0.3, "impulsiveness": 0.1}
|
||||
|
||||
# Low energy = longer silence before action
|
||||
min_silence = 1800 * (2.0 - profile["energy"]) # 3,240s = 54 minutes
|
||||
|
||||
# Low sociability = higher bar for joining conversations
|
||||
threshold = 0.6 * (2.0 - profile["sociability"]) # 1.02 (very high)
|
||||
```
|
||||
|
||||
**Jaison-core MCP**:
|
||||
```python
|
||||
# Personality must be consistently prompted
|
||||
system_prompt = f"""
|
||||
You are {character_name} in {mood} mood.
|
||||
{character_prompt}
|
||||
{scene_prompt}
|
||||
Consider these tools: {tooling_prompt}
|
||||
"""
|
||||
# Personality consistency depends on LLM following instructions
|
||||
```
|
||||
|
||||
**Winner**: Miku Bot (explicit mood-driven behavior guarantees)
|
||||
|
||||
---
|
||||
|
||||
### 3. Autonomous Behavior
|
||||
|
||||
**Miku Bot**:
|
||||
```python
|
||||
# True autonomy - tracks context passively
|
||||
autonomous_engine.track_message(guild_id, author_is_bot=False)
|
||||
|
||||
# Periodically checks if action needed (no LLM)
|
||||
@scheduler.scheduled_job('interval', minutes=5)
|
||||
async def autonomous_tick():
|
||||
for guild_id in servers:
|
||||
action = autonomous_engine.should_take_action(guild_id)
|
||||
if action:
|
||||
await execute_action(action, guild_id)
|
||||
```
|
||||
|
||||
**Jaison-core MCP**:
|
||||
```python
|
||||
# Reactive - waits for user input
|
||||
async def response_pipeline(user_message):
|
||||
# Only acts when user sends message
|
||||
mcp_results = await mcp_manager.use(user_message)
|
||||
response = await generate_response(user_message, mcp_results)
|
||||
return response
|
||||
```
|
||||
|
||||
**Winner**: Miku Bot (designed for autonomous, unprompted actions)
|
||||
|
||||
---
|
||||
|
||||
### 4. Extensibility
|
||||
|
||||
**Miku Bot**:
|
||||
```python
|
||||
# Add new action type requires code change
|
||||
def _should_play_music(self, ctx, profile, debug):
|
||||
# New heuristic function
|
||||
quiet_ok = ctx.messages_last_hour < 3
|
||||
mood_ok = ctx.current_mood in ["excited", "happy"]
|
||||
return quiet_ok and mood_ok and random.random() < 0.1
|
||||
|
||||
# Then add to should_take_action()
|
||||
if self._should_play_music(ctx, profile, debug):
|
||||
return "play_music"
|
||||
```
|
||||
|
||||
**Jaison-core MCP**:
|
||||
```yaml
|
||||
# Add new tool - just configure in YAML
|
||||
mcp:
|
||||
- id: music_player
|
||||
command: python
|
||||
args: ["music_mcp_server.py"]
|
||||
cwd: "models/mcp/music"
|
||||
|
||||
# Tool automatically available to LLM
|
||||
# No code changes needed
|
||||
```
|
||||
|
||||
**Winner**: Jaison-core MCP (easier to extend capabilities)
|
||||
|
||||
---
|
||||
|
||||
### 5. Resource Usage
|
||||
|
||||
**Miku Bot**:
|
||||
- Decision: 0 LLM calls (heuristics only)
|
||||
- Content generation: 1 LLM call
|
||||
- Total per action: **1 LLM call**
|
||||
|
||||
**Jaison-core MCP**:
|
||||
- Tool selection: 1 LLM call (MCP-role LLM)
|
||||
- Tool execution: 0-N external calls
|
||||
- Final response: 1 LLM call (main LLM)
|
||||
- Total per action: **2+ LLM calls** minimum
|
||||
|
||||
**Winner**: Miku Bot (more cost-effective for high-frequency autonomous actions)
|
||||
|
||||
---
|
||||
|
||||
## Key Philosophical Differences
|
||||
|
||||
### Miku Bot: Personality-First Design
|
||||
```
|
||||
"Miku feels lonely" → Break silence autonomously → Ask LLM to generate message
|
||||
"Miku feels FOMO" → Join conversation → Ask LLM to respond to recent messages
|
||||
"Miku is sleepy" → Wait 54 minutes before any action
|
||||
```
|
||||
|
||||
### Jaison-core: Tool-First Design
|
||||
```
|
||||
User: "What's the weather?" → LLM sees <weather_tool> → Calls tool → Responds with data
|
||||
User: "Remember this" → LLM sees <memory_tool> → Stores information → Confirms
|
||||
User: "Play music" → LLM sees <music_tool> → Starts playback → Responds
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## When to Use Each System
|
||||
|
||||
### Use Your Current System (Miku Bot) For:
|
||||
✅ **Social autonomous actions**
|
||||
- Joining conversations naturally
|
||||
- Reacting to user presence/status changes
|
||||
- Mood-driven spontaneous messages
|
||||
- FOMO-based engagement
|
||||
|
||||
✅ **Performance-critical decisions**
|
||||
- Real-time reactions (emoji responses)
|
||||
- High-frequency checks (every message)
|
||||
- Low-latency autonomous ticks
|
||||
|
||||
✅ **Personality consistency**
|
||||
- Mood-based behavior patterns
|
||||
- Predictable energy/sociability curves
|
||||
- Character trait enforcement
|
||||
|
||||
### Use MCP Tool Calling For:
|
||||
✅ **External data retrieval**
|
||||
- Web searches for questions
|
||||
- Weather/news lookups
|
||||
- Database queries
|
||||
- API integrations
|
||||
|
||||
✅ **Complex task execution**
|
||||
- File operations
|
||||
- Calendar management
|
||||
- Email/notification sending
|
||||
- Multi-step workflows
|
||||
|
||||
✅ **User-requested actions**
|
||||
- "Look up X for me"
|
||||
- "Remember this fact"
|
||||
- "Check my schedule"
|
||||
- "Search Twitter for Y"
|
||||
|
||||
---
|
||||
|
||||
## Hybrid Approach Recommendation
|
||||
|
||||
**Best Solution**: Keep your autonomous system, add MCP for specific capabilities.
|
||||
|
||||
### Architecture:
|
||||
```python
|
||||
# 1. Autonomous engine decides WHEN to act (current system)
|
||||
action_type = autonomous_engine.should_take_action(guild_id)
|
||||
|
||||
if action_type == "join_conversation":
|
||||
# 2. Get recent conversation context
|
||||
recent_messages = get_recent_messages(channel)
|
||||
|
||||
# 3. Check if user asked a question that needs tools
|
||||
if requires_external_data(recent_messages):
|
||||
# 4. Use MCP tool calling
|
||||
tool_results = await mcp_manager.analyze_and_use_tools(recent_messages)
|
||||
context = f"{recent_messages}\n\nAdditional info: {tool_results}"
|
||||
else:
|
||||
# 4. Regular personality-driven response
|
||||
context = recent_messages
|
||||
|
||||
# 5. Generate response with enriched context
|
||||
response = await llm_call(miku_personality + mood + context)
|
||||
await channel.send(response)
|
||||
```
|
||||
|
||||
### Integration Plan:
|
||||
|
||||
1. **Add MCPManager to Miku**:
|
||||
```python
|
||||
# bot/utils/mcp_integration.py
|
||||
from jaison_mcp import MCPManager
|
||||
|
||||
class MikuMCPManager:
|
||||
def __init__(self):
|
||||
self.mcp = MCPManager()
|
||||
|
||||
async def should_use_tools(self, message: str) -> bool:
|
||||
"""Decide if message needs external tools"""
|
||||
keywords = ["search", "look up", "weather", "news", "remember"]
|
||||
return any(kw in message.lower() for kw in keywords)
|
||||
|
||||
async def get_tool_results(self, message: str, mood: str):
|
||||
"""Use MCP tools and format results for Miku's personality"""
|
||||
raw_results = await self.mcp.use(message)
|
||||
# Add personality flair to tool results
|
||||
return self._format_with_personality(raw_results, mood)
|
||||
```
|
||||
|
||||
2. **Use MCP Selectively**:
|
||||
```python
|
||||
# Only for user-initiated queries, not autonomous actions
|
||||
async def handle_message(message):
|
||||
if is_miku_addressed(message):
|
||||
# Check if question needs tools
|
||||
if await mcp_manager.should_use_tools(message.content):
|
||||
mood = get_current_mood(message.guild.id)
|
||||
tool_results = await mcp_manager.get_tool_results(
|
||||
message.content,
|
||||
mood
|
||||
)
|
||||
context = f"User question: {message.content}\n"
|
||||
context += f"Info I found: {tool_results}"
|
||||
else:
|
||||
context = message.content
|
||||
|
||||
response = await generate_miku_response(context, mood)
|
||||
await message.reply(response)
|
||||
```
|
||||
|
||||
3. **Useful MCP Tools for Miku**:
|
||||
- **Internet search**: Answer factual questions
|
||||
- **Memory/notes**: Store user preferences/facts
|
||||
- **Image search**: Find relevant images to share
|
||||
- **Calendar**: Track server events
|
||||
- **Twitter API**: Better tweet integration
|
||||
- **YouTube API**: Music/video recommendations
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Your autonomous system is superior for Miku's core personality-driven behavior.**
|
||||
|
||||
The MCP tool calling in jaison-core is designed for a different use case:
|
||||
- **Jaison-core**: AI assistant that responds to user requests with helpful tools
|
||||
- **Miku**: Autonomous AI companion with consistent personality and spontaneous behavior
|
||||
|
||||
### Recommendations:
|
||||
|
||||
1. **✅ Keep your current autonomous engine**
|
||||
- It's perfectly designed for social autonomous behavior
|
||||
- Fast, cost-effective, personality-consistent
|
||||
- Already handles mood-driven decisions beautifully
|
||||
|
||||
2. **✅ Add selective MCP integration**
|
||||
- Only for user questions that need external data
|
||||
- Not for autonomous decision-making
|
||||
- Use it to enhance responses, not replace your system
|
||||
|
||||
3. **❌ Don't replace your system with MCP**
|
||||
- Would lose personality consistency
|
||||
- Much slower for real-time social interaction
|
||||
- Expensive for high-frequency autonomous checks
|
||||
- Not designed for unprompted autonomous actions
|
||||
|
||||
### Next Steps (if interested in MCP integration):
|
||||
|
||||
1. Extract MCP components from jaison-core
|
||||
2. Create a lightweight wrapper for Miku's use cases
|
||||
3. Add configuration for specific MCP servers (search, memory, etc.)
|
||||
4. Integrate at the response generation stage, not decision stage
|
||||
5. Test with non-critical features first
|
||||
|
||||
**Your bot's autonomous system is already excellent for its purpose. MCP would be a nice-to-have addon for specific query types, not a replacement.**
|
||||
|
||||
---
|
||||
|
||||
## Code Example: Hybrid Implementation
|
||||
|
||||
```python
|
||||
# bot/utils/hybrid_autonomous.py
|
||||
|
||||
from utils.autonomous_engine import autonomous_engine
|
||||
from utils.mcp_integration import MikuMCPManager
|
||||
|
||||
class HybridAutonomousSystem:
|
||||
def __init__(self):
|
||||
self.engine = autonomous_engine
|
||||
self.mcp = MikuMCPManager()
|
||||
|
||||
async def autonomous_tick(self, guild_id: int):
|
||||
"""Main autonomous check (your current system)"""
|
||||
# Decision made by heuristics (no LLM)
|
||||
action_type = self.engine.should_take_action(guild_id)
|
||||
|
||||
if not action_type:
|
||||
return
|
||||
|
||||
# Get current mood
|
||||
mood, _ = server_manager.get_server_mood(guild_id)
|
||||
|
||||
# Execute action based on type
|
||||
if action_type == "join_conversation":
|
||||
await self._join_conversation(guild_id, mood)
|
||||
elif action_type == "engage_user":
|
||||
await self._engage_user(guild_id, mood)
|
||||
# ... other action types
|
||||
|
||||
async def _join_conversation(self, guild_id: int, mood: str):
|
||||
"""Join conversation - optionally use MCP for context"""
|
||||
channel = get_autonomous_channel(guild_id)
|
||||
recent_msgs = await get_recent_messages(channel, limit=20)
|
||||
|
||||
# Check if conversation involves factual questions
|
||||
needs_tools = await self._check_if_tools_needed(recent_msgs)
|
||||
|
||||
if needs_tools:
|
||||
# Use MCP to enrich context
|
||||
tool_context = await self.mcp.get_relevant_context(
|
||||
recent_msgs,
|
||||
mood
|
||||
)
|
||||
context = f"Recent conversation:\n{recent_msgs}\n\n"
|
||||
context += f"Additional context: {tool_context}"
|
||||
else:
|
||||
# Standard personality-driven response
|
||||
context = f"Recent conversation:\n{recent_msgs}"
|
||||
|
||||
# Generate response with Miku's personality
|
||||
response = await generate_miku_message(
|
||||
context=context,
|
||||
mood=mood,
|
||||
response_type="join_conversation"
|
||||
)
|
||||
|
||||
await channel.send(response)
|
||||
|
||||
async def _check_if_tools_needed(self, messages: str) -> bool:
|
||||
"""Quick heuristic check (no LLM needed for most cases)"""
|
||||
# Simple keyword matching
|
||||
tool_keywords = [
|
||||
"what is", "who is", "when is", "where is", "how to",
|
||||
"look up", "search for", "find", "weather", "news"
|
||||
]
|
||||
|
||||
msg_lower = messages.lower()
|
||||
return any(keyword in msg_lower for keyword in tool_keywords)
|
||||
|
||||
async def handle_direct_question(self, message: discord.Message):
|
||||
"""Handle direct questions to Miku (always check for tool usage)"""
|
||||
mood = get_current_mood(message.guild.id)
|
||||
|
||||
# For direct questions, more likely to use tools
|
||||
if await self.mcp.should_use_tools(message.content):
|
||||
# Use MCP tool calling
|
||||
tool_results = await self.mcp.get_tool_results(
|
||||
message.content,
|
||||
mood
|
||||
)
|
||||
|
||||
# Format response with personality
|
||||
response = await generate_miku_response(
|
||||
question=message.content,
|
||||
tool_results=tool_results,
|
||||
mood=mood,
|
||||
personality_mode="helpful_but_sassy"
|
||||
)
|
||||
else:
|
||||
# Standard response without tools
|
||||
response = await generate_miku_response(
|
||||
question=message.content,
|
||||
mood=mood,
|
||||
personality_mode="conversational"
|
||||
)
|
||||
|
||||
await message.reply(response)
|
||||
```
|
||||
|
||||
This hybrid approach gives you the best of both worlds:
|
||||
- **Fast, personality-consistent autonomous behavior** (your system)
|
||||
- **Enhanced capability for factual queries** (MCP when needed)
|
||||
- **Cost-effective** (tools only used when genuinely helpful)
|
||||
Reference in New Issue
Block a user