Skip to content

Commit fbb70ec

Browse files
authored
chore: update the docs for io mapper (#54)
- Add examples of usage with LlamaIndex
1 parent abef172 commit fbb70ec

File tree

1 file changed

+296
-44
lines changed

1 file changed

+296
-44
lines changed

Diff for: docs/pages/semantic_sdk/io_mapper.md

+296-44
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ The IO mapper Agent can be fed the schema definitions of inputs and outputs as d
3131
To get a local copy up and running follow these simple steps.
3232

3333
### Prerequisites
34+
- [Poetry](https://python-poetry.org/)
35+
- [cmake](https://cmake.org/)
3436

3537
### Installation
3638

@@ -60,42 +62,13 @@ This project supports specifying model interations using [LangGraph](https://lan
6062

6163
## How to use the Agent IO mapping
6264
:warning:<b> For each example, the detailed process of creating agents and configuring the respective multi-agent software is omitted. Instead, only the essential steps for configuring and integrating the IO mapper agent are presented.</b>
63-
### LangGraph Example 1
64-
65-
This example involves a multi-agent software system designed to process a create engagement campaign and share within an organization. It interacts with an agent specialized in creating campaigns, another agent specialized in identifying suitable users. The information is then relayed to an IO mapper, which converts the list of users and the campaign details to present statistics about the campaign.
66-
67-
#### Define an agent io mapper metadata
68-
69-
```python
70-
metadata = IOMappingAgentMetadata(
71-
input_fields=["selected_users", "campaign_details.name"],
72-
output_fields=["stats.status"],
73-
)
74-
75-
```
76-
77-
The above instruction directs the IO mapper agent to utilize the `selected_users` and `name` from the `campaign_details` field and map them to the `stats.status`. No further information is needed since the type information can be derived from the input data which is a pydantic model.
65+
## LangGraph
66+
We support usages with both LangGraph state defined with TypedDict or as a Pydantic object
7867

79-
:information_source: <i>Both input_fields and output_fields can also be sourced with a list composed of str and/or instances of FieldMetadata as the bellow example shows</i>:
80-
81-
```python
82-
metadata = IOMappingAgentMetadata(
83-
input_fields=[
84-
FieldMetadata(
85-
json_path="selected_users", description="A list of users to be targeted"
86-
),
87-
FieldMetadata(
88-
json_path="campaign_details.name",
89-
description="The name that can be used by the campaign",
90-
examples=["Campaign A"]
91-
),
92-
],
93-
output_fields=["stats"],
94-
)
95-
```
68+
### Entities
9669

9770
<details>
98-
<summary><h4>Expand to better understand the IOMappingAgentMetadata Interface</h4></summary>
71+
<summary><h4>IOMappingAgentMetadata</h4></summary>
9972

10073
## IOMappingAgentMetadata model Interface
10174
<table>
@@ -161,14 +134,8 @@ TypeAdapter(GraphState).json_schema()
161134
</table>
162135
</details>
163136

164-
### Define an Instance of the Agent
165-
166-
```python
167-
mapping_agent = IOMappingAgent(metadata=metadata, llm=llm)
168-
```
169-
170137
<details>
171-
<summary>Expand for explanation of interface for IOMappingAgent model</summary>
138+
<summary><h4>IOMappingAgent</h4></summary>
172139

173140
## IOMappingAgent model
174141
<table>
@@ -222,6 +189,48 @@ IOMappingAgentMetadata(
222189
</table>
223190
</details>
224191

192+
### LangGraph Example 1
193+
194+
This example involves a multi-agent software system designed to process a create engagement campaign and share within an organization. It interacts with an agent specialized in creating campaigns, another agent specialized in identifying suitable users. The information is then relayed to an IO mapper, which converts the list of users and the campaign details to present statistics about the campaign.
195+
196+
#### Define an agent io mapper metadata
197+
198+
```python
199+
metadata = IOMappingAgentMetadata(
200+
input_fields=["selected_users", "campaign_details.name"],
201+
output_fields=["stats.status"],
202+
)
203+
204+
```
205+
206+
The above instruction directs the IO mapper agent to utilize the `selected_users` and `name` from the `campaign_details` field and map them to the `stats.status`. No further information is needed since the type information can be derived from the input data which is a pydantic model.
207+
208+
:information_source: <i>Both input_fields and output_fields can also be sourced with a list composed of str and/or instances of FieldMetadata as the bellow example shows</i>:
209+
210+
```python
211+
metadata = IOMappingAgentMetadata(
212+
input_fields=[
213+
FieldMetadata(
214+
json_path="selected_users", description="A list of users to be targeted"
215+
),
216+
FieldMetadata(
217+
json_path="campaign_details.name",
218+
description="The name that can be used by the campaign",
219+
examples=["Campaign A"]
220+
),
221+
],
222+
output_fields=["stats"],
223+
)
224+
```
225+
226+
### Define an Instance of the Agent
227+
228+
```python
229+
mapping_agent = IOMappingAgent(metadata=metadata, llm=llm)
230+
```
231+
232+
233+
225234
### Add the node to the LangGraph graph
226235

227236
```python
@@ -290,15 +299,258 @@ graph.add_node(
290299
graph.add_edge("recipe_expert", "recipe_io_mapper")
291300
```
292301

293-
#### LlamaIndex
302+
## LlamaIndex
303+
We support both LlamaIndex Workflow and the new AgentWorkflow multi agent software
304+
### Entities
305+
<details>
306+
<summary>IOMappingInputEvent</summary>
307+
308+
## IOMappingInputEvent event received by io mapper step
309+
<table>
310+
<tr>
311+
<td>Property</td>
312+
<td>Description</td>
313+
<td>Required</td>
314+
<td>Value Example</td>
315+
</tr>
316+
<tr>
317+
<td>metadata</td>
318+
<td>Object used to describe the input fields, output fields schema and any relevant information to be used in the mapping</td>
319+
<td>:white_check_mark:</td>
320+
<td>
321+
322+
```python
323+
IOMappingAgentMetadata(
324+
input_fields=["selected_users", "campaign_details.name"],
325+
output_fields=["stats"],
326+
)
327+
```
328+
329+
</td>
330+
</tr>
331+
<tr>
332+
<td>config</td>
333+
<td>Object containing information such as the llm instance that will be used to perform the translation</td>
334+
<td>:white_check_mark:</td>
335+
<td>
336+
337+
```python
338+
LLamaIndexIOMapperConfig(llm=llm)
339+
```
340+
341+
</td>
342+
</tr>
343+
<tr>
344+
<td>data</td>
345+
<td>Represents the input data to be used in the translation</td>
346+
<td>:white_check_mark:</td>
347+
<td>
348+
349+
```python
350+
OverallState(campaign_details=campaign_details, selected_users=ev.list_users),
351+
```
352+
353+
</td>
354+
</tr>
355+
</table>
356+
</details>
357+
358+
<details>
359+
<summary>IOMappingOutputEvent</summary>
360+
361+
## IOMappingOutputEvent event received by io mapper step
362+
<table>
363+
<tr>
364+
<td>Property</td>
365+
<td>Description</td>
366+
<td>Required</td>
367+
<td>Value Example</td>
368+
</tr>
369+
<tr>
370+
<td>mapping_result</td>
371+
<td>A dictionary containing the result of the mapping</td>
372+
<td>:white_check_mark:</td>
373+
<td>
374+
N/A
375+
</td>
376+
</tr>
377+
</table>
378+
379+
</details>
380+
381+
382+
### Example of usage in a LlamaIndex workflow
383+
384+
In this example we recreate the campaign workflow using [LlamaIndex workflow](https://docs.llamaindex.ai/en/stable/module_guides/workflow/)
385+
### Begin by importing the neccessary object
386+
```python
387+
from agntcy_iomapper import IOMappingAgent, IOMappingAgentMetadata
388+
```
389+
390+
#### Define the workflow
391+
392+
```python
393+
class CampaignWorkflow(Workflow):
394+
@step
395+
async def prompt_step(self, ctx: Context, ev: StartEvent) -> PickUsersEvent:
396+
await ctx.set("llm", ev.get("llm"))
397+
return PickUsersEvent(prompt=ev.get("prompt"))
398+
399+
@step
400+
async def pick_users_step(
401+
self, ctx: Context, ev: PickUsersEvent
402+
) -> CreateCampaignEvent:
403+
return CreateCampaignEvent(list_users=users)
404+
405+
# The step that will trigger IO mapping
406+
@step
407+
async def create_campaign(
408+
self, ctx: Context, ev: CreateCampaignEvent
409+
) -> IOMappingInputEvent:
410+
prompt = f"""
411+
You are a campaign builder for company XYZ. Given a list of selected users and a user prompt, create an engaging campaign.
412+
Return the campaign details as a JSON object with the following structure:
413+
{{
414+
"name": "Campaign Name",
415+
"content": "Campaign Content",
416+
"is_urgent": yes/no
417+
}}
418+
Selected Users: {ev.list_users}
419+
User Prompt: Create a campaign for all users
420+
"""
421+
parser = PydanticOutputParser(output_cls=Campaign)
422+
llm = await ctx.get("llm", default=None)
423+
424+
llm_response = llm.complete(prompt)
425+
try:
426+
campaign_details = parser.parse(str(llm_response))
427+
metadata = IOMappingAgentMetadata(
428+
input_fields=["selected_users", "campaign_details.name"],
429+
output_fields=["stats"],
430+
)
431+
config = LLamaIndexIOMapperConfig(llm=llm)
432+
433+
io_mapping_input_event = IOMappingInputEvent(
434+
metadata=metadata,
435+
config=config,
436+
data=OverallState(
437+
campaign_details=campaign_details,
438+
selected_users=ev.list_users,
439+
),
440+
)
441+
return io_mapping_input_event
442+
except Exception as e:
443+
print(f"Error parsing campaign details: {e}")
444+
return StopEvent(result=f"{e}")
445+
446+
@step
447+
async def after_translation(self, evt: IOMappingOutputEvent) -> StopEvent:
448+
return StopEvent(result="Done")
449+
```
450+
It is important to notice:
451+
The step create_campaign will trigger the IO mapper. Why?
452+
Well, because:
453+
454+
1. It declares that it returns an instance of IOMappingInputEvent
455+
```python
456+
async def create_campaign(self, ctx: Context, ev: CreateCampaignEvent) -> IOMappingInputEvent:
457+
```
458+
2. And finally it creates and returns a valid instance of the IOMappingInputEvent
459+
```python
460+
# define an instance metadata
461+
metadata = IOMappingAgentMetadata(
462+
input_fields=["selected_users", "campaign_details.name"],
463+
output_fields=["stats"]
464+
)
294465

295-
### LlamaIndex AgentWorkflow [WIP]
466+
#define an instance of config with must have an llm instance
467+
config = LLamaIndexIOMapperConfig(llm=llm)
468+
469+
# Finally return define and return the IOMappingInputEvent
470+
io_mapping_input_event = IOMappingInputEvent(
471+
metadata=metadata,
472+
config=config,
473+
data=OverallState(
474+
campaign_details=campaign_details,
475+
selected_users=ev.list_users,
476+
),
477+
)
478+
return io_mapping_input_event
479+
```
480+
481+
#### Add The IO mapper step
482+
483+
```python
484+
w = CampaignWorkflow()
485+
486+
IOMappingAgent.as_worfklow_step(workflow=w)
487+
```
488+
489+
### Example of usage in a LlamaIndex AgentWorkflow
490+
491+
In this example we recreate the recipe workflow using [LlamaIndex workflow]([https://docs.llamaindex.ai/en/stable/module_guides/workflow/](https://docs.llamaindex.ai/en/stable/examples/agent/agent_workflow_multi/))
492+
493+
#### Import the necessary objects
494+
```python
495+
from agntcy_iomapper import FieldMetadata, IOMappingAgent, IOMappingAgentMetadata
496+
```
497+
498+
#### Define an instance of the IOMappingAgentMetadata
499+
500+
```python
501+
mapping_metadata = IOMappingAgentMetadata(
502+
input_fields=["documents.0.text"],
503+
output_fields=[
504+
FieldMetadata(
505+
json_path="recipe",
506+
description="this is a recipe for the ingredients you've provided",
507+
)
508+
],
509+
input_schema=TypeAdapter(GraphState).json_schema(),
510+
output_schema={
511+
"type": "object",
512+
"properties": {
513+
"title": {"type": "string"},
514+
"ingredients": {"type": "array", "items": {"type": "string"}},
515+
"instructions": {"type": "string"},
516+
},
517+
"required": ["title", "ingredients, instructions"],
518+
},
519+
)
520+
521+
522+
```
523+
524+
#### Finally define the IOMappingAgent and add it to the AgentWorkflow.
525+
Important to note that a tool is passed, to instruct the io mapper where to go next in the flow.
526+
```
527+
io_mapping_agent = IOMappingAgent.as_workflow_agent(
528+
mapping_metadata=mapping_metadata,
529+
llm=llm,
530+
name="IOMapperAgent",
531+
description="Useful for mapping a recipe document into recipe object",
532+
can_handoff_to=["Formatter_Agent"],
533+
tools=[got_to_format],
534+
)
535+
536+
537+
io_mapping_agent = IOMappingAgent.as_workflow_agent(
538+
mapping_metadata=mapping_metadata,
539+
llm=llm,
540+
name="IOMapperAgent",
541+
description="Useful for mapping a recipe document into recipe object",
542+
can_handoff_to=["Formatter_Agent"],
543+
tools=[got_to_format],
544+
)
545+
546+
```
296547

297-
<b>WIP</b>
298548

299549
### Use Examples
300550

301-
1. Install [cmake](https://cmake.org/)
551+
1. Install:
552+
- [cmake](https://cmake.org/)
553+
- [pip](https://pip.pypa.io/en/stable/installation/)
302554
2. From within examples folder run the desired make command, for example:
303555

304556
```shell

0 commit comments

Comments
 (0)