programa
La mayoría de las demos de IA siguen pareciéndose a chatbots: haces una pregunta, el modelo responde y la interacción termina. Pero el trabajo real de productividad rara vez sucede en un solo paso. Un asistente útil debe descomponer una petición ambigua, reunir contexto, comparar opciones, producir un entregable utilizable y luego revisar su propio trabajo antes de devolverlo.
Qwen 3.7 Max es un modelo orientado a agentes del equipo de Qwen, diseñado para cargas de trabajo centradas en agentes, incluido código, tareas de productividad de oficina y ejecuciones de largo recorrido. Es un modelo agent-first pensado no solo para responder bien a un único prompt, sino para mantener la coherencia a lo largo de un flujo de trabajo más largo que incluye planificación, uso de herramientas, redacción y autocorrección.
En este tutorial, construiremos un agente de productividad compacto usando Qwen 3.7 Max y Streamlit. La app toma una petición de negocio ambigua, como preparar un análisis de la competencia de las bases de datos vectoriales, y la convierte en un archivo pulido competitive_analysis.md.
Al finalizar este tutorial, sabrás cómo:
-
Construir un flujo de trabajo fijo de cinco turnos para el agente
-
Usar
enable_thinking=Trueypreserve_thinking=True -
Añadir investigación ligera en paralelo
-
Escribir y corregir un entregable en Markdown
-
Crear una interfaz sencilla en Streamlit alrededor del flujo
El código completo está disponible en el repositorio de GitHub.
El proyecto es deliberadamente pequeño, con la lógica principal repartida entre agent.py para la app de Streamlit y thinking_agent.py para el flujo backend.
Si estás empezando con la IA agentic, te recomiendo nuestro itinerario de aprendizaje AI Agent Fundamentals.
¿Qué es Qwen 3.7 Max?
Qwen 3.7 Max es el nuevo modelo insignia de Alibaba, lanzado el 20 de mayo de 2026. Está creado para flujos de trabajo agentic. Es decir, en lugar de estar pensado solo para un chat de un turno, está optimizado para tareas que requieren planificación, uso de herramientas, programación, automatización de oficina, razonamiento con contexto largo y ejecución en múltiples pasos.
El equipo de Qwen lo describe como un modelo para la “era de los agentes”, con puntos fuertes en agentes de código, asistentes de productividad, flujos basados en MCP y tareas autónomas de largo recorrido.
Lo interesante de este modelo no es solo su rendimiento bruto en benchmarks, sino su capacidad para mantenerse consistente a lo largo de una tarea multi-turno donde cada turno tiene un propósito distinto, que incluye:
- planificación
- síntesis de evidencias
- redacción de largo formato
- autocrítica
- revisión
En X, usuarios señalaron que el modelo está a la altura de Opus 4.7 y GPT 5.5 para tareas de programación de largo recorrido.

Puntos fuertes y rendimiento en benchmarks de Qwen 3.7 Max
Qwen 3.7 Max rinde muy bien en benchmarks de agentes y razonamiento. En evaluaciones de agentes de código, obtiene
- 69,7 en Terminal-Bench 2.0-Terminus
- 60,6 en SWE-bench Pro
- 78,3 en SWE-bench Multilingual
- 47,2 en NL2Repo
- 53,5 en SciCode
En benchmarks de agentes generales, alcanza
- 60,8 en MCP-Mark
- 76,4 en MCP-Atlas
- 67,2 en CoWorkBench
- 87,0 en SpreadSheetBench-v1

Fuente: Blog de desarrolladores de Qwen
Para que te hagas una idea: todos esos resultados superan a las puntuaciones de DeepSeek V4 Pro; la mayoría por poco, pero en código de largo recorrido hay una brecha notable entre ambos (47,2 vs 35,5 en NL2Repo).
Esto nos lleva a un ejemplo destacado del lanzamiento: la optimización de kernel de largo recorrido de Qwen 3.7 Max. Según se informa, Qwen 3.7 Max se ejecutó durante unas 35 horas, realizó 1.158 llamadas a herramientas, completó 432 evaluaciones de kernel y logró una aceleración media geométrica de 10,0x frente a una implementación de referencia en Triton.
Esto es importante porque muestra al modelo evaluándose en mejora iterativa basada en herramientas, no solo en preguntas estáticas de benchmark.
En resumen, Qwen 3.7 Max encaja muy bien en esta demo porque está hecho para flujos de trabajo donde el modelo necesita razonar, usar herramientas, preservar contexto y mejorar un entregable a lo largo de varios turnos.
Crear un agente de productividad que preserve el razonamiento con Qwen 3.7 Max
En este proyecto, demostraremos tres ideas prácticas:
- Una petición ambigua del usuario puede convertirse en un flujo estructurado de varios pasos.
- Las salidas de herramientas pueden reintroducirse en el proceso de razonamiento en lugar de volcarse en un único prompt largo.
- Un modelo puede releer y mejorar su propia salida mediante chain-of-thought prompting antes de entregar el archivo final al usuario.
Visión general del proyecto
Construiremos una app sencilla con un campo de entrada y un botón, donde el usuario introduce una petición ambigua como:
I need to prepare a competitive analysis of the top 3 vector databases
for a team presentation next week. I have no idea where to start.

Después, el agente ejecuta un flujo fijo de cinco turnos:
User prompt
Turn 1: Plan the work
Parallel research for Pinecone, Weaviate, and Qdrant
Turn 2: Summarize research
Turn 3: Build comparison matrix
Turn 4: Write competitive_analysis.md
Turn 5: Self-review and patch the markdown file
Streamlit file preview
La interfaz muestra cada paso como una tarjeta de progreso. A medida que el flujo avanza, las tarjetas pasan de en espera a completadas. Al final, el usuario puede revisar cada etapa: planificación, investigación, síntesis, borrador, autorrevisión y vista previa del archivo final.
Esto hace visible el flujo de trabajo del agente en lugar de ocultarlo detrás de una única respuesta de chat.
El repositorio es intencionalmente pequeño. Las piezas principales son:
-
thinking_agent.py: contiene la lógica del agente en el backend, como llamadas al modelo, prompts, preservación del razonamiento, investigación, reintentos, escritura de archivos y autorrevisión. -
agent.py: contiene la interfaz de Streamlit, incluido el diseño de la página, el cuadro de prompt, la barra de progreso, las tarjetas de pasos, el selector de resultados, la vista previa de Markdown y el botón de descarga. -
requirements.txt: incluye las dependencias de ejecución necesarias para la demo
El backend gira en torno a una clase ThinkingAgent que ejecuta una secuencia fija de cinco turnos y devuelve registros estructurados de cada turno. La UI no necesita saber cómo funcionan las llamadas al modelo, los reintentos o la expansión de investigación. Solo debe renderizar cada turno conforme llega.
El código completo de este tutorial está disponible en GitHub.
Nota: usé OpenRouter para acceder a Qwen 3.7 Max, pero también puedes usar el modelo a través de la plataforma oficial de la API de Qwen.
Paso 1: Configuración del entorno
Antes de construir el agente de productividad con Qwen 3.7 Max, vamos a configurar un entorno pequeño de Python con Streamlit, el cliente compatible con OpenAI y httpx para búsquedas web ligeras.
En este tutorial usaremos OpenRouter como puerta de enlace del modelo, pero el backend está escrito con el formato de API compatible con OpenAI. Esto significa que la misma estructura se puede adaptar después a Alibaba Cloud Model Studio u otro proveedor compatible.
En este paso, vamos a:
-
Crear un entorno virtual
-
Instalar las dependencias requeridas
-
Definir
OPENROUTER_API_KEYoQWEN_API_KEY -
Confirmar que la app se lanza con Streamlit
Crea y activa un entorno virtual:
python3 -m venv .venv
source .venv/bin/activate
Instala las dependencias del proyecto:
pip install -r requirements.txt
El archivo requirements.txt es deliberadamente pequeño:
httpx>=0.23.0
openai>=1.30.0
streamlit>=1.45.0
Usamos streamlit para construir la interfaz web interactiva, openai para llamar a Qwen 3.7 Max mediante una API compatible con OpenAI y httpx para obtener resultados ligeros de búsqueda en vivo para el paso de investigación.
Paso 2: Configura el cliente de Qwen 3.7 Max
El backend usa el SDK de Python de OpenAI porque OpenRouter expone un endpoint compatible con OpenAI. El archivo thinking_agent.py define unos valores por defecto:
from openai import OpenAI
DEFAULT_MODEL = "qwen/qwen3.7-max"
DEFAULT_BASE_URL = "https://openrouter.ai/api/v1"
DEFAULT_REFERER = "https://qwen.ai"
DEFAULT_TITLE = "Qwen3.7-Max Productivity Agent"
Luego creamos un cliente:
def build_client(
api_key: str | None = None,
base_url: str | None = None,
referer: str = DEFAULT_REFERER,
title: str = DEFAULT_TITLE,
) -> OpenAI:
return OpenAI(
base_url=base_url or DEFAULT_BASE_URL,
api_key=api_key,
default_headers={
"HTTP-Referer": referer,
"X-Title": title,
},
)
La función build_client() centraliza toda la configuración específica del proveedor. El resto de la app no necesita saber si la petición pasa por OpenRouter, Alibaba Cloud Model Studio u otro endpoint compatible.
Una vez configurado el cliente, el backend puede llamar a Qwen 3.7 Max usando el formato estándar de chat completions.
Ahora construiremos el flujo central del ThinkingAgent.
Paso 3: Flujo de trabajo del agente en cinco turnos
Con el cliente del modelo configurado, definimos el flujo backend principal. En lugar de pedir a Qwen 3.7 Max que genere un informe completo de una vez, dividimos la tarea en cinco etapas controladas.
-
Planificación: convierte el prompt ambiguo en un plan de tareas estructurado.
-
Investigación: recopila y resume evidencias de fragmentos externos.
-
Síntesis: construye una matriz de comparación a partir de la investigación.
-
Borrador: redacta el primer informe
competitive_analysis.md. -
Autorrevisión: revisa y corrige el informe antes de devolver el archivo final.
class ThinkingAgent:
def run(
self,
goal: str,
preserve_thinking: bool = True,
data_mode: str = "live",
on_turn: Callable[[TurnRecord], None] | None = None,
) -> ThinkingRunResult:
history = [{"role": "system", "content": SYSTEM_PROMPT}]
turns = []
backend = self._build_search_backend(data_mode)
turn1 = self._run_turn(
history=history,
turn_index=1,
phase="planning",
user_prompt=_planning_prompt(goal),
preserve_thinking=preserve_thinking,
)
search_results = self._run_research(backend)
turn2 = self._run_turn(
history=history,
turn_index=2,
phase="research",
user_prompt=_research_prompt(goal, search_results),
preserve_thinking=preserve_thinking,
)
turn3 = self._run_turn(
history=history,
turn_index=3,
phase="synthesis",
user_prompt=_synthesis_prompt(),
preserve_thinking=preserve_thinking,
)
turn4 = self._run_turn(
history=history,
turn_index=4,
phase="draft",
user_prompt=_draft_prompt(goal),
preserve_thinking=preserve_thinking,
)
turn5 = self._run_turn(
history=history,
turn_index=5,
phase="self_review",
user_prompt=_self_review_prompt(draft_markdown),
preserve_thinking=preserve_thinking,
)
El método run() es el bucle principal de orquestación. Comienza con un prompt de sistema, crea un historial de conversación, construye un backend de investigación y luego ejecuta los cinco turnos uno a uno.
Cada llamada a _run_turn() tiene una fase concreta. Esto hace el flujo más fácil de depurar porque cada llamada del modelo tiene una responsabilidad clara. La fase de planificación planifica. La de investigación interpreta fragmentos externos. La de síntesis crea estructura. La de borrador escribe. La de autorrevisión mejora la salida.
La investigación se sitúa entre el turno 1 y el turno 2 porque el modelo primero debe entender la tarea antes de incorporar información externa al flujo.
En el siguiente paso añadiremos la lógica específica de Qwen para preservar el razonamiento y ayudar al modelo a mantener la continuidad entre estos turnos.
Paso 4: Preserva el razonamiento entre turnos
La razón principal por la que usamos Qwen 3.7 Max en esta demo es su soporte para flujos que preservan el razonamiento. El agente no trata cada llamada al modelo como un prompt aislado. En su lugar, puede conservar el razonamiento de turnos anteriores y pasar ese contexto a turnos posteriores.
En este paso, vamos a:
- Habilitar el razonamiento del modelo.
- Preservar el razonamiento entre turnos.
- Anexar las salidas del asistente de nuevo al historial compartido.
response = self.client.chat.completions.create(
model=self.config.model,
messages=request_messages,
extra_body={
"enable_thinking": True,
"preserve_thinking": preserve_thinking,
},
)
La bandera enable_thinking=True permite a Qwen 3.7 Max producir contenido de razonamiento durante la respuesta. Mientras que la bandera preserve_thinking controla si ese contenido de razonamiento debe conservarse para turnos posteriores.
Tras responder el modelo, el backend extrae tanto la respuesta visible como el razonamiento:
message = response.choices[0].message
assistant_content = _normalize_text(getattr(message, "content", ""))
reasoning_content = _extract_reasoning_content(message)
The visible answer is what the app can show to the user. The reasoning content is used internally to help the next turn stay aligned with the earlier plan.
Then the backend appends the assistant message back into the conversation history:
```python
assistant_message = {
"role": "assistant",
"content": assistant_content,
}
if preserve_thinking and reasoning_content:
assistant_message["reasoning_content"] = reasoning_content
history.append(assistant_message)
Si en la fase de planificación se decide que el informe final debe comparar bases de datos vectoriales por modelo de despliegue, escalabilidad, experiencia de desarrollador, búsqueda híbrida y preparación para enterprise, los turnos posteriores pueden seguir usando esos criterios. Sin esto, cada turno puede desviarse: la síntesis podría elegir criterios distintos a los de planificación, o la autorrevisión evaluar el informe con un objetivo diferente.
A continuación añadiremos la capa de investigación que aporta contexto externo antes de redactar el informe.
Paso 5: Añade investigación en paralelo con datos de respaldo
Antes de que el modelo escriba un análisis de la competencia, necesita contexto externo. En esta demo, acotamos el alcance comparando tres bases de datos vectoriales: Pinecone, Weaviate y Qdrant.
En este paso, vamos a:
- Definir las bases de datos objetivo.
- Ejecutar llamadas de investigación en paralelo.
- Usar datos deterministas de respaldo si falla la búsqueda en vivo.
DATABASES = ("Pinecone", "Weaviate", "Qdrant")
La lista de objetivos es fija a propósito. Mantiene la demo estable y más fácil de explicar. Más adelante puedes ampliar el proyecto para que el modelo elija dinámicamente los objetivos de comparación.
Luego, el backend lanza llamadas de investigación en paralelo:
from concurrent.futures import ThreadPoolExecutor, as_completed
with ThreadPoolExecutor(max_workers=3) as executor:
future_map = {
executor.submit(backend.search, database, query): database
for database, query in queries.items()
}
for future in as_completed(future_map):
database = future_map[future]
results[database] = future.result()
ThreadPoolExecutor inicia una búsqueda por base de datos. Es más rápido que ejecutarlas en secuencia porque la investigación sobre Pinecone, Weaviate y Qdrant puede correr en paralelo.
try:
results[database] = future.result()
except Exception as exc:
fallback = FixtureSearchBackend().search(database, queries[database])
fallback.warning = (
f"Live search failed for {database} ({exc}). "
"Fallback demo research was used."
)
results[database] = fallback
Si la búsqueda en vivo funciona, el agente usa fragmentos frescos. Si falla, la app igualmente completa el flujo con fragmentos deterministas integrados. El principio de diseño clave es la degradación elegante: el agente no debe caerse porque falle una dependencia externa.
En el siguiente paso, pasaremos estos resultados a Qwen 3.7 Max para que sintetice una matriz de comparación.
Paso 6: Genera la síntesis y la matriz de comparación
Una vez que el agente tiene fragmentos de investigación, el siguiente trabajo es la síntesis. Este paso convierte información dispersa en una comparación estructurada que apoye el informe final.
En este paso, vamos a:
- Enviar el contexto de investigación de vuelta a Qwen 3.7 Max.
- Pedir al modelo que cree una comparación estructurada.
- Renderizar después esa salida en la interfaz de Streamlit.
turn3 = self._run_turn(
history=history,
turn_index=3,
phase="synthesis",
user_prompt=_synthesis_prompt(),
preserve_thinking=preserve_thinking,
)
Cuando este código se ejecuta, el historial de conversación ya contiene la petición original del usuario, la salida de planificación, los resúmenes de investigación y, opcionalmente, el razonamiento preservado de los turnos anteriores.
Esto significa que el prompt de síntesis no necesita reiterar toda la tarea. Puede centrarse en un único trabajo: convertir la investigación en una matriz de comparación lista para decidir.
Una buena síntesis debería comparar las opciones en dimensiones como:
- Modelo de despliegue
- Escalabilidad
- Experiencia de desarrollador
- Soporte de búsqueda híbrida
- Preparación para enterprise
- Mejor caso de uso
Con esta estructura sintetizada, redactaremos el primer informe en Markdown.
Paso 7: Escribe el informe en Markdown
Tras la planificación, investigación y síntesis, el agente tiene suficiente contexto para escribir el primer entregable completo. En esta demo, el entregable es un archivo Markdown llamado competitive_analysis.md.
En este paso, vamos a:
- Pedir a Qwen 3.7 Max que escriba el primer borrador.
- Quitar bloques de código de Markdown innecesarios.
- Guardar el borrador en disco.
- Registrar la acción de escritura como un evento de herramienta.
turn4 = self._run_turn(
history=history,
turn_index=4,
phase="draft",
user_prompt=_draft_prompt(goal),
preserve_thinking=preserve_thinking,
)
El turno de borrador usa todo el contexto previo: el objetivo original del usuario, el plan, la investigación y la matriz de síntesis.
Luego se limpia la respuesta del modelo y se escribe en disco:
draft_markdown = _strip_markdown_fences(turn4.assistant_content)
report_path = run_output_dir / "competitive_analysis.md"
report_path.write_text(draft_markdown)
El helper _strip_markdown_fences() es útil porque los modelos a menudo envuelven la salida en Markdown dentro de triples comillas invertidas. Eso está bien en una respuesta de chat, pero no es ideal al escribir directamente a un archivo .md.
El backend también registra la escritura:
turn4.tool_events.append(
ToolEvent(
name="write_file",
status="completed",
input_payload={"path": str(report_path)},
output_payload={
"description": "Initial draft written to disk.",
},
)
)
Este evento de herramienta ayuda a la UI a mostrar que el backend creó un archivo real, no solo otro texto. En este punto, la app ya tiene un informe utilizable. Pero añadimos un turno más para mejorar la calidad antes de mostrar el entregable final.
En el siguiente paso pediremos a Qwen 3.7 Max que revise y corrija su propio borrador.
Paso 8: Autorrevisión y corrección del informe
El último turno del modelo es una autorrevisión. En lugar de entregar de inmediato el primer borrador, el agente relee el informe, lo contrasta con el objetivo original y escribe una versión mejorada.
En este paso, vamos a:
- Enviar el borrador en Markdown de vuelta al modelo.
- Pedir al modelo que identifique debilidades.
- Generar una versión revisada.
- Sobrescribir el informe con la versión final mejorada.
turn5 = self._run_turn(
history=history,
turn_index=5,
phase="self_review",
user_prompt=_self_review_prompt(draft_markdown),
preserve_thinking=preserve_thinking,
)
El prompt de autorrevisión pide al modelo comprobar cuestiones prácticas como si la recomendación es clara, si los criterios de comparación son consistentes y si el informe sirve para una presentación de equipo.
La salida revisada se escribe de nuevo en el mismo archivo:
final_markdown = _strip_markdown_fences(turn5.assistant_content)
report_path.write_text(final_markdown)
El agente también puede registrar el evento final de escritura:
turn5.tool_events.append(
ToolEvent(
name="write_file",
status="completed",
input_payload={"path": str(report_path)},
output_payload={
"description": "Self-reviewed final report written to disk.",
},
)
)
Este paso convierte la app de un simple generador en un pequeño flujo editorial. Lo que ve el usuario no es el primer borrador, sino la versión revisada y corregida.
A continuación conectaremos este flujo backend con la app de Streamlit.
Paso 9: Construye la interfaz de progreso en Streamlit
Ahora pasamos de la lógica backend a la interfaz de usuario. La app de Streamlit debe permitir que el usuario introduzca un prompt, ejecute el flujo y vea completar cada etapa.
Nota: este código pertenece a agent.py porque controla lo que el usuario ve y pulsa.
En este paso, vamos a:
-
Configurar la página de Streamlit.
-
Crear la entrada para el prompt.
-
Añadir un botón de ejecución.
-
Llamar a la función
ThinkingAgent.run(). -
Actualizar la UI conforme se completen los turnos.
def render_streamlit_app() -> None:
st.set_page_config(
page_title="Qwen3.7-Max Demo Agent",
page_icon=":material/psychology:",
layout="wide",
initial_sidebar_state="collapsed",
)
La app usa un diseño ancho porque la UI incluye tarjetas de pasos, indicadores de progreso y paneles de resultados.
El área de entrada es sencilla:
goal = st.text_area(
"Prompt",
value=DEFAULT_GOAL,
height=120,
label_visibility="collapsed",
)
run_clicked = st.button("Run Demo", use_container_width=True)
El usuario solo necesita proporcionar la tarea. La app no le pide configurar temperatura, modo de búsqueda, ID de modelo o ajustes de razonamiento. Esos detalles los gestiona el backend.
Cuando el usuario hace clic en el botón, agent.py crea el agente backend y lo ejecuta:
agent = ThinkingAgent(config=config)
result = agent.run(
goal=goal,
preserve_thinking=True,
data_mode="live",
on_turn=on_turn,
)
Aquí es donde se encuentran ambos archivos. agent.py dispara el flujo, pero thinking_agent.py controla el comportamiento real del agente. El callback de UI actualiza la página tras cada turno:
def on_turn(turn: TurnRecord) -> None:
partial_turns.append(turn)
progress_placeholder.progress(
len(partial_turns) / len(phase_order),
text=f"Completed {_phase_label(turn.phase)}",
)
with steps_placeholder.container():
_render_step_cards(partial_turns, result_ready=False)
El callback recibe un TurnRecord completado y refresca la barra de progreso y las tarjetas de pasos. Durante la ejecución, las tarjetas actúan como indicadores de estado. Al finalizar, se convierten en vistas de resultados clicables.
Ahora renderizaremos el informe final en Markdown y lo expondremos como archivo descargable.
Paso 10: Vista previa y descarga del informe final
Tras terminar el backend, la UI debe mostrar el informe final. El backend ya ha creado el archivo Markdown, así que agent.py solo necesita leerlo, renderizarlo y ofrecer un botón de descarga.
En este paso, vamos a:
- Comprobar si existe el archivo del informe.
- Leer el contenido final en Markdown.
- Mostrar un botón de descarga.
- Renderizar el Markdown en la app de Streamlit
def _render_file_preview(report_path: str) -> None:
path = Path(report_path)
if not path.exists():
st.info("No file was written yet.")
return
content = path.read_text()
st.caption(f"Created file: {path.name}")
st.download_button(
"Download competitive_analysis.md",
data=content,
file_name=path.name,
use_container_width=True,
)
st.markdown(content)
La función empieza comprobando si el archivo existe. Esto evita que la app falle si el backend terminó antes de escribir el informe. Luego lee el contenido en Markdown y crea un botón de descarga. Finalmente, renderiza el Markdown directamente en la página de Streamlit.
Es una separación clara de responsabilidades donde:
-
thinking_agent.pyescribe el informe -
agent.pyprevisualiza y descarga el informe
En el siguiente paso añadiremos manejo básico de errores para que la demo se comporte mejor cuando fallen las rutas del proveedor o haya límites de tasa.
Paso 11: Manejo de errores y límites de tasa
Los proveedores de modelos pueden agotar el tiempo, devolver fallos temporales o limitar las solicitudes. Si mostramos esos errores en crudo a los usuarios, la app parece inacabada.
Este paso se reparte entre ambos archivos. La lógica de reintentos pertenece a thinking_agent.py porque forma parte de la llamada al modelo en el backend. El mensaje de error pertenece a agent.py porque controla lo que ve el usuario.
En este paso, vamos a:
- Reintentar fallos temporales del proveedor en el backend.
- Detectar errores tipo rate limit.
- Mostrar un mensaje más claro en la UI de Streamlit
delays = (1.0, 2.0)
for attempt_index in range(len(delays) + 1):
try:
return self.client.chat.completions.create(...)
except Exception as exc:
if not _is_retryable_provider_error(exc):
raise
if attempt_index >= len(delays):
raise
time.sleep(delays[attempt_index])
El backend intenta la llamada al modelo, captura fallos reintentables, espera brevemente y lo intenta de nuevo. Estos pequeños retrasos suavizan inestabilidades temporales del proveedor sin hacer esperar demasiado al usuario.
def _friendly_rate_limit_message(exc: Any) -> str:
return (
"Qwen 3.7 Max is temporarily rate-limited upstream. "
"Please wait 30 to 60 seconds and try again."
)
Así evitamos JSON crudos del proveedor o trazas en la UI. El usuario recibe una explicación clara y un siguiente paso práctico.
Con este último paso, ya podemos ejecutar la app completa y probar el flujo de extremo a extremo.
Paso 12: Ejecuta la demo
Conectados el flujo backend y la interfaz de Streamlit, podemos ejecutar la app completa.
En este paso, vamos a:
- Iniciar la app de Streamlit.
- Introducir el prompt de productividad por defecto.
- Ejecutar el flujo de cinco etapas.
- Previsualizar y descargar el informe final en Markdown
Inicia la app:
streamlit run agent.py
Usa el prompt por defecto:
I need to prepare a competitive analysis of the top 3 vector databases
for a team presentation next week. I have no idea where to start.
Al hacer clic en Run Demo, la app recorrerá el flujo completo:
-
Planificación: crea un plan estructurado.
-
Investigación: recopila fragmentos para Pinecone, Weaviate y Qdrant.
-
Síntesis: construye una matriz de comparación.
-
Borrador: escribe el primer informe en Markdown.
-
Autorrevisión: corrige el informe.
-
Vista previa: muestra el archivo final
competitive_analysis.md.
El informe final se guarda en:
output/showcase_runs/<timestamp>/with_preserve/competitive_analysis.md
Al final, deberías ver la vista previa del informe y un botón de descarga en la interfaz de Streamlit.
Conclusión
En este tutorial, hemos construido un agente de productividad compacto con Qwen 3.7 Max que ejecuta un flujo fijo e interpretable: planificación, investigación, síntesis, redacción y autorrevisión. Por el camino, muestra por qué preservar el razonamiento entre turnos puede ser útil para tareas agentic de largo formato.
La versión actual usa únicamente Streamlit, llamadas a modelos compatibles con OpenAI, una capa de búsqueda ligera y salida en Markdown. Esto facilita estudiarlo, modificarlo y reutilizarlo en tus propios experimentos.
A partir de aquí, hay muchas extensiones naturales:
-
Dejar que el modelo elija los objetivos de comparación en lugar de usar una lista fija
-
añadir ejecuciones en paralelo “con
preserve_thinking” vs “sinpreserve_thinking” -
Exponer uso de tokens y estimaciones de coste en la UI
-
generar un esquema de diapositivas o un gráfico junto al informe en Markdown
-
Sustituir el scraping de DuckDuckGo por una API de búsqueda más robusta
Si quieres ir más allá de un flujo fijo y aprender a construir aplicaciones de IA de nivel producción, desde prompt engineering y RAG hasta sistemas agentic, nuestro itinerario AI Engineering with LangChain es un buen siguiente paso.
Preguntas frecuentes del tutorial de la API de Qwen 3.7 Max
¿Cuándo debería usar preserve_thinking=True con Qwen 3.7 Max?
preserve_thinking=True ayuda a que los turnos posteriores se mantengan alineados con las decisiones anteriores en flujos multi-turno. En nuestro ejemplo, si el turno de planificación elige criterios de comparación específicos, los turnos de síntesis y autorrevisión pueden seguir usando ese mismo razonamiento en lugar de desviarse.
¿Qwen 3.7 Max es solo para agentes de código?
No. La programación es uno de sus puntos fuertes, pero el modelo también está orientado a agentes de productividad, automatización de oficina, flujos basados en MCP, tareas multilingües, razonamiento con contexto largo y uso de herramientas de largo recorrido.
¿La app de demo usa búsqueda web real?
Sí. La ruta actual por defecto intenta hacer scraping en vivo con DuckDuckGo. Si falla, recurre a investigación de respaldo integrada.
¿El modelo crea subagentes en nuestra app de demo?
No. La app usa una única sesión de modelo. La parte “paralela” ocurre en la capa de investigación, donde el backend lanza tres búsquedas web concurrentes y devuelve los resultados a la misma sesión del modelo.
¿Por qué separamos agent.py y thinking_agent.py?
agent.py mantiene la UI de Streamlit limpia. thinking_agent.py contiene el flujo backend, la construcción de prompts, los reintentos y la lógica de investigación para que el comportamiento del agente se pueda probar de forma independiente de la interfaz.
Soy experta Google Developers en ML (Gen AI), triple experta en Kaggle y embajadora de Women Techmakers, con más de tres años de experiencia en el sector tecnológico. Cofundé una startup de salud en 2020 y actualmente curso un máster en informática en Georgia Tech, con especialización en aprendizaje automático.



