¿Qué pasaría si después de terminar una reunión con un colega ya tendría todos sus elementos discutidos en su herramienta de gestión de proyectos? ¡No hay necesidad de escribir nada durante la reunión, ni crear manualmente los boletos correspondientes! Esa fue la idea de este breve proyecto experimental.
En esta guía paso a paso, crearemos la aplicación Python “Taskpilot” usando Agentes de Openai SDK Para crear automáticamente problemas de JIRA dado una transcripción de reunión.
El desafío: desde la conversación hasta las tareas procesables
Dada la transcripción de una reunión, cree problemas en un proyecto JIRA automáticamente y correspondiente a lo que se discutió en la reunión.
La solución: automatizar con agentes de OpenAI
Usando el Agentes de Operai SDK Implementaremos un flujo de trabajo de agentes que:
- Recibe y lee una transcripción de la reunión.
- Utiliza un agente de IA para extraer elementos de acción de la conversación.
- Utiliza otro agente de IA para crear problemas de JIRA a partir de esos elementos de acción.
Los agentes de Operai SDK
El Agentes de Operai SDK es una biblioteca de Python para crear agentes de IA mediante programación que pueda interactuar con las herramientas, usar servidores de MCP o entregar tareas a otros agentes.
Estas son algunas de las características clave del SDK:
- Bucle del agente: Un bucle de agente incorporado que maneja la comunicación de ida y vuelta con el LLM hasta que el agente se realiza con su tarea.
- Herramientas de función: Convierte cualquier función de Python en una herramienta, con generación automática de esquemas y validación de energía pydantic.
- Soporte de MCP: Permite a los agentes usar servidores MCP para extender sus capacidades de interactuar con el mundo exterior.
- Traspasos: Permite a los agentes delegar tareas a otros agentes dependiendo de su experiencia/rol.
- Barandas: Valida las entradas y salidas de los agentes. Aborta la ejecución temprano si el agente recibe entrada no válida.
- Sesiones: Gestiona automáticamente el historial de conversación. Asegura que los agentes tengan el contexto que necesitan para realizar sus tareas.
- Rastreo: Proporciona un gerente de contexto de rastreo que permite visualizar todo el flujo de ejecución de los agentes, lo que facilita la depuración y comprender lo que está sucediendo debajo del capó.
¡Ahora, vamos a sumergirnos en la implementación!
Implementación
Implementaremos nuestro proyecto en 8 pasos simples:
- Configuración de la estructura del proyecto
- El taskpilotrunner
- Definición de nuestros modelos de datos
- Creando los agentes
- Proporcionando herramientas
- Configuración de la aplicación
- Reuniendo todo en
main.py - Monitorear nuestras ejecuciones en la plataforma Operai Dev
¡Vamos a tener en la mano!
Paso 1: Configuración de la estructura del proyecto
Primero, creemos la estructura básica de nuestro proyecto:
- El
taskpilotDirectorio: contendrá nuestra lógica de aplicación principal. - El
local_agentsDirectorio: contendrá donde definimos los agentes que usaremos en este proyecto (“Local_agents” para que no haya interferencia con la Biblioteca OpenAIagents) - El
utilsDirectorio: para funciones auxiliares, un analizador de configuración y modelos de datos.
taskpilot_repo/
├── config.yml
├── .env
├── README.md
├── taskpilot/
│ ├── main.py
│ ├── taskpilot_runner.py
│ ├── local_agents/
│ │ ├── __init__.py
│ │ ├── action_items_extractor.py
│ │ └── tickets_creator.py
│ └── utils/
│ ├── __init__.py
│ ├── agents_tools.py
│ ├── config_parser.py
│ ├── jira_interface_functions.py
│ └── models.py
Paso 2: Taskpilotrunner
El TaskPilotRunner clasificar taskpilot/taskpilot_runner.py Será el corazón de nuestra aplicación. Orquestará todo el flujo de trabajo, extraerá elementos de acción de la transcripción de la reunión y luego creará los boletos JIRA de los elementos de acción. Al mismo tiempo, activará el rastreo incorporado del SDK de los agentes para recopilar un registro de eventos durante la ejecución de los agentes que ayudarán a depurar y monitorear los flujos de trabajo del agente.
Comencemos con la implementación:
- En el
__init__()Método Crearemos los dos agentes utilizados para este flujo de trabajo. - El
run()El método será el más importante delTaskPilotRunnerClase, que recibirá la transcripción de la reunión y la pasará a los agentes para crear los problemas de JIRA. Los agentes serán iniciados y correrán dentro de un Rastreador de gerentes de contexto es decirwith trace("TaskPilot run", trace_id):. Un rastro de los agentes SDK representa una única operación de extremo a extremo de un “flujo de trabajo”. - El
_extract_action_items()y_create_tickets()Los métodos comenzarán y ejecutarán cada uno de los agentes respectivamente. Dentro de estos métodos elRunner.run()El método de los agentes de OpenAI SDK se utilizará para activar los agentes. Se necesita un agente y una entrada, y devuelve la salida final de la ejecución del agente. Finalmente, el resultado de cada agente se analizará a su tipo de salida definido.
# taskpilot/taskpilot_runner.py
from agents import Runner, trace, gen_trace_id
from local_agents import create_action_items_agent, create_tickets_creator_agent
from utils.models import ActionItemsList, CreateIssuesResponse
class TaskPilotRunner:
def __init__(self):
self.action_items_extractor = create_action_items_agent()
self.tickets_creator = create_tickets_creator_agent()
async def run(self, meeting_transcript: str) -> None:
trace_id = gen_trace_id()
print(f"Starting TaskPilot run... (Trace ID: {trace_id})")
print(
f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}"
)
with trace("TaskPilot run", trace_id=trace_id):
# 1. Extract action items from meeting transcript
action_items = await self._extract_action_items(meeting_transcript)
# 2. Create tickets from action items
tickets_creation_response = await self._create_tickets(action_items)
# 3. Return the results
print(tickets_creation_response.text)
async def _extract_action_items(self, meeting_transcript: str) -> ActionItemsList:
result = await Runner.run(
self.action_items_extractor, input=meeting_transcript
)
final_output = result.final_output_as(ActionItemsList)
return final_output
async def _create_tickets(self, action_items: ActionItemsList) -> CreateIssuesResponse:
result = await Runner.run(
self.tickets_creator, input=str(action_items)
)
final_output = result.final_output_as(CreateIssuesResponse)
return final_output
Los tres métodos se definen como funciones asincrónicas. La razón de esto es que el Runner.run() El método de los agentes de OpenAI SDK se define como un async Coroutine. Esto permite que se ejecuten múltiples agentes, llamadas de herramientas o transmisión de puntos finales En paralelo sin bloquear.
Paso 3: Definición de nuestros modelos de datos
Sin que los agentes de configuración específicos devuelvan el texto en str como salida. Para garantizar que nuestros agentes proporcionen respuestas estructuradas y predecibles, la biblioteca admite el uso de Pydantico modelos para definir el output_type de los agentes (En realidad, admite cualquier tipo que se pueda envolver en un typeadapter pydantic: dataclasses, listas, typeddict, etc.). Los modelos de datos que definimos serán las estructuras de datos con las que nuestros agentes trabajarán.
Para nuestro USECase definiremos tres modelos en taskpilot/utils/models.py:
ActionItem: Este modelo representa un elemento de acción único que se extrae de la transcripción de la reunión.ActionItemsList: Este modelo es una lista deActionItemobjetos.CreateIssuesResponse: Este modelo define la estructura de la respuesta del agente que creará los problemas/boletos.
# taskpilot/utils/models.py
from typing import Optional
from pydantic import BaseModel
class ActionItem(BaseModel):
title: str
description: str
assignee: str
status: str
issuetype: str
project: Optional[str] = None
due_date: Optional[str] = None
start_date: Optional[str] = None
priority: Optional[str] = None
parent: Optional[str] = None
children: Optional[list[str]] = None
class ActionItemsList(BaseModel):
action_items: list[ActionItem]
class CreateIssuesResponse(BaseModel):
action_items: list[ActionItem]
error_messages: list[str]
success_messages: list[str]
text: str
Paso 4: Creación de los agentes
Los agentes son el núcleo de nuestra aplicación. Los agentes están básicamente un LLM configurado con instrucciones (el AGENT_PROMPT) y acceso a herramientas para que actúen por sí solo en tareas definidas. Un agente de los agentes de OpenAI SDK se define mediante los siguientes parámetros:
name: El nombre del agente para la identificación.instructions: El indicador para decirle al agente su rol o tarea que ejecutará (también conocido como solicitado del sistema).model: Que LLM usar para el agente. El SDK proporciona soporte listo para usar para modelos Operai, sin embargo, también puede usar modelos no openai (ver Agentes SDK: Modelos).output_type: Objeto Python que el agente devolverá, como se mencionó anteriormente.tools: Una lista de Python Callables, que serán las herramientas que el agente puede usar para realizar sus tareas.
Basado en esta información, creemos nuestros dos agentes: el ActionItemsExtractor y el TicketsCreator.
Extractor de elementos de acción
El trabajo de este agente es leer la transcripción de la reunión y extraer los elementos de acción. Lo crearemos en taskpilot/local_agents/action_items_extractor.py.
# taskpilot/local_agents/action_items_extractor.py
from agents import Agent
from utils.config_parser import Config
from utils.models import ActionItemsList
AGENT_PROMPT = """
Your are an assistant to extract action items from a meeting transcript.
You will be given a meeting transcript and you need to extract the action items so that they can be converted into tickets by another assistant.
The action items should contain the following information:
- title: The title of the action item. It should be a short description of the action item. It should be short and concise. This is mandatory.
- description: The description of the action item. It should be a more extended description of the action item. This is mandatory.
- assignee: The name of the person who will be responsible for the action item. You shall infer from the conversation the name of the assignee and not use "Speaker 1" or "Speaker 2" or any other speaker identifier. This is mandatory.
- status: The status of the action item. It can be "To Do", "In Progress", "In Review" or "Done". You shall extract from the transcript in which state the action item is. If it is a new action item, you shall set it to "To Do".
- due_date: The due date of the action item. It shall be in the format "YYYY-MM-DD". You shall extract this from the transcript, however if it is not explicitly mentioned, you shall set it to None. If relative dates are mentioned (eg. by tomorrow, in a week,...), you shall convert them to absolute dates in the format "YYYY-MM-DD".
- start_date: The start date of the action item. It shall be in the format "YYYY-MM-DD". You shall extract this from the transcript, however if it is not explicitly mentioned, you shall set it to None.
- priority: The priority of the action item. It can be "Lowest", "Low", "Medium", "High" or "Highest". You shall interpret the priority of the action item from the transcript, however if it is not clear, you shall set it to None.
- issuetype: The type of the action item. It can be "Epic", "Bug", "Task", "Story", "Subtask". You shall interpret the issuetype of the action item from the transcript, if it is unclear set it to "Task".
- project: The project to which the action item belongs. You shall interpret the project of the action item from the transcript, however if it is not clear, you shall set it to None.
- parent: If the action item is a subtask, you shall set the parent of the action item to the title of the parent action item. If the parent action item is not clear or the action item is not a subtask, you shall set it to None.
- children: If the action item is a parent task, you shall set the children of the action item to the titles of the child action items. If the children action items are not clear or the action item is not a parent task, you shall set it to None.
"""
def create_action_items_agent() -> Agent:
return Agent(
name="Action Items Extractor",
instructions=AGENT_PROMPT,
output_type=ActionItemsList,
model=Config.get().agents.model,
)
Como puede ver, en el AGENT_PROMPT Le decimos al agente muy detallado que su trabajo es extraer elementos de acción y proporcionar una descripción detallada de cómo queremos que se extraan los elementos de acción.
Creador de boletos
Este agente toma la lista de elementos de acción y crea problemas de JIRA. Lo crearemos en taskpilot/local_agents/tickets_creator.py.
# taskpilot/local_agents/tickets_creator.py
from agents import Agent
from utils.config_parser import Config
from utils.agents_tools import create_jira_issue
from utils.models import CreateIssuesResponse
AGENT_PROMPT = """
You are an assistant that creates Jira issues given action items.
You will be given a list of action items and for each action item you shall create a Jira issue using the `create_jira_issue` tool.
You shall collect the responses of the `create_jira_issue` tool and return them as the provided type `CreateIssuesResponse` which contains:
- action_items: list containing the action_items that were provided to you
- error_messages: list containing the error messages returned by the `create_jira_issue` tool whenever there was an error trying to create the issue.
- success_messages: list containing the response messages returned by the `create_jira_issue` tool whenever the issue creation was successful.
- text: A text that summarizes the result of the tickets creation. It shall be a string created as following:
f"From the {len(action_items)} action items provided {len(success_messages)} were successfully created in the Jira project.\n {len(error_messages)} failed to be created in the Jira project.\n\nError messages:\n{error_messages}"
"""
def create_tickets_creator_agent() -> Agent:
return Agent(
name="Tickets Creator",
instructions=AGENT_PROMPT,
tools=[create_jira_issue],
model=Config.get().agents.model,
output_type=CreateIssuesResponse
)
Aquí establecemos el tools parámetro y darle al agente el create_jira_issue herramienta, que crearemos en el siguiente paso.
Paso 5: proporcionar herramientas
Una de las características más poderosas de los agentes es su capacidad de usar herramientas para interactuar con el mundo exterior. Se podría argumentar que el uso de herramientas es lo que convierte la interacción con un LLM en un agente. El SDK de los agentes de OpenAI permite a los agentes usar tres tipos de herramientas:
- Herramientas alojadas: Proporcionado directamente desde OpenAI, como buscar la web o los archivos, el uso de la computadora, la ejecución del código, entre otros.
- Funciones llamadas: Uso de cualquier función de Python como herramienta.
- Agentes como herramientas: Permitir que los agentes llamen a otros agentes sin entregar.
Para nuestro USECASE, utilizaremos las llamadas de funciones e implementaremos una función para crear los problemas de JIRA usando API REST de Jira. Por elección personal, decidí separarlo en dos archivos:
- En
taskpilot/utils/jira_interface_functions.pyEscribiremos las funciones para interactuar a través de solicitudes HTTP con la API JIRA REST. - En
taskpilot/utils/agents_tools.pyEscribiremos envoltorios de las funciones que se proporcionarán a los agentes. Estas funciones de envoltura tienen un análisis de respuesta adicional para proporcionar al agente una respuesta de texto procesada en lugar de un JSON. Sin embargo, el agente también debe poder manejar y comprender a JSON como respuesta.
Primero implementamos el create_issue() función en taskpilot/utils/jira_interface_functions.py :
# taskpilot/utils/jira_interface_functions.py
import os
from typing import Optional
import json
from urllib.parse import urljoin
import requests
from requests.auth import HTTPBasicAuth
from utils.config_parser import Config
JIRA_AUTH = HTTPBasicAuth(Config.get().jira.user, str(os.getenv("ATLASSIAN_API_KEY")))
def create_issue(
project_key: str,
title: str,
description: str,
issuetype: str,
duedate: Optional[str] = None,
assignee_id: Optional[str] = None,
labels: Optional[list[str]] = None,
priority_id: Optional[str] = None,
reporter_id: Optional[str] = None,
) -> requests.Response:
payload = {
"fields": {
"project": {"key": project_key},
"summary": title,
"issuetype": {"name": issuetype},
"description": {
"content": [
{
"content": [
{
"text": description,
"type": "text",
}
],
"type": "paragraph",
}
],
"type": "doc",
"version": 1,
},
}
}
if duedate:
payload["fields"].update({"duedate": duedate})
if assignee_id:
payload["fields"].update({"assignee": {"id": assignee_id}})
if labels:
payload["fields"].update({"labels": labels})
if priority_id:
payload["fields"].update({"priority": {"id": priority_id}})
if reporter_id:
payload["fields"].update({"reporter": {"id": reporter_id}})
endpoint_url = urljoin(Config.get().jira.url_rest_api, "issue")
headers = {"Accept": "application/json", "Content-Type": "application/json"}
response = requests.post(
endpoint_url,
data=json.dumps(payload),
headers=headers,
auth=JIRA_AUTH,
timeout=Config.get().jira.request_timeout,
)
return response
Como puede ver, necesitamos autenticarnos en nuestra cuenta JIRA utilizando nuestro usuario de JIRA y un correspondiente API_KEY que podemos obtener en Gestión de cuentas Atlassian.
En taskpilot/utils/agents_tools.py Implementamos el create_jira_issue() función que luego proporcionaremos al TicketsCreator agente:
# taskpilot/utils/agents_tools.py
from agents import function_tool
from utils.models import ActionItem
from utils.jira_interface_functions import create_issue
@function_tool
def create_jira_issue(action_item: ActionItem) -> str:
response = create_issue(
project_key=action_item.project,
title=action_item.title,
description=action_item.description,
issuetype=action_item.issuetype,
duedate=action_item.due_date,
assignee_id=None,
labels=None,
priority_id=None,
reporter_id=None,
)
if response.ok:
return f"Successfully created the issue. Response message: {response.text}"
else:
return f"There was an error trying to create the issue. Error message: {response.text}"
Muy importante: El @function_tool El decorador es lo que hace que esta función sea utilizable para nuestro agente. El agente ahora puede llamar a esta función y pasarla un ActionItem objeto. La función luego usa el create_issue función que accede a la API JIRA para crear un nuevo problema.
Paso 6: Configuración de la aplicación
Para hacer que nuestra aplicación parametrizable, usaremos un config.yml Archivo para la configuración de configuración, así como un .env Archivo para las claves API.
La configuración de la aplicación está separada en:
agents: Para configurar los agentes y el acceso a la API de OpenAI. Aquí tenemos dos parámetros:modelque es el LLM que será utilizado por los agentes, yOPENAI_API_KEYen el.envArchivo, para autenticar el uso de la API de OpenAI. Puede obtener una llave de API de OpenAI en su Plataforma de desarrollo de OpenAi.jira: Para configurar el acceso a la API JIRA. Aquí necesitamos cuatro parámetros:url_rest_apique es la URL a la API REST de nuestra instancia de Jira;userque es el usuario que usamos para acceder a JIRA;request_timeoutque es el tiempo de espera en segundos para esperar a que el servidor envíe datos antes de rendirse, y finalmenteATLASSIAN_API_KEYen el.envArchivo, para autenticar en su instancia de JIRA.
Aquí está nuestro .env archivo, que en el siguiente paso se cargará a nuestra aplicación en el main.py usando el python-dotenv biblioteca:
OPENAI_API_KEY=some-api-key
ATLASSIAN_API_KEY=some-api-key
Y aquí está nuestro config.yml archivo:
# config.yml
agents:
model: "o4-mini"
jira:
url_rest_api: "https://your-domain.atlassian.net/rest/api/3/"
user: "[email protected]"
request_timeout: 5
También crearemos un analizador de configuración en taskpilot/utils/config_parser.py Para cargar esta configuración. Para esto implementamos el Config clase como un singleton (lo que significa que solo puede haber una instancia de esta clase a lo largo de la vida útil de la aplicación).
# taskpilot/utils/config_parser.py
from pathlib import Path
import yaml
from pydantic import BaseModel
class AgentsConfig(BaseModel):
model: str
class JiraConfig(BaseModel):
url_rest_api: str
user: str
request_timeout: int
class ConfigModel(BaseModel):
agents: AgentsConfig
jira: JiraConfig
class Config:
_instance: ConfigModel | None = None
@classmethod
def load(cls, path: str = "config.yml") -> None:
if cls._instance is None:
with open(Path(path), "r", encoding="utf-8") as config_file:
raw_config = yaml.safe_load(config_file)
cls._instance = ConfigModel(**raw_config)
@classmethod
def get(cls, path: str = "config.yml") -> ConfigModel:
if cls._instance is None:
cls.load(path)
return cls._instance
Paso 7: reunirlo todo en main.py
Finalmente, en taskpilot/main.pyreuniremos todo. Este script cargará la transcripción de la reunión, creará una instancia del TaskPilotRunner y luego llame al run() método.
# taskpilot/main.py
import os
import asyncio
from dotenv import load_dotenv
from taskpilot_runner import TaskPilotRunner
# Load the variables in the .env file
load_dotenv()
def load_meeting_transcript_txt(file_path: str) -> str:
# ...
return meeting_transcript
async def main():
print("TaskPilot application starting...")
meeting_transcript = load_meeting_transcript_txt("meeting_transcript.txt")
await TaskPilotRunner().run(meeting_transcript)
if __name__ == "__main__":
asyncio.run(main())
Paso 8: Monitorear nuestras ejecuciones en la plataforma Operai Dev Operai
Como se mencionó, una de las ventajas del SDK de los agentes de Operai es que, debido a su característica de rastreo, es posible visualizar todo el flujo de ejecución de nuestros agentes. Esto hace que sea fácil depurar y comprender lo que está sucediendo debajo del capó en el Plataforma de desarrollo de OpenAi.
En el Tablero de trajes uno puede:
- Rastree cada carrera del flujo de trabajo de los agentes.
- Comprenda exactamente qué hicieron los agentes dentro del flujo de trabajo del agente y monitorear el rendimiento.
- Depurar cada llamada a la API de OpenAI, así como monitorear cuántas tokens se usaron en cada entrada y salida.
Así que aproveche esta característica para evaluar, depurar y monitorear su agente.
Conclusión
¡Y eso es todo! En estos ocho simples pasos, hemos implementado una aplicación que puede crear automáticamente problemas de JIRA a partir de una transcripción de la reunión. ¡Gracias a la simple interfaz del SDK de OpenAI Agents, puede crear fácilmente agentes programáticamente para ayudarlo a automatizar sus tareas!
Siéntase libre de clonar el repositorio (el proyecto como se describe en esta publicación está en la rama function_calling), Pruébelo usted mismo y comience a construir sus propias aplicaciones con AI.
💡 Poner a continuación:
En una próxima publicación, nos sumergiremos en Cómo implementar su propio servidor MCP Para extender aún más las capacidades de nuestros agentes y permitirles interactuar con sistemas externos más allá de sus herramientas locales. ¡Manténganse al tanto!
🙋️ Vamos a conectarnos
Si tiene preguntas, comentarios o simplemente desea seguir con proyectos futuros:
Referencia
Este artículo está inspirado en el “Openai: agentes SDK” de un curso de LinkedInlearning.