3.3 Gestió del Context Window¶
El Repte
El context window és el recurs més limitat i car d'un agent. Gestionar-lo bé és la diferència entre un agent eficient i un que talla converses, oblida informació o genera factures enormes.
📏 Anatomia d'un Context Window¶
En cada crida a un LLM, el context window conté:
| Component | Tokens Típics | Notes |
|---|---|---|
| System prompt | 200-2000 | Constant en cada crida |
| Historial de conversa | Creix amb el temps | El gran consumidor |
| Resultats d'eines | 100-2000 per eina | Pot ser molt gran |
| Context RAG | 500-4000 | Fragments recuperats |
| Missatge actual | 10-500 | La pregunta de l'usuari |
| TOTAL | ~2000-10000 | Per consulta típica |
⚡ Estratègies de Compressió¶
1. Compressió per Resum¶
from langchain.memory import ConversationSummaryBufferMemory
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# Combina: missatges recents íntegres + resum dels anteriors
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=800, # Quan supera 800 tokens → comença a resumir
memory_key="history",
return_messages=True
)
# El resum es genera automàticament:
# "L'usuari Anna pregunta sobre ASIX. Hem parlat de:
# 1. Conceptes de subnetting IPv4
# 2. Configuració de VLANs en Cisco
# [Darrera conversa íntegra...]"
2. Prompt Caching (OpenAI i Anthropic)¶
# OpenAI suporta Prompt Caching automàticament per a prompts de >1024 tokens
# → Estalvia fins al 50% del cost en el prefix del prompt!
from openai import OpenAI
client = OpenAI()
# El system prompt llarg es pot cachear:
SYSTEM_LONG = """
[...2000 paraules de context constant...]
""" # → Cacheada automàticament per OpenAI
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": SYSTEM_LONG}, # ← Cacheada!
{"role": "user", "content": "Pregunta nova"}
]
)
# Verificar si s'ha usat la caché
usage = response.usage
print(f"Tokens cacheats: {getattr(usage, 'prompt_tokens_details', {}).get('cached_tokens', 0)}")
3. Selecció Intel·ligent de Context¶
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
# En lloc de posar TOT l'historial al context,
# recuperar ÚNICAMENT els missatges rellevants per a la pregunta actual
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Indexar l'historial de conversa
historial_vs = Chroma(
collection_name="historial",
embedding_function=embeddings
)
def context_rellevant(pregunta: str, k: int = 3) -> str:
"""Recupera els missatges de l'historial més rellevants per a la pregunta."""
docs = historial_vs.similarity_search(pregunta, k=k)
return "\n".join(d.page_content for d in docs)
# En lloc de: history = TOTS_ELS_MISSATGES (pot ser 50k tokens)
# Usem: history = context_rellevant(pregunta_actual) (~1k tokens)
💰 Estimació i Control de Costos¶
import tiktoken # pip install tiktoken
def comptar_tokens(text: str, model: str = "gpt-4o") -> int:
"""Compta els tokens d'un text per a un model específic."""
enc = tiktoken.encoding_for_model(model)
return len(enc.encode(text))
def estimar_cost(tokens_input: int, tokens_output: int,
model: str = "gpt-4o-mini") -> float:
"""Estima el cost en USD d'una crida."""
PREUS = { # Per milió de tokens (USD) — actualitzar periòdicament!
"gpt-4o": {"input": 5.0, "output": 15.0},
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
}
p = PREUS.get(model, PREUS["gpt-4o-mini"])
return (tokens_input * p["input"] + tokens_output * p["output"]) / 1_000_000
# Exemple de càlcul
system_tokens = comptar_tokens("Ets un assistent expert en ASIX...")
historial_tok = comptar_tokens("Conversa de 20 missatges...")
pregunta_tok = comptar_tokens("Com configuro una VLAN?")
total_input = system_tokens + historial_tok + pregunta_tok
cost_estimat = estimar_cost(total_input, tokens_output=500)
print(f"Cost estimat: ${cost_estimat:.6f}")
print(f"Cost 1000 consultes: ${cost_estimat * 1000:.4f}")
🔧 Bones Pràctiques de Context Window¶
Truncar els Resultats d'Eines
Limitar la sortida de cada eina a un màxim de tokens. Una cerca web no necessita retornar 10.000 paraules; 500-1000 és suficient.
System Prompt Concís
Cada paraula del system prompt costa diners en cada crida. Revisar periòdicament i eliminar instruccions redundants.
Externalitzar el Coneixement
No posar el "manual d'instruccions" complet al context. Usar RAG per recuperar únicament les seccions rellevants per a cada consulta.
Monitorar amb LangSmith
Instrumentar l'agent per veure exactament quants tokens consumeix cada component en cada consulta real.
✅ Activitats¶
Exercici 3.3.1 — Audit de Tokens
Per a un agent de la Pràctica 1 o 2, usa tiktoken per mesurar exactament quants tokens consumeix cada component (system prompt, historial, eines, resposta) en 10 consultes típiques. On es poden reduir tokens sense perdre qualitat?
Exercici 3.3.2 — Implementar Compressió
Modifica l'agent de la Pràctica 1 per usar ConversationSummaryBufferMemory amb max_token_limit=800. Verifica que: (a) les converses llargues no superen el limit, (b) el resum manté la informació important.
Exercici 3.3.3 — Calculadora de Costos
Crea una funció que, donats: model, nombre de consultes/dia, tokens promig per consulta, calculi el cost mensual. Compara GPT-4o vs GPT-4o-mini vs Ollama local per a 1000 consultes/dia.