Impara a creare un Deep Research Assistant usando le capacità di ragionamento agentico di Jan-v1, inclusi deployment locale, sviluppo di un'app Streamlit e altro ancora.
Il team di Jan ha rilasciato di recente Jan-v1, un avanzato modello di ragionamento agentico che introduce sofisticate capacità di automazione della ricerca grazie a un uso migliorato degli strumenti e alla risoluzione di problemi in più passaggi.
In questo tutorial mi concentrerò sulle peculiari capacità di ragionamento agentico di Jan-v1, mostrando come possa gestire un workflow di ricerca complesso tramite un'interfaccia Streamlit eseguita in locale e basata su llama.cpp.
In questo tutorial ti spiegherò come:
Eseguire Jan-v1 in locale con quantizzazione GGUF per prestazioni e privacy ottimali
Creare un'app Streamlit per la ricerca automatizzata con tracciamento in tempo reale dell'avanzamento
Implementare un'integrazione intelligente della ricerca web con generazione dinamica delle query
Creare una sintesi in formato report professionale con strutturazione dell'output specifica per il formato
Applicare un'elaborazione testuale avanzata per garantire documentazione pulita e pronta per il business
Alla fine, la tua app apparirà così:
Che cos'è Jan-v1?
Jan-v1 è un modello da 4 miliardi di parametri, costruito sulle fondamenta di Lucy e Qwen3-4B-thinking, progettato per workflow agentici come l'uso di tool, il ragionamento multi-step e la ricerca automatizzata. A differenza degli LLM convenzionali, Jan-v1 eccelle nel coordinare strumenti, fonti dati e passaggi di ragionamento tramite uno scaffolding strutturato e ricompense allineate al comportamento.
Ecco alcune caratteristiche chiave di questo modello:
Architettura agent-ready: Il modello è ottimizzato per l'integrazione nel mondo reale e gestisce ricerca web, sintesi e generazione di report strutturati usando ragionamento avanzato e API di tool.
Efficienza: Nonostante le dimensioni ridotte, Jan-v1 offre prestazioni tipiche di modelli molto più grandi, grazie a un addestramento RL mirato che enfatizza output focalizzati e orientati all'obiettivo.
Deployment privacy-first: Il formato GGUF compatto abilita un'inferenza rapida in locale, ideale per attività di ricerca a bassa latenza e in privacy su laptop o CPU.
Training ottimizzato per la ricerca: Jan-v1 usa funzioni di ricompensa innovative che bilanciano informatività e sintesi, cruciali per compiti ad alto impatto come analisi e reportistica, riducendo al minimo allucinazioni e verbosità.
Basato su Qwen3-4B-thinking: Il modello eredita un robusto chain-of-thought e controllo degli strumenti dalla fusione in modalità "thinking" di Qwen3, risultando particolarmente efficace per pipeline di automazione della ricerca.
Configurare Jan-v1 in locale
Per questo progetto, eseguiremo Jan-v1 in locale usando Llama.cpp con la versione quantizzata GGUF per prestazioni ottimali ed efficienza delle risorse.
Passo 1: Installa le dipendenze
Per prima cosa, assicurati di avere i pacchetti Python richiesti:
pip install llama-cpp-python==0.3.15
pip install streamlit aiohttp Offerto da
Questo comando installa tutte le dipendenze principali necessarie per l'integrazione del modello AI, la creazione dell'interfaccia web e le operazioni web asincrone.
Passo 2: Scarica la versione GGUF di Jan-v1
Prima di scaricare il modello, crea una nuova directory chiamata models/ con il seguente 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.ggufOfferto da
Completando questo passaggio, hai scaricato correttamente il modello Jan-v1 4B in formato GGUF e lo hai collocato nella directory models/. Questa versione quantizzata offre un buon compromesso tra prestazioni ed efficienza della memoria, rendendola ideale per l'inferenza locale su CPU o Colab.
Passo 3: Configura la chiave API di Serper
Registrati o accedi al tuo account Serper: https://serper.dev/api-keys e seleziona la scheda API Keys, quindi copia la chiave API predefinita per questa demo. Impostiamo ora questa chiave come variabile d'ambiente come segue:
exportSERPER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxOfferto da
Ora sei pronto per caricare e interagire con il modello nella tua pipeline di assistente alla ricerca.
Demo: Deep Research Assistant con Jan-v1
Costruiamo un'applicazione Streamlit che mostri le avanzate capacità di ricerca di Jan-v1, con generazione intelligente delle query, ricerca web automatizzata (usando Serper) e sintesi professionale del report.
Passo 1: Importa le librerie
Iniziamo importando tutte le librerie necessarie per il nostro assistente alla ricerca. Supportano tutto, dalla creazione dell'interfaccia web alla ricerca web asincrona e all'integrazione del modello AI locale.
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 dataclassOfferto da
Importiamo tutte le librerie principali usate nell'app. Includono componenti UI (Streamlit), strumenti di concorrenza (asyncio, aiohttp) e il backend LLM (llama_cpp). Aggiungiamo anche utility per parsing, typing e gestione delle date.
Passo 2: Funzioni helper
Ora implementeremo alcune funzioni di supporto che gestiscono il formato del report e l'estrazione dei contenuti. Queste funzioni garantiscono che i report generati mantengano qualità professionale e una struttura coerente.
defsections_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"]defextract_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 preamblesr"^(?: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 =-1for h in sorted_headers:match= re.search(r'\b'+ re.escape(h)+r'\b', cleaned_text, flags=re.IGNORECASE)ifmatch:if first_pos ==-1ormatch.start()< first_pos:
first_pos =match.start()if first_pos >=0:
cleaned_text = cleaned_text[first_pos:].strip()return cleaned_textOfferto da
Ecco come ogni funzione si inserisce nella pipeline:
sections_for_format() function: questa funzione genera intestazioni di sezione su misura per il formato del report selezionato (ad es. executive, detailed, academic). Così ogni report rispetta standard professionali e soddisfa le aspettative dell'utente.
extract_final_block() function: questo passaggio di post-processing isola il contenuto centrale del report. Estrae il testo tra i tag <final> e rimuove preamboli, frasi di riempimento e artefatti markdown. Rileva anche la prima intestazione standard (ad es. "INTRODUCTION", "SUMMARY") per eliminare testo introduttivo non pertinente, assicurando che l'output finale sia pulito, strutturato e pronto all'uso.
Queste funzioni di supporto sono fondamentali per mantenere output coerenti e di alta qualità tra diversi formati di report e scenari di ricerca per un modello "pensante" come Jan-v1.
Passo 3: Configurare le impostazioni
Definiamo ora il sistema di configurazione principale che gestisce i parametri del modello, le impostazioni delle API e le preferenze di ricerca. Questo approccio modulare garantisce personalizzazione facile e prestazioni ottimali.
Passo 3.1: Configurazione della ricerca
Questo passaggio definisce un sistema di configurazione e un caricatore di modelli per un'inferenza locale efficiente con il modello Jan-v1. Il sistema è progettato per supportare attività di ricerca riproducibili in ambienti solo CPU, come laptop o Colab Pro, mantenendo flessibilità e sicurezza.
@dataclassclassResearchConfig:
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"Offerto da
Ecco una panoramica della configurazione del codice sopra:
Parametri centralizzati: ResearchConfig è una @dataclass che centralizza tutte le configurazioni dell'LLM e del motore di ricerca, consentendo un tuning semplice per scenari di ricerca diversi.
Iperparametri di inferenza: Parametri come temperature, top_p e top_k sono impostati per bilanciare creatività e aderenza ai fatti, importante per output orientati alla ricerca.
Memoria e contesto: context_length è impostato a 4096 token, ottimizzato per le capacità di ragionamento long-form di Jan-v1.
Integrazione API: search_api_key abilita l'integrazione con Serper per un arricchimento della ricerca web in tempo reale.
Passo 3.2: Deep Research assistant
In questo passaggio definiamo una classe Deep Research assistant che funge da controller principale per tutte le attività di ricerca, astraendo la gestione di basso livello di modello e configurazioni ed esponendo interfacce di alto livello per generazione, ricerca e sintesi.
classDeepResearchAssistant:def__init__(self, config: ResearchConfig):
self.config = config
self.llm =None
self.demo_mode =Falsedefload_model(self):try:ifnot os.path.exists(self.config.model_path):print(f"Model file not found: {self.config.model_path}")returnFalse
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).")returnFalse
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}")returnFalseOfferto da
DeepResearchAssistant è l'orchestratore principale che gestisce il caricamento del modello, la validazione della configurazione e fornisce un'interfaccia pulita per le operazioni di ricerca. Questo sistema di configurazione include gestione degli errori e validazioni, assicurando che il modello venga caricato correttamente e sia pronto per i compiti di ricerca. Ecco le caratteristiche chiave della classe:
Inizializzazione del modello: il metodo load_model() inizializza in sicurezza il modello GGUF di Jan-v1 usando llama-cpp-python, ottimizzato per l'inferenza su CPU locale.
Controlli di validazione: verifichiamo anzitutto il percorso del modello e la dimensione minima del file per intercettare file mancanti o corrotti.
Memory mapping: usiamo use_mmap=True per abilitare un caricamento efficiente basato su disco senza consumare tutta la RAM.
Inferenza ottimizzata: configuriamo anche thread, dimensione batch e abilitiamo f16_kv=True per ridurre l'uso di memoria. Il parametro n_gpu_layers=0 garantisce l'esecuzione solo su CPU.
Sanity test: eseguiamo un test leggero inviando un prompt dopo il caricamento per confermare che il modello risponda correttamente.
Questa configurazione garantisce un'inferenza locale rapida e leggera, ideale per eseguire Jan-v1 su laptop o Colab senza GPU.
Passo 3.3: Generare una risposta
Successivamente, implementeremo il sistema centrale di generazione delle risposte insieme alle capacità di ricerca web che alimentano la nostra automazione della ricerca. Per questo usiamo i servizi API di Serper come mostrato di seguito:
defgenerate_response(self, prompt:str, max_tokens:int=None, extra_stops: Optional[List[str]]=None)->str:ifnot 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:returnf"Error generating response: {str(e)}"asyncdefsearch_web(self, query:str, num_results:int=10)-> List[Dict]:if self.config.search_api_key:returnawait self.search_serper(query, num_results)return[]asyncdefsearch_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"}asyncwith aiohttp.ClientSession()as session:asyncwith 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
defgenerate_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]Offerto da
Il codice sopra scompone la funzionalità principale come segue:
generate_response() function: questa funzione gestisce tutte le interazioni con il modello Jan-v1 con corretta gestione degli errori e sequenze di stop configurabili. Garantisce generazione di testo coerente e di alta qualità per la sintesi della ricerca.
search_web() e search_serper() functions: queste funzioni implementano la ricerca web asincrona usando l'API Serper, permettendo ricerche veloci e in parallelo su più query. Il design async evita blocchi dell'interfaccia durante le operazioni di ricerca.
generate_search_queries() function: per creare query di ricerca diversificate in base alla profondità della ricerca e al topic di interesse, implementiamo la funzione generate_search_queries(). Garantisce copertura completa del soggetto, dagli overview e approcci tecnici ai case study, regolamentazione e analisi di mercato. Consente di scalare il numero di query da 5 a 25 a seconda della profondità scelta (surface, moderate, deep o comprehensive).
Questo sistema di generazione delle risposte costituisce il nucleo della nostra automazione della ricerca, combinando le capacità di ragionamento di Jan-v1 con la ricerca web in tempo reale per creare report di ricerca.
Passo 3.4: Sintetizzare la ricerca
Implementeremo ora un motore di sintesi della ricerca che trasforma i risultati grezzi in report rifiniti e professionali.
defsynthesize_research(self, topic:str, search_results: List[Dict], focus_area:str, report_format:str)->str:
context_lines =[]for i, result inenumerate(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_reportOfferto da
Il codice sopra sfrutta le avanzate capacità di ragionamento di Jan-v1 per trasformare risultati di ricerca web grezzi in report professionali che normalmente richiederebbero ore di ricerca e scrittura manuale. Vediamo nel dettaglio le funzionalità chiave:
Incorporamento contestuale: il codice trasforma i risultati non strutturati in note di ricerca testuali strutturate concatenando titoli e sommari in formato numerato. Questo assicura alta densità informativa e riduce la frammentazione del contesto quando passato al modello.
Costruzione dinamica del prompt: usando la funzione sections_for_format() generiamo le intestazioni di sezione del report in base al formato selezionato, inserendole nel prompt con regole di generazione rigide per vincolare il comportamento del modello.
Riduzione delle allucinazioni: imponendo l'uso dei tag <final>...</final> e vietando impalcature conversazionali, si impedisce al modello di introdurre testo irrilevante, sintesi speculative o inquadramenti ridondanti.
Post-processing e normalizzazione: dopo il decoding, il report viene ripulito con filtri regex per rimuovere artefatti markdown, marcatori di lista e formattazioni spurie. La funzione assicura inoltre che l'output inizi dalla prima intestazione valida per migliorare la coerenza strutturale.
Passo 4: Flusso principale dell'app Streamlit
Infine, costruiremo l'interfaccia utente completa che riunisce tutte le nostre capacità di ricerca in un'applicazione interattiva.
Il codice sopra è suddiviso in livelli, dal caricamento del modello e raccolta degli input utente alla generazione delle query, ricerca web e sintesi del report finale. Analizziamo questi livelli nel dettaglio:
Livello UI (frontend Streamlit): l'app presenta un'intestazione con gradiente e un layout responsivo per un'esperienza utente curata. L'interfaccia resta intuitiva pur offrendo controllo granulare sui parametri di ricerca, risultando adatta sia a utenti tecnici sia non tecnici.
Pipeline configurabile: gli utenti possono personalizzare il workflow di ricerca con selettori per profondità, area di focus (general, academic, business), finestra temporale e stile di output (executive, academic, ecc.).
Gestione stateful dell'agente: DeepResearchAssistant viene inizializzato una sola volta per sessione usando st.session_state, preservando lo stato del modello ed evitando ricaricamenti ripetuti.
Feedback in tempo reale e ricerca asincrona: l'avanzamento è tracciato con barre di progresso dinamiche di Streamlit e aggiornamenti di stato. La ricerca web è eseguita in modo asincrono tramite asyncio, garantendo esecuzione parallela delle query senza bloccare la reattività della UI.
Ciclo di query e sintesi: le query di ricerca sono generate automaticamente in base a topic e profondità tramite una strategia di prompt engineering. I risultati recuperati sono aggregati e passati al modello Jan-v1 per la generazione di un report strutturato.
Visualizzazione ed export dell'output: il report finale è renderizzato in un blocco Markdown con citazioni espandibili. Gli utenti possono esportare il report in formato TXT o JSON o rieseguire il workflow con un clic.
Questo Deep Research Assistant dimostra la potenza pratica delle capacità avanzate di ragionamento di Jan-v1 nell'automazione di workflow di ricerca complessi. Il sistema combina con successo:
Automazione intelligente: consente una ricerca end-to-end, dalla generazione delle query alla sintesi del report professionale, eliminando ore di lavoro manuale.
Design scalabile: la funzione di profondità configurabile della ricerca si adatta da rapide panoramiche ad analisi complete in base alle esigenze dell'utente.
Qualità professionale: aiuta a generare report adatti a briefing esecutivi, ricerca accademica e documentazione tecnica.
Accessibilità per l'utente: questa interfaccia rende disponibili capacità avanzate di ricerca AI a utenti di ogni livello tecnico.
L'applicazione mostra come l'accuratezza SimpleQA del 91,1% di Jan-v1 e le sue capacità di ragionamento avanzate possano essere usate per costruire strumenti pronti per la produzione che portano valore immediato in workflow di ricerca, analisi e creazione di contenuti.
Sono una Google Developers Expert in ML (Gen AI), una Kaggle 3x Expert e una Women Techmakers Ambassador con oltre 3 anni di esperienza nel tech. Ho co-fondato una startup health-tech nel 2020 e sto conseguendo un master in informatica al Georgia Tech, con specializzazione in machine learning.
Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Il team di Jan ha rilasciato di recente Jan-v1, un avanzato modello di ragionamento agentico che introduce sofisticate capacità di automazione della ricerca grazie a un uso migliorato degli strumenti e alla risoluzione di problemi in più passaggi.
In questo tutorial mi concentrerò sulle peculiari capacità di ragionamento agentico di Jan-v1, mostrando come possa gestire un workflow di ricerca complesso tramite un'interfaccia Streamlit eseguita in locale e basata su llama.cpp.
In questo tutorial ti spiegherò come:
Alla fine, la tua app apparirà così:
Che cos'è Jan-v1?
Jan-v1 è un modello da 4 miliardi di parametri, costruito sulle fondamenta di Lucy e Qwen3-4B-thinking, progettato per workflow agentici come l'uso di tool, il ragionamento multi-step e la ricerca automatizzata. A differenza degli LLM convenzionali, Jan-v1 eccelle nel coordinare strumenti, fonti dati e passaggi di ragionamento tramite uno scaffolding strutturato e ricompense allineate al comportamento.
Ecco alcune caratteristiche chiave di questo modello:
Configurare Jan-v1 in locale
Per questo progetto, eseguiremo Jan-v1 in locale usando
Llama.cppcon la versione quantizzata GGUF per prestazioni ottimali ed efficienza delle risorse.Passo 1: Installa le dipendenze
Per prima cosa, assicurati di avere i pacchetti Python richiesti:
Questo comando installa tutte le dipendenze principali necessarie per l'integrazione del modello AI, la creazione dell'interfaccia web e le operazioni web asincrone.
Passo 2: Scarica la versione GGUF di Jan-v1
Prima di scaricare il modello, crea una nuova directory chiamata
models/con il seguente comando:Poi scarica il modello con il seguente comando:
Completando questo passaggio, hai scaricato correttamente il modello Jan-v1 4B in formato GGUF e lo hai collocato nella directory
models/. Questa versione quantizzata offre un buon compromesso tra prestazioni ed efficienza della memoria, rendendola ideale per l'inferenza locale su CPU o Colab.Passo 3: Configura la chiave API di Serper
Registrati o accedi al tuo account Serper: https://serper.dev/api-keys e seleziona la scheda API Keys, quindi copia la chiave API predefinita per questa demo. Impostiamo ora questa chiave come variabile d'ambiente come segue:
Ora sei pronto per caricare e interagire con il modello nella tua pipeline di assistente alla ricerca.
Demo: Deep Research Assistant con Jan-v1
Costruiamo un'applicazione Streamlit che mostri le avanzate capacità di ricerca di Jan-v1, con generazione intelligente delle query, ricerca web automatizzata (usando Serper) e sintesi professionale del report.
Passo 1: Importa le librerie
Iniziamo importando tutte le librerie necessarie per il nostro assistente alla ricerca. Supportano tutto, dalla creazione dell'interfaccia web alla ricerca web asincrona e all'integrazione del modello AI locale.
Importiamo tutte le librerie principali usate nell'app. Includono componenti UI (Streamlit), strumenti di concorrenza (asyncio, aiohttp) e il backend LLM (llama_cpp). Aggiungiamo anche utility per parsing, typing e gestione delle date.
Passo 2: Funzioni helper
Ora implementeremo alcune funzioni di supporto che gestiscono il formato del report e l'estrazione dei contenuti. Queste funzioni garantiscono che i report generati mantengano qualità professionale e una struttura coerente.
Ecco come ogni funzione si inserisce nella pipeline:
sections_for_format()function: questa funzione genera intestazioni di sezione su misura per il formato del report selezionato (ad es. executive, detailed, academic). Così ogni report rispetta standard professionali e soddisfa le aspettative dell'utente.extract_final_block()function: questo passaggio di post-processing isola il contenuto centrale del report. Estrae il testo tra i tag<final>e rimuove preamboli, frasi di riempimento e artefatti markdown. Rileva anche la prima intestazione standard (ad es. "INTRODUCTION", "SUMMARY") per eliminare testo introduttivo non pertinente, assicurando che l'output finale sia pulito, strutturato e pronto all'uso.Queste funzioni di supporto sono fondamentali per mantenere output coerenti e di alta qualità tra diversi formati di report e scenari di ricerca per un modello "pensante" come Jan-v1.
Passo 3: Configurare le impostazioni
Definiamo ora il sistema di configurazione principale che gestisce i parametri del modello, le impostazioni delle API e le preferenze di ricerca. Questo approccio modulare garantisce personalizzazione facile e prestazioni ottimali.
Passo 3.1: Configurazione della ricerca
Questo passaggio definisce un sistema di configurazione e un caricatore di modelli per un'inferenza locale efficiente con il modello Jan-v1. Il sistema è progettato per supportare attività di ricerca riproducibili in ambienti solo CPU, come laptop o Colab Pro, mantenendo flessibilità e sicurezza.
Ecco una panoramica della configurazione del codice sopra:
ResearchConfigè una@dataclassche centralizza tutte le configurazioni dell'LLM e del motore di ricerca, consentendo un tuning semplice per scenari di ricerca diversi.temperature,top_petop_ksono impostati per bilanciare creatività e aderenza ai fatti, importante per output orientati alla ricerca.context_lengthè impostato a 4096 token, ottimizzato per le capacità di ragionamento long-form di Jan-v1.search_api_keyabilita l'integrazione con Serper per un arricchimento della ricerca web in tempo reale.Passo 3.2: Deep Research assistant
In questo passaggio definiamo una classe Deep Research assistant che funge da controller principale per tutte le attività di ricerca, astraendo la gestione di basso livello di modello e configurazioni ed esponendo interfacce di alto livello per generazione, ricerca e sintesi.
DeepResearchAssistantè l'orchestratore principale che gestisce il caricamento del modello, la validazione della configurazione e fornisce un'interfaccia pulita per le operazioni di ricerca. Questo sistema di configurazione include gestione degli errori e validazioni, assicurando che il modello venga caricato correttamente e sia pronto per i compiti di ricerca. Ecco le caratteristiche chiave della classe:load_model()inizializza in sicurezza il modello GGUF di Jan-v1 usandollama-cpp-python, ottimizzato per l'inferenza su CPU locale.use_mmap=Trueper abilitare un caricamento efficiente basato su disco senza consumare tutta la RAM.f16_kv=Trueper ridurre l'uso di memoria. Il parametron_gpu_layers=0garantisce l'esecuzione solo su CPU.Questa configurazione garantisce un'inferenza locale rapida e leggera, ideale per eseguire Jan-v1 su laptop o Colab senza GPU.
Passo 3.3: Generare una risposta
Successivamente, implementeremo il sistema centrale di generazione delle risposte insieme alle capacità di ricerca web che alimentano la nostra automazione della ricerca. Per questo usiamo i servizi API di Serper come mostrato di seguito:
Il codice sopra scompone la funzionalità principale come segue:
generate_response()function: questa funzione gestisce tutte le interazioni con il modello Jan-v1 con corretta gestione degli errori e sequenze di stop configurabili. Garantisce generazione di testo coerente e di alta qualità per la sintesi della ricerca.search_web()esearch_serper()functions: queste funzioni implementano la ricerca web asincrona usando l'API Serper, permettendo ricerche veloci e in parallelo su più query. Il design async evita blocchi dell'interfaccia durante le operazioni di ricerca.generate_search_queries()function: per creare query di ricerca diversificate in base alla profondità della ricerca e al topic di interesse, implementiamo la funzionegenerate_search_queries(). Garantisce copertura completa del soggetto, dagli overview e approcci tecnici ai case study, regolamentazione e analisi di mercato. Consente di scalare il numero di query da 5 a 25 a seconda della profondità scelta (surface, moderate, deep o comprehensive).Questo sistema di generazione delle risposte costituisce il nucleo della nostra automazione della ricerca, combinando le capacità di ragionamento di Jan-v1 con la ricerca web in tempo reale per creare report di ricerca.
Passo 3.4: Sintetizzare la ricerca
Implementeremo ora un motore di sintesi della ricerca che trasforma i risultati grezzi in report rifiniti e professionali.
Il codice sopra sfrutta le avanzate capacità di ragionamento di Jan-v1 per trasformare risultati di ricerca web grezzi in report professionali che normalmente richiederebbero ore di ricerca e scrittura manuale. Vediamo nel dettaglio le funzionalità chiave:
sections_for_format()generiamo le intestazioni di sezione del report in base al formato selezionato, inserendole nel prompt con regole di generazione rigide per vincolare il comportamento del modello.<final>...</final>e vietando impalcature conversazionali, si impedisce al modello di introdurre testo irrilevante, sintesi speculative o inquadramenti ridondanti.regexper rimuovere artefatti markdown, marcatori di lista e formattazioni spurie. La funzione assicura inoltre che l'output inizi dalla prima intestazione valida per migliorare la coerenza strutturale.Passo 4: Flusso principale dell'app Streamlit
Infine, costruiremo l'interfaccia utente completa che riunisce tutte le nostre capacità di ricerca in un'applicazione interattiva.
Il codice sopra è suddiviso in livelli, dal caricamento del modello e raccolta degli input utente alla generazione delle query, ricerca web e sintesi del report finale. Analizziamo questi livelli nel dettaglio:
DeepResearchAssistantviene inizializzato una sola volta per sessione usandost.session_state, preservando lo stato del modello ed evitando ricaricamenti ripetuti.asyncio, garantendo esecuzione parallela delle query senza bloccare la reattività della UI.TXToJSONo rieseguire il workflow con un clic.Per provarlo, salva il codice come
app.pye avvia: