New specialized agent: Identity Graph Operator - operates a shared identity graph so multiple agents in a system all resolve to the same canonical entity. Prevents duplicate records, conflicting actions, and cascading errors when agents encounter the same real-world entity from different sources. New example workflow: Multi-Agent Shared Identity - step-by-step walkthrough of 3 agents (Support, Backend, Analytics) handling the same customer across email, phone, and web channels with shared identity resolution. Enhanced Agentic Identity & Trust Architect with a section showing how it complements the Identity Graph Operator (agent identity vs entity identity).
234 lines
7.5 KiB
Markdown
234 lines
7.5 KiB
Markdown
# Multi-Agent Workflow: Shared Identity Resolution
|
|
|
|
> What happens when three agents all encounter the same customer from different sources - and how to prevent duplicate records, conflicting actions, and cascading errors.
|
|
|
|
## The Problem
|
|
|
|
You're running a customer support system with three agents:
|
|
- **Support Responder** processes incoming tickets
|
|
- **Backend Architect** maintains the customer database
|
|
- **Analytics Reporter** generates weekly customer reports
|
|
|
|
A customer named "Bill Smith" (wsmith@acme.com) contacts you through email support, then calls your phone line, then submits a web form. Each channel uses a different source system. Without shared identity, you get three separate customer records and three separate responses.
|
|
|
|
## Agent Team
|
|
|
|
| Agent | Role in this workflow |
|
|
|-------|---------------------|
|
|
| Identity Graph Operator | Resolves all records to canonical entities before other agents act |
|
|
| Support Responder | Handles customer tickets (only after identity is resolved) |
|
|
| Backend Architect | Designs the data model with identity-first architecture |
|
|
| Analytics Reporter | Reports on unique customers, not duplicate records |
|
|
| Reality Checker | Verifies merge decisions meet quality gates |
|
|
|
|
## The Workflow
|
|
|
|
### Step 1 - Set Up the Identity Layer
|
|
|
|
**Activate Identity Graph Operator**
|
|
|
|
```
|
|
Activate Identity Graph Operator.
|
|
|
|
We have 3 data sources for customer records:
|
|
- "email_support" - tickets from email (fields: email, name, subject)
|
|
- "phone_support" - call logs (fields: phone, caller_name, call_date)
|
|
- "web_forms" - web submissions (fields: email, full_name, phone, message)
|
|
|
|
Set up the shared identity graph so all agents resolve to the same customer.
|
|
```
|
|
|
|
The Identity Graph Operator runs:
|
|
|
|
```
|
|
register_agent with capabilities: ["identity_resolution", "entity_matching", "merge_review"]
|
|
|
|
# Then resolves incoming records as they arrive
|
|
```
|
|
|
|
### Step 2 - First Record Arrives (Email)
|
|
|
|
The Support Responder receives a ticket from email_support:
|
|
|
|
```json
|
|
{
|
|
"source": "email_support",
|
|
"external_id": "ticket-9201",
|
|
"email": "wsmith@acme.com",
|
|
"name": "Bill Smith",
|
|
"subject": "Can't reset my password"
|
|
}
|
|
```
|
|
|
|
**Before responding, the Support Responder asks the Identity Graph Operator to resolve:**
|
|
|
|
```
|
|
resolve with source_name: "email_support", external_id: "ticket-9201",
|
|
data: { "email": "wsmith@acme.com", "first_name": "Bill", "last_name": "Smith" }
|
|
```
|
|
|
|
Result: New entity created (first time seeing this person).
|
|
|
|
```json
|
|
{
|
|
"entity_id": "ent-a1b2c3",
|
|
"is_new": true,
|
|
"confidence": 1.0,
|
|
"canonical_data": { "email": "wsmith@acme.com", "first_name": "bill", "last_name": "smith" }
|
|
}
|
|
```
|
|
|
|
Support Responder now handles the ticket, tagged with `entity_id: ent-a1b2c3`.
|
|
|
|
### Step 3 - Second Record Arrives (Phone)
|
|
|
|
A call comes in through phone_support:
|
|
|
|
```json
|
|
{
|
|
"source": "phone_support",
|
|
"external_id": "call-7744",
|
|
"phone": "+1-555-014-2",
|
|
"caller_name": "William Smith"
|
|
}
|
|
```
|
|
|
|
**Identity Graph Operator resolves:**
|
|
|
|
```
|
|
resolve with source_name: "phone_support", external_id: "call-7744",
|
|
data: { "phone": "+15550142", "first_name": "William", "last_name": "Smith" }
|
|
```
|
|
|
|
The engine doesn't have a phone match yet (the email record didn't include a phone). This creates a new entity:
|
|
|
|
```json
|
|
{
|
|
"entity_id": "ent-d4e5f6",
|
|
"is_new": true,
|
|
"confidence": 1.0
|
|
}
|
|
```
|
|
|
|
Two entities now exist. Are they the same person? The Identity Graph Operator isn't sure yet - no overlapping fields to match on.
|
|
|
|
### Step 4 - Third Record Arrives (Web Form)
|
|
|
|
A web form submission comes in with BOTH email and phone:
|
|
|
|
```json
|
|
{
|
|
"source": "web_forms",
|
|
"external_id": "form-3388",
|
|
"email": "wsmith@acme.com",
|
|
"full_name": "William Smith",
|
|
"phone": "555-0142",
|
|
"message": "Still can't reset my password, tried calling too"
|
|
}
|
|
```
|
|
|
|
**Identity Graph Operator resolves:**
|
|
|
|
```
|
|
resolve with source_name: "web_forms", external_id: "form-3388",
|
|
data: { "email": "wsmith@acme.com", "first_name": "William", "last_name": "Smith", "phone": "+15550142" }
|
|
```
|
|
|
|
Now it gets interesting. The engine:
|
|
1. Matches email to `ent-a1b2c3` (exact email match)
|
|
2. Matches phone to `ent-d4e5f6` (exact phone match after normalization)
|
|
3. Realizes both entities should be one person
|
|
|
|
```json
|
|
{
|
|
"entity_id": "ent-a1b2c3",
|
|
"is_new": false,
|
|
"confidence": 0.96,
|
|
"canonical_data": {
|
|
"email": "wsmith@acme.com",
|
|
"first_name": "william",
|
|
"last_name": "smith",
|
|
"phone": "+15550142"
|
|
}
|
|
}
|
|
```
|
|
|
|
The engine auto-merged `ent-d4e5f6` into `ent-a1b2c3` (the email entity had more members). The phone record is now linked to the same entity.
|
|
|
|
### Step 5 - Verify the Merge
|
|
|
|
**Activate Reality Checker to verify:**
|
|
|
|
```
|
|
Activate Reality Checker.
|
|
|
|
The identity graph just auto-merged two entities:
|
|
- ent-a1b2c3 (email: wsmith@acme.com, name: Bill Smith)
|
|
- ent-d4e5f6 (phone: +15550142, name: William Smith)
|
|
|
|
Review the merge evidence and verify this is correct.
|
|
```
|
|
|
|
The Reality Checker asks the Identity Graph Operator:
|
|
|
|
```
|
|
explain with entity_id: "ent-a1b2c3"
|
|
```
|
|
|
|
Gets back the full audit: merge chain, per-field scores, nickname mapping (Bill -> William), timeline of events. Confirms the merge is valid.
|
|
|
|
### Step 6 - Analytics Gets Clean Data
|
|
|
|
**Activate Analytics Reporter:**
|
|
|
|
```
|
|
Activate Analytics Reporter.
|
|
|
|
Generate a report on customer support volume this week.
|
|
Use the identity graph to count unique customers, not duplicate records.
|
|
```
|
|
|
|
The Analytics Reporter queries the identity graph:
|
|
|
|
```
|
|
search with q: "smith"
|
|
```
|
|
|
|
Gets back one entity with three linked source records, not three separate customers. The report shows 1 customer with 3 touchpoints, not 3 customers with 1 touchpoint each.
|
|
|
|
## What Would Have Happened Without Shared Identity
|
|
|
|
| With shared identity | Without shared identity |
|
|
|---|---|
|
|
| 1 customer record | 3 separate customer records |
|
|
| Support agent sees full history across channels | Support agent only sees the email ticket |
|
|
| Analytics reports 1 customer, 3 touchpoints | Analytics reports 3 customers |
|
|
| One password reset | Three separate password reset workflows |
|
|
| Customer gets one follow-up | Customer gets three follow-ups |
|
|
|
|
## Key Patterns
|
|
|
|
1. **Resolve before acting.** Every agent resolves incoming records through the identity graph BEFORE taking action. This is the single most important pattern.
|
|
|
|
2. **The bridge record.** The web form submission (Step 4) was the bridge - it had both email AND phone, connecting two previously separate entities. This is why multi-source ingestion matters.
|
|
|
|
3. **Propose, don't merge.** For lower confidence matches, the Identity Graph Operator creates proposals. The Reality Checker reviews them. Direct auto-merge only happens at high confidence.
|
|
|
|
4. **Memory compounds.** After this workflow, the identity graph remembers that "Bill" and "William" at the same phone number are the same person. Future agents benefit from this learned association.
|
|
|
|
## Scaling This Pattern
|
|
|
|
This 3-agent example works the same way with 30 agents or 300. The identity graph is the shared substrate:
|
|
|
|
- Sales agents resolve leads before adding to CRM
|
|
- Billing agents resolve customers before charging
|
|
- Shipping agents resolve addresses before dispatching
|
|
- Marketing agents resolve contacts before emailing
|
|
- Compliance agents resolve entities before flagging
|
|
|
|
Every agent resolves first. Every agent gets the same answer. That's the pattern.
|
|
|
|
---
|
|
|
|
**Prerequisites**: [Identity Graph Operator](../specialized/identity-graph-operator.md) agent must be activated first. Uses [Kanoniv](https://github.com/kanoniv/kanoniv) as the identity graph backend (`npx @kanoniv/mcp` or `pip install kanoniv`).
|