Ir al contenido principal

Jan-V1: Guía con proyecto de demostración

Aprende a crear un asistente de investigación profunda utilizando las capacidades de razonamiento agencial de Jan-v1, incluyendo la implementación local, el desarrollo de aplicaciones Streamlit y mucho más.
Actualizado 18 ago 2025  · 12 min de lectura

El equipo de Jan ha publicado recientemente Jan-v1, un modelo avanzado de razonamiento agencial que introduce sofisticadas capacidades de automatización de la investigación mediante una mejor utilización de las herramientas y la resolución de problemas en varios pasos.

En este tutorial me centraré en las capacidades únicas de razonamiento agencial de Jan-v1, demostrando cómo actúa como un complejo flujo de trabajo de investigación a través de una interfaz Streamlit implementada localmente y alimentada por llama.cpp.

En este tutorial, explicaré cómo:

  • Implementa Jan-v1 localmente con cuantificación GGUF para obtener un rendimiento y una privacidad óptimos.
  • Crea una aplicación Streamlit para la investigación automatizada con seguimiento del progreso en tiempo real.
  • Implementa la integración inteligente de búsquedas web con generación dinámica de consultas.
  • Crea un informe profesional con una estructura específica para cada formato.
  • Aplica un procesamiento de texto avanzado para garantizar una documentación limpia y lista para su uso empresarial.

Al final, tu aplicación tendrá este aspecto:

Demostración de Deep Research Assistant

¿Qué es Jan-v1?

Jan-v1 es un modelo de 4B parámetros basado en los fundamentos de Lucy y Qwen3-4B-thinking, diseñado para flujos de trabajo agenticos como el uso de herramientas, el razonamiento en varios pasos y la investigación automatizada. A diferencia de los LLM convencionales, Jan-v1 destaca en la coordinación entre herramientas, fuentes de datos y pasos de razonamiento mediante un andamiaje estructurado y recompensas alineadas con el comportamiento.

Estas son algunas de las características principales de este modelo:

  • Arquitectura preparada para agentes: Este modelo está optimizado para la integración en el mundo real y gestiona la búsqueda web, la síntesis y la generación de informes estructurados mediante un razonamiento mejorado y API de herramientas.
  • Eficiencia: A pesar de su pequeño tamaño, Jan-v1 ofrece un rendimiento típico de modelos mucho más grandes, gracias a un entrenamiento RL específico que hace hincapié en resultados centrados y orientados a objetivos.
  • Implementación con prioridad en la privacidad: Su formato GGUF compacto permite una inferencia rápida y local, lo que resulta ideal para tareas de investigación privadas y de baja latencia en ordenadores portátiles o CPU.
  • Entrenamiento basado en la investigación: Jan-v1 utiliza funciones de recompensa novedosas que equilibran la informatividad con la brevedad, lo cual es fundamental para tareas de alto riesgo como el análisis y la elaboración de informes, minimizando así las alucinaciones y la verbosidad.
  • Basado en Qwen3-4B-thinking: Este modelo hereda el sólido razonamiento en cadena y el control de herramientas de la fusión del modo de pensamiento de Qwen3, lo que lo hace especialmente eficaz para los procesos de automatización de la investigación.

Configuración de Jan-v1 localmente

Para este proyecto, implementaremos Jan-v1 localmente utilizando Llama.cpp con la versión cuantificada GGUF para obtener un rendimiento óptimo y una eficiencia de recursos.

Paso 1: Instala las dependencias

En primer lugar, asegúrate de que tienes los paquetes Python necesarios:

pip install llama-cpp-python==0.3.15
pip install streamlit aiohttp 

Este comando instala todas las dependencias básicas necesarias para la integración del modelo de IA, la creación de la interfaz web y las operaciones web asíncronas.

Paso 2: Descargar la versión GGUF de enero-v1

Antes de descargar el modelo, crea un nuevo directorio llamado « models/ » con el siguiente comando:

 mkdir -p models

A continuación, descarga el modelo utilizando el siguiente comando:

curl -L https://huggingface.co/janhq/Jan-v1-4B-GGUF/resolve/main/Jan-v1-4B-Q4_K_M.gguf -o Jan-v1-4B-Q4_K_M.gguf

Al completar este paso, has descargado correctamente el modelo Jan-v1 4B en formato GGUF y lo has colocado en el directorio models/. Esta versión cuantificada ofrece un equilibrio entre rendimiento y eficiencia de memoria, lo que la hace ideal para la inferencia local en CPU o Colab.

Paso 3: Configura la clave API de Serper

Regístrate o inicia sesión en tu cuenta Serper: https://serper.dev/api-keys y selecciona la pestaña «Claves API». A continuación, copia la clave API predeterminada para esta demostración. Configuremos esta clave como variable de entorno de la siguiente manera:

export SERPER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxx

Clave API de Serper

Ya estás listo para cargar e interactuar con el modelo en tu canalización de asistente de investigación.

Demostración: Asistente de investigación profunda con Jan-v1

Construyamos un aplicación Streamlit que demuestre las capacidades avanzadas de investigación de Jan-v1, con generación inteligente de consultas, búsqueda web automatizada (utilizando Serper) y síntesis de informes profesionales.

Paso 1: Importa las bibliotecas.

Comenzamos importando todas las bibliotecas necesarias para nuestro asistente de investigación. Estos soportan todo, desde la creación de interfaces web hasta la búsqueda web asíncrona y la integración de modelos de IA locales.

import streamlit as st
import json
import time
import re
from datetime import datetime
from typing import List, Dict, Optional
import asyncio
import aiohttp
from llama_cpp import Llama
import os
from dataclasses import dataclass

Importamos todas las bibliotecas principales utilizadas en toda la aplicación. Entre ellos se incluyen componentes de la interfaz de usuario (Streamlit), herramientas de concurrencia (asyncio, aiohttp) y el backend LLM (llama_cpp). También incorporaremos utilidades para el análisis sintáctico, la tipificación y el manejo de fechas.

Paso 2: Funciones auxiliares

Ahora implementaremos algunas funciones auxiliares que se encargarán del formato de los informes y la extracción de contenido. Estas funciones garantizan que los informes generados mantengan una calidad profesional y una estructura coherente.

def sections_for_format(fmt: str) -> list[str]:
    fmt = (fmt or "").strip().lower()
    if fmt == "executive":
        return ["EXECUTIVE SUMMARY"]
    if fmt == "detailed":
        return [
            "INTRODUCTION",
            "DETAILED ANALYSIS",
            "CURRENT TRENDS AND DEVELOPMENTS",
            "IMPLICATIONS AND RECOMMENDATIONS",
            "CONCLUSION",
        ]
    if fmt == "academic":
        return [
            "ABSTRACT",
            "INTRODUCTION",
            "METHODOLOGY",
            "FINDINGS",
            "DISCUSSION",
            "CONCLUSION",
        ]
    if fmt == "presentation":
        return [
            "OVERVIEW",
            "KEY INSIGHTS",
            "RECOMMENDATIONS",
            "NEXT STEPS",
            "CONCLUSION",
        ]
    return ["INTRODUCTION", "DETAILED ANALYSIS", "CONCLUSION"]
def extract_final_block(text: str) -> str:
    m = re.search(r"<final>([\s\S]*?)</final>", text, flags=re.IGNORECASE)
    if m:
        cleaned_text = m.group(1).strip()
    else:
        cleaned_text = text
    preamble_patterns = [
        r"^(?:note:|okay,|hmm,|internal|let me|i (?:will|’ll)|as an ai|thinking|plan:|here is your report|the following is|i have prepared|i am presenting|based on the provided information|below is the report|i hope this meets your requirements|this report outlines|this is the final report).*?$",
        r"^(?:Here is the report|I have compiled the report|The report is provided below|This is the requested report).*?$", # More specific preambles
        r"^(?:Please find the report below|Here's the report).*?$"
    ]
    for pattern in preamble_patterns:
        cleaned_text = re.sub(pattern, "", cleaned_text, flags=re.IGNORECASE | re.MULTILINE).strip()
    cleaned_text = re.sub(r"(?m)^\s*[-*•]\s+", "", cleaned_text)
    cleaned_text = re.sub(r"[#`*_]{1,3}", "", cleaned_text)
    headers = [
        "EXECUTIVE SUMMARY","INTRODUCTION","DETAILED ANALYSIS","CURRENT TRENDS AND DEVELOPMENTS",
        "IMPLICATIONS AND RECOMMENDATIONS","CONCLUSION","ABSTRACT","METHODOLOGY","FINDINGS",
        "DISCUSSION","OVERVIEW","KEY INSIGHTS","RECOMMENDATIONS","NEXT STEPS"
    ]
    sorted_headers = sorted(headers, key=len, reverse=True)
    first_pos = -1
    for h in sorted_headers:
        match = re.search(r'\b' + re.escape(h) + r'\b', cleaned_text, flags=re.IGNORECASE)
        if match:
            if first_pos == -1 or match.start() < first_pos:
                first_pos = match.start()
    if first_pos >= 0:
        cleaned_text = cleaned_text[first_pos:].strip()
    return cleaned_text

A continuación se explica cómo encaja cada función en el proceso:

  • sections_for_format() función: Esta función genera encabezados de sección adaptados al formato de informe seleccionado (por ejemplo, ejecutivo, detallado, académico). Esto garantiza que cada informe cumpla con los estándares profesionales y satisfaga las expectativas de los usuarios.
  • extract_final_block() función: Este paso de posprocesamiento aísla el contenido principal del informe. Extrae el texto entre las etiquetas « » y elimina los preámbulos, las frases de relleno y los artefactos de marcado. También detecta el encabezado estándar más temprano (por ejemplo, «INTRODUCCIÓN», «RESUMEN») para eliminar el texto introductorio irrelevante, lo que garantiza que el resultado final sea limpio, estructurado y listo para su uso.

Estas funciones auxiliares son fundamentales para mantener una salida coherente y de alta calidad en diferentes formatos de informes y escenarios de investigación para un modelo de pensamiento como Jan-v1.

Paso 3: Configuración de los ajustes

Establezcamos el sistema de configuración básico que gestiona los parámetros del modelo, los ajustes de la API y las preferencias de investigación. Este enfoque modular garantiza una fácil personalización y un rendimiento óptimo.

Paso 3.1: Configuración de la investigación

Este paso define un sistema de configuración y un cargador de modelos para una inferencia local eficiente con el modelo Jan-v1. El sistema está diseñado para admitir tareas de investigación reproducibles en entornos que solo utilizan CPU, como ordenadores portátiles o Colab Pro, al tiempo que mantiene la flexibilidad y la seguridad.

@dataclass
class ResearchConfig:
    model_path: str = "models/Jan-v1-4B-Q4_K_M.gguf" #change as per your location
    max_tokens: int = 2048
    temperature: float = 0.6
    top_p: float = 0.95
    top_k: int = 20
    context_length: int = 4096
    search_api_key: str = os.getenv("SERPER_API_KEY", "")
    search_engine: str = "serper"  

A continuación se ofrece una descripción general de la configuración del código anterior:

  • Parámetros centralizados: ResearchConfig es un panel de control ( @dataclass ) que centraliza todas las configuraciones de LLM y del motor de búsqueda, lo que permite un fácil ajuste para diferentes escenarios de investigación.
  • Hiperparámetros de inferencia: Parámetros como « temperature » (creatividad), « top_p » (conocimiento) y « top_k » (conocimiento) se establecen para equilibrar la creatividad con la base factual, lo cual es importante para los resultados orientados a la investigación.
  • Memoria y contexto: El tamaño máximo de la pila ( context_length ) está establecido en 4096 tokens, lo que está optimizado para las capacidades de razonamiento de formato largo de Jan-v1.
  • Integración API: search_api_key permite la integración con Serper para mejorar las búsquedas web en tiempo real.

Paso 3.2: Asistente de investigación profunda 

En este paso, definimos una clase Deep Research assistant que actúa como controlador central de todas las tareas de investigación, abstrayendo el modelo de bajo nivel y la gestión de la configuración, al tiempo que expone interfaces de alto nivel para la generación, la búsqueda y la síntesis.

class DeepResearchAssistant:
    def __init__(self, config: ResearchConfig):
        self.config = config
        self.llm = None
        self.demo_mode = False
    def load_model(self):
        try:
            if not os.path.exists(self.config.model_path):
                print(f"Model file not found: {self.config.model_path}")
                return False
            file_size_gb = os.path.getsize(self.config.model_path) / (1024**3)
            if file_size_gb < 1.0:
                print(f"Model file too small ({file_size_gb:.1f} GB).")
                return False
            self.llm = Llama(
                model_path=self.config.model_path,
                n_ctx=self.config.context_length,
                verbose=False,
                n_threads=max(1, min(4, os.cpu_count() // 2)),
                n_gpu_layers=0,
                use_mmap=True,
                use_mlock=False,
                n_batch=128,
                f16_kv=True,
            )
            test = self.llm("Hi", max_tokens=3, temperature=0.1, echo=False)
            ok = bool(test and 'choices' in test)
            print("Model loaded " if ok else "Model loaded but test generation failed ")
            return ok
        except Exception as e:
            print(f"Model loading failed: {e}")
            return False

La clase DeepResearchAssistant es el principal coordinador que gestiona la carga de modelos, la validación de la configuración y proporciona una interfaz limpia para las operaciones de investigación. Este sistema de configuración proporciona gestión de errores y validación, lo que garantiza que el modelo se cargue correctamente y esté listo para las tareas de investigación. Estas son las características principales de esta clase:

  • Inicializar modelo: El método « load_model() » inicializa de forma segura el modelo Jan-v1 GGUF utilizando « llama-cpp-python », optimizado para la inferencia de la CPU local.
  • Comprobaciones de validación: En primer lugar, verificamos la ruta del modelo y el tamaño mínimo del archivo para detectar archivos que faltan o están dañados.
  • Mapeo de memoria: A continuación, utilizamos use_mmap=True para habilitar una carga eficiente respaldada por disco sin consumir toda la RAM.
  • Inferencia optimizada: También configuramos subprocesos, tamaño de lote y habilitamos la optimización de memoria ( f16_kv=True ) para reducir el uso de memoria. El parámetro « n_gpu_layers=0 » garantiza la ejecución solo en la CPU.
  • Prueba de cordura: Realizamos una prueba de integridad que envía un mensaje ligero después de la carga para confirmar que el modelo responde correctamente.

Esta configuración garantiza una inferencia local rápida y ligera, ideal para ejecutar Jan-v1 en ordenadores portátiles o Colab sin GPU.

Paso 3.3: Generar una respuesta

A continuación, implementaremos el sistema central de generación de respuestas junto con las capacidades de búsqueda web que impulsan nuestra automatización de la investigación. Para ello, utilizamos los servicios de la API de Serper, tal y como se muestra a continuación:

def generate_response(self, prompt: str, max_tokens: int = None, extra_stops: Optional[List[str]] = None) -> str:
        if not self.llm:
            return "Model not loaded."
        stops = ["</s>", "<|im_end|>", "<|endoftext|>"]
        if extra_stops:
            stops.extend(extra_stops)
        mt = max_tokens or self.config.max_tokens
        try:
            resp = self.llm(
                prompt,
                max_tokens=mt,
                temperature=self.config.temperature,
                top_p=self.config.top_p,
                top_k=self.config.top_k,
                stop=stops,
                echo=False
            )
            return resp["choices"][0]["text"].strip()
        except Exception as e:
            return f"Error generating response: {str(e)}"
    async def search_web(self, query: str, num_results: int = 10) -> List[Dict]:
        if self.config.search_api_key:
            return await self.search_serper(query, num_results)
        return []
    async def search_serper(self, query: str, num_results: int) -> List[Dict]:
        url = "https://google.serper.dev/search"
        payload = {"q": query, "num": num_results}
        headers = {"X-API-KEY": self.config.search_api_key, "Content-Type": "application/json"}
        async with aiohttp.ClientSession() as session:
            async with session.post(url, json=payload, headers=headers) as response:
                data = await response.json()
                results = []
                for item in data.get('organic', []):
                    results.append({
                        'title': item.get('title', ''),
                        'url': item.get('link', ''),
                        'snippet': item.get('snippet', ''),
                        'source': 'web'
                    })
                return results
    def generate_search_queries(self, topic: str, focus_area: str, depth: str) -> List[str]:
        counts = {'surface': 5, 'moderate': 8, 'deep': 15, 'comprehensive': 25}
        n = counts.get(depth, 8)
        base = [
            f"{topic} overview",
            f"{topic} recent developments",
            f"{topic} academic studies",
            f"{topic} case studies",
            f"{topic} policy and regulation",
            f"{topic} technical approaches",
            f"{topic} market analysis",
            f"{topic} statistics and data",
        ]
        return base[:n]

El código anterior desglosa la funcionalidad principal de la siguiente manera:

  • generate_response() función: Esta función gestiona todas las interacciones del modelo Jan-v1 con un manejo adecuado de los errores y secuencias de parada configurables. Esto garantiza una generación de texto coherente y de alta calidad para la síntesis de investigaciones.
  • search_web() y las funciones search_serper(): Estas funciones implementan búsquedas web asíncronas mediante la API Serper, lo que permite realizar búsquedas rápidas y paralelas en varias consultas. El diseño asíncrono evita que la interfaz de usuario se bloquee durante las operaciones de investigación.
  • generate_search_queries() función: Para crear consultas de búsqueda diversas basadas en la profundidad de la investigación y el tema central, implementamos la función « generate_search_queries() » (Búsqueda avanzada). Garantiza una cobertura exhaustiva del tema de investigación, desde descripciones generales y enfoques técnicos hasta casos prácticos, normativas y análisis de mercado. Permite al usuario escalar el número de consultas de 5 a 25 en función de la profundidad elegida (superficial, moderada, profunda o exhaustiva).

Este sistema de generación de respuestas constituye el núcleo de nuestra automatización de la investigación, ya que combina las capacidades de razonamiento de Jan-v1 con la búsqueda web en tiempo real para crear informes de investigación.

Paso 3.4: Sintetizar la investigación

A continuación, implementaremos un motor de síntesis de investigación que transforma los resultados de búsqueda sin procesar en informes pulidos y profesionales.

def synthesize_research(self, topic: str, search_results: List[Dict], focus_area: str, report_format: str) -> str:
        context_lines = []
        for i, result in enumerate(search_results[:20]):
            title = result.get("title", "")
            snippet = result.get("snippet", "")
            context_lines.append(f"Source {i+1} Title: {title}\nSource {i+1} Summary: {snippet}")
        context = "\n".join(context_lines)
        sections = sections_for_format(report_format)
        sections_text = "\n".join(sections)
        synthesis_prompt = f"""
You are an expert research analyst. Write the final, polished report on: "{topic}" for a professional, real-world audience.
***CRITICAL INSTRUCTIONS:***
- Your entire response MUST be the final report, wrapped **EXACTLY** inside <final> and </final> tags.
- DO NOT output any text, thoughts, or commentary BEFORE the <final> tag or AFTER the </final> tag.
- DO NOT include any conversational filler, internal thoughts, or commentary about the generation process (e.g., "As an AI...", "I will now summarize...", "Here is your report:").
- DO NOT use markdown formatting (e.g., #, ##, *, -).
- DO NOT use bullet points or lists.
- Maintain a formal, academic/professional tone throughout.
- Ensure the report is complete and self-contained.
- Include the following section headers, in this order, and no others:
{sections_text}
Guidance:
- Base your writing strictly on the Research Notes provided below. If the notes lack specific data, write a careful, methodology-forward analysis without inventing facts or numbers.
Research Notes:
{context}
Now produce ONLY the final report:
<final>
...your report here...
</final>
"""
        raw = self.generate_response(synthesis_prompt, max_tokens=1800, extra_stops=["</final>"])
        final_report = extract_final_block(raw)
        final_report = re.sub(r"(?m)^\s*[-*•]\s+", "", final_report)
        final_report = re.sub(r"[#`*_]{1,3}", "", final_report)
        first = next((h for h in sections if h in final_report), None)
        if first:
            final_report = final_report[final_report.find(first):].strip()
        return final_report

El código anterior aprovecha las capacidades avanzadas de razonamiento de Jan-v1 para transformar los resultados sin procesar de una búsqueda web en informes profesionales que normalmente requerirían horas de investigación y redacción manuales. Veamos en detalle las capacidades clave:

  • Incrustación contextual: El código anterior transforma los resultados de búsqueda no estructurados en notas de investigación textuales estructuradas, concatenando títulos y resúmenes en un formato numerado. Esto garantiza una alta densidad de información y minimiza la fragmentación del contexto cuando se transfiere al modelo.
  • Construcción dinámica de mensajes: Mediante la función « sections_for_format() », generamos encabezados de sección del informe adaptados al formato de salida seleccionado, que se insertan en el mensaje con reglas de generación estrictas para limitar el comportamiento del modelo.
  • Mitigación de alucinaciones: Al imponer el uso de etiquetas de ... y prohibir los andamios conversacionales, se evita que el modelo introduzca texto irrelevante, resúmenes especulativos o enmarcamientos redundantes.
  • Postprocesamiento y normalización: Después de la decodificación, el informe se limpia con filtros de regex para eliminar artefactos de marcado, marcadores de lista y formateo erróneo. La función también garantiza que la salida comience desde el primer encabezado de sección válido para mejorar la coherencia estructural.

Paso 4: Flujo principal de la aplicación Streamlit

Por último, crearemos la interfaz de usuario completa que reunirá todas nuestras capacidades de investigación en una aplicación interactiva.

def main():
    st.set_page_config(page_title="Deep Research Assistant", page_icon="", layout="wide")
    st.markdown("""
    <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 1.25rem; border-radius: 10px; color: white; text-align: center; margin-bottom: 1rem;">
        <h1 style="margin:0;"> Deep Research Assistant</h1>
    </div>
    """, unsafe_allow_html=True)
    if 'research_assistant' not in st.session_state:
        config = ResearchConfig()
        st.session_state.research_assistant = DeepResearchAssistant(config)
        st.session_state.model_loaded = st.session_state.research_assistant.load_model()
        st.session_state.research_results = None
    if not st.session_state.research_assistant.config.search_api_key:
        st.warning("SERPER_API_KEY not found in environment. Using fallback demo results.")
    st.header("Research Configuration")
    research_topic = st.text_area(
        "Research Topic",
        placeholder="e.g., Impact of artificial intelligence on healthcare efficiency and patient outcomes",
        height=100
    )
    col1a, col1b = st.columns(2)
    with col1a:
        research_depth = st.selectbox(
            "Research Depth",
            ["surface", "moderate", "deep", "comprehensive"],
            index=1,
            format_func=lambda x: {
                "surface": "Surface (5-8 sources)",
                "moderate": "Moderate (10-15)",
                "deep": "Deep Dive (20-30)",
                "comprehensive": "Comprehensive (40+)"
            }[x]
        )
        focus_area = st.selectbox("Focus Area", ["general", "academic", "business", "technical", "policy"], index=0, format_func=str.title)
    with col1b:
        time_frame = st.selectbox(
            "Time Frame",
            ["current", "recent", "comprehensive"],
            index=1,
            format_func=lambda x: {"current":"Current (≤6 months)","recent":"Recent (≤2 years)","comprehensive":"All time"}[x]
        )
        report_format = st.selectbox(
            "Report Format",
            ["executive", "detailed", "academic", "presentation"],
            index=1,
            format_func=lambda x: {
                "executive":"Executive Summary",
                "detailed":"Detailed Analysis",
                "academic":"Academic Style",
                "presentation":"Presentation Format"
            }[x]
        )
    if st.button("Start Deep Research", type="primary", use_container_width=True):
        if not st.session_state.model_loaded:
            st.error("Model not loaded. See terminal logs for details.")
        elif not research_topic.strip():
            st.error("Please enter a research topic.")
        else:
            start_research(research_topic, research_depth, focus_area, time_frame, report_format)
    if st.session_state.research_results:
        display_research_results(st.session_state.research_results)
def start_research(topic: str, depth: str, focus: str, timeframe: str, format_type: str):
    assistant = st.session_state.research_assistant
    progress_bar = st.progress(0)
    status_text = st.empty()
    try:
        status_text.text("Generating search queries...")
        progress_bar.progress(15)
        queries = assistant.generate_search_queries(topic, focus, depth)
        status_text.text("Searching sources...")
        progress_bar.progress(40)
        all_results = []
        for i, query in enumerate(queries):
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            results = loop.run_until_complete(assistant.search_web(query, 5))
            all_results.extend(results)
            loop.close()
            progress_bar.progress(40 + int(((i + 1) / max(1, len(queries))) * 30))
            time.sleep(0.05)
        status_text.text("Synthesizing report...")
        progress_bar.progress(80)
        research_report = assistant.synthesize_research(topic, all_results, focus, format_type)
        status_text.text("Done.")
        progress_bar.progress(100)
        st.session_state.research_results = {
            'topic': topic,
            'report': research_report,
            'sources': all_results,
            'queries': queries,
            'config': {'depth': depth, 'focus': focus, 'timeframe': timeframe, 'format': format_type},
            'timestamp': datetime.now()
        }
        time.sleep(0.3)
        status_text.empty()
        progress_bar.empty()
    except Exception as e:
        st.error(f"Research failed: {str(e)}")
        status_text.empty()
        progress_bar.empty()
def display_research_results(results: Dict):
    st.header("Research Report")
    st.subheader(f"Topic: {results['topic']}")
    st.markdown(
        f'<div style="background:#f8f9ff;padding:1rem;border-radius:10px;border:1px solid #e1e8ed;">{results["report"]}</div>',
        unsafe_allow_html=True,
    )
    with st.expander("Sources", expanded=False):
        for i, source in enumerate(results['sources'][:12]):
            st.markdown(f"""
            <div style="background:#fff;padding:0.75rem;border-radius:8px;border:1px solid #e1e8ed;margin:0.4rem 0;">
                <h4 style="margin:0 0 .25rem 0;">{source['title']}</h4>
                <p style="margin:0 0 .25rem 0;">{source['snippet']}</p>
                <small><a href="{source['url']}" target="_blank">{source['url']}</a></small>
            </div>
            """, unsafe_allow_html=True)
    st.markdown("### Export")
    c1, c2, c3 = st.columns(3)
    with c1:
        report_text = f"Research Report: {results['topic']}\n\n{results['report']}"
        st.download_button("Download Text", data=report_text, file_name=f"research_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt", mime="text/plain")
    with c2:
        json_data = json.dumps(results, default=str, indent=2)
        st.download_button("Download JSON", data=json_data, file_name=f"research_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", mime="application/json")
    with c3:
        if st.button("Start New Research"):
            st.session_state.research_results = None
            st.experimental_rerun()
if __name__ == "__main__":
    main()

El código anterior se divide en capas, desde la carga del modelo y la recopilación de datos del usuario hasta la generación de consultas, la búsqueda web y la síntesis del informe final. Analicemos estas capas en detalle:

  • Capa de interfaz de usuario (frontend Streamlit): La aplicación cuenta con un encabezado con estilo degradado y un diseño adaptable para ofrecer una experiencia de usuario impecable. La interfaz sigue siendo intuitiva y ofrece un control preciso de los parámetros de búsqueda, lo que la hace ideal tanto para usuarios técnicos como no técnicos.
  • Pipeline configurable: Los usuarios pueden personalizar el flujo de trabajo de investigación con selectores de profundidad, área de interés (general, académica, empresarial), periodo de tiempo y estilo de resultado (ejecutivo, académico, etc.).
  • Gestión de agentes con estado: El objeto de caché de modelo ( DeepResearchAssistant ) se inicializa una vez por sesión mediante st.session_state, lo que conserva el estado del modelo y evita que se cargue repetidamente. 
  • Comentarios en tiempo real y búsqueda asíncrona: El progreso se supervisa con barras de progreso dinámicas de Streamlit y actualizaciones de estado. La búsqueda web se ejecuta de forma asíncrona a través de asyncio, lo que garantiza la ejecución paralela de las consultas sin bloquear la capacidad de respuesta de la interfaz de usuario.
  • Bucle de consulta y síntesis: Las consultas de búsqueda se generan automáticamente en función del tema y la profundidad utilizando una estrategia de ingeniería de indicaciones. Los resultados obtenidos se agregan y se envían al modelo Jan-v1 para generar un informe estructurado.
  • Visualización y exportación de resultados: El informe final se presenta en un bloque Markdown con citas ampliables. Los usuarios pueden exportar el informe en formato TXT o JSON, o volver a ejecutar el flujo de trabajo con un solo clic.

Para probarlo tú mismo, guarda el código como app.py y ejecútalo:

streamlit run app.py

Conclusión

Este asistente de investigación profunda demuestra el poder práctico de las capacidades avanzadas de razonamiento de Jan-v1 para automatizar flujos de trabajo de investigación complejos. El sistema combina con éxito:

  • Automatización inteligente: Permite realizar investigaciones integrales, desde la generación de consultas hasta la síntesis de informes profesionales, lo que elimina horas de trabajo manual.
  • Diseño escalable: La función de profundidad de investigación configurable se adapta desde resúmenes rápidos hasta análisis exhaustivos en función de las necesidades de los usuarios.
  • de calidad profesional: Ayuda a generar informes adecuados para reuniones ejecutivas, investigaciones académicas y documentación técnica.
  • Accesibilidad del usuario: Esta interfaz pone a disposición de los usuarios, independientemente de sus conocimientos técnicos, funciones avanzadas de investigación en IA.

La aplicación muestra cómo la precisión del 91,1 % de SimpleQA de Jan-v1 y sus capacidades de razonamiento mejoradas pueden utilizarse para crear herramientas listas para la producción que aportan un valor inmediato en los flujos de trabajo de investigación, análisis y creación de contenidos.


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Soy una Google Developers Expert en ML(Gen AI), una Kaggle 3x Expert y una Women Techmakers Ambassador con más de 3 años de experiencia en tecnología. Cofundé una startup de tecnología sanitaria en 2020 y estoy cursando un máster en informática en Georgia Tech, especializándome en aprendizaje automático.

Temas

¡Aprende IA con estos cursos!

Curso

Modelos de IA escalables con PyTorch Lightning

3 h
365
Optimiza tus proyectos de IA creando modelos modulares y dominando la optimización avanzada con PyTorch Lightning.
Ver detallesRight Arrow
Comienza el curso
Ver másRight Arrow
Relacionado
An AI juggles tasks

blog

Cinco proyectos que puedes crear con modelos de IA generativa (con ejemplos)

Aprende a utilizar modelos de IA generativa para crear un editor de imágenes, un chatbot similar a ChatGPT con pocos recursos y una aplicación clasificadora de aprobación de préstamos y a automatizar interacciones PDF y un asistente de voz con GPT.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

7 proyectos de IA para todos los niveles

Desarrolla tu portafolio y mejora tus habilidades para crear soluciones innovadoras a problemas complejos trabajando en proyectos de IA.
Abid Ali Awan's photo

Abid Ali Awan

8 min

Tutorial

Tutorial de la API de OpenAI Assistants

Una visión completa de la API Assistants con nuestro artículo, que ofrece una mirada en profundidad a sus características, usos en la industria, guía de configuración y las mejores prácticas para maximizar su potencial en diversas aplicaciones empresariales.
Zoumana Keita 's photo

Zoumana Keita

Tutorial

Guía para principiantes de la API de OpenAI: Tutorial práctico y prácticas recomendadas

Este tutorial te presenta la API de OpenAI, sus casos de uso, un enfoque práctico para utilizar la API y todas las prácticas recomendadas que debes seguir.
Arunn Thevapalan's photo

Arunn Thevapalan

Tutorial

Tutorial sobre cómo crear aplicaciones LLM con LangChain

Explore el potencial sin explotar de los grandes modelos lingüísticos con LangChain, un marco Python de código abierto para crear aplicaciones avanzadas de IA.
Moez Ali's photo

Moez Ali

Tutorial

Cómo ejecutar Stable Diffusion:

Explora la IA generativa con nuestro tutorial introductorio sobre Stable Diffusion. Aprende a ejecutar el modelo de aprendizaje profundo en línea y localmente para generar imágenes detalladas.
Kurtis Pykes 's photo

Kurtis Pykes

Ver másVer más