कंटेंट पर जाएं

प्रैक्टिकल गाइड: ओपन-सोर्स एजेंट फ्रेमवर्क्स और ElevenAgents

लेखक
Akhil Chauhan
प्रकाशित
आखिरी बार अपडेट किया गया

सुनेंइस आर्टिकल को सुनें

हमारी पिछली पोस्ट ElevenLabs वॉइस ऑर्केस्ट्रेशन के साथ बाहरी एजेंट्स को इंटीग्रेट करना में, हमने बताया था कि टीमें अपने मौजूदा टेक्स्ट-आधारित एजेंट ऑर्केस्ट्रेशन को ElevenLabs से Custom LLM के ज़रिए कैसे जोड़ सकती हैं। उसी आधार पर आगे बढ़ते हुए, यह गाइड दिखाती है कि प्रमुख ओपन-सोर्स एजेंट फ्रेमवर्क्स को Custom LLM इंटरफ़ेस के पीछे कैसे अनुकूलित और डिप्लॉय किया जा सकता है। इसका नतीजा एक लचीला आर्किटेक्चर है, जिसमें स्टेट मैनेजमेंट, टूल ऑर्केस्ट्रेशन या ऐप्लिकेशन-विशिष्ट नियंत्रण से समझौता किए बिना, परिपक्व एजेंट सिस्टम्स पर वॉइस की एक लेयर जोड़ी जा सकती है। फ्रेमवर्क कोई भी हो, हम एक ही तीन-स्टेप पैटर्न अपनाते हैं: जनरेशन रिक्वेस्ट बनाना, अंतिम टेक्स्ट रिस्पॉन्स निकालना, और उसे OpenAI-संगत Server-Sent Events (SSE) फ़ॉर्मैट में दोबारा फ़ॉर्मैट करना। ElevenLabs Chat Completions और Responses दोनों फ़ॉर्मैट को सपोर्ट करता है। यह गाइड चार व्यापक रूप से अपनाए गए फ्रेमवर्क्स को कवर करती है, लेकिन ये पैटर्न OpenAI-संगत स्ट्रीमिंग आउटपुट देने वाले किसी भी रनटाइम पर लागू होते हैं।

A proxy layer translates between ElevenLabs voice orchestration and an agent framework, converting OpenAI-style messages into framework inputs and streaming SSE chunks back as agent voice output.

सामान्य सेटअप

इस सेक्शन के उदाहरण Python और FastAPI का इस्तेमाल करते हैं, हालांकि HTTP POST रिक्वेस्ट और स्ट्रीमिंग SSE रिस्पॉन्स संभालने वाला कोई भी स्टैक काम करेगा। जब ElevenLabs का वॉइस ऑर्केस्ट्रेशन किसी टर्न के खत्म होने की संभावना पहचानता है, तो वह कॉन्फ़िगर किए गए Custom LLM एंडपॉइंट पर जनरेशन रिक्वेस्ट भेजता है। इस सेक्शन में उस ट्रांसलेशन लेयर के मुख्य हिस्सों के बारे में बताया गया है—वह ब्रिज या प्रॉक्सी जो वॉइस ऑर्केस्ट्रेशन और एजेंट फ्रेमवर्क को एक ही भाषा में बात करने देता है।

स्वाभाविक रूप से, ग्राहक किसी फ्रेमवर्क को उससे परिचित होने या किसी खास काम को पूरा करने की उसकी क्षमता के आधार पर चुन सकते हैं। उदाहरण के लिए, LlamaIndex को मूल रूप से Retrieval-Augmented Generation (RAG) सेटअप करना आसान बनाने के लिए विकसित किया गया था, जबकि CrewAI को एजेंट्स के दौर में तय कार्यों को ऑटोमेट करने के लिए बनाया गया था। अलग-अलग डिज़ाइन लक्ष्य अलग-अलग रिस्पॉन्स स्ट्रक्चर बनाते हैं, और हर एक को अलग तरीके से संभालना पड़ता है। पूरा टर्न तैयार होने का इंतज़ार करने के बजाय, LLM के जनरेट करते ही चंक्स को स्ट्रीम करना महत्वपूर्ण है, क्योंकि इससे टेक्स्ट टू स्पीच (TTS) मॉडल पहले ही स्पीच जनरेट करना शुरू कर सकता है, जिससे महसूस होने वाली लेटेंसी कम होती है। हम चार लोकप्रिय फ्रेमवर्क्स—मुख्य रूप से LangGraph, Google ADK, CrewAI और LlamaIndex—पर ध्यान देते हैं।

शेयर किए गए कोड पर एक नोट

हर फ्रेमवर्क को OpenAI-संगत SSE चंक्स के रूप में रिस्पॉन्स स्ट्रीम करना चाहिए। इन चंक्स को बनाने के लिए हम उदाहरणों में इस्तेमाल होने वाला एक छोटा हेल्पर फ़ंक्शन पेश करते हैं।

def sse_chunk(response_id: str, delta: dict, finish_reason=None) -> str:
    payload = {
        "id": response_id,
        "object": "chat.completion.chunk",
        "choices": [{"index": 0, "delta": delta, "finish_reason": finish_reason}],
    }
    return f"data: {json.dumps(payload)}\n\n"

इस आधार के साथ, आइए LangGraph से शुरू करते हैं। 

LangGraph

LangGraph एजेंट्स को ग्राफ़ के रूप में मॉडल करता है, जहाँ नोड्स अलग-अलग स्टेप्स को दर्शाते हैं और एजेज़ उनके बीच कंट्रोल फ़्लो तय करते हैं। न्यूनतम सेटअप सीधा है: एक चैट मॉडल इनिशियलाइज़ करें, एजेंट टूल्स तय करें और एजेंट ग्राफ़ रनटाइम बनाएं।

from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
llm = ChatOpenAI(
    model=model_id,
    api_key=os.getenv("OPENAI_API_KEY"),
)
agent = create_agent(
    llm,
	tools=tool_list,
	system_prompt=system_prompt,
)

हर जनरेशन रिक्वेस्ट के लिए, LangGraph Agent को पूरा बातचीत इतिहास मिलता है, जिससे वह ज़रूरी स्टेट को अंदरूनी रूप से बनाए रख सकता है। LangGraph सर्वर-साइड पर्सिस्टेंस को Checkpoints के ज़रिए सपोर्ट करता है, हालांकि इम्प्लीमेंटेशन को न्यूनतम रखने के लिए हमने उन्हें यहाँ शामिल नहीं किया है।

स्टेट मैनेजमेंट हो जाने के बाद, LangGraph-विशिष्ट अगला निर्णय स्ट्रीमिंग मोड का होता है। LangGraph दो विकल्प देता है, जिनमें से हर एक अलग उपयोग के लिए उपयुक्त है:

  • stream_mode="values" ग्राफ़ स्टेट स्नैपशॉट देता है। इसे इम्प्लीमेंट करना आसान है, लेकिन हर रिस्पॉन्स में अधिक पूरा मैसेज स्टेट शामिल होता है, जो रियल-टाइम बातचीत के फ़्लो में लेटेंसी बढ़ाता है।
  • stream_mode="messages" मॉडल से क्रमिक मैसेज चंक्स स्ट्रीम करता है। रियलटाइम वॉइस इंटरैक्शन के लिए इसे आम तौर पर प्राथमिकता दी जाती है, क्योंकि यह ElevenLabs ऑर्केस्ट्रेशन लेयर में पहले ऑडियो तक का समय कम करता है।

खास तौर पर, एजेंट लूप के messages इम्प्लीमेंटेशन में टूल कॉलिंग अपडेट्स जैसे मध्यवर्ती स्टेप्स शामिल होते हैं, जिन्हें बोलकर नहीं सुनाया जाना चाहिए। प्रॉक्सी इन्हें फ़िल्टर करता है और TTS लेयर तक सिर्फ़ यूज़र के लिए रिस्पॉन्स टेक्स्ट भेजता है। नीचे टूल-समर्थित टर्न का एक उदाहरण है।

[1] मॉडल टूल कॉल करने का निर्णय लेता है (tool_calls=["get_price"])
[2] टूल चलकर डेटा लौटाता है (result="$24.99") 
[3] मॉडल नतीजे से रिस्पॉन्स तैयार करता है (content="इसकी कीमत $24.99 है") 

स्वाभाविक रूप से, SSE स्ट्रीम में सिर्फ़ स्टेप 3 के चंक्स ही फ़ॉरवर्ड किए जाने चाहिए। व्यवहार में, स्ट्रीमिंग लूप में दो गार्ड चेक इस फ़िल्टरिंग को संभालते हैं: एक केवल langgraph_node == "model" इवेंट्स रखने के लिए, और दूसरा खाली कंटेंट को छोड़ने के लिए। साथ मिलकर, ये चेक सुनिश्चित करते हैं कि सिर्फ़ यूज़र के लिए असिस्टेंट टेक्स्ट ही SSE के रूप में ElevenLabs को फ़ॉरवर्ड हो। इन अवधारणाओं को एक साथ रखते हुए, हम रिक्वेस्ट प्रॉक्सी का एक हल्का इम्प्लीमेंटेशन देते हैं।

@app.post("/chat/completions")
async def chat_completions(req: ChatCompletionRequest):
    input = {"messages": req.messages}
    async def stream():
        response_id = f"chatcmpl-{uuid.uuid4().hex[:12]}"
        sent_role = False
        async for message_chunk, metadata in agent.astream(input, stream_mode="messages"):
            # Only forward model text chunks; skip tool updates and non-text events.
            if metadata.get("langgraph_node") != "model":
                continue
            content = getattr(message_chunk, "content", None)
            if not content:
                continue
            if not sent_role:
                yield sse_chunk(response_id, {"role": "assistant"})
                sent_role = True
            # Send incremental token-like chunks to ElevenLabs in OpenAI format.
            yield sse_chunk(response_id, {"content": content})
         # Signal natural completion before using the finish_reason: "stop" [DONE]
        yield sse_chunk(response_id, {}, finish_reason="stop")
        yield "data: [DONE]\n\n"
    return StreamingResponse(stream(), media_type="text/event-stream")

इससे सिर्फ़ यूज़र के लिए मॉडल चंक्स ही ElevenLabs को फ़ॉरवर्ड होते हैं। LangGraph अपने स्टेट स्ट्रीम के ज़रिए अंदरूनी टूल एक्ज़ीक्यूशन को दिखाता है, इसलिए फ़िल्टरिंग स्पष्ट होती है और प्रॉक्सी के नियंत्रण में रहती है। 

अब हम Google के Agent Development Kit (ADK) के साथ काम करने की बारीकियों को समझते हैं

Google ADK

Google का ADK रनटाइम लूप को कुछ मुख्य प्रिमिटिव्स—Agent, Runner और SessionService—के पीछे एब्स्ट्रैक्ट करता है। ADK का Runner HTTP लेयर और एजेंट डेफ़िनिशन के बीच होता है। यह मैसेज रूटिंग, टूल ऑर्केस्ट्रेशन, सेशन लाइफ़साइकल और इवेंट स्ट्रीमिंग संभालता है। 

from google.adk.agents import Agent
from google.adk.runners import Runner
from google.adk.agents.run_config import RunConfig, StreamingMode
from google.adk.sessions import InMemorySessionService
from google.genai import types as genai_types
agent = Agent(
    name=name,
    model=model,
    instruction=instruction,
    tools=[tool_list],
)
session_service = InMemorySessionService()
	runner = Runner(
	agent=agent,
	app_name=app_name,
	session_service=session_service
)

एजेंट, सेशन बैकएंड और रनर इनिशियलाइज़ होने पर, प्रॉक्सी हर आने वाली रिक्वेस्ट के लिए ADK सेशन खोजता या बनाता है। ADK में session_id मेमोरी पर्सिस्टेंस को नियंत्रित करता है: अलग-अलग टर्न्स में उसी session_id को दोबारा इस्तेमाल करने पर इतिहास, टूल कॉल्स और पिछले रिस्पॉन्स अपने-आप आगे बढ़ जाते हैं। बातचीत की पहचान ElevenLabs में अपस्ट्रीम रहती है, इसलिए प्रॉक्सी इस मैपिंग को स्पष्ट रूप से संभालता है। जनरेशन रिक्वेस्ट के लिए सही आइडेंटिफ़ायर देने पर, SDK पिछले कॉन्टेक्स्ट को अंदरूनी रूप से संभाल सकता है। बातचीत शुरू करते समय हम मनमाना आइडेंटिफ़ायर extra parameters के ज़रिए रिक्वेस्ट की बॉडी में भेजते हैं।  

मैसेज और सेशन तैयार होने पर रनर को चलाया जा सकता है। एक्ज़ीक्यूशन के दौरान टूल कॉल्स और टूल रिज़ल्ट्स अंदरूनी ADK इवेंट्स के रूप में दिखते रहते हैं, लेकिन उन्हें यूज़र-फेसिंग आउटपुट के बजाय मध्यवर्ती ऑर्केस्ट्रेशन स्टेप्स माना जाता है। इससे उन फ्रेमवर्क्स की तुलना में मैन्युअल फ़िल्टर की ज़रूरत नहीं पड़ती, जहाँ टूल कॉल्स यूज़र को दिखने वाले टेक्स्ट में आते हैं। 

नीचे दिया गया हैंडलर सेशन रिज़ॉल्यूशन और get-or-create लॉजिक को इनलाइन शामिल करने वाला एक सरल इम्प्लीमेंटेशन है।

@app.post("/chat/completions")
async def chat_completions(req: ChatCompletionRequest, request: Request):
    # In production, prefer a stable identifier from your upstream system.
    session_id = req.elevenlabs_extra_body.arbitrary_identifier
    session = await session_service.get_session(
        app_name="elevenlabs", user_id="user", session_id=session_id
    )
    if not session:
        session = await session_service.create_session(
            app_name="elevenlabs", user_id="user", session_id=session_id
        )
    user_text = next((m["content"] for m in reversed(req.messages) if m["role"] == "user"), "")
    content = genai_types.Content(role="user", parts=[genai_types.Part(text=user_text)])
   async def stream():
        response_id = f"chatcmpl-{uuid.uuid4().hex[:12]}"
        sent_role = False
        async for event in runner.run_async(
            user_id="user",
            session_id=session.id,
            new_message=content,
            run_config=RunConfig(streaming_mode=StreamingMode.SSE),
        ):
            if not event.content or not event.content.parts:
                continue
            # In SSE mode, ADK emits partial (incremental) and final (complete) events.
            # Forwarding only partial events avoids duplicating the full text.
            # Note: SSE streaming is experimental in ADK. For production, reconcile
            # both event types in case the model backend doesn't emit partials.
            if not getattr(event, "partial", False):
                continue
            text = "".join((getattr(p, "text", "") or "") for p in event.content.parts)
            if not text:
                continue
            if not sent_role:
                yield sse_chunk(response_id, {"role": "assistant"})
                sent_role = True
            yield sse_chunk(response_id, {"content": text})
        yield sse_chunk(response_id, {}, finish_reason="stop")
        yield "data: [DONE]\n\n"
    return StreamingResponse(stream(), media_type="text/event-stream")

अब हम CrewAI को देखेंगे, जो डिज़ाइन के हिसाब से ज़्यादा टास्क-केंद्रित है।

CrewAI

CrewAI को खुले संवाद लूप्स के बजाय स्ट्रक्चर्ड टास्क्स—जैसे रिसर्च, लिखना और सारांश बनाना—के आसपास मल्टी-एजेंट वर्कफ़्लोज़ को ऑर्केस्ट्रेट करने के लिए डिज़ाइन किया गया था। एजेंट्स को एक भूमिका, लक्ष्य और बैकस्टोरी के साथ परिभाषित किया जाता है। एक्ज़ीक्यूशन Task ऑब्जेक्ट्स के इर्द-गिर्द केंद्रित होता है, जिनमें से हर एक का स्पष्ट विवरण और अपेक्षित आउटपुट होता है। 

from crewai import Agent, Task, Crew, Process, LLM
from crewai.tools import tool
from crewai.types.streaming import StreamChunkType
llm = LLM(
    model=model_id,
    api_key=os.getenv("OPENAI_API_KEY")
)
store_agent = Agent(
    role=role,
    goal=goal,
    backstory=backstory,
    tools=tools,
    llm=llm,
    verbose=False,
)

LangGraph और ADK में इस्तेमाल होने वाले एजेंट-लूप मॉडल के विपरीत, CrewAI आम तौर पर बातचीत के उस टर्न के कार्य-इकाई को तय करने के लिए हर रिक्वेस्ट पर Task और Crew बनाता है। हम प्लेसहोल्डर के ज़रिए पिछले टर्न्स को अगले टास्क में जोड़कर बातचीत का कॉन्टेक्स्ट आगे बढ़ाते हैं। {crew_chat_messages} वैरिएबल में हर रिक्वेस्ट पर चल रहा बातचीत इतिहास भरा जाता है, फिर एक्ज़ीक्यूशन के समय इसे टास्क विवरण में इंटरपोलेट किया जाता है। हम मध्यवर्ती ट्रेसिंग पैटर्न्स (Thought, Action, Action Input, Observation) को साफ़ तौर पर फ़िल्टर करके और सिर्फ़ अंतिम उत्तर का टेक्स्ट भेजकर, साफ़ और स्पीच-रेडी टेक्स्ट तैयार करते हैं। 

नीचे दिया गया हैंडलर हर-रिक्वेस्ट टास्क निर्माण, हिस्ट्री इंटरपोलेशन, Crew-लेवल स्ट्रीमिंग, ट्रेस फ़िल्टरिंग और आउटपुट फ़ॉर्मैटिंग को एक साथ लाता है। 

@app.post("/chat/completions")
async def chat_completions(req: ChatCompletionRequest):
    # Task and Crew are assembled per request (not at startup).	
    task = Task(
        description=(
            "Conversation history:\n{crew_chat_messages}\n\n"
            "Respond to the user's latest message."
        ),
        expected_output=expected_output,
        agent=store_agent,
    )
    # stream=True returns CrewStreamingOutput instead of a single CrewOutput.
    crew = Crew(
        agents=[store_agent],
        tasks=[task],
        process=Process.sequential,
        verbose=False,
        stream=True,
    )
    async def stream():
        response_id = f"chatcmpl-{uuid.uuid4().hex[:12]}"
        sent_role = False
        final_marker = "final answer:"
        marker_buffer = ""
        marker_found = False
        emitted_any_content = False
        streaming = await crew.kickoff_async(
            inputs={"crew_chat_messages": json.dumps(req.messages)}
        )
       async for chunk in streaming:
            # Skip non-text events (e.g. tool calls).
            if chunk.chunk_type != StreamChunkType.TEXT or not chunk.content:
                continue
            # Only forward text after the "Final Answer:" marker
            if not marker_found:
                marker_buffer += chunk.content
                idx = marker_buffer.lower().find("final answer:")
                if idx == -1:
                    continue
                marker_found = True
                content = marker_buffer[idx + 13:].lstrip()
                marker_buffer = ""
            else:
                content = chunk.content
            # Clean up any trailing markdown artifacts from CrewAI output.
            content = content.rstrip("`").rstrip()
            if not content:
                continue
            if not sent_role:
                yield sse_chunk(response_id, {"role": "assistant"})
                sent_role = True
            yield sse_chunk(response_id, {"content": content})
        # Fallback to handle short responses without the "Final Answer:" marker
        if not sent_role:
            raw = getattr(streaming, "result", None)
            fallback = (raw.raw if raw else marker_buffer).strip().rstrip("`").rstrip()
            if fallback:
                yield sse_chunk(response_id, {"role": "assistant"})
                yield sse_chunk(response_id, {"content": fallback})
        yield sse_chunk(response_id, {}, finish_reason="stop")
        yield "data: [DONE]\n\n"

अब हम LlamaIndex को देखते हैं, जो नेटिव इवेंट-ड्रिवन स्ट्रीमिंग मॉडल पर केंद्रित एक अलग तरीका अपनाता है।

LlamaIndex

इस पोस्ट में कवर किए गए अन्य फ्रेमवर्क्स के विपरीत, LlamaIndex को LLMs को बाहरी डेटा सोर्सेज़—डॉक्यूमेंट स्टोर्स, इंडेक्स और रिट्रीवल पाइपलाइन्स—से जोड़ने के लिए डिज़ाइन किया गया था। इसकी एजेंट लेयर, FunctionAgent, खुले संवाद या टास्क एक्ज़ीक्यूशन के बजाय स्ट्रक्चर्ड कॉन्टेक्स्ट को रिट्रीव करने और उस पर तर्क करने के लिए इसी आधार पर काम करती है।

from llama_index.llms.openai import OpenAI
from llama_index.core.agent.workflow import FunctionAgent, AgentStream
from llama_index.core.base.llms.types import ChatMessage, MessageRole
llm = OpenAI(
    model=model,
    api_key=os.getenv("OPENAI_API_KEY")
)
agent = FunctionAgent(
    tools=[list_inventory, get_item_price],
    llm=llm,
    system_prompt=system_prompt,
)

बातचीत की निरंतरता बनाए रखने के लिए, प्रॉक्सी आने वाले मैसेजेस को LlamaIndex चैट मैसेजेस में बदलता है, फिर उन्हें सबसे नए यूज़र टर्न (user_msg) और पिछले टर्न्स (chat_history) में बाँटता है। हर AgentStream इवेंट के event.delta फ़ील्ड में अगला टेक्स्ट फ़्रैगमेंट होता है, जो सीधे OpenAI-स्टाइल delta.content चंक में मैप हो जाता है। खाली न होने वाले डेल्टाज़ को जैसा है वैसा फ़ॉरवर्ड किया जा सकता है, जिससे यह गाइड का सबसे सीधा स्ट्रीमिंग ब्रिज बनता है। स्ट्रीम में ऑर्केस्ट्रेशन इवेंट्स (टूल कॉल्स, रिज़ल्ट्स) और स्पीच इवेंट्स (असिस्टेंट टेक्स्ट डेल्टाज़), दोनों होते हैं। वॉइस आउटपुट को साफ़ रखने के लिए, प्रॉक्सी सिर्फ़ AgentStream इवेंट्स रखता है और खाली डेल्टाज़ छोड़ देता है।

[1] AgentStream (delta='')       ← अनदेखा किया गया
[2] ToolCall                     ← अनदेखा किया गया
[3] ToolCallResult               ← अनदेखा किया गया
[4] AgentStream (delta='It')     ← फ़ॉरवर्ड किया गया ✓
[5] AgentStream (delta=' costs') ← फ़ॉरवर्ड किया गया ✓
[6] AgentStream (delta=' $49.99')← फ़ॉरवर्ड किया गया ✓

यह अलगाव मध्यवर्ती टूल मैकेनिक्स को बोले जाने वाले आउटपुट से बाहर रखता है और कम-लेटेंसी वाली क्रमिक स्पीच बनाए रखता है। नीचे दिया गया ड्रॉप-इन हैंडलर इन स्टेप्स को एक साथ लाता है।

@app.post("/chat/completions")
async def chat_completions(req: ChatCompletionRequest):
    # This assumes the last message is always a user turn with string content.
    # For production, add defensive role/content handling for non-text payloads.
    chat_history = [
        ChatMessage(role=MessageRole(m["role"]), content=m.get("content") or "")
        for m in req.messages
    ]
    user_text = chat_history.pop().content
    async def stream():
        response_id = f"chatcmpl-{uuid.uuid4().hex[:12]}"
        handler = agent.run(user_msg=user_text, chat_history=chat_history)
        async for event in handler.stream_events():
            if not isinstance(event, AgentStream):
                continue
            if not event.delta:
                continue
            yield sse_chunk(response_id, {"content": event.delta})
        yield sse_chunk(response_id, {}, finish_reason="stop")
        yield "data: [DONE]\n\n"
    return StreamingResponse(stream(), media_type="text/event-stream")

LlamaIndex, भारी बिल्ट-इन ऑर्केस्ट्रेशन लेयर्स वाले फ्रेमवर्क्स की तुलना में, एंड-टू-एंड बातचीत के रनटाइम पैटर्न्स के लिए कम निर्देशात्मक है। प्रोडक्शन डिप्लॉयमेंट्स में, आम तौर पर ग्राहकों को सेशन हैंडलिंग, रिस्पॉन्स गार्डरेल्स, टूल ऑर्केस्ट्रेशन और ट्रेसिंग लागू करनी होती है।

निष्कर्ष

इस गाइड का हर फ्रेमवर्क एक ही कॉन्ट्रैक्ट के ज़रिए ElevenLabs से जुड़ता है: OpenAI-स्टाइल Completions या Responses रिक्वेस्ट स्वीकार करना और SSE चंक्स वापस स्ट्रीम करना। इससे टीमें मौजूदा एजेंट इम्प्लीमेंटेशन पर बहुत कम बदलावों के साथ वॉइस ऑर्केस्ट्रेशन की लेयर जोड़ सकती हैं। वे पहले से बनाए गए काम को बरकरार रखते हुए रियल-टाइम कन्वर्सेशनल AI को अनलॉक कर सकती हैं। यही मॉड्यूलैरिटी ElevenAgents प्लैटफ़ॉर्म का एक मूल सिद्धांत है। चाहे संगठन किसी मौजूदा एजेंट को आगे बढ़ा रहे हों या शुरुआत से वॉइस-नेटिव बना रहे हों, ElevenAgents का वॉइस ऑर्केस्ट्रेशन उन्हें उनकी मौजूदा स्थिति के अनुसार सहयोग देने के लिए बनाया गया है।

अगर आप पहले से किसी ओपन-सोर्स फ्रेमवर्क के साथ एजेंट चला रहे हैं और वॉइस सक्षम करना चाहते हैं, तो यह तरीका आज़माएं और हमें बताएं कि आपको कैसा लगा।

संबंधित लेख

उच्चतम गुणवत्ता वाले AI ऑडियो के साथ बनाएं