line-voice-agent
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLine SDK Voice Agent Guide
Line SDK 语音Agent指南
Build production voice agents with the Cartesia Line SDK. This guide covers agent creation, tool patterns, multi-agent workflows, and LLM provider configuration.
使用Cartesia Line SDK构建生产级语音Agent。本指南涵盖Agent创建、工具模式、多Agent工作流以及LLM提供商配置。
How Line Works
Line 工作原理
Line is Cartesia's voice agent deployment platform. You write Python agent code using the Line SDK, deploy it to Cartesia's managed cloud via the CLI, and Cartesia hosts it with auto-scaling. Cartesia handles STT (Ink), TTS (Sonic), telephony, and audio orchestration. Only one deployment per agent is active at a time; once deployed, your agent receives calls automatically.
cartesia┌─────────────────────────────────────────────────────────────────┐
│ Cartesia Line Platform │
│ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Ink │───▶│ Your Agent │───▶│ Sonic │ │
│ │ (STT) │ │ (Line SDK) │ │ (TTS) │ │
│ └──────────┘ └──────────────┘ └──────────┘ │
│ ▲ │ │
│ │ Audio Orchestration │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
▲ │
│ WebSocket ▼
┌───────┴────────────────────────────────────┴───────┐
│ Client (Phone / Web / Mobile) │
└─────────────────────────────────────────────────────┘Your code handles:
- LLM reasoning and conversation flow
- Tool execution (API calls, database lookups)
- Multi-agent coordination and handoffs
Cartesia handles:
- Speech-to-text (Ink)
- Text-to-speech (Sonic)
- Real-time audio streaming
- Turn-taking and interruption detection
- Deployment and auto-scaling
Audio Input Options:
- Cartesia Telephony - Managed phone numbers
- Calls API - Web apps, mobile apps, custom telephony
Line是Cartesia的语音Agent部署平台。你可以使用Line SDK编写Python Agent代码,通过 CLI将其部署到Cartesia的托管云服务中,Cartesia会提供自动扩缩容的托管服务。Cartesia负责处理STT(Ink)、TTS(Sonic)、电话通信和音频编排。每个Agent同一时间只能有一个部署处于活跃状态;部署完成后,你的Agent会自动接收呼叫。
cartesia┌─────────────────────────────────────────────────────────────────┐
│ Cartesia Line Platform │
│ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Ink │───▶│ Your Agent │───▶│ Sonic │ │
│ │ (STT) │ │ (Line SDK) │ │ (TTS) │ │
│ └──────────┘ └──────────────┘ └──────────┘ │
│ ▲ │ │
│ │ Audio Orchestration │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
▲ │
│ WebSocket ▼
┌───────┴────────────────────────────────────┴───────┐
│ Client (Phone / Web / Mobile) │
└─────────────────────────────────────────────────────┘你的代码负责:
- LLM推理和对话流程
- 工具执行(API调用、数据库查询)
- 多Agent协调与交接
Cartesia负责:
- 语音转文本(Ink)
- 文本转语音(Sonic)
- 实时音频流
- 话轮转换和中断检测
- 部署与自动扩缩容
音频输入选项:
- Cartesia 电话通信 - 托管电话号码
- 呼叫API - 网页应用、移动应用、自定义电话系统
Prerequisites
前置条件
- Python 3.9+ and uv (recommended package manager)
- Cartesia API key — get one at play.cartesia.ai/keys (used by the CLI and for deployment)
- LLM API key — for whichever LLM provider your agent calls (e.g. ,
ANTHROPIC_API_KEY,OPENAI_API_KEY)GEMINI_API_KEY - Cartesia CLI — install with:
bash
curl -fsSL https://cartesia.sh | sh
- Python 3.9+ 和 uv(推荐的包管理器)
- Cartesia API密钥 — 前往play.cartesia.ai/keys获取(供CLI和部署使用)
- LLM API密钥 — 用于你Agent调用的任意LLM提供商(例如、
ANTHROPIC_API_KEY、OPENAI_API_KEY)GEMINI_API_KEY - Cartesia CLI — 安装命令:
bash
curl -fsSL https://cartesia.sh | sh
Cartesia CLI Reference
Cartesia CLI 参考
bash
undefinedbash
undefinedAuthentication
身份验证
cartesia auth login # Login with Cartesia API key
cartesia auth status # Check auth status
cartesia auth login # 使用Cartesia API密钥登录
cartesia auth status # 检查身份验证状态
Project Setup
项目设置
cartesia create [project-name] # Create project from template
cartesia init # Link existing directory to an agent
cartesia create [project-name] # 从模板创建项目
cartesia init # 将现有目录关联到Agent
Local Development
本地开发
cartesia chat <port> # Chat with local agent (text mode)
cartesia chat <port> # 与本地Agent聊天(文本模式)
Deployment
部署
cartesia deploy # Deploy to Cartesia cloud
cartesia status # Check deployment status
cartesia deploy # 部署到Cartesia云
cartesia status # 检查部署状态
Environment Variables (encrypted, stored on Cartesia)
环境变量(加密存储在Cartesia)
cartesia env set KEY=VALUE # Set a single env var
cartesia env set --from .env # Import all vars from .env file
cartesia env rm <name> # Remove an env var
cartesia env set KEY=VALUE # 设置单个环境变量
cartesia env set --from .env # 从.env文件导入所有变量
cartesia env rm <name> # 删除环境变量
Agents & Calls
Agent与呼叫
cartesia agents ls # List all agents
cartesia deployments ls # List deployments
cartesia call <phone> [agent-id] # Make outbound call
undefinedcartesia agents ls # 列出所有Agent
cartesia deployments ls # 列出部署记录
cartesia call <phone> [agent-id] # 发起外呼
undefinedQuick Start
快速开始
1. Create Project
1. 创建项目
bash
cartesia auth login
cartesia create my-agent
cd my-agentbash
cartesia auth login
cartesia create my-agent
cd my-agent2. Write Agent Code
2. 编写Agent代码
main.pypython
import os
from line.llm_agent import LlmAgent, LlmConfig, end_call
from line.voice_agent_app import AgentEnv, CallRequest, VoiceAgentApp
async def get_agent(env: AgentEnv, call_request: CallRequest):
return LlmAgent(
model="anthropic/claude-haiku-4-5-20251001",
api_key=os.getenv("ANTHROPIC_API_KEY"),
tools=[end_call],
config=LlmConfig(
system_prompt="You are a helpful voice assistant.",
introduction="Hello! How can I help you today?",
),
)
app = VoiceAgentApp(get_agent=get_agent)
if __name__ == "__main__":
app.run()main.pypython
import os
from line.llm_agent import LlmAgent, LlmConfig, end_call
from line.voice_agent_app import AgentEnv, CallRequest, VoiceAgentApp
async def get_agent(env: AgentEnv, call_request: CallRequest):
return LlmAgent(
model="anthropic/claude-haiku-4-5-20251001",
api_key=os.getenv("ANTHROPIC_API_KEY"),
tools=[end_call],
config=LlmConfig(
system_prompt="You are a helpful voice assistant.",
introduction="Hello! How can I help you today?",
),
)
app = VoiceAgentApp(get_agent=get_agent)
if __name__ == "__main__":
app.run()3. Test Locally
3. 本地测试
bash
ANTHROPIC_API_KEY=your-key python main.py
cartesia chat 8000 # Text chat with your running agentbash
ANTHROPIC_API_KEY=your-key python main.py
cartesia chat 8000 # 与运行中的Agent进行文本聊天4. Deploy
4. 部署
bash
cartesia env set ANTHROPIC_API_KEY=your-key # Encrypted, stored on Cartesia
cartesia deploy
cartesia status # Verify deployment is activebash
cartesia env set ANTHROPIC_API_KEY=your-key # 加密存储在Cartesia
cartesia deploy
cartesia status # 验证部署是否活跃5. Make a Call
5. 发起呼叫
bash
cartesia call +1234567890 # Outbound call via CLIOr trigger calls from the Cartesia dashboard.
bash
cartesia call +1234567890 # 通过CLI发起外呼或者从Cartesia控制台触发呼叫。
Project Structure
项目结构
Every Line agent project MUST have:
my_agent/
├── main.py # VoiceAgentApp entry point (REQUIRED)
├── cartesia.toml # Deployment config, created by cartesia init or cartesia create (REQUIRED)
└── pyproject.toml # Dependencies: cartesia-line每个Line Agent项目必须包含:
my_agent/
├── main.py # VoiceAgentApp入口(必填)
├── cartesia.toml # 部署配置,由cartesia init或cartesia create创建(必填)
└── pyproject.toml # 依赖项:cartesia-lineCore Concepts
核心概念
LlmAgent
LlmAgent
The main agent class that wraps LLM providers via LiteLLM:
python
from line.llm_agent import LlmAgent, LlmConfig
agent = LlmAgent(
model="gemini/gemini-2.5-flash-preview-09-2025", # LiteLLM model string
api_key=os.getenv("GEMINI_API_KEY"), # Provider API key
tools=[end_call, my_custom_tool], # List of tools
config=LlmConfig(...), # Agent configuration
max_tool_iterations=10, # Max tool call loops (default: 10)
)通过LiteLLM封装LLM提供商的主要Agent类:
python
from line.llm_agent import LlmAgent, LlmConfig
agent = LlmAgent(
model="gemini/gemini-2.5-flash-preview-09-2025", # LiteLLM模型字符串
api_key=os.getenv("GEMINI_API_KEY"), # 提供商API密钥
tools=[end_call, my_custom_tool], # 工具列表
config=LlmConfig(...), # Agent配置
max_tool_iterations=10, # 最大工具调用循环次数(默认:10)
)LlmConfig
LlmConfig
Configuration for agent behavior and LLM sampling:
python
from line.llm_agent import LlmConfig
config = LlmConfig(
# Agent behavior
system_prompt="You are a helpful assistant.",
introduction="Hello! How can I help?", # Set to "" to wait for user first
# Sampling parameters (optional)
temperature=0.7,
max_tokens=1024,
top_p=0.9,
# Resilience (optional)
num_retries=2,
timeout=30.0,
fallbacks=["gpt-4o-mini"], # Fallback models
)用于配置Agent行为和LLM采样参数:
python
from line.llm_agent import LlmConfig
config = LlmConfig(
# Agent行为
system_prompt="You are a helpful assistant.",
introduction="Hello! How can I help?", # 设置为""以等待用户先发言
# 采样参数(可选)
temperature=0.7,
max_tokens=1024,
top_p=0.9,
# 容错机制(可选)
num_retries=2,
timeout=30.0,
fallbacks=["gpt-4o-mini"], # 备用模型
)Dynamic Configuration from CallRequest
从CallRequest动态配置
Use to pull configuration from the incoming call:
LlmConfig.from_call_request()python
async def get_agent(env: AgentEnv, call_request: CallRequest):
return LlmAgent(
model="anthropic/claude-sonnet-4-20250514",
api_key=os.getenv("ANTHROPIC_API_KEY"),
tools=[end_call],
config=LlmConfig.from_call_request(
call_request,
fallback_system_prompt="Default system prompt if not in request.",
fallback_introduction="Default introduction if not in request.",
temperature=0.7, # Additional LlmConfig options
),
)Priority order: CallRequest value > fallback argument > SDK default
使用从呼入请求中获取配置:
LlmConfig.from_call_request()python
async def get_agent(env: AgentEnv, call_request: CallRequest):
return LlmAgent(
model="anthropic/claude-sonnet-4-20250514",
api_key=os.getenv("ANTHROPIC_API_KEY"),
tools=[end_call],
config=LlmConfig.from_call_request(
call_request,
fallback_system_prompt="如果请求中没有提供,使用默认系统提示词。",
fallback_introduction="如果请求中没有提供,使用默认开场白。",
temperature=0.7, # 额外的LlmConfig选项
),
)优先级顺序:CallRequest值 > 备用参数 > SDK默认值
VoiceAgentApp
VoiceAgentApp
The application harness that manages HTTP endpoints and WebSocket connections:
python
from line.voice_agent_app import VoiceAgentApp, AgentEnv, CallRequest
async def get_agent(env: AgentEnv, call_request: CallRequest):
# env.loop - asyncio event loop
# call_request.call_id - unique call identifier
# call_request.agent.system_prompt - from request
# call_request.agent.introduction - from request
# call_request.metadata - custom metadata dict
return LlmAgent(...)
app = VoiceAgentApp(get_agent=get_agent)
app.run(host="0.0.0.0", port=8000)管理HTTP端点和WebSocket连接的应用框架:
python
from line.voice_agent_app import VoiceAgentApp, AgentEnv, CallRequest
async def get_agent(env: AgentEnv, call_request: CallRequest):
# env.loop - asyncio事件循环
# call_request.call_id - 唯一呼叫标识符
# call_request.agent.system_prompt - 来自请求
# call_request.agent.introduction - 来自请求
# call_request.metadata - 自定义元数据字典
return LlmAgent(...)
app = VoiceAgentApp(get_agent=get_agent)
app.run(host="0.0.0.0", port=8000)Built-in Tools
内置工具
Import from :
line.llm_agentpython
from line.llm_agent import end_call, send_dtmf, transfer_call, web_search从导入:
line.llm_agentpython
from line.llm_agent import end_call, send_dtmf, transfer_call, web_searchend_call
end_call
End the current call. Tell the LLM to say goodbye before calling this.
python
tools=[end_call]结束当前呼叫。告诉LLM在调用此工具前先道别。
python
tools=[end_call]System prompt: "Say goodbye before ending the call with end_call."
系统提示词:"在使用end_call结束呼叫前先道别。"
undefinedundefinedsend_dtmf
send_dtmf
Send DTMF tones (touch-tone buttons). Useful for IVR navigation.
python
tools=[send_dtmf]发送DTMF音调(按键音)。适用于IVR导航。
python
tools=[send_dtmf]Buttons: "0"-"9", "*", "#" (strings, not integers!)
按键:"0"-"9"、"*"、"#"(字符串类型,不是整数!)
undefinedundefinedtransfer_call
transfer_call
Transfer to another phone number (E.164 format required).
python
tools=[transfer_call]转接至另一个电话号码(必须使用E.164格式)。
python
tools=[transfer_call]Example: +14155551234
示例:+14155551234
undefinedundefinedweb_search
web_search
Search the web for real-time information. Uses native LLM web search when available, falls back to DuckDuckGo.
python
undefined搜索网页获取实时信息。支持原生LLM网页搜索, fallback到DuckDuckGo。
python
undefinedDefault settings
默认设置
tools=[web_search]
tools=[web_search]
Custom settings
自定义设置
tools=[web_search(search_context_size="high")] # "low", "medium", "high"
undefinedtools=[web_search(search_context_size="high")] # "low"、"medium"、"high"
undefinedCustom Tool Types
自定义工具类型
Three tool paradigms for different use cases:
| Type | Decorator | Use Case | Result Handling |
|---|---|---|---|
| Loopback | | API calls, database lookups | Result sent back to LLM |
| Passthrough | | End call, transfer, DTMF | Bypasses LLM, goes to user |
| Handoff | | Multi-agent workflows | Transfers control to another agent |
三种适用于不同场景的工具范式:
| 类型 | 装饰器 | 使用场景 | 结果处理 |
|---|---|---|---|
| Loopback | | API调用、数据库查询 | 结果返回给LLM |
| Passthrough | | 结束呼叫、转接、DTMF | 绕过LLM,直接发送给用户 |
| Handoff | | 多Agent工作流 | 将控制权转交给另一个Agent |
Tool Type Decision Tree
工具类型决策树
Does the result need LLM processing?
├─ YES → @loopback_tool
│ └─ Is it long-running (>1s)? → @loopback_tool(is_background=True)
│ └─ Yield interim status, then final result
├─ NO, deterministic action → @passthrough_tool
│ └─ Yields OutputEvent objects directly (AgentSendText, AgentEndCall, etc.)
└─ Transfer to another agent → @handoff_tool or agent_as_handoff()结果是否需要LLM处理?
├─ 是 → @loopback_tool
│ └─ 是否为长耗时操作(>1s)? → @loopback_tool(is_background=True)
│ └─ 返回临时状态,再返回最终结果
├─ 否,确定性操作 → @passthrough_tool
│ └─ 直接生成OutputEvent对象(AgentSendText、AgentEndCall等)
└─ 转交给另一个Agent → @handoff_tool或agent_as_handoff()Loopback Tools
Loopback工具
Results are sent back to the LLM to inform the next response:
python
from typing import Annotated
from line.llm_agent import loopback_tool, ToolEnv
@loopback_tool
async def get_order_status(
ctx: ToolEnv,
order_id: Annotated[str, "The order ID to look up"],
) -> str:
"""Look up the current status of an order."""
order = await db.get_order(order_id)
return f"Order {order_id} status: {order.status}, ETA: {order.eta}"Parameter syntax:
- First parameter MUST be
ctx: ToolEnv - Use for LLM-visible parameters
Annotated[type, "description"] - Tool description comes from the docstring
- Optional parameters need default values (not just )
Optional[T]
python
@loopback_tool
async def search_products(
ctx: ToolEnv,
query: Annotated[str, "Search query"],
category: Annotated[str, "Product category"] = "all", # Optional with default
limit: Annotated[int, "Max results"] = 10,
) -> str:
"""Search the product catalog."""
...结果返回给LLM以生成下一轮响应:
python
from typing import Annotated
from line.llm_agent import loopback_tool, ToolEnv
@loopback_tool
async def get_order_status(
ctx: ToolEnv,
order_id: Annotated[str, "要查询的订单ID"],
) -> str:
"""查询订单的当前状态。"""
order = await db.get_order(order_id)
return f"订单{order_id}状态:{order.status},预计送达时间:{order.eta}"参数语法:
- 第一个参数必须是
ctx: ToolEnv - 对LLM可见的参数使用
Annotated[type, "描述"] - 工具描述来自文档字符串
- 可选参数需要设置默认值(不能仅用)
Optional[T]
python
@loopback_tool
async def search_products(
ctx: ToolEnv,
query: Annotated[str, "搜索关键词"],
category: Annotated[str, "产品分类"] = "all", # 带默认值的可选参数
limit: Annotated[int, "最大结果数"] = 10,
) -> str:
"""搜索产品目录。"""
...Passthrough Tools
Passthrough工具
Results bypass the LLM and go directly to the user/system:
python
from line.events import AgentSendText, AgentTransferCall
from line.llm_agent import passthrough_tool, ToolEnv
@passthrough_tool
async def transfer_to_support(
ctx: ToolEnv,
reason: Annotated[str, "Reason for transfer"],
):
"""Transfer the call to the support team."""
yield AgentSendText(text="Let me transfer you to our support team now.")
yield AgentTransferCall(target_phone_number="+18005551234")Output event types (from ):
line.events- - Speak text to user
AgentSendText(text="...") - - End the call
AgentEndCall() - - Transfer call
AgentTransferCall(target_phone_number="+1...") - - Send DTMF tone
AgentSendDtmf(button="5")
结果绕过LLM直接发送给用户/系统:
python
from line.events import AgentSendText, AgentTransferCall
from line.llm_agent import passthrough_tool, ToolEnv
@passthrough_tool
async def transfer_to_support(
ctx: ToolEnv,
reason: Annotated[str, "转接原因"],
):
"""将呼叫转接至支持团队。"""
yield AgentSendText(text="现在为您转接至我们的支持团队。")
yield AgentTransferCall(target_phone_number="+18005551234")输出事件类型(来自):
line.events- - 向用户朗读文本
AgentSendText(text="...") - - 结束呼叫
AgentEndCall() - - 转接呼叫
AgentTransferCall(target_phone_number="+1...") - - 发送DTMF音调
AgentSendDtmf(button="5")
Handoff Tools
Handoff工具
Transfer control to another agent. See Multi-Agent Workflows.
将控制权转交给另一个Agent。详见多Agent工作流。
Model Selection Strategy
模型选择策略
Use FAST models for the main conversational agent:
- (recommended)
gemini/gemini-2.5-flash-preview-09-2025 anthropic/claude-haiku-4-5-20251001gpt-4o-mini
Use POWERFUL models only via background tool calls for complex reasoning:
anthropic/claude-opus-4-5gpt-4o
This pattern keeps conversations responsive while accessing deep reasoning when needed. See the Two-Tier Agent Pattern in Advanced Patterns for implementation.
主对话Agent使用快速模型:
- (推荐)
gemini/gemini-2.5-flash-preview-09-2025 anthropic/claude-haiku-4-5-20251001gpt-4o-mini
仅在后台工具调用中使用高性能模型处理复杂推理:
anthropic/claude-opus-4-5gpt-4o
这种模式既能保持对话响应速度,又能在需要时调用深度推理能力。实现方式详见高级模式中的双层Agent模式。
LLM Providers
LLM提供商
Line SDK uses LiteLLM model strings. Common formats:
| Provider | Format | Example |
|---|---|---|
| OpenAI | | |
| Anthropic | | |
| Google Gemini | | |
| Azure OpenAI | | |
Set the appropriate API key environment variable:
OPENAI_API_KEYANTHROPIC_API_KEYGEMINI_API_KEYAZURE_API_KEY
Full list: https://docs.litellm.ai/docs/providers
Line SDK使用LiteLLM模型字符串。常见格式:
| 提供商 | 格式 | 示例 |
|---|---|---|
| OpenAI | | |
| Anthropic | | |
| Google Gemini | | |
| Azure OpenAI | | |
设置对应的API密钥环境变量:
OPENAI_API_KEYANTHROPIC_API_KEYGEMINI_API_KEYAZURE_API_KEY
Common Patterns
常见模式
Agent with Custom Tools
带自定义工具的Agent
python
from typing import Annotated
from line.llm_agent import LlmAgent, LlmConfig, loopback_tool, end_call, ToolEnv
@loopback_tool
async def check_appointment(
ctx: ToolEnv,
date: Annotated[str, "Date in YYYY-MM-DD format"],
) -> str:
"""Check available appointment slots for a given date."""
slots = await calendar.get_available_slots(date)
return f"Available slots on {date}: {', '.join(slots)}"
@loopback_tool
async def book_appointment(
ctx: ToolEnv,
date: Annotated[str, "Date in YYYY-MM-DD format"],
time: Annotated[str, "Time in HH:MM format"],
name: Annotated[str, "Customer name"],
) -> str:
"""Book an appointment slot."""
result = await calendar.book(date, time, name)
return f"Appointment booked for {name} on {date} at {time}. Confirmation: {result.id}"
async def get_agent(env: AgentEnv, call_request: CallRequest):
return LlmAgent(
model="gemini/gemini-2.5-flash-preview-09-2025",
api_key=os.getenv("GEMINI_API_KEY"),
tools=[check_appointment, book_appointment, end_call],
config=LlmConfig(
system_prompt="""You are an appointment scheduling assistant.
Help users check availability and book appointments.
Always confirm the booking details before finalizing.""",
introduction="Hi! I can help you schedule an appointment. What date works for you?",
),
)python
from typing import Annotated
from line.llm_agent import LlmAgent, LlmConfig, loopback_tool, end_call, ToolEnv
@loopback_tool
async def check_appointment(
ctx: ToolEnv,
date: Annotated[str, "日期格式为YYYY-MM-DD"],
) -> str:
"""查询指定日期的可用预约时段。"""
slots = await calendar.get_available_slots(date)
return f"{date}的可用时段:{', '.join(slots)}"
@loopback_tool
async def book_appointment(
ctx: ToolEnv,
date: Annotated[str, "日期格式为YYYY-MM-DD"],
time: Annotated[str, "时间格式为HH:MM"],
name: Annotated[str, "客户姓名"],
) -> str:
"""预约时段。"""
result = await calendar.book(date, time, name)
return f"已为{name}预约{date} {time}的时段。确认码:{result.id}"
async def get_agent(env: AgentEnv, call_request: CallRequest):
return LlmAgent(
model="gemini/gemini-2.5-flash-preview-09-2025",
api_key=os.getenv("GEMINI_API_KEY"),
tools=[check_appointment, book_appointment, end_call],
config=LlmConfig(
system_prompt="""您是一位预约调度助手。
帮助用户查询可用时段并完成预约。
在最终确认前务必核实预约详情。""",
introduction="您好!我可以帮您预约时段。请问您想预约哪天?",
),
)Wait for User to Speak First
等待用户先发言
Set to have the agent wait for the user:
introduction=""python
config=LlmConfig(
system_prompt="You are a helpful assistant.",
introduction="", # Empty string = wait for user
)设置让Agent等待用户先发言:
introduction=""python
config=LlmConfig(
system_prompt="您是一位乐于助人的助手。",
introduction="", # 空字符串 = 等待用户先发言
)Form Filling Pattern
表单填写模式
See the form filler example for collecting structured data via voice. Key pattern:
python
@loopback_tool
async def record_answer(
ctx: ToolEnv,
answer: Annotated[str, "The user's answer"],
) -> dict:
"""Record an answer to the current question."""
# Process and validate answer
# Return next question or completion status
return {"next_question": "What is your email?", "is_complete": False}详见表单填写示例,通过语音收集结构化数据。核心模式:
python
@loopback_tool
async def record_answer(
ctx: ToolEnv,
answer: Annotated[str, "用户的回答"],
) -> dict:
"""记录当前问题的用户回答。"""
# 处理并验证回答
# 返回下一个问题或完成状态
return {"next_question": "请问您的邮箱是多少?", "is_complete": False}Common Mistakes to Avoid
常见错误规避
-
Missingtool - If not included (or a similar custom tool), the agent cannot end the call on its own and must wait for the user to hang up
end_call -
Raising exceptions in tools - Return user-friendly error strings:python
# BAD raise ValueError("Invalid order ID") # GOOD return "I couldn't find that order. Please check the ID and try again." -
Forgettingparameter - First parameter must be
ctx:ctx: ToolEnvpython# GOOD @loopback_tool async def my_tool(ctx: ToolEnv, order_id: Annotated[str, "Order ID"]): ... -
Forgettingin handoff tools - Handoff tools MUST have
eventparameter:eventpython# GOOD @handoff_tool async def my_handoff(ctx: ToolEnv, param: Annotated[str, "desc"], event): ... -
Missing Annotated descriptions - LLM needs parameter descriptions:python
# GOOD async def my_tool(ctx, order_id: Annotated[str, "The order ID to look up"]): ... -
Blocking on long operations - Useand yield interim status:
is_background=Truepython@loopback_tool(is_background=True) async def slow_search(ctx: ToolEnv, query: Annotated[str, "Query"]): yield "Searching..." # Immediate feedback result = await slow_operation() yield result -
Using sync APIs directly - Wrap sync calls with:
asyncio.to_thread()pythonresult = await asyncio.to_thread(sync_api_call, params) -
Using slow models for main conversation - Use fast models (haiku, flash, mini) for the main agent, powerful models only via background tools.
-
缺少工具 - 如果未包含(或类似的自定义工具),Agent无法主动结束呼叫,只能等待用户挂断
end_call -
在工具中抛出异常 - 返回用户友好的错误信息:python
# 错误示例 raise ValueError("无效的订单ID") # 正确示例 return "我无法找到该订单,请检查订单ID后重试。" -
忘记参数 - 第一个参数必须是
ctx:ctx: ToolEnvpython# 正确示例 @loopback_tool async def my_tool(ctx: ToolEnv, order_id: Annotated[str, "订单ID"]): ... -
Handoff工具缺少参数 - Handoff工具必须包含
event参数:eventpython# 正确示例 @handoff_tool async def my_handoff(ctx: ToolEnv, param: Annotated[str, "描述"], event): ... -
缺少Annotated描述 - LLM需要参数描述:python
# 正确示例 async def my_tool(ctx, order_id: Annotated[str, "要查询的订单ID"]): ... -
阻塞长耗时操作 - 使用并返回临时状态:
is_background=Truepython@loopback_tool(is_background=True) async def slow_search(ctx: ToolEnv, query: Annotated[str, "查询关键词"]): yield "搜索中..." # 即时反馈 result = await slow_operation() yield result -
直接使用同步API - 使用包装同步调用:
asyncio.to_thread()pythonresult = await asyncio.to_thread(sync_api_call, params) -
主对话使用慢模型 - 主Agent使用快速模型(haiku、flash、mini),仅在后台工具中使用高性能模型。
Reference Documentation
参考文档
- Tool Patterns - Deep dive on tool implementation
- Multi-Agent Workflows - Handoffs, wrappers, guardrails
- Advanced Patterns - Background tools, state, events
- Calls API - WebSocket integration for web/mobile apps
- Troubleshooting - Common issues and debugging
- 工具模式 - 工具实现深度解析
- 多Agent工作流 - 交接、包装、防护措施
- 高级模式 - 后台工具、状态、事件
- 呼叫API - 网页/移动应用的WebSocket集成
- 故障排除 - 常见问题与调试
Key Imports
核心导入
python
undefinedpython
undefinedCore
核心模块
from line.llm_agent import LlmAgent, LlmConfig
from line.voice_agent_app import VoiceAgentApp, AgentEnv, CallRequest
from line.llm_agent import LlmAgent, LlmConfig
from line.voice_agent_app import VoiceAgentApp, AgentEnv, CallRequest
Built-in tools
内置工具
from line.llm_agent import end_call, send_dtmf, transfer_call, web_search
from line.llm_agent import end_call, send_dtmf, transfer_call, web_search
Tool decorators
工具装饰器
from line.llm_agent import loopback_tool, passthrough_tool, handoff_tool
from line.llm_agent import loopback_tool, passthrough_tool, handoff_tool
Tool context
工具上下文
from line.llm_agent import ToolEnv
from line.llm_agent import ToolEnv
Multi-agent
多Agent
from line.llm_agent import agent_as_handoff
from line.llm_agent import agent_as_handoff
Events (for passthrough/handoff tools and custom agents)
事件(用于passthrough/handoff工具和自定义Agent)
from line.events import (
AgentSendText,
AgentEndCall,
AgentTransferCall,
AgentSendDtmf,
AgentUpdateCall,
)
undefinedfrom line.events import (
AgentSendText,
AgentEndCall,
AgentTransferCall,
AgentSendDtmf,
AgentUpdateCall,
)
undefinedKey Reference Files
核心参考文件
When implementing Line SDK agents, reference these example files:
- - Simplest agent pattern
examples/basic_chat/main.py - - Loopback tools with state
examples/form_filler/ - - Background tools with two-tier model strategy
examples/chat_supervisor/main.py - - Multi-agent handoffs
examples/transfer_agent/main.py - - Custom handoff tools
examples/echo/tools.py
实现Line SDK Agent时,可参考以下示例文件:
- - 最简Agent模式
examples/basic_chat/main.py - - 带状态的Loopback工具
examples/form_filler/ - - 带双层模型策略的后台工具
examples/chat_supervisor/main.py - - 多Agent交接
examples/transfer_agent/main.py - - 自定义Handoff工具 ",
examples/echo/tools.py