Skip to main content
Glama
QuantQJ
by QuantQJ

filings-search

Híbrido (BM25 + kNN) recuperación basada en agentes sobre presentaciones 10-K de la SEC, en OpenSearch, con un agente de uso de herramientas de Claude que planifica sus propias búsquedas y responde con citas por afirmación y una verificación estricta de fundamentación numérica. Interfaz FastAPI + servidor de herramientas MCP en TypeScript. Construido como el sucesor de OpenSearch de mi pipeline Qdrant; la fundamentación de citar o abstenerse está adaptada de mi envoltorio de procedencia de 12 dominios.

EDGAR ──► connector ──► section splitter ──► chunker ──► embeddings ──► OpenSearch (BM25 + HNSW kNN)
(SEC API)  (ticker→CIK,   (Item 1/1A/1C/7/8…)  (450 tok,    (nomic-embed-text            │
            10-K list,     order-constrained,    60 overlap)  local via Ollama, or        │
            iXBRL strip)   x-ref filtered)                     OpenAI)                     ▼
                                                                          hybrid search (RRF) + filters
                                                                                       │
                                                       ┌───────────────────────────────┼─────────────────────┐
                                                       ▼                               ▼                     ▼
                                              FastAPI /search /ask           TS MCP server            eval harness
                                              /chunk /companies         (search_filings, ask_filings)  (P@k/MRR, LLM-judge)
                                                       ▲
                                              Claude agent (tool loop):
                                              resolve_company → search_filings (item/ticker/FY filters, hybrid|bm25|knn)
                                              → expand_chunk → answer with [c:chunk_id] cites → numeric grounding check

Qué incluye

Capa

Archivo

Notas

Conector

filings_search/edgar.py

Mapa de tickers de la SEC + fallback de browse-edgar (maneja CIKs de shell sucesor), envíos de data.sec.gov, recuperación de documento principal, eliminación de iXBRL/HTML, caché en disco

Análisis

filings_search/parse.py

Divisor de ítems 10-K: encabezados verificados por título, filtro de referencias cruzadas, orden canónico + selección de tramo más largo (derrota filas de tabla de contenido)

Fragmentación

filings_search/chunk.py

Respetando párrafos, limitado por tokens (solapamiento 450/60), ids de fragmento deterministas `sha1(accession

item

idx)`

Incrustaciones

filings_search/embed.py

nomic-embed-text (768-d) en Ollama local por defecto; fallback OpenAI text-embedding-3-small

Índice

filings_search/index.py

Mapeo de OpenSearch 2.19: campo BM25 con analizador inglés + knn_vector (lucene HNSW, coseno) + metadatos de palabras clave (ticker, cik, item, fiscal_year, accession…)

Recuperación

filings_search/search.py

bm25, knn, hybrid (fusión de rango recíproco del lado del cliente), filtros de metadatos, expansión de vecinos

Agente

filings_search/agent.py

Bucle de herramientas de Claude (claude-opus-5); herramientas: list_indexed_companies, resolve_company, search_filings, expand_chunk; la respuesta debe citar [c:id]; cada cifra en la respuesta debe aparecer en un fragmento citado o la respuesta se marca como grounded_numbers=false

API

filings_search/api.py

FastAPI: GET /search, POST /ask, GET /chunk/{id}?expand=, GET /companies, GET /health

MCP

mcp/src/server.ts

Servidor MCP stdio en TypeScript que expone list_companies, search_filings, get_chunk, ask_filings

Evaluación

eval/

run_retrieval_eval.py (acierto@1/acierto@5/MRR@10 por modo, consultas etiquetadas), run_grounding_eval.py (fundamentación numérica + soporte de citas mediante LLM como juez)

Ejecútalo

docker compose up -d                       # OpenSearch 2.19 (knn + neural plugins), :9200
ollama pull nomic-embed-text               # local embeddings
python3.12 -m venv .venv && ./.venv/bin/pip install -r requirements.txt
./.venv/bin/python ingest.py --recreate AAPL MSFT NVDA JPM XOM WMT TSLA JNJ   # ~2 min, 8 filings, ~2.1k chunks
./run_api.sh                               # FastAPI on :8801
./.venv/bin/python -m filings_search.agent "What does NVIDIA disclose about export controls to China?"
./.venv/bin/python eval/run_retrieval_eval.py
./.venv/bin/python eval/run_grounding_eval.py

MCP (Claude Desktop / Claude Code / Cursor):

{"mcpServers": {"filings-search": {"command": "node", "args": ["/ABS/PATH/filings-search/mcp/dist/server.js"],
                                    "env": {"FILINGS_API_URL": "http://127.0.0.1:8801"}}}}

Configuración mediante variables de entorno: FS_OPENSEARCH_URL, FS_INDEX, FS_EMBED_BACKEND=ollama|openai, FS_AGENT_MODEL, FS_JUDGE_MODEL, SEC_USER_AGENT. ANTHROPIC_API_KEY (o ~/.env) para el agente/juez.

Resultados (2026-08-18, 8 presentaciones / 2.101 fragmentos, 28 consultas etiquetadas)

Recuperación — ver eval/retrieval_results.json:

configuración

modo

acierto@1

acierto@5

MRR@10

media ms

sin filtrar

bm25

0.571

0.857

0.686

5.7

sin filtrar

knn

0.679

0.857

0.759

29.7

sin filtrar

hybrid

0.679

0.857

0.759

37.9

filtrado por ticker

bm25

0.679

0.929

0.772

3.8

filtrado por ticker

knn

0.679

0.893

0.779

26.6

filtrado por ticker

hybrid

0.714

0.929

0.812

34.9

Fundamentación del agente — 10 preguntas de analistas, agente claude-opus-5 + juez claude-opus-5 (ver eval/grounding_results.json):

métrica

valor

tasa de fundamentación numérica (cada cifra aparece en un fragmento citado)

10/10 = 1,00

veredicto del juez LLM: fundamentado / parcialmente fundamentado / no fundamentado

9 / 1 / 0

fracción media de afirmaciones respaldadas por un fragmento citado

0,968

promedio de citas por respuesta

9,7

promedio de llamadas a herramientas por respuesta (búsquedas/expansiones elegidas por el agente)

7,6

latencia media

41 s (13 s simple → 59 s multi-ítem)

tokens para la ejecución de 10 preguntas

563k in / 23k out

El único partially_grounded (aranceles de Walmart, 0,87) fue el agente resumiendo una mitigación que el fragmento citado establece de manera más restrictiva — el juez lo detectó; para eso está el juez.

Notas de diseño / limitaciones honestas

  • Agéntico ≠ RAG fijo. El modelo elige empresa, Ítem, modo y cuántas rondas; un pipeline fijo de top-k no tiene segunda oportunidad. Las descripciones de las herramientas contienen la guía de 'cuándo usar' (mapa de ítems, bm25 para cifras, ampliar si está vacío).

  • La fundamentación es estricta a propósito. Un redondeo derivado ("$99.779M" → "~$99.8B") se marca como no fundamentado; los analistas quieren la cifra tal como se presentó. Afloje con una tolerancia si no está de acuerdo.

  • Las peculiaridades de la estructura 10-K son reales, no errores del analizador: JPM y XOM son 10-K 'envoltorio' cuyos MD&A/estados financieros se encuentran en una Sección Financiera al final del libro (etiquetada bajo el último Ítem); NVIDIA presenta estados bajo el Ítem 15. Las etiquetas de evaluación para esos son solo ticker. Un seguimiento es la detección de páginas F (encabezados Consolidated Statements of …) para reetiquetar como Ítem 8.

  • RRF es del lado del cliente — transparente y fácil de razonar; el pipeline de normalización de consultas hybrid de OpenSearch es la alternativa dentro del clúster. Aún no hay re-ranker de codificador cruzado.

  • Una sola presentación por empresa en esta ejecución; --filings N obtiene años anteriores (el filtro fiscal_year ya está en el mapeo y las herramientas).

  • Sin autenticación, sin límites de tasa, OpenSearch de un solo nodo — esto es un vertical funcional, no un despliegue.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/QuantQJ/filings-search'

If you have feedback or need assistance with the MCP directory API, please join our Discord server