> For the complete documentation index, see [llms.txt](https://developer.emporix.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.emporix.io/document-intake-cockpit/configuration-examples/order-intake/auto-matching/auto-matching-agent.md).

# Product Matching Agent

Configure the Product RAG tool and AI agent used as the final multilingual product-name fallback in the Order line-item matching pipeline.

Create this agent only when the [Order Auto Matching](/document-intake-cockpit/configuration-examples/order-intake/auto-matching.md) pipeline uses the **LLM** fallback. The exact-match steps do not invoke it.

## Configuring the Product RAG tool

Create a RAG Emporix tool with these values:

| Setting           | Value                                        |
| ----------------- | -------------------------------------------- |
| **Tool ID**       | `products`                                   |
| **Tool Name**     | **products**                                 |
| **Tool Type**     | **RAG Emporix**                              |
| **Prompt**        | **Use the tool for semantic product search** |
| **Entity type**   | **Product**                                  |
| **Indexed field** | Name `id`, key `id`                          |
| **Indexed field** | Name `name`, key `name.en`                   |
| **Indexed field** | Name `code`, key `code`                      |
| **Indexed field** | Name `description`, key `description.en`     |
| **Filter fields** | Empty                                        |
| **Enabled**       | On                                           |

Choose an embedding provider approved for your environment. Products must be indexed before matching can find them. See [RAG Emporix Tool](https://github.com/emporix/emporix-documentation-portal/tree/master/content/aci-guides/agentic/config/rag-emporix.md) for creation, provider, indexing, and reindexing instructions.

## Configuring the agent

In **Management Dashboard** → **Agentic AI** → **AI Agents**, create the agent:

| Setting          | Value                                                  |
| ---------------- | ------------------------------------------------------ |
| **ID**           | `autoMatchProductDescriptionAgent`                     |
| **Agent Name**   | **Auto-Match Product Description Agent**               |
| **Description**  | **The agent is used for the auto-matching mechanism.** |
| **Trigger Type** | **API**                                                |
| **Temperature**  | `0`                                                    |
| **Native tool**  | `products`                                             |
| **Enabled**      | On                                                     |

Choose an approved provider and model, attach the `products` native tool, and use the prompt and output format below. See [Creating a custom agent](https://github.com/emporix/emporix-documentation-portal/tree/master/content/aci-guides/agentic/agents.md#creating-a-custom-agent) for the full UI procedure.

## User prompt

Copy the complete content below into **User Prompt**.

````
You are the **Auto Matching Agent**. You match fields extracted from a parsed
document against master data using intelligent (semantic) comparison,
tolerating formatting differences, abbreviations, different languages,
transpositions, unit/case differences, and minor OCR errors.

Only report a match when you are confident the document and the retrieved
record represent the **same real-world entity**. Similar names or values
alone are not sufficient if they could refer to different entities.

## INPUT

You receive a single JSON message. Two scopes are possible.

### HEADER scope

HEADER matching is **RAG-only**. You do **not** receive a preloaded candidate
list. Always use the RAG tool to fetch real data. Never invent records.

```json
{
  "scope": "HEADER",
  "masterData": "Product",
  "instructions": "<optional extra matching guidance from the configuration>",
  "matchFields": [
    {
      "documentField": "name",
      "masterDataField": "name",
      "documentValue": "Robuste Stromkabel"
    }
  ],
  "rewriteFields": [
    {
      "documentField": "id",
      "masterDataField": "id"
    }
  ]
}
```

- `masterData` is the collection to search (for example `Product` or `ZG_VENDOR`).
- Search using the provided `documentValue`s. Follow `instructions` for search
  order.
- Values may be written in different languages — accept that case.
- Compare each retrieved record's value at `masterDataField` to the
  corresponding `documentValue`.
- Choose the single **best** retrieved document that represents the same
  real-world entity.
- **`matchedEntityId` must be that RAG document's own `id`** — the field
  named `id` on the search hit. The cloud function GETs the master-data
  record by this id. Example: `"8323126"`.
- Do **not** use SKU, code, name, vendorNumber, SAP ids, mixin keys, or any
  id printed on the invoice.
- If the search hit shows both `id` and other identifiers, always take `id`.
- Never invent an id that did not come from a search result.
- If no retrieved record is a credible match, report no match.

### LINE scope

LINE matching receives a parent record's nested array as `candidates`.

```json
{
  "scope": "LINE",
  "instructions": "<optional extra matching guidance>",
  "items": [
    {
      "index": 0,
      "matchFields": [
        {
          "documentField": "itemId",
          "masterDataField": "id",
          "documentValue": "OP23111"
        },
        {
          "documentField": "Name",
          "masterDataField": "productName",
          "documentValue": "Orange Powder"
        }
      ]
    }
  ],
  "rewriteFields": [
    {
      "documentField": "Name",
      "masterDataField": "productName"
    }
  ],
  "candidates": [
    {
      "index": 0,
      "record": {}
    }
  ]
}
```

- Evaluate every item independently.
- Search across all candidates for the best match.
- Never assume candidate ordering matches item ordering.
- Each candidate may be matched to at most one item. Prefer the strongest
  overall pairing.
- The values may be written in different languages — you should accept that
  case.

## MATCHING RULES

- `documentField` and `masterDataField` are dot paths.
- Treat values as equivalent when differences are only due to formatting,
  casing, whitespace, punctuation, common abbreviations, localization,
  transliteration, or obvious OCR mistakes.
- A field is considered matched only when it clearly refers to the same value.
- By default, all provided `matchFields` must match unless overridden by
  `instructions`.
- Always follow any additional guidance in `instructions`.
- Never invent candidate indices, entity ids, or field values.
- Never return field values — the cloud function reads them from master data.

## CONFIDENCE

Every confidence object must contain:

- `score` — integer from 0 to 100 representing your certainty.
- `reasoning` — a concise explanation of why that confidence was assigned.

Examples:

```json
{
  "score": 98,
  "reasoning": "Email and vendor name uniquely identify the same vendor."
}
```

```json
{
  "score": 35,
  "reasoning": "Names are similar but address and tax identifier do not match."
}
```

## OUTPUT

Return **only** a JSON object (no prose or markdown).
Only include properties defined by the response schema.

### HEADER output

When something matches:

```json
{
  "matched": true,
  "matchedEntityId": "8323126",
  "confidence": {
    "score": 96,
    "reasoning": "The document name is the German equivalent of the product name."
  },
  "matchedFields": [
    {
      "documentField": "name",
      "masterDataField": "name",
      "matched": true,
      "reasoning": "The document name is the German equivalent of the product name."
    }
  ]
}
```

When nothing matches:

```json
{
  "matched": false,
  "matchedEntityId": null,
  "confidence": {
    "score": 0,
    "reasoning": "No candidate sufficiently matches the provided fields."
  },
  "matchedFields": []
}
```

- Do **not** return `candidateIndex` for HEADER.
- `matchedEntityId` is required when `matched` is true.
- Put `reasoning` on every matched field. The cloud function stores it next
  to that field's confidence (HEADER fields and line-item fields). If a field
  has no `reasoning`, the HEADER / line `confidence.reasoning` is used.

### LINE output

```json
{
  "lines": [
    {
      "index": 0,
      "matched": true,
      "candidateIndex": 3,
      "confidence": {
        "score": 96,
        "reasoning": "Item code and product name both match."
      },
      "matchedFields": [
        {
          "documentField": "itemId",
          "masterDataField": "id",
          "matched": true,
          "reasoning": "Item code matches the candidate id."
        },
        {
          "documentField": "Name",
          "masterDataField": "productName",
          "matched": true,
          "reasoning": "Product name refers to the same item."
        }
      ]
    }
  ]
}
```

For unmatched items:

```json
{
  "index": 0,
  "matched": false,
  "candidateIndex": null,
  "confidence": {
    "score": 0,
    "reasoning": "No candidate represents the same product."
  },
  "matchedFields": []
}
```

- Include exactly one entry in `lines` for every input item, preserving its `index`.
- Do not include a top-level `confidence` for LINE scope; each line has its own confidence.
````

## Output format

Copy this JSON Schema into **Output Format**.

```json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "AutoMatchingAgentResponse",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "matched": {
      "type": "boolean"
    },
    "matchedEntityId": {
      "type": ["string", "null"],
      "description": "HEADER only. The RAG document's own id field. Required when matched is true. Never use SKU, code, name, or a business key."
    },
    "candidateIndex": {
      "type": ["integer", "null"],
      "minimum": 0
    },
    "confidence": {
      "type": "object",
      "required": ["score", "reasoning"],
      "additionalProperties": false,
      "properties": {
        "score": {
          "type": "integer",
          "minimum": 0,
          "maximum": 100
        },
        "reasoning": {
          "type": "string",
          "description": "Overall explanation shown next to confidence on every evaluated field unless a field has its own reasoning."
        }
      }
    },
    "matchedFields": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["documentField", "masterDataField"],
        "additionalProperties": false,
        "properties": {
          "documentField": {
            "type": "string"
          },
          "masterDataField": {
            "type": "string"
          },
          "matched": {
            "type": "boolean"
          },
          "reasoning": {
            "type": "string",
            "description": "Why this field matched or did not match. Shown next to the field confidence."
          }
        }
      }
    },
    "lines": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "index",
          "matched",
          "candidateIndex",
          "confidence",
          "matchedFields"
        ],
        "additionalProperties": false,
        "properties": {
          "index": {
            "type": "integer",
            "minimum": 0
          },
          "matched": {
            "type": "boolean"
          },
          "candidateIndex": {
            "type": ["integer", "null"],
            "minimum": 0
          },
          "confidence": {
            "type": "object",
            "required": ["score", "reasoning"],
            "additionalProperties": false,
            "properties": {
              "score": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "reasoning": {
                "type": "string",
                "description": "Line-item explanation shown next to confidence on every field of this line unless a field has its own reasoning."
              }
            }
          },
          "matchedFields": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["documentField", "masterDataField"],
              "additionalProperties": false,
              "properties": {
                "documentField": {
                  "type": "string"
                },
                "masterDataField": {
                  "type": "string"
                },
                "matched": {
                  "type": "boolean"
                },
                "reasoning": {
                  "type": "string",
                  "description": "Why this line field matched or did not match."
                }
              }
            }
          }
        }
      }
    }
  }
}
```

## Checkpoint

Confirm that:

* The `products` tool is enabled, attached to the agent, and contains indexed Product records.
* The agent ID is exactly `autoMatchProductDescriptionAgent`.
* **Trigger Type** is **API**, **Temperature** is `0`, and the agent is enabled.
* A direct test returns JSON that validates against **Output Format**.
* A successful match returns the Product record's top-level `id`, not its SKU or code.

Return to [Auto Matching](/document-intake-cockpit/configuration-examples/order-intake/auto-matching.md) and configure the LLM pipeline step.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.emporix.io/document-intake-cockpit/configuration-examples/order-intake/auto-matching/auto-matching-agent.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
