line-voice-agent

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Line 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
cartesia
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 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代码,通过
cartesia
CLI将其部署到Cartesia的托管云服务中,Cartesia会提供自动扩缩容的托管服务。Cartesia负责处理STT(Ink)、TTS(Sonic)、电话通信和音频编排。每个Agent同一时间只能有一个部署处于活跃状态;部署完成后,你的Agent会自动接收呼叫。
┌─────────────────────────────────────────────────────────────────┐
│                     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
undefined
bash
undefined

Authentication

身份验证

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
undefined
cartesia agents ls # 列出所有Agent cartesia deployments ls # 列出部署记录 cartesia call <phone> [agent-id] # 发起外呼
undefined

Quick Start

快速开始

1. Create Project

1. 创建项目

bash
cartesia auth login
cartesia create my-agent
cd my-agent
bash
cartesia auth login
cartesia create my-agent
cd my-agent

2. Write Agent Code

2. 编写Agent代码

main.py
:
python
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.py
:
python
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 agent
bash
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 active
bash
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 CLI
Or 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-line

Core 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
LlmConfig.from_call_request()
to pull configuration from the incoming call:
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_agent
:
python
from line.llm_agent import end_call, send_dtmf, transfer_call, web_search
line.llm_agent
导入:
python
from line.llm_agent import end_call, send_dtmf, transfer_call, web_search

end_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结束呼叫前先道别。"

undefined
undefined

send_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"、"*"、"#"(字符串类型,不是整数!)

undefined
undefined

transfer_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

undefined
undefined

web_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
undefined

Default settings

默认设置

tools=[web_search]
tools=[web_search]

Custom settings

自定义设置

tools=[web_search(search_context_size="high")] # "low", "medium", "high"
undefined
tools=[web_search(search_context_size="high")] # "low"、"medium"、"high"
undefined

Custom Tool Types

自定义工具类型

Three tool paradigms for different use cases:
TypeDecoratorUse CaseResult Handling
Loopback
@loopback_tool
API calls, database lookupsResult sent back to LLM
Passthrough
@passthrough_tool
End call, transfer, DTMFBypasses LLM, goes to user
Handoff
@handoff_tool
Multi-agent workflowsTransfers control to another agent
三种适用于不同场景的工具范式:
类型装饰器使用场景结果处理
Loopback
@loopback_tool
API调用、数据库查询结果返回给LLM
Passthrough
@passthrough_tool
结束呼叫、转接、DTMF绕过LLM,直接发送给用户
Handoff
@handoff_tool
多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
    Annotated[type, "description"]
    for LLM-visible parameters
  • 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
):
  • AgentSendText(text="...")
    - Speak text to user
  • AgentEndCall()
    - End the call
  • AgentTransferCall(target_phone_number="+1...")
    - Transfer call
  • AgentSendDtmf(button="5")
    - Send DTMF tone
结果绕过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...")
    - 转接呼叫
  • AgentSendDtmf(button="5")
    - 发送DTMF音调

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:
  • gemini/gemini-2.5-flash-preview-09-2025
    (recommended)
  • anthropic/claude-haiku-4-5-20251001
  • gpt-4o-mini
Use POWERFUL models only via background tool calls for complex reasoning:
  • anthropic/claude-opus-4-5
  • gpt-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-20251001
  • gpt-4o-mini
仅在后台工具调用中使用高性能模型处理复杂推理:
  • anthropic/claude-opus-4-5
  • gpt-4o
这种模式既能保持对话响应速度,又能在需要时调用深度推理能力。实现方式详见高级模式中的双层Agent模式。

LLM Providers

LLM提供商

Line SDK uses LiteLLM model strings. Common formats:
ProviderFormatExample
OpenAI
model_name
gpt-4o
,
gpt-4o-mini
Anthropic
anthropic/model_name
anthropic/claude-sonnet-4-20250514
Google Gemini
gemini/model_name
gemini/gemini-2.5-flash-preview-09-2025
Azure OpenAI
azure/deployment_name
azure/my-gpt4-deployment
Set the appropriate API key environment variable:
  • OPENAI_API_KEY
  • ANTHROPIC_API_KEY
  • GEMINI_API_KEY
  • AZURE_API_KEY
Line SDK使用LiteLLM模型字符串。常见格式:
提供商格式示例
OpenAI
model_name
gpt-4o
,
gpt-4o-mini
Anthropic
anthropic/model_name
anthropic/claude-sonnet-4-20250514
Google Gemini
gemini/model_name
gemini/gemini-2.5-flash-preview-09-2025
Azure OpenAI
azure/deployment_name
azure/my-gpt4-deployment
设置对应的API密钥环境变量:
  • OPENAI_API_KEY
  • ANTHROPIC_API_KEY
  • GEMINI_API_KEY
  • AZURE_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
introduction=""
to have the agent wait for the user:
python
config=LlmConfig(
    system_prompt="You are a helpful assistant.",
    introduction="",  # Empty string = wait for user
)
设置
introduction=""
让Agent等待用户先发言:
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

常见错误规避

  1. Missing
    end_call
    tool
    - 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
  2. 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."
  3. Forgetting
    ctx
    parameter
    - First parameter must be
    ctx: ToolEnv
    :
    python
    # GOOD
    @loopback_tool
    async def my_tool(ctx: ToolEnv, order_id: Annotated[str, "Order ID"]): ...
  4. Forgetting
    event
    in handoff tools
    - Handoff tools MUST have
    event
    parameter:
    python
    # GOOD
    @handoff_tool
    async def my_handoff(ctx: ToolEnv, param: Annotated[str, "desc"], event): ...
  5. Missing Annotated descriptions - LLM needs parameter descriptions:
    python
    # GOOD
    async def my_tool(ctx, order_id: Annotated[str, "The order ID to look up"]): ...
  6. Blocking on long operations - Use
    is_background=True
    and yield interim status:
    python
    @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
  7. Using sync APIs directly - Wrap sync calls with
    asyncio.to_thread()
    :
    python
    result = await asyncio.to_thread(sync_api_call, params)
  8. Using slow models for main conversation - Use fast models (haiku, flash, mini) for the main agent, powerful models only via background tools.
  1. 缺少
    end_call
    工具
    - 如果未包含(或类似的自定义工具),Agent无法主动结束呼叫,只能等待用户挂断
  2. 在工具中抛出异常 - 返回用户友好的错误信息:
    python
    # 错误示例
    raise ValueError("无效的订单ID")
    
    # 正确示例
    return "我无法找到该订单,请检查订单ID后重试。"
  3. 忘记
    ctx
    参数
    - 第一个参数必须是
    ctx: ToolEnv
    python
    # 正确示例
    @loopback_tool
    async def my_tool(ctx: ToolEnv, order_id: Annotated[str, "订单ID"]): ...
  4. Handoff工具缺少
    event
    参数
    - Handoff工具必须包含
    event
    参数:
    python
    # 正确示例
    @handoff_tool
    async def my_handoff(ctx: ToolEnv, param: Annotated[str, "描述"], event): ...
  5. 缺少Annotated描述 - LLM需要参数描述:
    python
    # 正确示例
    async def my_tool(ctx, order_id: Annotated[str, "要查询的订单ID"]): ...
  6. 阻塞长耗时操作 - 使用
    is_background=True
    并返回临时状态:
    python
    @loopback_tool(is_background=True)
    async def slow_search(ctx: ToolEnv, query: Annotated[str, "查询关键词"]):
        yield "搜索中..."  # 即时反馈
        result = await slow_operation()
        yield result
  7. 直接使用同步API - 使用
    asyncio.to_thread()
    包装同步调用:
    python
    result = await asyncio.to_thread(sync_api_call, params)
  8. 主对话使用慢模型 - 主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
undefined
python
undefined

Core

核心模块

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, )
undefined
from line.events import ( AgentSendText, AgentEndCall, AgentTransferCall, AgentSendDtmf, AgentUpdateCall, )
undefined

Key Reference Files

核心参考文件

When implementing Line SDK agents, reference these example files:
  • examples/basic_chat/main.py
    - Simplest agent pattern
  • examples/form_filler/
    - Loopback tools with state
  • examples/chat_supervisor/main.py
    - Background tools with two-tier model strategy
  • examples/transfer_agent/main.py
    - Multi-agent handoffs
  • examples/echo/tools.py
    - Custom handoff tools
实现Line SDK Agent时,可参考以下示例文件:
  • examples/basic_chat/main.py
    - 最简Agent模式
  • examples/form_filler/
    - 带状态的Loopback工具
  • examples/chat_supervisor/main.py
    - 带双层模型策略的后台工具
  • examples/transfer_agent/main.py
    - 多Agent交接
  • examples/echo/tools.py
    - 自定义Handoff工具 ",