Les agents du modèle de langue grand sont des outils puissants pour automatiser des tâches telles que la recherche, la génération de contenu et la révision de la qualité. Cependant, un seul agent ne peut souvent pas tout faire efficacement, surtout lorsque vous devez intégrer des ressources externes (comme les recherches Web) et plusieurs étapes spécialisées (par exemple, rédaction vs revues). Les workflows multi-agents vous permettent de diviser ces tâches entre les différents agents, chacun avec ses propres outils, contraintes et responsabilités. Dans cet article, nous allons examiner comment construire un système à trois agents - Researchagent, WriteAgent et ReviewAgent - où chaque agent gère une partie spécifique de la création d'un rapport historique concis sur Internet. Nous nous assurerons également que le système ne restera pas coincé dans une boucle de recherche, ce qui peut perdre du temps et des crédits.
Cet article a été publié dans le cadre du Data Science Blogathon.
############################################################################### # 1. INSTALLATION ############################################################################### # Make sure you have the following installed: # pip install llama-index langchain duckduckgo-search ############################################################################### # 2. IMPORTS ############################################################################### %pip install llama-index langchain duckduckgo-search from llama_index.llms.openai import OpenAI # For DuckDuckGo search via LangChain from langchain.utilities import DuckDuckGoSearchAPIWrapper # llama-index workflow classes from llama_index.core.workflow import Context from llama_index.core.agent.workflow import ( FunctionAgent, AgentWorkflow, AgentInput, AgentOutput, ToolCall, ToolCallResult, AgentStream ) import asyncio ############################################################################### # 3. CREATE LLM ############################################################################### # Replace "sk-..." with your actual OpenAI API key llm = OpenAI(model="gpt-4", api_key="OPENAI_API_KEY")
############################################################################### # 1. INSTALLATION ############################################################################### # Make sure you have the following installed: # pip install llama-index langchain duckduckgo-search ############################################################################### # 2. IMPORTS ############################################################################### %pip install llama-index langchain duckduckgo-search from llama_index.llms.openai import OpenAI # For DuckDuckGo search via LangChain from langchain.utilities import DuckDuckGoSearchAPIWrapper # llama-index workflow classes from llama_index.core.workflow import Context from llama_index.core.agent.workflow import ( FunctionAgent, AgentWorkflow, AgentInput, AgentOutput, ToolCall, ToolCallResult, AgentStream ) import asyncio ############################################################################### # 3. CREATE LLM ############################################################################### # Replace "sk-..." with your actual OpenAI API key llm = OpenAI(model="gpt-4", api_key="OPENAI_API_KEY")
Un agentworkflow coordonne comment les messages et l'état se déplacent entre les agents. Lorsque l'utilisateur initie une demande (par exemple, «Écrivez-moi un rapport concis sur l'historique d'Internet…»), le workflow:
Le flux de travail se termine une fois le contenu approuvé et qu'aucune autre modification n'est demandée.
À cette étape, nous définissons le flux de travail de l'agent, qui comprend des agents de recherche, d'écriture et de révision. Le root_agent est défini sur la recherche_agent, ce qui signifie que le processus commence par la collecte de recherche. L'état initial contient des espaces réservés pour les notes de recherche, le contenu du contenu et le statut de revue.
############################################################################### # 4. DEFINE DUCKDUCKGO SEARCH TOOL WITH SAFEGUARDS ############################################################################### # We wrap LangChain's DuckDuckGoSearchAPIWrapper with our own logic # to prevent repeated or excessive searches. duckduckgo = DuckDuckGoSearchAPIWrapper() MAX_SEARCH_CALLS = 2 search_call_count = 0 past_queries = set() async def safe_duckduckgo_search(query: str) -> str: """ A DuckDuckGo-based search function that: 1) Prevents more than MAX_SEARCH_CALLS total searches. 2) Skips duplicate queries. """ global search_call_count, past_queries # Check for duplicate queries if query in past_queries: return f"Already searched for '{query}'. Avoiding duplicate search." # Check if we've reached the max search calls if search_call_count >= MAX_SEARCH_CALLS: return "Search limit reached, no more searches allowed." # Otherwise, perform the search search_call_count += 1 past_queries.add(query) # DuckDuckGoSearchAPIWrapper.run(...) is synchronous, but we have an async signature result = duckduckgo.run(query) return str(result) ############################################################################### # 5. OTHER TOOL FUNCTIONS: record_notes, write_report, review_report ############################################################################### async def record_notes(ctx: Context, notes: str, notes_title: str) -> str: """Store research notes under a given title in the shared context.""" current_state = await ctx.get("state") if "research_notes" not in current_state: current_state["research_notes"] = {} current_state["research_notes"][notes_title] = notes await ctx.set("state", current_state) return "Notes recorded." async def write_report(ctx: Context, report_content: str) -> str: """Write a report in markdown, storing it in the shared context.""" current_state = await ctx.get("state") current_state["report_content"] = report_content await ctx.set("state", current_state) return "Report written." async def review_report(ctx: Context, review: str) -> str: """Review the report and store feedback in the shared context.""" current_state = await ctx.get("state") current_state["review"] = review await ctx.set("state", current_state) return "Report reviewed."
Le workflow est exécuté à l'aide d'une demande utilisateur, qui spécifie le sujet et les points clés à couvrir dans le rapport. La demande de cet exemple demande un rapport concis sur l'histoire d'Internet, y compris ses origines, le développement du World Wide Web et son évolution moderne. Le workflow traite cette demande en coordonnant les agents.
############################################################################### # 6. DEFINE AGENTS ############################################################################### # We have three agents with distinct responsibilities: # 1. ResearchAgent - uses DuckDuckGo to gather info (max 2 searches). # 2. WriteAgent - composes the final report. # 3. ReviewAgent - reviews the final report. research_agent = FunctionAgent( name="ResearchAgent", description=( "A research agent that searches the web using DuckDuckGo. " "It must not exceed 2 searches total, and must avoid repeating the same query. " "Once sufficient information is collected, it should hand off to the WriteAgent." ), system_prompt=( "You are the ResearchAgent. Your goal is to gather sufficient information on the topic. " "Only perform at most 2 distinct searches. If you have enough info or have reached 2 searches, " "handoff to the next agent. Avoid infinite loops!" ), llm=llm, tools=[ safe_duckduckgo_search, # Our DuckDuckGo-based search function record_notes ], can_handoff_to=["WriteAgent"] ) write_agent = FunctionAgent( name="WriteAgent", description=( "Writes a markdown report based on the research notes. " "Then hands off to the ReviewAgent for feedback." ), system_prompt=( "You are the WriteAgent. Draft a structured markdown report based on the notes. " "After writing, hand off to the ReviewAgent." ), llm=llm, tools=[write_report], can_handoff_to=["ReviewAgent", "ResearchAgent"] ) review_agent = FunctionAgent( name="ReviewAgent", description=( "Reviews the final report for correctness. Approves or requests changes." ), system_prompt=( "You are the ReviewAgent. Read the report, provide feedback, and either approve " "or request revisions. If revisions are needed, handoff to WriteAgent." ), llm=llm, tools=[review_report], can_handoff_to=["WriteAgent"] )
Pour surveiller l'exécution du workflow, nous diffusons des événements et imprimons les détails des activités d'agent. Cela nous permet de suivre quel agent fonctionne actuellement, d'afficher les sorties intermédiaires et d'inspecter les appels d'outils effectués par les agents. Les informations de débogage telles que l'utilisation et les réponses des outils sont affichées pour une meilleure visibilité.
############################################################################### # 1. INSTALLATION ############################################################################### # Make sure you have the following installed: # pip install llama-index langchain duckduckgo-search ############################################################################### # 2. IMPORTS ############################################################################### %pip install llama-index langchain duckduckgo-search from llama_index.llms.openai import OpenAI # For DuckDuckGo search via LangChain from langchain.utilities import DuckDuckGoSearchAPIWrapper # llama-index workflow classes from llama_index.core.workflow import Context from llama_index.core.agent.workflow import ( FunctionAgent, AgentWorkflow, AgentInput, AgentOutput, ToolCall, ToolCallResult, AgentStream ) import asyncio ############################################################################### # 3. CREATE LLM ############################################################################### # Replace "sk-..." with your actual OpenAI API key llm = OpenAI(model="gpt-4", api_key="OPENAI_API_KEY")
Une fois le flux de travail terminé, nous extraisons l'état final, qui contient le rapport généré. Le contenu du rapport est imprimé, suivi de tout commentaire d'examen de l'agent de révision. Cela garantit que la sortie est complète et peut être affinée si nécessaire.
############################################################################### # 4. DEFINE DUCKDUCKGO SEARCH TOOL WITH SAFEGUARDS ############################################################################### # We wrap LangChain's DuckDuckGoSearchAPIWrapper with our own logic # to prevent repeated or excessive searches. duckduckgo = DuckDuckGoSearchAPIWrapper() MAX_SEARCH_CALLS = 2 search_call_count = 0 past_queries = set() async def safe_duckduckgo_search(query: str) -> str: """ A DuckDuckGo-based search function that: 1) Prevents more than MAX_SEARCH_CALLS total searches. 2) Skips duplicate queries. """ global search_call_count, past_queries # Check for duplicate queries if query in past_queries: return f"Already searched for '{query}'. Avoiding duplicate search." # Check if we've reached the max search calls if search_call_count >= MAX_SEARCH_CALLS: return "Search limit reached, no more searches allowed." # Otherwise, perform the search search_call_count += 1 past_queries.add(query) # DuckDuckGoSearchAPIWrapper.run(...) is synchronous, but we have an async signature result = duckduckgo.run(query) return str(result) ############################################################################### # 5. OTHER TOOL FUNCTIONS: record_notes, write_report, review_report ############################################################################### async def record_notes(ctx: Context, notes: str, notes_title: str) -> str: """Store research notes under a given title in the shared context.""" current_state = await ctx.get("state") if "research_notes" not in current_state: current_state["research_notes"] = {} current_state["research_notes"][notes_title] = notes await ctx.set("state", current_state) return "Notes recorded." async def write_report(ctx: Context, report_content: str) -> str: """Write a report in markdown, storing it in the shared context.""" current_state = await ctx.get("state") current_state["report_content"] = report_content await ctx.set("state", current_state) return "Report written." async def review_report(ctx: Context, review: str) -> str: """Review the report and store feedback in the shared context.""" current_state = await ctx.get("state") current_state["review"] = review await ctx.set("state", current_state) return "Report reviewed."
Lorsque vous utilisez un outil de recherche Web, il est possible que le LLM soit «confus» et d'appeler à plusieurs reprises la fonction de recherche. Cela peut entraîner des coûts inutiles ou une consommation de temps. Pour éviter cela, nous utilisons deux mécanismes:
Si l'une ou l'autre condition est remplie (les recherches maximales ou une requête en double), notre fonction safe_duckduckgo_search renvoie un message en conserve au lieu d'effectuer une nouvelle recherche.
ResearchAgent
writeAgent
revoiragent
Le flux de travail se termine
La sortie finale est stockée dans final_state ["report_content"].
En divisant votre flux de travail en agents distincts pour Rechercher , Écriture , et Review , vous pouvez créer un système puissant et modulaire qui:
L'intégration de DuckDuckgo utilisant Langchain propose une solution de recherche Web plug-and-play pour le flux de travail multi-agents sans nécessiter des clés API ou des informations d'identification spécialisées. Combiné avec des garanties intégrées (limites d'appel de recherche, détection en double), ce système est robuste, efficace et adapté à un large éventail de tâches de recherche et de génération de contenu.
a. La division des responsabilités entre les agents (recherche, écriture, révision) garantit que chaque étape est clairement définie et plus facile à gérer. Il réduit également la confusion dans la prise de décision du modèle et favorise les sorties structurées plus précises.
Q2. Comment limiter le nombre de recherches Web?a. Dans le code, nous utilisons un compteur global (search_call_count) et une constante (max_search_calls = 2). Chaque fois que l'agent de recherche appelle Safe_DUCKDUCKGO_SEARCH, il vérifie si le compteur a atteint la limite. Si c'est le cas, il renvoie un message au lieu d'effectuer une autre recherche.
Q3. Et si l'agent répète la même requête plusieurs fois?a. Nous maintenons un ensemble Python appelé Past_queries pour détecter les requêtes répétées. Si la requête est déjà dans cet ensemble, l'outil sautera effectuer la recherche réelle et renverra un court message, empêchant les requêtes en double de l'exécution.
Q4. Puis-je changer les invites pour adapter ce flux de travail pour un autre sujet ou style?a. Absolument. Vous pouvez modifier System_Prompt de chaque agent pour adapter les instructions à votre domaine ou à votre style d'écriture souhaité. Par exemple, vous pouvez demander à l'écriture de produire une liste de points, un essai narratif ou un résumé technique.
Q5. Ai-je besoin de GPT-4, ou puis-je utiliser un autre modèle?a. Vous pouvez échanger OpenAI (Model = ”GPT-4 ″) pour un autre modèle pris en charge par Llama-Index (par exemple, GPT-3.5, ou même un modèle local). L'architecture reste la même, bien que certains modèles puissent produire des sorties de différentes qualité.
Le média présenté dans cet article ne appartient pas à l'analyse vidhya et est utilisé à la discrétion de l'auteur.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!