使用工件编辑器工具构建订单完成助手¶
在本示例中,我们将构建一个专门用于填写自定义"表单"的聊天助手。
作为用例示例,我们将构建一个接单助手,该助手需要从终端用户获取几项预设信息才能继续操作。例如用户的送货地址和订单内容。
为此,我们使用了新的 ArtifactEditorToolSpec
和 ArtifactMemoryBlock
In [ ]:
Copied!
!pip install llama-index llama-index-tools-artifact-editor
!pip install llama-index llama-index-tools-artifact-editor
In [ ]:
Copied!
import os
import json
from getpass import getpass
from pydantic import BaseModel, Field
from llama_index.llms.openai import OpenAI
from llama_index.core.memory import Memory
from llama_index.core.agent.workflow import (
FunctionAgent,
AgentWorkflow,
ToolCallResult,
AgentStream,
)
from llama_index.tools.artifact_editor import (
ArtifactEditorToolSpec,
ArtifactMemoryBlock,
)
import os
import json
from getpass import getpass
from pydantic import BaseModel, Field
from llama_index.llms.openai import OpenAI
from llama_index.core.memory import Memory
from llama_index.core.agent.workflow import (
FunctionAgent,
AgentWorkflow,
ToolCallResult,
AgentStream,
)
from llama_index.tools.artifact_editor import (
ArtifactEditorToolSpec,
ArtifactMemoryBlock,
)
In [ ]:
Copied!
if "OPENAI_API_KEY" not in os.environ:
os.environ["OPENAI_API_KEY"] = getpass("OpenAI API Key: ")
if "OPENAI_API_KEY" not in os.environ:
os.environ["OPENAI_API_KEY"] = getpass("OpenAI API Key: ")
In [ ]:
Copied!
class Pizza(BaseModel):
name: str = Field(description="The name of the pizza")
remove: list[str] | None = Field(
description="If exists, the ingredients the customer requests to remove",
default=None,
)
add: list[str] | None = Field(
description="If exists, the ingredients the customer requests to be added",
default=None,
)
class Address(BaseModel):
street_address: str = Field(
description="The street address of the customer"
)
city: str = Field(description="The city of the customer")
state: str = Field(description="The state of the customer")
zip_code: str = Field(description="The zip code of the customer")
class Order(BaseModel):
pizzas: list[Pizza] | None = Field(
description="The pizzas ordered by the customer", default=None
)
address: Address | None = Field(
description="The full address of the customer", default=None
)
class Pizza(BaseModel):
name: str = Field(description="The name of the pizza")
remove: list[str] | None = Field(
description="If exists, the ingredients the customer requests to remove",
default=None,
)
add: list[str] | None = Field(
description="If exists, the ingredients the customer requests to be added",
default=None,
)
class Address(BaseModel):
street_address: str = Field(
description="The street address of the customer"
)
city: str = Field(description="The city of the customer")
state: str = Field(description="The state of the customer")
zip_code: str = Field(description="The zip code of the customer")
class Order(BaseModel):
pizzas: list[Pizza] | None = Field(
description="The pizzas ordered by the customer", default=None
)
address: Address | None = Field(
description="The full address of the customer", default=None
)
In [ ]:
Copied!
tool_spec = ArtifactEditorToolSpec(Order)
tools = tool_spec.to_tool_list()
# Initialize the memory
memory = Memory.from_defaults(
session_id="order_editor",
memory_blocks=[ArtifactMemoryBlock(artifact_spec=tool_spec)],
token_limit=60000,
chat_history_token_ratio=0.7,
)
llm = OpenAI(model="gpt-4.1")
agent = AgentWorkflow(
agents=[
FunctionAgent(
llm=llm,
tools=tools,
system_prompt="""You are a worker at a Pizzeria. Your job is to talk to users and gather order information.
At every step, you should check the order completeness before responding to the user, and ask for any possibly
missing information.""",
)
],
)
tool_spec = ArtifactEditorToolSpec(Order)
tools = tool_spec.to_tool_list()
# Initialize the memory
memory = Memory.from_defaults(
session_id="order_editor",
memory_blocks=[ArtifactMemoryBlock(artifact_spec=tool_spec)],
token_limit=60000,
chat_history_token_ratio=0.7,
)
llm = OpenAI(model="gpt-4.1")
agent = AgentWorkflow(
agents=[
FunctionAgent(
llm=llm,
tools=tools,
system_prompt="""You are a worker at a Pizzeria. Your job is to talk to users and gather order information.
At every step, you should check the order completeness before responding to the user, and ask for any possibly
missing information.""",
)
],
)
In [ ]:
Copied!
async def chat():
while True:
user_msg = input("User: ").strip()
if user_msg.lower() in ["exit", "quit"]:
print("\n------ORDER COMPLETION-------\n")
print(
f"The Order was placed with the following Order schema:\n: {json.dumps(tool_spec.get_current_artifact(), indent=4)}"
)
break
handler = agent.run(user_msg, memory=memory)
async for ev in handler.stream_events():
if isinstance(ev, AgentStream):
print(ev.delta, end="", flush=True)
elif isinstance(ev, ToolCallResult):
print(
f"\n\nCalling tool: {ev.tool_name} with kwargs: {ev.tool_kwargs}"
)
# response = await handler
# print(str(response))
print("\n\nCurrent artifact: ", tool_spec.get_current_artifact())
async def chat():
while True:
user_msg = input("User: ").strip()
if user_msg.lower() in ["exit", "quit"]:
print("\n------ORDER COMPLETION-------\n")
print(
f"The Order was placed with the following Order schema:\n: {json.dumps(tool_spec.get_current_artifact(), indent=4)}"
)
break
handler = agent.run(user_msg, memory=memory)
async for ev in handler.stream_events():
if isinstance(ev, AgentStream):
print(ev.delta, end="", flush=True)
elif isinstance(ev, ToolCallResult):
print(
f"\n\nCalling tool: {ev.tool_name} with kwargs: {ev.tool_kwargs}"
)
# response = await handler
# print(str(response))
print("\n\nCurrent artifact: ", tool_spec.get_current_artifact())
In [ ]:
Copied!
await chat()
await chat()
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
Hello! Welcome to our pizzeria. Would you like to place an order? If so, could you please tell me what kind of pizza you’d like? Current artifact: None
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
Calling tool: create_artifact with kwargs: {'pizzas': [{'name': 'pepperoni', 'add': ['olives']}, {'name': 'margherita'}]}
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
You’ve ordered: - 1 Pepperoni pizza with added olives - 1 Margherita pizza To complete your order, could you please provide your delivery address (street address, city, state, and zip code)? Current artifact: {'pizzas': [{'name': 'pepperoni', 'remove': None, 'add': ['olives']}, {'name': 'margherita', 'remove': None, 'add': None}], 'address': None}
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
Calling tool: apply_patch with kwargs: {'patch': {'operations': [{'op': 'replace', 'path': '/address', 'value': {'street_address': '1 Sesame Street', 'city': 'Amsterdam', 'state': 'North-Holand', 'zip_code': '1111AB'}}]}}
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
Thank you! Your order is now complete: - 1 Pepperoni pizza with added olives - 1 Margherita pizza Delivery address: 1 Sesame Street, Amsterdam, North-Holand, 1111AB Would you like to add anything else to your order, or should I proceed with placing it? Current artifact: {'pizzas': [{'name': 'pepperoni', 'remove': None, 'add': ['olives']}, {'name': 'margherita', 'remove': None, 'add': None}], 'address': {'street_address': '1 Sesame Street', 'city': 'Amsterdam', 'state': 'North-Holand', 'zip_code': '1111AB'}}
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
Great! Your order has been placed: - 1 Pepperoni pizza with added olives - 1 Margherita pizza Delivery to: 1 Sesame Street, Amsterdam, North-Holand, 1111AB Thank you for ordering with us! Your pizzas will be delivered soon. Have a delicious day! Current artifact: {'pizzas': [{'name': 'pepperoni', 'remove': None, 'add': ['olives']}, {'name': 'margherita', 'remove': None, 'add': None}], 'address': {'street_address': '1 Sesame Street', 'city': 'Amsterdam', 'state': 'North-Holand', 'zip_code': '1111AB'}} ------ORDER COMPLETION------- The Order was placed with the following Order schema: : { "pizzas": [ { "name": "pepperoni", "remove": null, "add": [ "olives" ] }, { "name": "margherita", "remove": null, "add": null } ], "address": { "street_address": "1 Sesame Street", "city": "Amsterdam", "state": "North-Holand", "zip_code": "1111AB" } }