Introducción
En este tutorial, construiremos un agente de noticias avanzado con motor AI que pueda buscar en la Web las últimas noticias sobre un tema determinado y resumir los resultados. Este agente sigue un flujo de trabajo estructurado:
- Hojeada: Genere consultas de búsqueda relevantes y recopile información de la web.
- Escribiendo: Extrae y compila resúmenes de noticias de la información recopilada.
- Reflexión: Critica los resúmenes al verificar la corrección objetiva y sugiere mejoras.
- Refinamiento: Mejora los resúmenes basados en la crítica.
- Generación de titulares: Genera titulares apropiados para cada resumen de noticias.
Para mejorar la usabilidad, también crearemos una GUI simple usando Streamlit. Similar a los tutoriales anteriores, usaremos Hacer surgimiento para procesamiento basado en LLM y Tavily para navegación web. Puede generar claves API gratuitas de sus respectivos sitios web.
Configuración del medio ambiente
Comenzamos configurando variables de entorno, instalando las bibliotecas requeridas e importando las dependencias necesarias:
Instale bibliotecas requeridas
pip install langgraph==0.2.53 langgraph-checkpoint==2.0.6 langgraph-sdk==0.1.36 langchain-groq langchain-community langgraph-checkpoint-sqlite==2.0.1 tavily-python streamlit
Importar bibliotecas y establecer claves API
import os
import sqlite3
from langgraph.graph import StateGraph
from langchain_core.messages import SystemMessage, HumanMessage
from langchain_groq import ChatGroq
from tavily import TavilyClient
from langgraph.checkpoint.sqlite import SqliteSaver
from typing import TypedDict, List
from pydantic import BaseModel
import streamlit as st
# Set API Keys
os.environ['TAVILY_API_KEY'] = "your_tavily_key"
os.environ['GROQ_API_KEY'] = "your_groq_key"
# Initialize Database for Checkpointing
sqlite_conn = sqlite3.connect("checkpoints.sqlite", check_same_thread=False)
memory = SqliteSaver(sqlite_conn)
# Initialize Model and Tavily Client
model = ChatGroq(model="Llama-3.1-8b-instant")
tavily = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
Definición del estado del agente
El agente mantiene información estatal a lo largo de su flujo de trabajo:
- Tema: El tema sobre el cual el usuario quiere los últimos borradores de noticias: los primeros borradores de los resúmenes de noticias
- Contenido: El contenido de investigación extraído de los resultados de búsqueda de Tavily
- Crítica: La crítica y las recomendaciones generadas para el borrador en el estado de reflexión.
- Resúmenes refinados: Resúmenes de noticias actualizados después de incorporar sugerencias de la crítica
Encabezados: Titulares generados para cada clase de artículo de noticias
class AgentState(TypedDict):
topic: str
drafts: List[str]
content: List[str]
critiques: List[str]
refined_summaries: List[str]
headings: List[str]
Definición de indicaciones
Definimos las indicaciones del sistema para cada fase del flujo de trabajo del agente:
BROWSING_PROMPT = """You are an AI news researcher tasked with finding the latest news articles on given topics. Generate up to 3 relevant search queries."""
WRITER_PROMPT = """You are an AI news summarizer. Write a detailed summary (1 to 2 paragraphs) based on the given content, ensuring factual correctness, clarity, and coherence."""
CRITIQUE_PROMPT = """You are a teacher reviewing draft summaries against the source content. Ensure factual correctness, identify missing or incorrect details, and suggest improvements.
----------
Content: {content}
----------"""
REFINE_PROMPT = """You are an AI news editor. Given a summary and critique, refine the summary accordingly.
-----------
Summary: {summary}"""
HEADING_GENERATION_PROMPT = """You are an AI news summarizer. Generate a short, descriptive headline for each news summary."""
Estructurar consultas y noticias
Utilizamos Pydantic para definir la estructura de consultas y artículos de noticias. Pydantic nos permite definir la estructura de la salida del LLM. Esto es importante porque queremos que las consultas sean una lista de cadenas y el contenido extraído de la web tendrá múltiples artículos de noticias, de ahí una lista de cadenas.
from pydantic import BaseModel
class Queries(BaseModel):
queries: List[str]
class News(BaseModel):
news: List[str]
Implementación de los agentes de IA
1. Nodo de navegación
Este nodo genera consultas de búsqueda y recupera contenido relevante de la web.
def browsing_node(state: AgentState):
queries = model.with_structured_output(Queries).invoke([
SystemMessage(content=BROWSING_PROMPT),
HumanMessage(content=state['topic'])
])
content = state.get('content', [])
for q in queries.queries:
response = tavily.search(query=q, max_results=2)
for r in response['results']:
content.append(r['content'])
return {"content": content}
2. Nodo de escritura
Extrae resúmenes de noticias del contenido recuperado.
def writing_node(state: AgentState):
content = "\n\n".join(state['content'])
news = model.with_structured_output(News).invoke([
SystemMessage(content=WRITER_PROMPT),
HumanMessage(content=content)
])
return {"drafts": news.news}
3. Nodo de reflexión
Critica los resúmenes generados contra el contenido.
def reflection_node(state: AgentState):
content = "\n\n".join(state['content'])
critiques = []
for draft in state['drafts']:
response = model.invoke([
SystemMessage(content=CRITIQUE_PROMPT.format(content=content)),
HumanMessage(content="draft: " + draft)
])
critiques.append(response.content)
return {"critiques": critiques}
4. Nodo de refinamiento
Mejora los resúmenes basados en la crítica.
def refine_node(state: AgentState):
refined_summaries = []
for summary, critique in zip(state['drafts'], state['critiques']):
response = model.invoke([
SystemMessage(content=REFINE_PROMPT.format(summary=summary)),
HumanMessage(content="Critique: " + critique)
])
refined_summaries.append(response.content)
return {"refined_summaries": refined_summaries}
5. Nodo de generación de titulares
Genera un breve titular para cada resumen de noticias.
def heading_node(state: AgentState):
headings = []
for summary in state['refined_summaries']:
response = model.invoke([
SystemMessage(content=HEADING_GENERATION_PROMPT),
HumanMessage(content=summary)
])
headings.append(response.content)
return {"headings": headings}
Construyendo la interfaz de usuario con simpatía
# Define Streamlit app
st.title("News Summarization Chatbot")
# Initialize session state
if "messages" not in st.session_state:
st.session_state["messages"] = []
# Display past messages
for message in st.session_state["messages"]:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Input field for user
user_input = st.chat_input("Ask about the latest news...")
thread = 1
if user_input:
st.session_state["messages"].append({"role": "user", "content": user_input})
with st.chat_message("assistant"):
loading_text = st.empty()
loading_text.markdown("*Thinking...*")
builder = StateGraph(AgentState)
builder.add_node("browser", browsing_node)
builder.add_node("writer", writing_node)
builder.add_node("reflect", reflection_node)
builder.add_node("refine", refine_node)
builder.add_node("heading", heading_node)
builder.set_entry_point("browser")
builder.add_edge("browser", "writer")
builder.add_edge("writer", "reflect")
builder.add_edge("reflect", "refine")
builder.add_edge("refine", "heading")
graph = builder.compile(checkpointer=memory)
config = {"configurable": {"thread_id": f"{thread}"}}
for s in graph.stream({"topic": user_input}, config):
# loading_text.markdown(f"*{st.session_state['loading_message']}*")
print(s)
s = graph.get_state(config).values
refined_summaries = s['refined_summaries']
headings = s['headings']
thread+=1
# Display final response
loading_text.empty()
response_text = "\n\n".join([f"{h}\n{s}" for h, s in zip(headings, refined_summaries)])
st.markdown(response_text)
st.session_state["messages"].append({"role": "assistant", "content": response_text})
Conclusión
Este tutorial cubrió todo el proceso de construcción de un agente de resumen de noticias con IA con una IU simple a simpatículo. Ahora puedes jugar con esto y hacer más mejoras como:
- A mejor gui Para una interacción mejorada del usuario.
- Incorporación Refinamiento iterativo Para asegurarse de que los resúmenes sean precisos y apropiados.
- Mantener un contexto para continuar la conversación sobre noticias particulares.
¡Feliz codificación!
Además, siéntete libre de seguirnos Gorjeo Y no olvides unirte a nuestro 75k+ ml de subreddit.
Vineet Kumar es un pasante de consultoría en MarktechPost. Actualmente está persiguiendo su BS del Instituto Indio de Tecnología (IIT), Kanpur. Es un entusiasta del aprendizaje automático. Le apasiona la investigación y los últimos avances en aprendizaje profundo, visión por computadora y campos relacionados.