> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Knowledge Search Results

> Understand the SearchResult returned by Knowledge.search()

Knowledge search returns a typed result you can loop over and score.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    A[👤 Agent] --> B[🔍 Knowledge.search]
    B --> C[📦 SearchResult]
    C --> D[📄 SearchResultItem × N]

    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff
    classDef item fill:#6366F1,stroke:#7C90A0,color:#fff

    class A agent
    class B process
    class C result
    class D item
```

## Quick Start

<Steps>
  <Step title="Loop over results">
    Call `knowledge.search()` and iterate the `results` list.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent
    from praisonaiagents.knowledge import Knowledge

    knowledge = Knowledge()
    knowledge.store("Paris is the capital of France.")

    results = knowledge.search("capital of France", user_id="alice")

    for item in results.results:
        print(f"[{item.score:.2f}] {item.text}  ({item.source or '-'})")
    ```
  </Step>

  <Step title="Convert to a plain dict">
    Use `to_legacy_format()` or `to_dict()` when you need raw data.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    results = knowledge.search("capital of France", user_id="alice")

    legacy = results.to_legacy_format()   # {"results": [{"memory": ..., "text": ...}, ...]}
    plain = results.to_dict()             # {"results": [...], "metadata": {}, "query": ..., "total_count": N}
    ```
  </Step>
</Steps>

***

## How It Works

`Knowledge.search()` normalises every backend into one typed `SearchResult`.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant Knowledge
    participant Backend

    User->>Agent: Ask a question
    Agent->>Knowledge: search(query, user_id)
    Knowledge->>Backend: Retrieve matches
    Backend-->>Knowledge: Raw results
    Knowledge-->>Agent: SearchResult
    Agent-->>User: Ranked items
```

***

## The `SearchResult` shape

The container holds the ranked items plus search-level metadata.

| Field         | Type                     | Description                                              |
| ------------- | ------------------------ | -------------------------------------------------------- |
| `results`     | `list[SearchResultItem]` | Ranked items                                             |
| `metadata`    | `dict`                   | Search-level metadata (always dict, never None)          |
| `query`       | `str`                    | Original query string                                    |
| `total_count` | `int \| None`            | Total available (may exceed `len(results)` if paginated) |

***

## The `SearchResultItem` shape

Each item carries the content, its score, and optional source hints.

| Field        | Type          | Description                                                   |
| ------------ | ------------- | ------------------------------------------------------------- |
| `id`         | `str`         | Backend identifier                                            |
| `text`       | `str`         | Content (normalised from `memory` / `text` / `metadata.data`) |
| `score`      | `float`       | Relevance score (`0.0` default)                               |
| `metadata`   | `dict`        | Item metadata (always dict, never None)                       |
| `source`     | `str \| None` | Optional source hint                                          |
| `filename`   | `str \| None` | Optional filename                                             |
| `created_at` | `str \| None` | Timestamp                                                     |
| `updated_at` | `str \| None` | Timestamp                                                     |

***

## Common Patterns

### Show top-N with scores

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
results = knowledge.search("machine learning", user_id="alice")

for rank, item in enumerate(results.results, start=1):
    print(f"{rank}. [{item.score:.2f}] {item.text}")
```

### Convert to legacy dict format

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
results = knowledge.search("machine learning", user_id="alice")

legacy = results.to_legacy_format()
for row in legacy["results"]:
    print(row["memory"])  # legacy consumers expect the "memory" key
```

### Handle any backend shape

Custom backends can return a typed `SearchResult`, a legacy dict, or a plain list. Normalise them with one call.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.knowledge.models import normalize_search_result

raw = my_custom_backend.query("machine learning")   # dict, list, or SearchResult
results = normalize_search_result(raw)               # always a SearchResult

for item in results.results:
    print(item.text)
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Check .results, not the object">
    An empty `SearchResult` is still a dataclass instance, so it is always truthy.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # ❌ Wrong — SearchResult is a dataclass, always truthy
    if not results:
        print("No results")

    # ✅ Right — check .results (or .total_count)
    if not results.results:
        print("No results")
    ```
  </Accordion>

  <Accordion title="Trust metadata is a dict">
    `metadata` is never `None` on `SearchResult` or `SearchResultItem` — it defaults to an empty dict, so you never need to guard against `None`.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    for item in results.results:
        page = item.metadata.get("page")  # safe, metadata is always a dict
    ```
  </Accordion>

  <Accordion title="Use to_legacy_format() for dict consumers">
    Older code that expects mem0-shaped `{"results": [...]}` dicts stays compatible.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    legacy = results.to_legacy_format()
    send_to_older_pipeline(legacy)
    ```
  </Accordion>

  <Accordion title="Prefer typed access over dict access">
    Typed attributes are clearer and safer than dict lookups.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # ✅ Preferred
    print(item.text)

    # ❌ Avoid
    print(item.get("memory"))
    ```
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Knowledge Overview" icon="book-open" href="/docs/knowledge/overview">
    Give agents access to your documents
  </Card>

  <Card title="Knowledge CLI" icon="terminal" href="/docs/cli/knowledge-cli">
    Search from the command line
  </Card>
</CardGroup>
