{"id":2473,"date":"2025-09-17T15:02:58","date_gmt":"2025-09-17T13:02:58","guid":{"rendered":"https:\/\/davidka.net\/ru\/?p=2473"},"modified":"2025-09-22T02:14:05","modified_gmt":"2025-09-22T00:14:05","slug":"ai-agent-with-mcp","status":"publish","type":"post","link":"https:\/\/it.davidka.net\/it\/ai-agent-with-mcp\/","title":{"rendered":"Guida pratica alla creazione di agenti IA con LangGraph e MCP"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Questo articolo \u00e8 una guida pratica per sviluppatori sulla creazione di agenti IA autonomi in Python. Non ripeteremo la teoria su cosa siano LangChain e LangGraph. Ci concentreremo invece sul codice, sull&#8217;architettura e sulla risoluzione di problemi reali.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Obiettivo:<\/strong> Costruire due progetti da zero:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Un Agente Classificatore:<\/strong> Un agente multi-step con stato gestito, ma senza strumenti esterni.<\/li>\n\n\n\n<li><strong>Un Agente Assistente:<\/strong> Un agente completo con accesso al file system e alla ricerca web tramite il protocollo MCP, basato su una logica ciclica.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Tratteremo le best practice: gestione della configurazione, selezione dei modelli e gestione degli errori per creare sistemi robusti.<\/p>\n\n\n\n<div id=\"rtoc-mokuji-wrapper\" class=\"rtoc-mokuji-content frame2 preset1 animation-fade rtoc_open default\" data-id=\"2473\" data-theme=\"Neve - Davidka\">\n\t\t\t<div id=\"rtoc-mokuji-title\" class=\"rtoc_btn_none rtoc_left\">\n\t\t\t\n\t\t\t<span>In Questo Articolo<\/span>\n\t\t\t<\/div><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#rtoc-1\">Breve panoramica dei concetti: L&#8217;Agente e il ponte MCP<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#rtoc-2\">Parte 1: Configurazione di un ambiente robusto<\/a><ul class=\"rtoc-mokuji mokuji_none level-3\"><li class=\"rtoc-item\"><a href=\"#rtoc-3\">Passo 1: Ambiente virtuale e dipendenze<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#rtoc-4\">Conclusione<\/a><\/li><\/ul><\/li><\/ol><\/div><h3 id=\"rtoc-1\"  class=\"wp-block-heading\">Breve panoramica dei concetti: L&#8217;Agente e il ponte MCP<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Prima di immergerci nel codice, fissiamo due concetti:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Agente IA:<\/strong> Un programma costruito attorno a un ciclo &#8220;ragionamento-azione&#8221;. Riceve un compito, utilizza un LLM per decidere cosa fare dopo (es. chiamare uno strumento), esegue l&#8217;azione e ripete il ciclo finch\u00e9 il compito non \u00e8 completato.<\/li>\n\n\n\n<li><strong>MCP (Model Context Protocol):<\/strong> Uno standard che funge da <strong>ponte<\/strong> tra la logica dell&#8217;agente e gli strumenti esterni. Permette all&#8217;agente di lavorare con file, API o ricerche in modo unificato, senza preoccuparsi dei dettagli della loro implementazione.<\/li>\n<\/ul>\n\n\n\n<h3 id=\"rtoc-2\"  class=\"wp-block-heading\">Parte 1: Configurazione di un ambiente robusto<\/h3>\n\n\n\n<h4 id=\"rtoc-3\"  class=\"wp-block-heading\">Passo 1: Ambiente virtuale e dipendenze<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Crea e attiva un ambiente virtuale. Successivamente, crea un file <code class=\"\" data-line=\"\">requirements.txt<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\"># Framework principali\nlangchain\nlanggraph\n\n# Adattatori per modelli\nlangchain-openai\nlangchain-google-genai\nlangchain-mistralai\nlangchain-community # Per Ollama\n\n# Strumenti e protocolli\nlangchain-mcp-adapters\nmcp\nollama\n\n# Utilit\u00e0\npython-dotenv\ntenacity # Per una gestione robusta degli errori<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Installa le dipendenze:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">pip install -r requirements.txt```\n\n#### Passo 2: Configurazione delle chiavi API\n\nCrea un file `.env` per memorizzare le tue chiavi:<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">OPENAI_API_KEY=&#8221;sk-\u2026&#8221;<br>GOOGLE_API_KEY=&#8221;AIzaSy\u2026&#8221;<br>MISTRAL_API_KEY=&#8221;\u2026&#8221;<br>BRAVE_API_KEY=&#8221;\u2026&#8221; # Per lo strumento di ricerca web tramite MCP<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">#### Passo 3: Il pattern &quot;Model Factory&quot;\n\nPer passare in modo flessibile tra modelli cloud e locali senza modificare il codice dell&#039;agente, utilizzeremo il pattern factory.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">llm_factory.py<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">import os<br>from enum import Enum<br>from dotenv import load_dotenv<br>from langchain_openai import ChatOpenAI<br>from langchain_google_genai import ChatGoogleGenerativeAI<br>from langchain_mistralai import ChatMistralAI<br>from langchain_community.chat_models import ChatOllama<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">load_dotenv()<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">class ModelProvider(Enum):<br>OPENAI = &#8220;openai&#8221;<br>GEMINI = &#8220;gemini&#8221;<br>MISTRAL_API = &#8220;mistral_api&#8221;<br>OLLAMA = &#8220;ollama&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">def get_llm(provider: ModelProvider, model_name: str = None):<br>&#8220;&#8221;&#8221;Una factory per creare istanze di LLM.&#8221;&#8221;&#8221;<br>if provider == ModelProvider.OPENAI:<br>return ChatOpenAI(model=model_name or &#8220;gpt-4o-mini&#8221;, temperature=0)<br>elif provider == ModelProvider.GEMINI:<br>return ChatGoogleGenerativeAI(model=model_name or &#8220;gemini-1.5-flash&#8221;, temperature=0)<br>elif provider == ModelProvider.MISTRAL_API:<br>return ChatMistralAI(model=model_name or &#8220;mistral-large-latest&#8221;, temperature=0)<br>elif provider == ModelProvider.OLLAMA:<br># Assicurati che Ollama sia in esecuzione con il modello richiesto<br># docker exec -it ollama ollama pull mistral<br>return ChatOllama(model=model_name or &#8220;mistral&#8221;, temperature=0)<br>raise ValueError(f&#8221;Provider del modello sconosciuto: {provider}&#8221;)<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Esempio di utilizzo<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">if <strong>name<\/strong> == &#8220;<strong>main<\/strong>&#8220;:<br># local_llm = get_llm(ModelProvider.OLLAMA)<br>openai_llm = get_llm(ModelProvider.OPENAI)<br>response = openai_llm.invoke(&#8220;Spiega il concetto di RAG in tre frasi.&#8221;)<br>print(response.content)<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">### Parte 2: Progetto 1 \u2014 Agente di Classificazione Annunci di Lavoro\n\nQuesto agente dimostra come utilizzare LangGraph per creare un **grafo lineare** con stato gestito. Prender\u00e0 una descrizione di un annuncio di lavoro e la classificher\u00e0 sequenzialmente in base a tre parametri.\n\n#### Passo 1: Definizione dello Stato\n\nLo stato \u00e8 la &quot;memoria&quot; del nostro grafo, passata da un nodo all&#039;altro.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">vacancy_classifier.py<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">from typing import TypedDict, Dict<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">class ClassificationState(TypedDict):<br>&#8220;&#8221;&#8221;Stato per l&#8217;agente classificatore.&#8221;&#8221;&#8221;<br>description: str # Testo di origine<br>job_type: str # Tipo di lavoro (progetto\/permanente)<br>category: str # Professione<br>search_type: str # Scopo (cerca lavoro\/prestatore)<br>classification_log: list # Log di debug<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">#### Passo 2: Implementazione dei Nodi del Grafo\n\nOgni nodo \u00e8 una funzione che prende lo stato, esegue la sua parte di lavoro e restituisce lo stato aggiornato.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<br>import asyncio<br>import json<br>from langchain_core.prompts import ChatPromptTemplate<br>from llm_factory import get_llm, ModelProvider<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">class VacancyClassifierAgent:<br>def <strong>init<\/strong>(self):<br>self.llm = get_llm(ModelProvider.OPENAI, model_name=&#8221;gpt-4o-mini&#8221;)<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">async def _classify_job_type(self, state: ClassificationState) -&gt; ClassificationState:\n    &quot;&quot;&quot;Nodo 1: Determina il tipo di lavoro.&quot;&quot;&quot;\n    prompt = ChatPromptTemplate.from_messages(&#091;\n        (&quot;system&quot;, &quot;Determina il tipo di lavoro. La risposta deve essere &#039;a progetto&#039; o &#039;permanente&#039;.&quot;),\n        (&quot;human&quot;, &quot;Descrizione dell&#039;annuncio:\\n\\n{description}&quot;)\n    ])\n    chain = prompt | self.llm\n    result = await chain.ainvoke({&quot;description&quot;: state&#091;&quot;description&quot;]})\n\n    state&#091;&quot;job_type&quot;] = result.content.strip()\n    state&#091;&quot;classification_log&quot;].append(&quot;Tipo di lavoro determinato.&quot;)\n    return state\n\nasync def _classify_category(self, state: ClassificationState) -&gt; ClassificationState:\n    &quot;&quot;&quot;Nodo 2: Determina la categoria professionale.&quot;&quot;&quot;\n    # Le categorie possono essere caricate da un file o da un database\n    categories = &#091;&quot;Sviluppatore Python&quot;, &quot;Designer&quot;, &quot;Marketer&quot;, &quot;Animatore 3D&quot;]\n    prompt = ChatPromptTemplate.from_messages(&#091;\n        (&quot;system&quot;, f&quot;Scegli la categoria pi\u00f9 adatta dalla lista: {&#039;, &#039;.join(categories)}.&quot;),\n        (&quot;human&quot;, &quot;Descrizione dell&#039;annuncio:\\n\\n{description}&quot;)\n    ])\n    chain = prompt | self.llm\n    result = await chain.ainvoke({&quot;description&quot;: state&#091;&quot;description&quot;]})\n\n    state&#091;&quot;category&quot;] = result.content.strip()\n    state&#091;&quot;classification_log&quot;].append(&quot;Categoria determinata.&quot;)\n    return state\n\nasync def _classify_search_type(self, state: ClassificationState) -&gt; ClassificationState:\n    &quot;&quot;&quot;Nodo 3: Determina lo scopo della ricerca.&quot;&quot;&quot;\n    prompt = ChatPromptTemplate.from_messages(&#091;\n        (&quot;system&quot;, &quot;Determina lo scopo dell&#039;autore. La risposta deve essere &#039;cerca lavoro&#039; o &#039;cerca prestatore&#039;.&quot;),\n        (&quot;human&quot;, &quot;Descrizione dell&#039;annuncio:\\n\\n{description}&quot;)\n    ])\n    chain = prompt | self.llm\n    result = await chain.ainvoke({&quot;description&quot;: state&#091;&quot;description&quot;]})\n\n    state&#091;&quot;search_type&quot;] = result.content.strip()\n    state&#091;&quot;classification_log&quot;].append(&quot;Scopo della ricerca determinato.&quot;)\n    return state<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">#### Passo 3: Assemblaggio ed Esecuzione del Grafo\n\nAssembliamo i nodi in un unico flusso di lavoro.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">\u2026 continuazione della classe VacancyClassifierAgent \u2026<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">from langgraph.graph import StateGraph, END<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">def build_graph(self):\n    &quot;&quot;&quot;Assembla il grafo di stati.&quot;&quot;&quot;\n    workflow = StateGraph(ClassificationState)\n\n    workflow.add_node(&quot;job_type_classifier&quot;, self._classify_job_type)\n    workflow.add_node(&quot;category_classifier&quot;, self._classify_category)\n    workflow.add_node(&quot;search_type_classifier&quot;, self._classify_search_type)\n\n    workflow.set_entry_point(&quot;job_type_classifier&quot;)\n    workflow.add_edge(&quot;job_type_classifier&quot;, &quot;category_classifier&quot;)\n    workflow.add_edge(&quot;category_classifier&quot;, &quot;search_type_classifier&quot;)\n    workflow.add_edge(&quot;search_type_classifier&quot;, END)\n\n    return workflow.compile()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">async def main():<br>agent = VacancyClassifierAgent()<br>graph = agent.build_graph()<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">description = &quot;Cerchiamo uno sviluppatore Python esperto per unirsi al nostro team a tempo pieno per lavorare su un progetto fintech.&quot;\n\ninitial_state = ClassificationState(\n    description=description,\n    job_type=&quot;&quot;, category=&quot;&quot;, search_type=&quot;&quot;,\n    classification_log=&#091;]\n)\n\nfinal_state = await graph.ainvoke(initial_state)\n\nprint(&quot;--- Risultato della Classificazione ---&quot;)\nprint(json.dumps(final_state, indent=2, ensure_ascii=False))<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">if <strong>name<\/strong> == &#8220;<strong>main<\/strong>&#8220;:<br>asyncio.run(main())<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">### Parte 3: Progetto 2 \u2014 Agente Assistente con Strumenti (MCP)\n\nQuesto agente dimostra una **logica ciclica**, in cui pu\u00f2 chiamare ripetutamente degli strumenti per risolvere un compito.\n\n#### Passo 1: Gestione della Configurazione\n\nPer gli agenti che interagiscono con il mondo esterno, una configurazione robusta \u00e8 essenziale.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">mcp_agent_config.py<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">from dataclasses import dataclass, field<br>import os<br>from llm_factory import ModelProvider<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">@dataclass<br>class AgentConfig:<br>workdir: str = &#8220;.\/agent_workdir&#8221;<br>model_provider: ModelProvider = ModelProvider.OLLAMA<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">def __post_init__(self):\n    &quot;&quot;&quot;Validazione post-inizializzazione.&quot;&quot;&quot;\n    os.makedirs(self.workdir, exist_ok=True)<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">#### Passo 2: Definizione dello Stato per il Dialogo\n\nLo stato ora memorizzer\u00e0 la cronologia dei messaggi.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">mcp_agent.py<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">from typing import TypedDict, Annotated, Sequence<br>from langchain_core.messages import BaseMessage<br>import operator<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">class AgentState(TypedDict):<br>messages: Annotated[Sequence[BaseMessage], operator.add]<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">#### Passo 3: Implementazione del Grafo Ciclico\n\nIl grafo consister\u00e0 in due nodi principali e un arco condizionale che crea il ciclo &quot;ragionamento-azione&quot;.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<br>from langgraph.graph import StateGraph, END<br>from langgraph.prebuilt import ToolExecutor<br>from langchain_mcp_adapters.langchain import V1ToolExecutor<br>from langchain_mcp_adapters.clients import MultiServerMCPClient<br>from llm_factory import get_llm<br>from mcp_agent_config import AgentConfig<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">class MCPAgent:<br>def <strong>init<\/strong>(self, config: AgentConfig):<br>self.config = config<br>self.llm = get_llm(config.model_provider)<br>self.tools = []<br>self.tool_executor = None<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">async def setup_tools(self):\n    &quot;&quot;&quot;Inizializza gli strumenti tramite MCP.&quot;&quot;&quot;\n    mcp_config = {\n        &quot;filesystem&quot;: {\n            &quot;command&quot;: &quot;npx&quot;, &quot;args&quot;: &#091;&quot;-y&quot;, &quot;@modelcontextprotocol\/server-filesystem&quot;, self.config.workdir],\n            &quot;transport&quot;: &quot;stdio&quot;\n        },\n        # Aggiungi brave-search se hai una BRAVE_API_KEY\n    }\n    mcp_client = MultiServerMCPClient(mcp_config)\n    self.tools = await mcp_client.get_tools()\n    self.tool_executor = ToolExecutor(&#091;V1ToolExecutor(tool) for tool in self.tools])\n\n    # Collega gli strumenti al modello\n    self.llm = self.llm.bind_tools(self.tools)\n\ndef _should_continue(self, state: AgentState):\n    &quot;&quot;&quot;Arco condizionale: decide se chiamare uno strumento.&quot;&quot;&quot;\n    last_message = state&#091;&#039;messages&#039;]&#091;-1]\n    if not last_message.tool_calls:\n        return &quot;end&quot;\n    return &quot;continue&quot;\n\ndef _call_model(self, state: AgentState):\n    &quot;&quot;&quot;Nodo 1: Chiama il LLM per prendere una decisione.&quot;&quot;&quot;\n    response = self.llm.invoke(state&#091;&#039;messages&#039;])\n    return {&quot;messages&quot;: &#091;response]}\n\ndef _call_tool(self, state: AgentState):\n    &quot;&quot;&quot;Nodo 2: Esegue la chiamata allo strumento.&quot;&quot;&quot;\n    last_message = state&#091;&#039;messages&#039;]&#091;-1]\n    tool_call = last_message.tool_calls&#091;0]\n\n    action = {&quot;tool&quot;: tool_call&#091;&quot;name&quot;], &quot;tool_input&quot;: tool_call&#091;&quot;args&quot;], &quot;log&quot;: &quot;&quot;}\n    response = self.tool_executor.invoke(action)\n\n    return {&quot;messages&quot;: &#091;response]}\n\ndef build_graph(self):\n    workflow = StateGraph(AgentState)\n    workflow.add_node(&quot;agent&quot;, self._call_model)\n    workflow.add_node(&quot;action&quot;, self._call_tool)\n\n    workflow.set_entry_point(&quot;agent&quot;)\n    workflow.add_conditional_edges(\n        &quot;agent&quot;,\n        self._should_continue,\n        {&quot;continue&quot;: &quot;action&quot;, &quot;end&quot;: END}\n    )\n    workflow.add_edge(&quot;action&quot;, &quot;agent&quot;)\n\n    return workflow.compile()<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">#### Passo 4: Esecuzione e Interazione<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">python<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">\u2026 continuazione di mcp_agent.py \u2026<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">import asyncio<br>from langchain_core.messages import HumanMessage<br>from tenacity import retry, stop_after_attempt, wait_fixed<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))<br>async def run_agent_task(graph, task):<br>&#8220;&#8221;&#8221;Esegue un compito con gestione degli errori.&#8221;&#8221;&#8221;<br>return await graph.ainvoke({&#8220;messages&#8221;: [HumanMessage(content=task)]})<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">async def main():<br>config = AgentConfig(model_provider=ModelProvider.OPENAI) # o OLLAMA<br>agent = MCPAgent(config)<br>await agent.setup_tools()<br>graph = agent.build_graph()<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">task = &quot;Crea un file chiamato &#039;ciao.txt&#039; nella directory di lavoro e scrivici dentro &#039;Ciao, mondo!&#039;.&quot;\nresult = await run_agent_task(graph, task)\n\nprint(&quot;\\n--- Risposta Finale dell&#039;Agente ---&quot;)\nprint(result&#091;&#039;messages&#039;]&#091;-1].content)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">if <strong>name<\/strong> == &#8220;<strong>main<\/strong>&#8220;:<br>asyncio.run(main())<br><code class=\"\" data-line=\"\">`` Qui abbiamo aggiunto il decoratore<\/code>tenacity` per la robustezza: se la chiamata all&#8217;agente fallisce a causa di un errore di rete temporaneo, verr\u00e0 automaticamente ritentata.<\/p>\n\n\n\n<h3 id=\"rtoc-4\"  class=\"wp-block-heading\">Conclusione<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Abbiamo costruito due tipi di agenti utilizzando pratiche moderne:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Un <strong>grafo lineare<\/strong> \u00e8 eccellente per compiti con una sequenza chiara di passaggi, come processi ETL o analisi multi-step.<\/li>\n\n\n\n<li>Un <strong>grafo ciclico<\/strong> \u00e8 la base per la creazione di assistenti interattivi e agenti autonomi in grado di risolvere problemi complessi con strumenti.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">I pattern architetturali presentati \u2014 la factory di modelli, la gestione della configurazione, la separazione della logica in nodi e l&#8217;uso di grafi di stati \u2014 sono i fondamenti per la costruzione di sistemi IA scalabili e robusti.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Questo articolo \u00e8 una guida pratica per sviluppatori sulla creazione di agenti IA autonomi in Python. Non ripeteremo la teoria su cosa siano LangChain e LangGraph. Ci concentreremo invece sul codice, sull&#8217;architettura e sulla risoluzione di problemi reali. Obiettivo: Costruire due progetti da zero: Tratteremo le best practice: gestione della configurazione, selezione dei modelli e&hellip;&nbsp;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[540],"tags":[104,863,864,169,108],"class_list":["post-2473","post","type-post","status-publish","format-standard","hentry","category-llm","tag-tag-ai-agent","tag-tag-langchain","tag-tag-langgraph","tag-169","tag-tag-mcp"],"acf":[],"_links":{"self":[{"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/posts\/2473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/comments?post=2473"}],"version-history":[{"count":0,"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/posts\/2473\/revisions"}],"wp:attachment":[{"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/media?parent=2473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/categories?post=2473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/it.davidka.net\/it\/wp-json\/wp\/v2\/tags?post=2473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}