Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

logger = get_logger("OllamaEmbeddingEngine")

# Error message constants
_MISSING_EMBEDDING_KEY_MSG = "No 'embedding' or 'embeddings' key found in Ollama API response"


class OllamaEmbeddingEngine(EmbeddingEngine):
"""
Expand Down Expand Up @@ -123,8 +126,14 @@ async def _get_embedding(self, prompt: str) -> List[float]:
async with session.post(
self.endpoint, json=payload, headers=headers, timeout=60.0
) as response:
response.raise_for_status()
data = await response.json()
return data["embeddings"][0]
# Handle both "embedding" (singular, Ollama API) and "embeddings" (plural, backwards compatibility)
if "embedding" in data:
return data["embedding"]
if "embeddings" in data:
return data["embeddings"][0]
raise KeyError(_MISSING_EMBEDDING_KEY_MSG)

def get_vector_size(self) -> int:
"""
Expand Down
96 changes: 96 additions & 0 deletions cognee/tests/test_ollama_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Test script to verify OllamaEmbeddingEngine fix with real Ollama server.
Tests that the fix correctly handles Ollama's API response format.
"""
import asyncio
import sys
from cognee.infrastructure.databases.vector.embeddings.OllamaEmbeddingEngine import (
OllamaEmbeddingEngine,
)


async def test_ollama_embedding():
"""Test OllamaEmbeddingEngine with real Ollama server."""

print("=" * 80)
print("Testing OllamaEmbeddingEngine Fix")
print("=" * 80)

# Configure for your Ollama server
ollama_endpoint = "http://10.0.10.9:11434/api/embeddings"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Hardcoded private IP address will break CI/CD and other environments.

The endpoint "http://10.0.10.9:11434/api/embeddings" is a private network address specific to your local setup. This test will fail in:

  • Continuous integration pipelines
  • Other developers' machines
  • Production environments
  • Any system without access to this specific IP

Apply this diff to make the endpoint configurable:

-    ollama_endpoint = "http://10.0.10.9:11434/api/embeddings"
+    ollama_endpoint = os.getenv("OLLAMA_ENDPOINT", "http://localhost:11434/api/embeddings")
     ollama_model = "nomic-embed-text"

Add this import at the top:

 import asyncio
 import sys
+import os
 from cognee.infrastructure.databases.vector.embeddings.OllamaEmbeddingEngine import (

This allows customization via environment variables while defaulting to localhost.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In cognee/tests/test_ollama_fix.py around line 21, the test uses a hardcoded
private IP endpoint "http://10.0.10.9:11434/api/embeddings" which will break CI
and other environments; change it to read from an environment variable (e.g.,
OLLAMA_ENDPOINT) with a sensible default like
"http://localhost:11434/api/embeddings", add the necessary import for os at the
top of the file, and replace the hardcoded string with
os.getenv("OLLAMA_ENDPOINT", "http://localhost:11434/api/embeddings") so the
endpoint can be configured externally while preserving local defaults.

ollama_model = "nomic-embed-text"

print("\nConfiguration:")
print(f" Endpoint: {ollama_endpoint}")
print(f" Model: {ollama_model}")
print(" Expected dimensions: 768")

# Initialize the embedding engine
print("\n1. Initializing OllamaEmbeddingEngine...")
try:
engine = OllamaEmbeddingEngine(
model=ollama_model,
dimensions=768,
endpoint=ollama_endpoint,
huggingface_tokenizer="bert-base-uncased",
)
print(" ✅ Engine initialized successfully")
except Exception as e:
print(f" ❌ Failed to initialize engine: {e}")
sys.exit(1)
Comment on lines +38 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Replace sys.exit() with proper test assertions.

Using sys.exit(1) is unconventional for tests. Standard test frameworks use assertions or raise exceptions to indicate failures, allowing test runners to properly collect and report results.

If keeping this as an integration test script, at least replace sys.exit() with exceptions:

     except Exception as e:
         print(f"   ❌ Failed to initialize engine: {e}")
-        sys.exit(1)
+        raise RuntimeError(f"Engine initialization failed: {e}") from e

Better yet, use the proper unit test approach suggested in the previous comment.

Also applies to: 59-64, 81-83

🧰 Tools
🪛 Ruff (0.14.5)

39-39: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
In cognee/tests/test_ollama_fix.py around lines 39-41, 59-64 and 81-83, replace
the calls to sys.exit(1) inside exception handlers with proper test failures by
either raising an exception or using the test framework's failure helpers (e.g.,
pytest.fail("...") or assert False, with a clear message containing the original
exception), so the test runner can record the failure instead of terminating the
process; ensure the original exception text is included in the failure message
for diagnostics.


# Test single text embedding
print("\n2. Testing single text embedding...")
test_texts = ["The sky is blue and the grass is green."]

try:
embeddings = await engine.embed_text(test_texts)
print(" ✅ Embedding generated successfully")
print(f" 📊 Embedding shape: {len(embeddings)} texts, {len(embeddings[0])} dimensions")
print(f" 📊 First 5 values: {embeddings[0][:5]}")

# Verify dimensions
if len(embeddings[0]) == 768:
print(" ✅ Dimensions match expected (768)")
else:
print(f" ⚠️ Dimensions mismatch: got {len(embeddings[0])}, expected 768")

except KeyError as e:
print(f" ❌ KeyError (this is the bug we're fixing): {e}")
sys.exit(1)
except Exception as e:
print(f" ❌ Failed to generate embedding: {type(e).__name__}: {e}")
sys.exit(1)

# Test multiple texts
print("\n3. Testing multiple text embeddings...")
test_texts_multiple = [
"Hello world",
"Machine learning is fascinating",
"Ollama embeddings work great"
]

try:
embeddings = await engine.embed_text(test_texts_multiple)
print(" ✅ Multiple embeddings generated successfully")
print(f" 📊 Generated {len(embeddings)} embeddings")
for i, emb in enumerate(embeddings):
print(f" 📊 Text {i+1}: {len(emb)} dimensions, first 3 values: {emb[:3]}")

except Exception as e:
print(f" ❌ Failed to generate embeddings: {type(e).__name__}: {e}")
sys.exit(1)

# Success!
print("\n" + "=" * 80)
print("✅ ALL TESTS PASSED!")
print("=" * 80)
print("\nThe OllamaEmbeddingEngine fix is working correctly!")
print("- Handles 'embedding' (singular) response from Ollama API")
print("- Generates embeddings successfully")
print("- Correct dimensions (768 for nomic-embed-text)")
print("\n✅ Ready to submit PR!")


if __name__ == "__main__":
asyncio.run(test_ollama_embedding())
12 changes: 10 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.