Files
run-llama--llama_index/docs/examples/prompts/structured_input.ipynb
T
wehub-resource-sync a0c8464e58
Build Package / build (ubuntu-latest) (push) Failing after 1s
CodeQL / Analyze (python) (push) Failing after 1s
Core Typecheck / core-typecheck (push) Failing after 1s
Linting / lint (push) Failing after 1s
llama-dev tests / test-llama-dev (push) Failing after 1s
Publish Sub-Package to PyPI if Needed / publish_subpackage_if_needed (push) Has been skipped
Sync Docs to Developer Hub / sync-docs (push) Failing after 0s
Build Package / build (windows-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:26:52 +08:00

392 lines
12 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Structured Input for LLMs\n",
"\n",
"It has been observed that most LLMs perfom better when prompted with XML-like content (you can see it in [Anthropic's prompting guide](https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/use-xml-tags), for instance).\n",
"\n",
"We could refer to this kind of prompting as _structured input_, and LlamaIndex offers you the possibility of chatting with LLMs exactly through this technique - let's go through an example in this notebook!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1. Install Needed Dependencies\n",
"\n",
"> _Make sure to have `llama-index>=0.12.34` installed if you wish to follow this tutorial along without any problem😄_\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m7.6/7.6 MB\u001b[0m \u001b[31m65.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m284.6/284.6 kB\u001b[0m \u001b[31m21.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.0/41.0 kB\u001b[0m \u001b[31m2.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m40.4/40.4 kB\u001b[0m \u001b[31m2.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m309.7/309.7 kB\u001b[0m \u001b[31m23.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.2/1.2 MB\u001b[0m \u001b[31m55.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.9/50.9 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m129.3/129.3 kB\u001b[0m \u001b[31m9.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25h\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
"ipython 7.34.0 requires jedi>=0.16, which is not installed.\u001b[0m\u001b[31m\n",
"\u001b[0m"
]
}
],
"source": [
"! pip install -q llama-index"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Version: 0.12.50\n"
]
}
],
"source": [
"! pip show llama-index | grep \"Version\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2. Create a Prompt Template\n",
"\n",
"In order to use the structured input, we need to create a prompt template that would have a [Jinja](https://jinja.palletsprojects.com/en/stable/) expression (recognizable by the `{{}}`) with a specific filter (`to_xml`) that will turn inputs such as Pydantic `BaseModel` subclasses, dictionaries or JSON-like strings into XML representations."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.prompts import RichPromptTemplate\n",
"\n",
"template_str = \"Please extract from the following XML code the contact details of the user:\\n\\n```xml\\n{{ data | to_xml }}\\n```\\n\\n\"\n",
"prompt = RichPromptTemplate(template_str)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's now try to format the input as a string, using different objects as `data`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Please extract from the following XML code the contact details of the user:\n",
"\n",
"```xml\n",
"<user>\n",
"\t<name>John</name>\n",
"\t<surname>Doe</surname>\n",
"\t<age>30</age>\n",
"\t<email>john.doe@example.com</email>\n",
"\t<phone>123-456-7890</phone>\n",
"\t<social_accounts>{'bluesky': 'john.doe', 'instagram': 'johndoe1234'}</social_accounts>\n",
"</user>\n",
"\n",
"```\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Using a BaseModel\n",
"\n",
"from pydantic import BaseModel\n",
"from typing import Dict\n",
"from IPython.display import Markdown, display\n",
"\n",
"\n",
"class User(BaseModel):\n",
" name: str\n",
" surname: str\n",
" age: int\n",
" email: str\n",
" phone: str\n",
" social_accounts: Dict[str, str]\n",
"\n",
"\n",
"user = User(\n",
" name=\"John\",\n",
" surname=\"Doe\",\n",
" age=30,\n",
" email=\"john.doe@example.com\",\n",
" phone=\"123-456-7890\",\n",
" social_accounts={\"bluesky\": \"john.doe\", \"instagram\": \"johndoe1234\"},\n",
")\n",
"\n",
"display(Markdown(prompt.format(data=user)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Please extract from the following XML code the contact details of the user:\n",
"\n",
"```xml\n",
"<input>\n",
"\t<name>John</name>\n",
"\t<surname>Doe</surname>\n",
"\t<age>30</age>\n",
"\t<email>john.doe@example.com</email>\n",
"\t<phone>123-456-7890</phone>\n",
"\t<social_accounts>{'bluesky': 'john.doe', 'instagram': 'johndoe1234'}</social_accounts>\n",
"</input>\n",
"\n",
"```\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# with a dictionary\n",
"\n",
"user_dict = {\n",
" \"name\": \"John\",\n",
" \"surname\": \"Doe\",\n",
" \"age\": 30,\n",
" \"email\": \"john.doe@example.com\",\n",
" \"phone\": \"123-456-7890\",\n",
" \"social_accounts\": {\"bluesky\": \"john.doe\", \"instagram\": \"johndoe1234\"},\n",
"}\n",
"\n",
"display(Markdown(prompt.format(data=user_dict)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Please extract from the following XML code the contact details of the user:\n",
"\n",
"```xml\n",
"<input>\n",
"\t<name>John</name>\n",
"\t<surname>Doe</surname>\n",
"\t<age>30</age>\n",
"\t<email>john.doe@example.com</email>\n",
"\t<phone>123-456-7890</phone>\n",
"\t<social_accounts>{'bluesky': 'john.doe', 'instagram': 'johndoe1234'}</social_accounts>\n",
"</input>\n",
"\n",
"```\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Using a JSON-like string\n",
"\n",
"user_str = '{\"name\":\"John\",\"surname\":\"Doe\",\"age\":30,\"email\":\"john.doe@example.com\",\"phone\":\"123-456-7890\",\"social_accounts\":{\"bluesky\":\"john.doe\",\"instagram\":\"johndoe1234\"}}'\n",
"\n",
"display(Markdown(prompt.format(data=user_str)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3. Chat With an LLM\n",
"\n",
"Now that we know how to produce structured input, let's employ it to chat with an LLM!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"··········\n"
]
}
],
"source": [
"import os\n",
"from getpass import getpass\n",
"\n",
"os.environ[\"OPENAI_API_KEY\"] = getpass()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.llms.openai import OpenAI\n",
"\n",
"llm = OpenAI(model=\"gpt-4.1-mini\")\n",
"\n",
"response = await llm.achat(prompt.format_messages(data=user))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The contact details of the user are:\n",
"\n",
"- Email: john.doe@example.com \n",
"- Phone: 123-456-7890 \n",
"- Social Accounts: \n",
" - Bluesky: john.doe \n",
" - Instagram: johndoe1234\n"
]
}
],
"source": [
"print(response.message.content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4. Use Structured Input and Structured Output\n",
"\n",
"Combining structured input and structured output might really help to boost the reliability of the outputs of your LLMs - so let's give it a go!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pydantic import Field\n",
"from typing import Optional\n",
"\n",
"\n",
"class SocialAccounts(BaseModel):\n",
" instagram: Optional[str] = Field(default=None)\n",
" bluesky: Optional[str] = Field(default=None)\n",
" x: Optional[str] = Field(default=None)\n",
" mastodon: Optional[str] = Field(default=None)\n",
"\n",
"\n",
"class ContactDetails(BaseModel):\n",
" email: str\n",
" phone: str\n",
" social_accounts: SocialAccounts"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"sllm = llm.as_structured_llm(ContactDetails)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"structured_response = await sllm.achat(prompt.format_messages(data=user))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"john.doe@example.com\n",
"123-456-7890\n",
"johndoe1234\n",
"john.doe\n"
]
}
],
"source": [
"print(structured_response.raw.email)\n",
"print(structured_response.raw.phone)\n",
"print(structured_response.raw.social_accounts.instagram)\n",
"print(structured_response.raw.social_accounts.bluesky)"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}