chore: initialize sandbox and overwrite remote content
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_en (ubuntu-latest, 3.10) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_zh (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.12) (push) Has been cancelled
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_en (ubuntu-latest, 3.10) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_zh (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.12) (push) Has been cancelled
This commit is contained in:
29
examples/workflows/multiagent_concurrent/README.md
Normal file
29
examples/workflows/multiagent_concurrent/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Multiagent Concurrent
|
||||
|
||||
This example demonstrates how to run multiple agents concurrently in AgentScope, where each agent operates
|
||||
independently and can perform tasks simultaneously.
|
||||
|
||||
Specifically, we showcase two ways to achieve concurrency:
|
||||
|
||||
- Using Python's `asyncio.gather` to run multiple agents asynchronously.
|
||||
- Using `fanout_pipeline` to execute multiple agents in parallel and gather their results.
|
||||
|
||||
The fanout pipeline will distribute the input to multiple agents and collect their outputs, which is appropriate for
|
||||
scenarios like voting or parallel question answering.
|
||||
|
||||
## QuickStart
|
||||
|
||||
Install the agentscope package if you haven't already:
|
||||
|
||||
```bash
|
||||
pip install agentscope
|
||||
```
|
||||
|
||||
Then run the example script:
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
## Further Reading
|
||||
- [Pipelines](https://doc.agentscope.io/tutorial/task_pipeline.html)
|
||||
93
examples/workflows/multiagent_concurrent/main.py
Normal file
93
examples/workflows/multiagent_concurrent/main.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Parallel Multi-Perspective Discussion System."""
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
|
||||
from agentscope.agent import AgentBase
|
||||
from agentscope.message import Msg
|
||||
from agentscope.pipeline import fanout_pipeline
|
||||
|
||||
|
||||
class ExampleAgent(AgentBase):
|
||||
"""The example agent used to label the time."""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
"""The constructor of the example agent
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The agent name.
|
||||
"""
|
||||
super().__init__()
|
||||
self.name = name
|
||||
|
||||
async def reply(self, *args: Any, **kwargs: Any) -> Msg:
|
||||
"""The reply function of the example agent."""
|
||||
# we record the start time
|
||||
start_time = datetime.now()
|
||||
await self.print(
|
||||
Msg(
|
||||
self.name,
|
||||
f"begins at {start_time.strftime('%H:%M:%S.%f')}",
|
||||
"assistant",
|
||||
),
|
||||
)
|
||||
|
||||
# Sleep some time
|
||||
await asyncio.sleep(np.random.choice([2, 3, 4]))
|
||||
|
||||
end_time = datetime.now()
|
||||
msg = Msg(
|
||||
self.name,
|
||||
f"finishes at {end_time.strftime('%H:%M:%S.%f')}",
|
||||
"user",
|
||||
# Add some metadata for demonstration
|
||||
metadata={
|
||||
"time": (end_time - start_time).total_seconds(),
|
||||
},
|
||||
)
|
||||
await self.print(msg)
|
||||
return msg
|
||||
|
||||
async def handle_interrupt(
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Msg:
|
||||
"""We leave this function unimplemented in this example, because we
|
||||
won't use the interrupt functionality"""
|
||||
|
||||
async def observe(self, *args: Any, **kwargs: Any) -> None:
|
||||
"""Similar with the handle_interrupt function, leaving this empty"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""The main entry of the concurrent example."""
|
||||
alice = ExampleAgent("Alice")
|
||||
bob = ExampleAgent("Bob")
|
||||
chalice = ExampleAgent("Chalice")
|
||||
|
||||
print("Use 'asyncio.gather' to run the agents concurrently:")
|
||||
futures = [alice(), bob(), chalice()]
|
||||
|
||||
await asyncio.gather(*futures)
|
||||
|
||||
print("\n\nUse fanout pipeline to run the agents concurrently:")
|
||||
collected_res = await fanout_pipeline(
|
||||
agents=[alice, bob, chalice],
|
||||
enable_gather=True,
|
||||
)
|
||||
# Print the collected results
|
||||
print("\n\nThe collected time used by each agent:")
|
||||
for res in collected_res:
|
||||
print(f"{res.name}: {res.metadata['time']} seconds")
|
||||
|
||||
print("\nThe average time used:")
|
||||
avg_time = np.mean([res.metadata["time"] for res in collected_res])
|
||||
print(f"{avg_time} seconds")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
24
examples/workflows/multiagent_conversation/README.md
Normal file
24
examples/workflows/multiagent_conversation/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# MultiAgent Conversation
|
||||
|
||||
This example demonstrates how to build a multi-agent conversation workflow using ``MsgHub`` in AgentScope,
|
||||
where multiple agents broadcast messages to each other in a shared conversation space.
|
||||
|
||||
## Setup
|
||||
|
||||
The example is built upon the DashScope LLM API in [main.py](https://github.com/agentscope-ai/agentscope/blob/main/examples/workflows/multiagent_conversation/main.py). You can switch to other LLMs by modifying the ``model`` and ``formatter`` parameters in the code.
|
||||
|
||||
To run the example, first install the latest version of AgentScope, then run:
|
||||
|
||||
```bash
|
||||
python examples/workflows/multiagent_conversation/main.py
|
||||
```
|
||||
|
||||
## Main Workflow
|
||||
|
||||
- Create multiple participant agents with different attributes (e.g., Alice, Bob, Charlie).
|
||||
- Agents introduce themselves and interact in the message hub.
|
||||
- Supports dynamic addition and removal of agents, as well as broadcasting messages.
|
||||
|
||||
> Note: The example is built with DashScope chat model. If you want to change the model in this example, don't forget
|
||||
> to change the formatter at the same time! The corresponding relationship between built-in models and formatters are
|
||||
> list in [our tutorial](https://doc.agentscope.io/tutorial/task_prompt.html#id1)
|
||||
80
examples/workflows/multiagent_conversation/main.py
Normal file
80
examples/workflows/multiagent_conversation/main.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The example of how to construct multi-agent conversation with MsgHub and
|
||||
pipeline in AgentScope."""
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agentscope.agent import ReActAgent
|
||||
from agentscope.formatter import DashScopeMultiAgentFormatter
|
||||
from agentscope.message import Msg
|
||||
from agentscope.model import DashScopeChatModel
|
||||
from agentscope.pipeline import MsgHub, sequential_pipeline
|
||||
|
||||
|
||||
def create_participant_agent(
|
||||
name: str,
|
||||
age: int,
|
||||
career: str,
|
||||
character: str,
|
||||
) -> ReActAgent:
|
||||
"""Create a participant agent with a specific name, age, and character."""
|
||||
return ReActAgent(
|
||||
name=name,
|
||||
sys_prompt=(
|
||||
f"You're a {age}-year-old {career} named {name} and you're "
|
||||
f"a {character} person."
|
||||
),
|
||||
model=DashScopeChatModel(
|
||||
model_name="qwen-max",
|
||||
api_key=os.environ["DASHSCOPE_API_KEY"],
|
||||
stream=True,
|
||||
),
|
||||
# Use multiagent formatter because the multiple entities will
|
||||
# occur in the prompt of the LLM API call
|
||||
formatter=DashScopeMultiAgentFormatter(),
|
||||
)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run a multi-agent conversation workflow."""
|
||||
|
||||
# Create multiple participant agents with different characteristics
|
||||
alice = create_participant_agent("Alice", 30, "teacher", "friendly")
|
||||
bob = create_participant_agent("Bob", 14, "student", "rebellious")
|
||||
charlie = create_participant_agent("Charlie", 28, "doctor", "thoughtful")
|
||||
|
||||
# Create a conversation where participants introduce themselves within
|
||||
# a message hub
|
||||
async with MsgHub(
|
||||
participants=[alice, bob, charlie],
|
||||
# The greeting message will be sent to all participants at the start
|
||||
announcement=Msg(
|
||||
"system",
|
||||
"Now you meet each other with a brief self-introduction.",
|
||||
"system",
|
||||
),
|
||||
) as hub:
|
||||
# Quick construct a pipeline to run the conversation
|
||||
await sequential_pipeline([alice, bob, charlie])
|
||||
# Or by the following way:
|
||||
# await alice()
|
||||
# await bob()
|
||||
# await charlie()
|
||||
|
||||
# Delete a participant agent from the hub and fake a broadcast message
|
||||
print("##### We fake Bob's departure #####")
|
||||
hub.delete(bob)
|
||||
await hub.broadcast(
|
||||
Msg(
|
||||
"bob",
|
||||
"I have to start my homework now, see you later!",
|
||||
"assistant",
|
||||
),
|
||||
)
|
||||
await alice()
|
||||
await charlie()
|
||||
|
||||
# ...
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
24
examples/workflows/multiagent_debate/README.md
Normal file
24
examples/workflows/multiagent_debate/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# MultiAgent Debate
|
||||
|
||||
Debate workflow simulates a multi-turn discussion between different agents, mostly several solvers and an aggregator.
|
||||
Typically, the solvers generate and exchange their answers, while the aggregator collects and summarizes the answers.
|
||||
|
||||
We implement the examples in [EMNLP 2024](https://aclanthology.org/2024.emnlp-main.992/), where two debater agents
|
||||
will discuss a topic in a fixed order, and express their arguments based on the previous debate history.
|
||||
At each round a moderator agent will decide whether the correct answer can be obtained in the current iteration.
|
||||
|
||||
## Setup
|
||||
|
||||
The example is built upon DashScope LLM API in [main.py](https://github.com/agentscope-ai/agentscope/blob/main/examples/workflows/multiagent_debate/main.py).
|
||||
You can also change to the other LLMs by modifying the ``model`` and ``formatter`` parameters in the code.
|
||||
|
||||
To run the example, first install the latest version of AgentScope, then run:
|
||||
|
||||
```bash
|
||||
python examples/workflows/multiagent_debate/main.py
|
||||
```
|
||||
|
||||
|
||||
> Note: The example is built with DashScope chat model. If you want to change the model in this example, don't forget
|
||||
> to change the formatter at the same time! The corresponding relationship between built-in models and formatters are
|
||||
> list in [our tutorial](https://doc.agentscope.io/tutorial/task_prompt.html#id1)
|
||||
130
examples/workflows/multiagent_debate/main.py
Normal file
130
examples/workflows/multiagent_debate/main.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The multi-agent debate workflow example in AgentScope."""
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
Field,
|
||||
)
|
||||
|
||||
from agentscope.agent import ReActAgent
|
||||
from agentscope.formatter import (
|
||||
DashScopeChatFormatter,
|
||||
DashScopeMultiAgentFormatter,
|
||||
)
|
||||
from agentscope.message import Msg
|
||||
from agentscope.model import DashScopeChatModel
|
||||
from agentscope.pipeline import MsgHub
|
||||
|
||||
topic = (
|
||||
"The two circles are externally tangent and there is no relative sliding. "
|
||||
"The radius of circle A is 1/3 the radius of circle B. Circle A rolls "
|
||||
"around circle B one trip back to its starting point. How many times will "
|
||||
"circle A revolve in total?"
|
||||
)
|
||||
|
||||
|
||||
# Create two debater agents, Alice and Bob, who will discuss the topic.
|
||||
def create_solver_agent(name: str) -> ReActAgent:
|
||||
"""Get a solver agent."""
|
||||
return ReActAgent(
|
||||
name=name,
|
||||
sys_prompt=f"You're a debater named {name}. Hello and welcome to the "
|
||||
"debate competition. It's not necessary to fully agree "
|
||||
"with each other's perspectives, as our objective is to "
|
||||
"find the correct answer. The debate topic is stated as "
|
||||
f"follows: {topic}. Use Chinese to answer the question",
|
||||
model=DashScopeChatModel(
|
||||
model_name="qwen-max",
|
||||
api_key=os.environ["DASHSCOPE_API_KEY"],
|
||||
stream=True,
|
||||
),
|
||||
formatter=DashScopeChatFormatter(),
|
||||
)
|
||||
|
||||
|
||||
alice, bob = [create_solver_agent(name) for name in ["Alice", "Bob"]]
|
||||
|
||||
# Create a moderator agent
|
||||
moderator = ReActAgent(
|
||||
name="Aggregator",
|
||||
sys_prompt=(
|
||||
"You're a moderator. There will be two debaters involved in a debate "
|
||||
"competition. They will present their answer and discuss their "
|
||||
"perspectives on the topic:\n"
|
||||
"```\n"
|
||||
"{topic}\n"
|
||||
"```\n"
|
||||
"At the end of each round, you will evaluate both sides' answers "
|
||||
"and decide which one is correct."
|
||||
),
|
||||
model=DashScopeChatModel(
|
||||
model_name="qwen-max",
|
||||
api_key=os.environ["DASHSCOPE_API_KEY"],
|
||||
stream=True,
|
||||
),
|
||||
formatter=DashScopeMultiAgentFormatter(),
|
||||
)
|
||||
|
||||
|
||||
# A structured output model for the moderator
|
||||
class JudgeModel(BaseModel):
|
||||
"""The structured output model for the moderator."""
|
||||
|
||||
finished: bool = Field(
|
||||
description="Whether the debate is finished.",
|
||||
)
|
||||
correct_answer: str | None = Field(
|
||||
description="The correct answer to the debate topic, only if the "
|
||||
"debate is finished. Otherwise, leave it as None.",
|
||||
default=None,
|
||||
)
|
||||
|
||||
|
||||
async def run_multiagent_debate() -> None:
|
||||
"""Run the multi-agent debate workflow."""
|
||||
while True:
|
||||
# The reply messages in MsgHub from the participants will be
|
||||
# broadcasted to all participants.
|
||||
async with MsgHub(participants=[alice, bob, moderator]):
|
||||
await alice(
|
||||
Msg(
|
||||
"user",
|
||||
"You are affirmative side, Please express your "
|
||||
"viewpoints.",
|
||||
"user",
|
||||
),
|
||||
)
|
||||
await bob(
|
||||
Msg(
|
||||
"user",
|
||||
"You are negative side. You disagree with the "
|
||||
"affirmative side. Provide your reason and answer.",
|
||||
"user",
|
||||
),
|
||||
)
|
||||
|
||||
# Alice and Bob doesn't need to know the moderator's message,
|
||||
# so moderator is called outside the MsgHub.
|
||||
msg_judge = await moderator(
|
||||
Msg(
|
||||
"user",
|
||||
"Now you have heard the answers from the others, have "
|
||||
"the debate finished, and can you get the correct answer?",
|
||||
"user",
|
||||
),
|
||||
structured_model=JudgeModel,
|
||||
)
|
||||
|
||||
print("【STRUCTURED_OUTPUT】: ", msg_judge.metadata)
|
||||
|
||||
if msg_judge.metadata.get("finished"):
|
||||
print(
|
||||
"The debate is finished, and the correct answer is: ",
|
||||
msg_judge.metadata.get("correct_answer"),
|
||||
)
|
||||
break
|
||||
|
||||
|
||||
asyncio.run(run_multiagent_debate())
|
||||
160
examples/workflows/multiagent_realtime/README.md
Normal file
160
examples/workflows/multiagent_realtime/README.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Multi-Agent Realtime Voice Interaction Example
|
||||
|
||||
This example demonstrates how to use AgentScope's `ChatRoom` class to create a multi-agent real-time voice interaction system where two AI agents can have autonomous conversations without user input.
|
||||
|
||||
## Features
|
||||
|
||||
- 🗣️ **Real-time Voice Interaction**: Two agents communicate through voice in real-time
|
||||
- 🤖 **Autonomous Conversation**: Agents converse with each other without user intervention
|
||||
- ⚙️ **Customizable Configuration**: Configure agent names and instructions through the web interface
|
||||
- 🎨 **Modern UI**: Clean, shadcn-inspired interface for easy interaction
|
||||
- 📊 **Live Transcript**: See the conversation transcripts in real-time
|
||||
|
||||
## Architecture
|
||||
|
||||
The example uses:
|
||||
- **Backend**: FastAPI server with WebSocket support
|
||||
- **Frontend**: HTML5 with Web Audio API for audio playback
|
||||
- **AgentScope Components**:
|
||||
- `ChatRoom`: Manages multiple `RealtimeAgent` instances
|
||||
- `RealtimeAgent`: Handles real-time voice interaction with AI models
|
||||
- `DashScopeRealtimeModel`: DashScope's Qwen3-Omni realtime model
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Python Dependencies**:
|
||||
```bash
|
||||
pip install agentscope[dashscope]
|
||||
pip install fastapi uvicorn
|
||||
```
|
||||
|
||||
2. **DashScope API Key**:
|
||||
- Set your DashScope API key as an environment variable:
|
||||
```bash
|
||||
export DASHSCOPE_API_KEY="your-api-key-here"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Start the Server**:
|
||||
```bash
|
||||
python run_server.py
|
||||
```
|
||||
|
||||
2. **Open the Web Interface**:
|
||||
- Navigate to `http://localhost:8000` in your web browser
|
||||
|
||||
3. **Configure Agents**:
|
||||
- Set names and instructions for both Agent 1 and Agent 2
|
||||
- Example configurations:
|
||||
- **Agent 1 (Alice)**: "You are Alice, a cheerful and optimistic person who loves to share stories and ask questions. Keep your responses brief and conversational."
|
||||
- **Agent 2 (Bob)**: "You are Bob, a thoughtful and analytical person who enjoys deep conversations. Keep your responses brief and conversational."
|
||||
|
||||
4. **Start the Conversation**:
|
||||
- Click the "▶️ Start Conversation" button
|
||||
- The agents will begin conversing autonomously
|
||||
- You'll see transcripts and system messages in the message panel
|
||||
- Audio playback will stream in real-time
|
||||
|
||||
5. **Stop the Conversation**:
|
||||
- Click the "⏹️ Stop Conversation" button when you want to end the session
|
||||
|
||||
## How It Works
|
||||
|
||||
### Backend Flow
|
||||
|
||||
1. **WebSocket Connection**: Client connects via WebSocket to `/ws/{user_id}/{session_id}`
|
||||
2. **Session Creation**:
|
||||
- Client sends `client_session_create` event with agent configurations
|
||||
- Server creates two `RealtimeAgent` instances with specified names and instructions
|
||||
- Server creates a `ChatRoom` with both agents
|
||||
- Server starts the chat room and returns `session_created` event
|
||||
3. **Message Broadcasting**:
|
||||
- `ChatRoom` automatically broadcasts messages between agents
|
||||
- All events (audio, transcripts, etc.) are forwarded to the frontend
|
||||
4. **Session End**: Client sends `client_session_end` event to stop the conversation
|
||||
|
||||
### Frontend Flow
|
||||
|
||||
1. **WebSocket Setup**: Establishes connection and waits for server events
|
||||
2. **Session Management**: Sends configuration and manages conversation state
|
||||
3. **Audio Playback**:
|
||||
- Receives base64-encoded PCM16 audio chunks
|
||||
- Decodes and queues audio data
|
||||
- Uses Web Audio API `ScriptProcessorNode` for streaming playback at 24kHz
|
||||
4. **Transcript Display**: Shows real-time transcripts from both agents
|
||||
|
||||
## Key Components
|
||||
|
||||
### ChatRoom
|
||||
|
||||
The `ChatRoom` class manages multiple `RealtimeAgent` instances:
|
||||
- Establishes connections for all agents
|
||||
- Broadcasts messages between agents automatically
|
||||
- Forwards events to the frontend
|
||||
- Handles lifecycle management (start/stop)
|
||||
|
||||
### RealtimeAgent
|
||||
|
||||
Each `RealtimeAgent`:
|
||||
- Connects to the DashScope realtime API
|
||||
- Processes audio input from other agents
|
||||
- Generates voice responses
|
||||
- Emits events for transcripts, audio, and status updates
|
||||
|
||||
## Customization
|
||||
|
||||
### Changing the Model
|
||||
|
||||
To use a different model, modify the `DashScopeRealtimeModel` configuration in `run_server.py`:
|
||||
|
||||
```python
|
||||
model=DashScopeRealtimeModel(
|
||||
model_name="your-model-name",
|
||||
api_key=os.getenv("DASHSCOPE_API_KEY"),
|
||||
)
|
||||
```
|
||||
|
||||
### Adding More Agents
|
||||
|
||||
To add more agents, modify the agent creation section in `run_server.py`:
|
||||
|
||||
```python
|
||||
agent3 = RealtimeAgent(
|
||||
name=agent3_name,
|
||||
sys_prompt=agent3_instructions,
|
||||
model=DashScopeRealtimeModel(
|
||||
model_name="qwen3-omni-flash-realtime",
|
||||
api_key=os.getenv("DASHSCOPE_API_KEY"),
|
||||
),
|
||||
)
|
||||
|
||||
chat_room = ChatRoom(agents=[agent1, agent2, agent3])
|
||||
```
|
||||
|
||||
And update the frontend to include configuration fields for the additional agents.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Audio Playback
|
||||
- Ensure your browser supports Web Audio API
|
||||
- Check browser console for audio-related errors
|
||||
- Verify the audio format matches the expected PCM16 at 24kHz
|
||||
|
||||
### Connection Issues
|
||||
- Verify your DashScope API key is set correctly
|
||||
- Check that port 8000 is not blocked by firewall
|
||||
- Review server logs for error messages
|
||||
|
||||
### Agents Not Responding
|
||||
- Ensure both agent configurations have valid instructions
|
||||
- Check that the instructions encourage conversational behavior
|
||||
- Review the console logs for API errors
|
||||
|
||||
## References
|
||||
|
||||
- [AgentScope Documentation](https://modelscope.github.io/agentscope/)
|
||||
- [DashScope API Documentation](https://help.aliyun.com/zh/model-studio/)
|
||||
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
|
||||
- [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
|
||||
|
||||
1273
examples/workflows/multiagent_realtime/multi_agent.html
Normal file
1273
examples/workflows/multiagent_realtime/multi_agent.html
Normal file
File diff suppressed because it is too large
Load Diff
220
examples/workflows/multiagent_realtime/run_server.py
Normal file
220
examples/workflows/multiagent_realtime/run_server.py
Normal file
@@ -0,0 +1,220 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A multi-agent realtime voice interaction server using ChatRoom."""
|
||||
import asyncio
|
||||
import os
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI, WebSocket
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
from agentscope import logger
|
||||
from agentscope.agent import RealtimeAgent
|
||||
from agentscope.message import TextBlock
|
||||
from agentscope.pipeline import ChatRoom
|
||||
from agentscope.realtime import (
|
||||
ClientEvents,
|
||||
ServerEvents,
|
||||
ClientEventType,
|
||||
DashScopeRealtimeModel,
|
||||
GeminiRealtimeModel,
|
||||
OpenAIRealtimeModel,
|
||||
)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def get() -> FileResponse:
|
||||
"""Serve the HTML test page."""
|
||||
html_path = Path(__file__).parent / "multi_agent.html"
|
||||
return FileResponse(html_path)
|
||||
|
||||
|
||||
@app.get("/model_availability")
|
||||
async def model_availability() -> dict:
|
||||
"""Check which model API keys are available in environment variables."""
|
||||
return {
|
||||
"dashscope": bool(os.getenv("DASHSCOPE_API_KEY")),
|
||||
"gemini": bool(os.getenv("GEMINI_API_KEY")),
|
||||
"openai": bool(os.getenv("OPENAI_API_KEY")),
|
||||
}
|
||||
|
||||
|
||||
async def frontend_receive(
|
||||
websocket: WebSocket,
|
||||
frontend_queue: asyncio.Queue,
|
||||
) -> None:
|
||||
"""Forward the message received from the agents to the frontend."""
|
||||
try:
|
||||
while True:
|
||||
msg: ServerEvents.EventBase = await frontend_queue.get()
|
||||
|
||||
# Send the message as JSON
|
||||
await websocket.send_json(msg.model_dump())
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] frontend_receive error: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
@app.websocket("/ws/{user_id}/{session_id}")
|
||||
async def multi_agent_endpoint(
|
||||
websocket: WebSocket,
|
||||
user_id: str,
|
||||
session_id: str,
|
||||
) -> None:
|
||||
"""WebSocket endpoint for multi-agent realtime voice interaction."""
|
||||
try:
|
||||
await websocket.accept()
|
||||
|
||||
logger.info(
|
||||
"Connected to WebSocket: user_id=%s, session_id=%s",
|
||||
user_id,
|
||||
session_id,
|
||||
)
|
||||
|
||||
# Create the queue to forward messages to the frontend
|
||||
frontend_queue = asyncio.Queue()
|
||||
asyncio.create_task(
|
||||
frontend_receive(websocket, frontend_queue),
|
||||
)
|
||||
|
||||
# Chat room and agents
|
||||
chat_room = None
|
||||
|
||||
while True:
|
||||
# Handle the incoming messages from the frontend
|
||||
# i.e. ClientEvents
|
||||
data = await websocket.receive_json()
|
||||
|
||||
client_event = ClientEvents.from_json(data)
|
||||
|
||||
if isinstance(
|
||||
client_event,
|
||||
ClientEvents.ClientSessionCreateEvent,
|
||||
):
|
||||
# Create agents by the given session arguments
|
||||
agent1_name = client_event.config.get("agent1_name", "Agent1")
|
||||
agent1_instructions = client_event.config.get(
|
||||
"agent1_instructions",
|
||||
"You are a helpful assistant.",
|
||||
)
|
||||
|
||||
agent2_name = client_event.config.get("agent2_name", "Agent2")
|
||||
agent2_instructions = client_event.config.get(
|
||||
"agent2_instructions",
|
||||
"You are a helpful assistant.",
|
||||
)
|
||||
|
||||
model_provider = client_event.config.get(
|
||||
"model_provider",
|
||||
"dashscope",
|
||||
)
|
||||
|
||||
# Create the appropriate model based on provider
|
||||
if model_provider == "dashscope":
|
||||
model1 = DashScopeRealtimeModel(
|
||||
model_name="qwen3-omni-flash-realtime",
|
||||
api_key=os.getenv("DASHSCOPE_API_KEY"),
|
||||
voice="Dylan",
|
||||
enable_input_audio_transcription=False,
|
||||
)
|
||||
model2 = DashScopeRealtimeModel(
|
||||
model_name="qwen3-omni-flash-realtime",
|
||||
api_key=os.getenv("DASHSCOPE_API_KEY"),
|
||||
voice="Peter",
|
||||
enable_input_audio_transcription=False,
|
||||
)
|
||||
|
||||
elif model_provider == "gemini":
|
||||
model1 = GeminiRealtimeModel(
|
||||
model_name=(
|
||||
"gemini-2.5-flash-native-audio-preview-09-2025"
|
||||
),
|
||||
api_key=os.getenv("GEMINI_API_KEY"),
|
||||
voice="Puck",
|
||||
)
|
||||
model2 = GeminiRealtimeModel(
|
||||
model_name=(
|
||||
"gemini-2.5-flash-native-audio-preview-09-2025"
|
||||
),
|
||||
api_key=os.getenv("GEMINI_API_KEY"),
|
||||
voice="Charon",
|
||||
)
|
||||
|
||||
elif model_provider == "openai":
|
||||
model1 = OpenAIRealtimeModel(
|
||||
model_name="gpt-4o-realtime-preview",
|
||||
api_key=os.getenv("OPENAI_API_KEY"),
|
||||
voice="alloy",
|
||||
)
|
||||
model2 = OpenAIRealtimeModel(
|
||||
model_name="gpt-4o-realtime-preview",
|
||||
api_key=os.getenv("OPENAI_API_KEY"),
|
||||
voice="echo",
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unsupported model provider: {model_provider}",
|
||||
)
|
||||
|
||||
# Create the first agent
|
||||
agent1 = RealtimeAgent(
|
||||
name=agent1_name,
|
||||
sys_prompt=agent1_instructions,
|
||||
model=model1,
|
||||
)
|
||||
|
||||
# Create the second agent
|
||||
agent2 = RealtimeAgent(
|
||||
name=agent2_name,
|
||||
sys_prompt=agent2_instructions,
|
||||
model=model2,
|
||||
)
|
||||
|
||||
# Create chat room with both agents
|
||||
chat_room = ChatRoom(agents=[agent1, agent2])
|
||||
|
||||
await chat_room.start(frontend_queue)
|
||||
|
||||
# Send session_created event to frontend
|
||||
await websocket.send_json(
|
||||
ServerEvents.ServerSessionCreatedEvent(
|
||||
session_id=session_id,
|
||||
).model_dump(),
|
||||
)
|
||||
|
||||
await agent1.model.send(
|
||||
TextBlock(
|
||||
type="text",
|
||||
text="<system>Now you can talk.</system>",
|
||||
),
|
||||
)
|
||||
|
||||
elif client_event.type == ClientEventType.CLIENT_SESSION_END:
|
||||
# End the session with the chat room
|
||||
if chat_room:
|
||||
await chat_room.stop()
|
||||
chat_room = None
|
||||
|
||||
else:
|
||||
# Forward other events to the chat room
|
||||
if chat_room:
|
||||
await chat_room.handle_input(client_event)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] WebSocket endpoint error: {e}")
|
||||
traceback.print_exc()
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(
|
||||
"run_server:app",
|
||||
host="localhost",
|
||||
port=8000,
|
||||
reload=True,
|
||||
log_level="info",
|
||||
)
|
||||
Reference in New Issue
Block a user