基于 LiveKit Agents 的酒店客房送餐策略设计:以 hotel_receptionist 知识库条目为例
【免费下载链接】agentsA framework for building realtime voice AI agents 🤖🎙️📹项目地址: https://gitcode.com/GitHub_Trending/agen/agents
导读
在 LiveKit Agents 的 hotel_receptionist 实时语音前台 Agent 示例中,客房送餐(Room Service)并非写死在提示词里的硬编码事实,而是以一份独立 Markdown 策略文件的形式存在,由「渐进式披露」工具在通话中按需加载。本文以 room_service.md 为核心,讲解这条策略的知识结构、它如何被 Agent 路由与调用、与餐厅策略家族的关系,以及账单争议处理等周边机制,帮助读者理解 LiveKit Agents 中「长尾知识外置、热路径内联」的落地模式。
一、策略条目的原始内容与事实解读
room_service.md全文只有三行,分为两部分:
Room service hours and menu; takeout and delivery policy. Room service: same menu as the restaurant, 5:30 to 9:30 PM. Takeout and delivery: not offered.第一行是整份文件的一句话摘要(在知识库体系中它还有特殊用途,见下文);其余部分是需要回答的关键事实:
| 事实维度 | 策略内容 |
|---|---|
| 送餐时间 | 每天 17:30~21:30(5:30 to 9:30 PM) |
| 菜单来源 | 与餐厅菜单完全一致(same menu as the restaurant) |
| 外卖与自提配送 | 不提供(not offered) |
这份策略的实际含义:酒店有现场餐厅但不提供把餐食送出酒店的「外卖/外带配送」服务;客房送餐仅在晚餐时段开放,且菜品与店内餐厅共用一套菜单。对照 instructions.py 中给出的餐厅快速事实「Restaurant: on-site, dinner only, 5:30 to 9 PM last seating」,以及 hotel_db.py 中餐厅可用时段 SQL 枚举的17:30:00到21:00:00八个时段,可以推断:客房送餐的 21:30 截止时间比餐厅最后入座时间(21:00)晚半小时,是独立于餐厅叫号体系之外的一条服务窗口。
二、这份文件在知识库体系中的角色:渐进式披露
room_service.md位于 policies/ 目录。该目录的模块文档字符串(policies/init.py)明确说明了设计原则:
The receptionist's prompt keeps only hot-path facts inline; everything long-tail lives here as one markdown file per topic.
也就是说,前台 Agent 的提示词只内联高频事实(check-in/check-out、取消窗口、早餐时段等),所有长尾知识按主题拆成一个个 Markdown 文件存放于此。room_service.md正是「餐厅详情」这一长尾主题中的一员。
其核心机制在build_lookup_policy_tool()中实现:
- 启动时遍历目录下所有
*.md文件,把每个文件的第一行解析为该主题在工具 schema 中的索引条目描述,其余内容作为模型查询时返回的正文; - 动态构造
lookup_policy函数工具的 raw schema,其topic参数是一个由全部文件名构成的enum,因此索引永远与语料库保持一致,不会漂移; - 查询时若 topic 不在
policies字典中,会抛出ToolError并列出合法主题,引导模型修正调用。
这意味着:新增一个主题(比如「泳池开放时间」)只需在policies/下增加一个*.md文件,无需改动任何代码——索引、枚举、工具描述在启动时自动重建。
三、Agent 如何路由到客房送餐话题
策略文件本身不会自动生效,它需要提示词把话题路由到lookup_policy工具。
- instructions.py 的路由规则明确写出:「Detail beyond the quick facts: lookup_policy. Its topic index covers hotel detail(…), restaurant detail(menu, dietary, dining, room service), payments and currency exchange, and group bookings. Look the topic up before answering - don't improvise policy.」——即凡是超出快速事实的细节,必须先查策略再回答,禁止凭记忆即兴发挥政策。
- persona.py 在「What you can help with」中把可答复范围声明为「restaurant info (menu, dietary, dress code, private dining,room service, celebrations)」,与
policies/下的restaurant_menu.md、restaurant_dietary.md、restaurant_dining.md、room_service.md一一对应。
因此,当来电者询问「你们客房送餐到几点?能点牛排吗?能送外卖到楼下吗?」这类问题时,Agent 的调用链为:识别话题属于长尾策略 → 调用lookup_policy(topic="room_service")→ 工具返回正文 → Agent 据此组织自然语言回答。工具调用对来电者不可见(persona 中明确「Tool interactions are invisible to the caller」),模型只把结论性内容说出口。
四、客房送餐与餐厅策略家族的联动
room_service.md中「same menu as the restaurant」一句,决定了它必须与餐厅策略家族的其余文件配合解读:
| 策略文件 | 覆盖内容 | 与客房送餐的关联 |
|---|---|---|
| restaurant_menu.md | 菜品构成(前菜/沙拉、主菜、配菜、甜点、吧台)、菜品价格会变动 | 送餐菜单即此菜单,价格同样「不记在脑子里」 |
| restaurant_dining.md | 着装要求、座位区、订位规则、私人包间、庆祝甜点 | 送餐场景通常不涉及着装与订位,但庆祝甜点、私人包间等属于同一餐饮体系 |
| restaurant_dietary.md | 素食与多数饮食需求可满足;严重/过敏性过敏需在订位时告知厨房 | 送餐点单同样适用此过敏告知逻辑 |
从restaurant_menu.md的措辞「specific dish prices rotate and I don't keep them memorized; if the caller asks about a particular dish or price I don't have, offer to note the question for the kitchen via record_followup (kind="other")」可以看出一个通用模式:策略文件负责「是什么」,具体菜品价格等易变信息不硬编码,而是通过record_followup记录给厨房。这是 LiveKit Agents 中工具化知识库的常见写法——把「稳定策略」与「易变数据」分层。
五、客房送餐账单争议:策略之外的数据库支撑
客房送餐不只是「知识问答」,它还牵涉到账单争议处理。hotel_db.py 中定义了DisputeCategory枚举,其中包含"room_service_restaurant"分类,对应的争议处理策略为:
action="verify_explain_then_offer_credit":先调出订单核实,若确有异常可申请信用抵扣,或升级给餐饮经理;escalation="manager":升级到经理。
种子数据 fake_data/seed.py 中提供了一个现成的争议示例:("DSP-2H6T", "HTL-ZP19", "Room service", 8800, "room_service_restaurant", "Charged for a dinner they didn't order.", "escalated_to_manager", 0, "open")—— 一笔 88 美元的客房送餐费用被客人否认,当前状态为已升级经理、待处理。这印证了「客房送餐」在整个示例中是一条贯通知识库、账单表、争议流程的完整业务线,而非孤立的问答条目。
六、运行示例并验证客房送餐问答
要实际观察 Agent 如何应答客房送餐问题,可参照 README.md 的启动方式:
uv run examples/hotel_receptionist/fake_data/seed.py uv run examples/hotel_receptionist/agent.py console # 或使用 LiveKit Playground 进行带界面调试: uv run examples/hotel_receptionist/agent.py devfake_data/seed.py会打印可供试用的示例确认码(例如取消流程的last name 'Smith', code 'HTL-AB12')。在 console 模式下,可以尝试如下提问来触发策略查询链路:
- 「你们客房送餐几点到几点?」→ 期望回答 5:30 到 9:30 PM;
- 「客房送餐能点菜单上没有的东西吗?」→ 期望回答菜单与餐厅一致、价格会变动;
- 「你们提供外卖吗?」→ 期望明确回答不提供。
需要注意的是,Agent 的语音与模型栈在 agent.py 中配置为inference.STT("deepgram/nova-3")、inference.LLM("google/gemma-4-31b-it")、inference.TTS("inworld/inworld-tts-2"),并显式指定了 Silero VAD;运行前请确保相应的云端推理凭据已就绪(示例通过.env.local加载环境变量)。
七、小结:一份三行策略文件背后的设计方法论
room_service.md篇幅虽短,却是 LiveKit Agents 中「策略外置 + 渐进式披露」模式的微型样板,其方法论可以归纳为四点:
- 长尾外置:只有热路径事实进提示词,其余全部以「一主题一文件」的形式放目录,提示词只保留路由规则;
- 自描述索引:文件第一行即工具 schema 的索引条目,目录扫描自动构建 enum,语料与索引永不漂移;
- 禁止即兴:提示词强制「查了再答」,杜绝模型凭记忆编造政策;
- 业务贯通:知识条目与账单、争议分类、种子数据协同,形成可运行、可评测的完整闭环。
如果要在自己的 LiveKit Agents 项目中复用这套机制,只需参照 policies/init.py 的build_lookup_policy_tool()实现,并在 instructions.py 中加入对应的路由提示即可。
【免费下载链接】agentsA framework for building realtime voice AI agents 🤖🎙️📹项目地址: https://gitcode.com/GitHub_Trending/agen/agents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考