案例目标
本案例演示了如何使用LlamaIndex的Return Direct Agent功能,通过设置工具的return_direct参数为True,控制智能体的推理循环。当设置了该参数的工具被调用时(且没有其他工具被调用),智能体推理循环将结束,工具输出将直接返回给用户,无需经过LLM重新处理。这种机制可以加速响应时间,特别是在工具输出已经足够好的情况下,避免智能体重写响应,并提前结束推理循环。
案例通过一个餐厅预订系统的实际场景,展示了智能体如何收集用户信息并完成预订的全过程,同时演示了Return Direct功能在特定工具上的应用效果。
技术栈与核心依赖
LlamaIndexAnthropic ClaudePydanticFunctionAgentFunctionTool
本案例主要使用以下技术组件:
- LlamaIndex: 提供智能体框架和工具集成能力
- Anthropic Claude: 作为智能体的语言模型,使用claude-3-sonnet-20240229模型
- Pydantic: 用于定义数据模型和验证
- FunctionAgent: LlamaIndex的智能体实现,支持工具调用和推理循环
- FunctionTool: 用于将Python函数转换为智能体可调用的工具
环境配置
1. 安装依赖
%pip install llama-index-core llama-index-llms-anthropic2. 配置API密钥
import os os.environ["ANTHROPIC_API_KEY"] = "sk-..."注意:需要设置有效的Anthropic API密钥才能使用Claude模型。
3. 初始化语言模型
from llama_index.llms.anthropic import Anthropic llm = Anthropic(model="claude-3-sonnet-20240229", temperature=0.1)案例实现
1. 定义预订数据模型
使用Pydantic定义预订状态的数据模型,包含姓名、邮箱、电话、日期和时间等字段:
from typing import Optional from pydantic import BaseModel class Booking(BaseModel): name: Optional[str] = None email: Optional[str] = None phone: Optional[str] = None date: Optional[str] = None time: Optional[str] = None # 存储预订数据 bookings = {}2. 定义预订管理函数
创建四个核心函数用于预订管理:
def get_booking_state(user_id: str) -> str: """获取指定预订ID的当前状态""" try: return str(bookings[user_id].dict()) except: return f"Booking ID {user_id} not found" def update_booking(user_id: str, property: str, value: str) -> str: """更新指定预订ID的属性""" booking = bookings[user_id] setattr(booking, property, value) return f"Booking ID {user_id} updated with {property} = {value}" def create_booking(user_id: str) -> str: """创建新预订并返回预订ID""" bookings[user_id] = Booking() return "Booking created, but not yet confirmed. Please provide your name, email, phone, date, and time." def confirm_booking(user_id: str) -> str: """确认指定预订ID的预订""" booking = bookings[user_id] # 验证所有必要字段是否已填写 if booking.name is None: raise ValueError("Please provide your name.") if booking.email is None: raise ValueError("Please provide your email.") if booking.phone is None: raise ValueError("Please provide your phone number.") if booking.date is None: raise ValueError("Please provide the date of your booking.") if booking.time is None: raise ValueError("Please provide the time of your booking.") return f"Booking ID {user_id} confirmed!"3. 创建智能体工具
将上述函数转换为智能体可调用的工具,并为create_booking和confirm_booking工具设置return_direct=True参数:
from llama_index.core.tools import FunctionTool # 为每个函数创建工具 get_booking_state_tool = FunctionTool.from_defaults(fn=get_booking_state) update_booking_tool = FunctionTool.from_defaults(fn=update_booking) create_booking_tool = FunctionTool.from_defaults( fn=create_booking, return_direct=True # 设置return_direct为True ) confirm_booking_tool = FunctionTool.from_defaults( fn=confirm_booking, return_direct=True # 设置return_direct为True )关键点:return_direct=True参数使得当这些工具被调用时(且没有其他工具被调用),智能体推理循环将结束,工具输出将直接返回给用户。
4. 初始化智能体
from llama_index.core.agent.workflow import FunctionAgent from llama_index.core.workflow import Context user = "user123" system_prompt = f"""You are now connected to the booking system and helping {user} with making a booking. Only enter details that the user has explicitly provided. Do not make up any details. """ agent = FunctionAgent( tools=[ get_booking_state_tool, update_booking_tool, create_booking_tool, confirm_booking_tool, ], llm=llm, system_prompt=system_prompt, ) # 创建智能体上下文,用于保存会话状态/历史 ctx = Context(agent)5. 智能体交互流程
通过以下步骤演示智能体如何处理用户请求:
步骤1:用户发起预订请求
handler = agent.run( "Hello! I would like to make a booking, around 5pm?", ctx=ctx ) async for ev in handler.stream_events(): if isinstance(ev, AgentStream): print(f"{ev.delta}", end="", flush=True) elif isinstance(ev, ToolCallResult): print( f"\nCall {ev.tool_name} with {ev.tool_kwargs}\nReturned: {ev.tool_output}" ) response = await handler输出结果:
智能体调用create_booking工具,由于设置了return_direct=True,工具输出直接返回给用户,无需经过LLM重新处理。
Call create_booking with {'user_id': 'user123'} Returned: Booking created, but not yet confirmed. Please provide your name, email, phone, date, and time.步骤2:用户提供姓名和邮箱
handler = agent.run( "Sure! My name is Logan, and my email is test@gmail.com?", ctx=ctx ) async for ev in handler.stream_events(): if isinstance(ev, AgentStream): print(f"{ev.delta}", end="", flush=True) elif isinstance(ev, ToolCallResult): print( f"\nCall {ev.tool_name} with {ev.tool_kwargs}\nReturned: {ev.tool_output}" ) response = await handler输出结果:
智能体调用两次update_booking工具更新姓名和邮箱,由于未设置return_direct=True,智能体会继续处理并生成响应。
Call update_booking with {'user_id': 'user123', 'property': 'name', 'value': 'Logan'} Returned: Booking ID user123 updated with name = Logan Call update_booking with {'user_id': 'user123', 'property': 'email', 'value': 'test@gmail.com'} Returned: Booking ID user123 updated with email = test@gmail.com步骤3:用户提供电话、日期和时间
handler = agent.run( "Right! My phone number is 1234567890, the date of the booking is April 5, at 5pm.", ctx=ctx, ) async for ev in handler.stream_events(): if isinstance(ev, AgentStream): print(f"{ev.delta}", end="", flush=True) elif isinstance(ev, ToolCallResult): print( f"\nCall {ev.tool_name} with {ev.tool_kwargs}\nReturned: {ev.tool_output}" ) response = await handler输出结果:
智能体调用三次update_booking工具更新电话、日期和时间,然后调用confirm_booking工具确认预订。由于confirm_booking设置了return_direct=True,工具输出直接返回给用户。
Call update_booking with {'user_id': 'user123', 'property': 'phone', 'value': '1234567890'} Returned: Booking ID user123 updated with phone = 1234567890 Call update_booking with {'user_id': 'user123', 'property': 'date', 'value': '2023-04-05'} Returned: Booking ID user123 updated with date = 2023-04-05 Call update_booking with {'user_id': 'user123', 'property': 'time', 'value': '17:00'} Returned: Booking ID user123 updated with time = 17:00 Call confirm_booking with {'user_id': 'user123'} Returned: Booking ID user123 confirmed!案例效果
通过本案例的实现,我们成功构建了一个具有Return Direct功能的餐厅预订智能体,实现了以下效果:
1. 预订创建与信息收集
当用户发起预订请求时,智能体自动调用create_booking工具创建预订记录,并直接返回工具输出,提示用户提供必要信息。
2. 渐进式信息更新
智能体能够根据用户提供的信息,逐步更新预订记录中的各个字段,包括姓名、邮箱、电话、日期和时间。
3. 预订确认与直接返回
当所有必要信息收集完毕后,智能体调用confirm_booking工具确认预订,并直接返回确认结果,无需经过LLM重新处理。
4. Return Direct功能验证
通过对比设置了return_direct=True的工具和未设置该参数的工具,我们可以清楚地看到:
- 设置了
return_direct=True的工具(如create_booking和confirm_booking)被调用时,工具输出直接返回给用户 - 未设置该参数的工具(如
update_booking)被调用时,智能体会继续处理并生成响应
最终结果:成功创建并确认了一个包含用户完整信息的预订记录,验证了Return Direct功能的有效性。
案例实现思路
本案例的实现基于以下思路:
1. Return Direct机制设计
Return Direct机制允许开发者为特定工具设置return_direct=True参数,当这些工具被调用时(且没有其他工具被调用),智能体推理循环将提前结束,工具输出直接返回给用户。这种设计适用于以下场景:
- 工具输出已经足够好,无需LLM重新处理
- 需要加速响应时间
- 希望提前结束推理循环
2. 预订系统数据模型设计
使用Pydantic定义预订数据模型,确保数据结构的一致性和验证。预订模型包含以下字段:
- name: 预订人姓名
- email: 预订人邮箱
- phone: 预订人电话
- date: 预订日期
- time: 预订时间
3. 工具设计策略
根据功能需求设计四个核心工具,并合理应用Return Direct机制:
- get_booking_state: 获取预订状态,不设置Return Direct
- update_booking: 更新预订信息,不设置Return Direct,允许智能体继续处理
- create_booking: 创建预订,设置Return Direct,直接返回创建结果
- confirm_booking: 确认预订,设置Return Direct,直接返回确认结果
4. 智能体交互流程设计
设计了一个渐进式的预订流程,引导用户逐步提供必要信息:
- 用户发起预订请求 → 智能体创建预订记录
- 用户提供部分信息 → 智能体更新预订记录
- 用户提供完整信息 → 智能体确认预订
5. 上下文管理
使用Context对象保存智能体会话状态和历史记录,确保智能体能够跟踪整个预订过程中的信息变化。
扩展建议
基于本案例的实现,可以考虑以下扩展方向:
1. 多用户支持
扩展系统以支持多用户并发预订,为每个用户分配唯一的预订ID,并实现用户隔离和权限管理。
2. 数据持久化
将预订数据持久化存储到数据库中,而不是仅存储在内存中,确保系统重启后数据不丢失。
3. 高级Return Direct策略
实现更复杂的Return Direct策略,例如基于工具输出质量或用户意图动态决定是否直接返回工具输出。
4. 预订冲突检测
添加预订冲突检测功能,当用户预订的时间段已被占用时,提供替代时间建议。
5. 集成外部服务
集成外部服务,如短信通知、邮件确认、支付处理等,增强预订系统的实用性。
6. 多语言支持
扩展系统以支持多语言交互,满足不同语言用户的需求。
7. 预订模板
实现预订模板功能,允许用户保存常用的预订信息,快速创建类似预订。
8. 预订历史与统计
添加预订历史记录和统计分析功能,为用户提供预订历史查询,为商家提供业务分析数据。
总结
本案例成功演示了LlamaIndex中Return Direct Agent的实现和应用,通过一个餐厅预订系统的实际场景,展示了如何使用return_direct参数控制智能体的推理循环。主要收获包括:
- Return Direct机制理解:深入理解了Return Direct机制的工作原理和适用场景,认识到它在加速响应时间和简化流程方面的价值。
- 智能体工具设计:掌握了如何根据功能需求设计智能体工具,并合理应用Return Direct机制。
- 数据模型设计:学习了使用Pydantic设计数据模型,确保数据结构的一致性和验证。
- 上下文管理:了解了如何使用Context对象管理智能体会话状态和历史记录。
- 渐进式交互设计:掌握了设计渐进式交互流程的方法,引导用户逐步提供必要信息。
Return Direct Agent功能为智能体开发提供了更精细的控制能力,特别适用于那些工具输出已经足够好,无需LLM重新处理的场景。通过合理应用这一机制,可以显著提升智能体的响应速度和用户体验。
应用前景:Return Direct Agent功能在客服系统、任务管理工具、预订系统等需要快速响应和精确控制的场景中具有广泛的应用前景,为智能体开发者提供了更灵活的工具控制手段。