Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)
Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
5.4 KiB
5.4 KiB
Tasks: Accelerate Embedding Similarity
Change:
accelerate-embedding-similarityStatus: Approved / Implemented
Overview
Reduce runtime of find_matching_capacities(...) by implementing:
- embedding text deduplication + global bulk prefetch (roles + competences for all free capacities at once, not person-by-person)
- in-memory embedding memoization
- true Azure embeddings batch requests with chunking
Task Breakdown
Phase 1: Design & Validation Plan
- 1.1 Identify hot paths during matching (where
_embed(...)is called most). - 1.2 Confirm normalization + cache key rules are unchanged and documented.
- 1.3 Define expected call-count behavior (upper bounds):
- per run: max 1 Azure embedding per unique normalized text (subject to chunking, after cache resolution)
- per run: max 1 SQLite read per unique normalized text (after in-memory cache check)
Phase 2: Global Bulk Prefetch in SimilarityEngine
- 2.1 Add a new instance variable
_run_cache: dict[str, list[float]]toSimilarityEngine(in-memory cache; not created/cleared per matching invocation). - 2.2 Implement a public method
prefetch_embeddings(required_texts: list[str], candidate_texts: list[str], required_roles: list[str], candidate_roles: list[str]) -> dict[str, list[float]]:- collect all input texts (required competences, required roles, all candidate competences, all candidate roles)
- normalize + deduplicate using existing
_normalize_text()logic - skip empty/whitespace-only texts
- emit a Python logger warning if all candidate competences normalize to empty
- 2.3 Implement prefetch resolution logic:
- check in-memory cache (
_run_cache) - check SQLite embedding cache
- batch-request only cache-missing texts from Azure API (chunked by batch size)
- check in-memory cache (
- 2.4 Refactor
_per_skill_similarityto use prefetched embeddings only (no embedding calls inside inner loops). - 2.5 Refactor
_aggregate_similarityto use prefetched embeddings only. - 2.6 Ensure output format is unchanged and remains deterministic.
Phase 3: In-memory Run Cache
- 3.1 Verify
_run_cacheis an instance-level cache that does not require per-invocation clearing. - 3.2 Add tests ensuring repeated embedding lookups for the same text:
- are served from
_run_cacheafter first lookup - do not call SQLite/API multiple times for the same text
- are served from
Phase 4: Azure Batch Embeddings Support
- 4.1 Modify
AzureOpenAIClient.get_embeddings_batch()to use Azure embeddings API withinput=[...]. - 4.2 Implement chunking using
azure_openai.embedding_batch_size(default: 128, configurable, no enforced maximum). - 4.3 Preserve ordering using
indexfield in API response if available, otherwise assume stable ordering. - 4.4 Ensure strict error semantics:
- entire matching operation fails immediately on error
- log the failing chunk input list via Python logging
- 4.5 Update
CostTrackerto log batch requests: log once per chunk with count of embeddings requested.
Phase 5: Configuration
- 5.1 Extend config model to include
azure_openai.embedding_batch_size(integer, default: 128, no enforced maximum). - 5.2 Update
config.toml.examplewith the new setting and comments. - 5.3 Ensure fallback: if
embedding_batch_sizeis not specified inconfig.toml, use the default value (128).
Phase 6: Tests
- 6.1 Unit tests: global prefetch/dedup
- verify dedup across required + all candidates (incl. roles)
- verify embedding client is called once per unique normalized text (only for cache misses)
- verify empty/whitespace-only texts are skipped
- verify a Python logger warning is emitted when all candidate competences normalize to empty
- 6.2 Unit tests: cache layering
- verify in-memory
_run_cacheprevents repeated SQLite reads within a run - verify SQLite hits prevent Azure calls
- verify in-memory
- 6.3 Unit tests: Azure batch request behavior (mocked)
- verifies batch call for N texts when
N <= batch_size - verifies chunking when
N > batch_size(multiple batch calls) - verifies output ordering is stable (using
indexfield or assuming stable order) - verifies strict error propagation
- verifies the failing chunk input list is logged
- verifies cost tracking logs once per chunk with count
- verifies batch call for N texts when
- 6.4 Integration test (manual/gated only): real Azure batch embeddings
- confirm request uses batch
input=[...]semantics - ensure behavior matches expected semantics for a representative set of texts
- confirm request uses batch
Phase 7: Documentation + Assistant Prompt Updates
- 7.1 Update
README.mdto describe the optimization at a high level and mention the new batch size knob. - 7.2 Update
docs/assistant_system_prompt.mdto reflect:- embeddings are prefetched globally per run
- batching/chunking is used and configurable
- failure semantics remain strict (no heuristics)
- 7.3 Update any Azure setup docs if needed (e.g.,
docs/azure_openai_setup.md) to mention embedding batch behavior and tuning.
Phase 8: Quality Gates / Release Hygiene
- 8.1 Run unit tests:
uv run pytest -m "not integration" -q - 8.2 Run Ruff and mypy via
uv. - 8.3 (Manual/gated only) Run integration tests (Azure) to validate real batch calls.
- 8.4 Update change docs status/checklists and ensure OpenSpec validates (
openspec validate accelerate-embedding-similarity --strict).