Lybic Docs

gRPC 和服务部署

gRPC 服务器(grpc_app

gRPC 应用将 GUI 智能体以长生命周期服务的形式对外暴露,用于多语言集成、远程编排、指标采集和持久化。 容器内的二进制入口:

/app/.venv/bin/lybic-guiagent-grpc

(若在本地安装,且环境变量 PATH 已配置该工具所在的 bin 目录,可直接通过 lybic-guiagent-grpc 命令调用。)

Proto 文件

下表简要介绍了智能体 gRPC API 的主要接口及其用途,并给出典型调用示例:

方法作用示例
GetAgentInfo获取智能体版本和能力信息resp = stub.GetAgentInfo(agent_pb2.GetAgentInfoRequest())
GetGlobalCommonConfig获取全局通用配置resp = stub.GetGlobalCommonConfig(agent_pb2.GetGlobalCommonConfigRequest())
SetGlobalCommonConfig设置全局通用配置resp = stub.SetGlobalCommonConfig(agent_pb2.SetGlobalCommonConfigRequest(commonConfig=...))
SetGlobalCommonLLMConfig/SetGlobalGroundingLLMConfig/SetGlobalEmbeddingLLMConfig配置全局 LLM/嵌入/grounding 模型.参考文档Model Support & Configuration Referenceresp = stub.SetGlobalCommonLLMConfig(agent_pb2.SetGlobalCommonLLMConfigRequest(llmConfig=...))
RunAgentInstruction同步执行自然语言指令,返回流式任务进度async for ev in stub.RunAgentInstruction(agent_pb2.RunAgentInstructionRequest(instruction="Open a calculator and compute 1+1")):
RunAgentInstructionAsync异步提交指令,返回 taskIdresp = await stub.RunAgentInstructionAsync(agent_pb2.RunAgentInstructionRequest(instruction="Create a new text document"))
GetAgentTaskStream获取异步任务流式进度async for ev in stub.GetAgentTaskStream(agent_pb2.GetAgentTaskStreamRequest(taskId=task_id)):
QueryTaskStatus查询任务状态和结果resp = await stub.QueryTaskStatus(agent_pb2.QueryTaskStatusRequest(taskId=task_id))
CancelTask取消指定任务resp = await stub.CancelTask(agent_pb2.CancelTaskRequest(taskId=task_id))

详细参数请参考下方 proto 定义。

/*
1. generate protobuf code
python3 -m grpc_tools.protoc -Igui_agents/proto \
  --python_out=gui_agents/proto/pb  \
  --grpc_python_out=gui_agents/proto/pb \
  --pyi_out=gui_agents/proto/pb \
  gui_agents/proto/agent.proto

2. resolve import path error:
sed -i 's/^import agent_pb2 as agent__pb2/from . import agent_pb2 as agent__pb2/' gui_agents/proto/pb/agent_pb2_grpc.py
*/

syntax = "proto3";

package lybic.agent;

option go_package = "github.com/lybic/lybic-sdk-go/agent";
option java_package = "com.lybic.agent";
option java_multiple_files = true;
option java_outer_classname = "AgentProto";
option py_generic_services = true;

import "google/protobuf/timestamp.proto";

service Agent {
  // get agent info
  rpc GetAgentInfo(GetAgentInfoRequest) returns (AgentInfo);

  // get agent config
  rpc GetGlobalCommonConfig(GetGlobalCommonConfigRequest) returns (CommonConfig);
  rpc GetCommonConfig(GetCommonConfigRequest) returns (CommonConfig);
  // set agent config
  rpc SetGlobalCommonConfig(SetGlobalCommonConfigRequest) returns (SetCommonConfigResponse);
  rpc SetGlobalCommonLLMConfig(SetGlobalCommonLLMConfigRequest) returns (LLMConfig);
  rpc SetGlobalGroundingLLMConfig(SetGlobalGroundingLLMConfigRequest) returns (LLMConfig);
  // set agent embedding
  rpc SetGlobalEmbeddingLLMConfig(SetGlobalEmbeddingLLMConfigRequest) returns (LLMConfig);

  // run agent sync
  rpc RunAgentInstruction(RunAgentInstructionRequest) returns (stream TaskStream);
  // run agent async
  rpc RunAgentInstructionAsync(RunAgentInstructionRequest) returns (RunAgentInstructionAsyncResponse);
  // get agent task stream
  rpc GetAgentTaskStream(GetAgentTaskStreamRequest) returns (stream GetAgentTaskStreamResponse);
  // query task status
  rpc QueryTaskStatus(QueryTaskStatusRequest)returns (QueryTaskStatusResponse);
  // cancel task
  rpc CancelTask(CancelTaskRequest) returns (CancelTaskResponse);
}

message SetGlobalCommonLLMConfigRequest {
  LLMConfig llmConfig = 1;
}

message SetGlobalEmbeddingLLMConfigRequest {
  LLMConfig llmConfig = 1;
}

message SetGlobalGroundingLLMConfigRequest {
  LLMConfig llmConfig = 1;
}

message SetGlobalCommonConfigRequest {
  CommonConfig commonConfig = 1;
}

message SetCommonConfigResponse {
  bool success = 1;
  string id = 2;
}

message GetAgentInfoRequest {
}
message GetGlobalCommonConfigRequest {
}

message GetCommonConfigRequest {
  string id = 1;
}

message AgentInfo {
  string version = 1;
  int32 maxConcurrentTasks = 2; // default 5
  string log_level = 3;
  optional string domain = 4;
}

message Sandbox {
  // sandbox id
  string id = 1;
  // sandbox name
  string name = 2;
  // sandbox description
  string description = 3;
  // sandbox shape
  string shapeName = 4;
  // is hardware accelerated encoding
  bool hardwareAcceleratedEncoding = 5;
  // sandbox os type
  SandboxOS os = 6;
  // virtualization
  string virtualization = 7; // KVM or Container
  // architecture
  string architecture = 8; // x86_64 or aarch64
}

enum SandboxOS {
  OSUNDEFINED = 0;
  WINDOWS = 1;
  LINUX = 2;
  ANDROID = 3;
}

message Authorization {
    string orgID = 1;
    string apiKey = 2;
    optional string apiEndpoint = 3; // default https://api.lybic.cn
}

message LLMConfig {
  string modelName = 1;
  optional string provider = 2; // if not specified, agent will automatically find the provider form the model name (support doubao,gemini,deepseek)
  optional string apiKey = 3;
  optional string apiEndpoint = 4;
}

message StageModelConfig{
  optional string webSearchEngine = 1;
  optional LLMConfig contextFusionModel = 2;
  optional LLMConfig subtaskPlannerModel = 3;
  optional LLMConfig trajReflectorModel = 4;
  optional LLMConfig memoryRetrivalModel = 5;
  optional LLMConfig groundingModel = 6;
  optional LLMConfig taskEvaluatorModel = 7;
  optional LLMConfig actionGeneratorModel = 8;
  optional LLMConfig actionGeneratorWithTakeoverModel = 9;
  optional LLMConfig fastActionGeneratorModel = 10;
  optional LLMConfig fastActionGeneratorWithTakeoverModel = 11;
  optional LLMConfig dagTranslatorModel = 12;
  optional LLMConfig embeddingModel = 13;
  optional LLMConfig queryFormulatorModel = 14;
  optional LLMConfig narrativeSummarizationModel = 15;
  optional LLMConfig textSpanModel = 16;
  optional LLMConfig episodeSummarizationModel = 17;
}

message CommonConfig {
  string id = 1;

  optional string backend = 2; // `lybic` for windows and linux or `lybic_mobile` for android
  InstanceMode mode = 3; // agent mode default is FAST
  optional int32 steps = 4; // default max steps is 50
  string platform = 5; // agent target plat。 this is not used now
  optional int32 taskTimeout = 6; // default 3600 (s)(1 hour)
  optional Authorization authorizationInfo = 7; // lybic authorization info
  optional StageModelConfig stageModelConfig = 8; // agent stage model config
}

enum InstanceMode {
  MODEUNDEFINED = 0;
  NORMAL = 1;
  FAST = 2;
}

message RunAgentInstructionRequest {
  //  natural language instruction
  string instruction = 1;

  optional Sandbox sandbox = 2; // if sandbox is not specified, agent will create a sandbox to execute the instruction
  optional CommonConfig runningConfig = 3; // if runningConfig is not specified, agent will use the default global config
  optional bool destroySandbox = 4; // if true, destroy the sandbox after task completion (default: false)
  optional string previousTaskId = 5; // if specified, restore conversation history from previous task to continue the context
}

message RunAgentInstructionAsyncResponse {
  string taskId = 1;
}

enum TaskStatus {
  TASKSTATUSUNDEFINED = 0;
  PENDING = 1;
  RUNNING = 2;
  SUCCESS = 3;
  FAILURE = 4;
  NOT_FOUND = 5;
  CANCELLED = 6;
}

message ExecutionStatistics {
  int32 steps = 1;
  int32 durationSeconds = 2;
  int64 inputTokens = 3;
  int64 outputTokens = 4;
  int64 totalTokens = 5;
  double cost = 6;
  string currencySymbol = 7;
}

message QueryTaskStatusRequest {
  string taskId = 1;
}

message QueryTaskStatusResponse {
  string taskId = 1;
  TaskStatus status = 2;
  string message = 3;
  string result = 4;
  optional Sandbox sandbox = 5;
  optional ExecutionStatistics executionStatistics = 6;
}

message GetAgentTaskStreamRequest {
  string taskId = 1;
}

message GetAgentTaskStreamResponse {
  TaskStream taskStream = 1;
}
message TaskStream{
  string taskId = 1;
  string stage = 2;
  string message = 3;
  google.protobuf.Timestamp timestamp = 4;
}

message CancelTaskRequest {
  string taskId = 1;
}

message CancelTaskResponse {
  string taskId = 1;
  bool success = 2;
  string message = 3;
}

快速开始(本地)

LYBIC_API_KEY=your_key \
LYBIC_ORG_ID=your_org \
python -m gui_agents.grpc_app  # 如果支持模块入口,否则使用已安装的脚本

推荐:在 Docker 内运行以实现隔离。

Docker 运行

基础启动:

docker run --rm -it \
  -p 50051:50051 \
  --env-file gui_agents/.env \
  agenticlybic/guiagent /app/.venv/bin/lybic-guiagent-grpc

启用 Prometheus 指标:

docker run --rm -it \
  -p 50051:50051 -p 8000:8000 \
  -e ENABLE_PROMETHEUS=true -e PROMETHEUS_PORT=8000 \
  --env-file gui_agents/.env \
  agenticlybic/guiagent /app/.venv/bin/lybic-guiagent-grpc

指标地址:http://HOST:8000/metrics

核心环境变量

变量用途示例
LYBIC_API_KEY对 Lybic 沙箱 API 的认证sk_live_...
LYBIC_ORG_ID指定所属组织org_123
LYBIC_PRECREATE_SID关联已预创建的沙箱SBX-XXXXXXXX
LYBIC_MAX_LIFE_SECONDS沙箱生命周期(单位:秒)3600
ENABLE_PROMETHEUS暴露指标端点true
PROMETHEUS_PORT指标端口8000
TASK_STORAGE_BACKEND任务存储后端(memory 内存 / postgres 数据库)postgres
POSTGRES_CONNECTION_STRING数据库连接字符串postgresql://user:pwd@host:5432/db
提供商密钥(Gemini/Ark 等)模型访问(参见 tools_config)

可选持久化(PostgreSQL)

安装额外依赖:

pip install lybic-guiagents[postgres]
# 或在 Docker 镜像中已存在

设置后端:

export TASK_STORAGE_BACKEND=postgres
export POSTGRES_CONNECTION_STRING=postgresql://user:password@db-host:5432/lybic_agent

存储的数据:任务元数据、状态、历史记录,用于恢复 / 分析。

Docker Compose 示例

version: '3.9'
services:
  agent-grpc:
    image: agenticlybic/guiagent:latest
    restart: unless-stopped
    ports:
      - '50051:50051'
      - '8000:8000' # 指标
    env_file: gui_agents/.env
    environment:
      ENABLE_PROMETHEUS: 'true'
      PROMETHEUS_PORT: '8000'
      TASK_STORAGE_BACKEND: 'postgres'
      POSTGRES_CONNECTION_STRING: 'postgresql://agent:agent@postgres:5432/agent'
    command: ['/app/.venv/bin/lybic-guiagent-grpc']
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: agent
      POSTGRES_PASSWORD: agent
      POSTGRES_DB: agent
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata: {}

Kubernetes 部署片段

apiVersion: apps/v1
kind: Deployment
metadata:
  name: lybic-agent-grpc
spec:
  replicas: 2
  selector:
    matchLabels:
      app: lybic-agent-grpc
  template:
    metadata:
      labels:
        app: lybic-agent-grpc
    spec:
      containers:
        - name: agent
          image: agenticlybic/guiagent:latest
          ports:
            - containerPort: 50051
            - containerPort: 8000
          env:
            - name: LYBIC_API_KEY
              valueFrom:
                secretKeyRef:
                  name: lybic-secrets
                  key: api_key
            - name: LYBIC_ORG_ID
              valueFrom:
                secretKeyRef:
                  name: lybic-secrets
                  key: org_id
            - name: ENABLE_PROMETHEUS
              value: 'true'
            - name: PROMETHEUS_PORT
              value: '8000'
            - name: TASK_STORAGE_BACKEND
              value: postgres
            - name: POSTGRES_CONNECTION_STRING
              valueFrom:
                secretKeyRef:
                  name: lybic-secrets
                  key: pg_conn
          readinessProbe:
            tcpSocket:
              port: 50051
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            tcpSocket:
              port: 50051
            initialDelaySeconds: 15
            periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
  name: lybic-agent-grpc
spec:
  selector:
    app: lybic-agent-grpc
  ports:
    - port: 50051
      targetPort: 50051
    - port: 8000
      targetPort: 8000

:8000/metrics 添加 Prometheus 抓取作业。

客户端使用(Python 异步)

流式传输(RunAgentInstruction)

返回实时 TaskStream 事件直到完成。

import asyncio, grpc
from gui_agents.proto.pb import agent_pb2, agent_pb2_grpc

async def streaming_example():
    async with grpc.aio.insecure_channel("localhost:50051") as channel:
        stub = agent_pb2_grpc.AgentStub(channel)
        # (可选)配置定位/动作模型
        await stub.SetGlobalGroundingLLMConfig(agent_pb2.SetGlobalGroundingLLMConfigRequest(
            llmConfig=agent_pb2.LLMConfig(modelName="doubao-1-5-ui-tars-250428")
        ))
        await stub.SetGlobalCommonLLMConfig(agent_pb2.SetGlobalCommonLLMConfigRequest(
            llmConfig=agent_pb2.LLMConfig(modelName="claude-sonnet-4-20250514")
        ))
        async for ev in stub.RunAgentInstruction(agent_pb2.RunAgentInstructionRequest(
            instruction="Open a calculator and compute 1 + 1"
        )):
            print(f"[STREAM {ev.taskStream.stage}] {ev.taskStream.message}")

asyncio.run(streaming_example())

异步生命周期(RunAgentInstructionAsync + GetAgentTaskStream + QueryTaskStatus)

import asyncio, grpc
from gui_agents.proto.pb import agent_pb2, agent_pb2_grpc

async def lifecycle_example():
    async with grpc.aio.insecure_channel("localhost:50051") as channel:
        stub = agent_pb2_grpc.AgentStub(channel)
        # 启动异步任务
        start = await stub.RunAgentInstructionAsync(agent_pb2.RunAgentInstructionRequest(
            instruction="Create a new text document and write today's date"
        ))
        task_id = start.taskId
        print("Started task", task_id)
        # 并发流和轮询
        async def stream_events():
            async for ev in stub.GetAgentTaskStream(agent_pb2.GetAgentTaskStreamRequest(taskId=task_id)):
                print(f"[STREAM {ev.taskStream.stage}] {ev.taskStream.message}")
        async def poll_status():
            while True:
                status = await stub.QueryTaskStatus(agent_pb2.QueryTaskStatusRequest(taskId=task_id))
                print("[STATUS]", status.status.name)
                if status.status in (agent_pb2.SUCCESS, agent_pb2.FAILURE, agent_pb2.CANCELLED):
                    print("Final result:", status.result)
                    if status.executionStatistics:
                        print("Steps:", status.executionStatistics.steps,
                              "Duration(s):", status.executionStatistics.durationSeconds,
                              "Tokens:", status.executionStatistics.totalTokens)
                    break
                await asyncio.sleep(4)
        await asyncio.gather(stream_events(), poll_status())

asyncio.run(lifecycle_example())

取消任务

cancel_resp = await stub.CancelTask(agent_pb2.CancelTaskRequest(taskId=task_id))
print("Cancel success?", cancel_resp.success, cancel_resp.message)

配置更新示例

# 仅更新定位模型
await stub.SetGlobalGroundingLLMConfig(agent_pb2.SetGlobalGroundingLLMConfigRequest(
    llmConfig=agent_pb2.LLMConfig(modelName="doubao-1-5-ui-tars-250428")
))
# 更新动作生成器
await stub.SetGlobalCommonLLMConfig(agent_pb2.SetGlobalCommonLLMConfigRequest(
    llmConfig=agent_pb2.LLMConfig(modelName="claude-sonnet-4-20250514")
))
# 设置完整全局配置(模式 FAST,最大 40 步)
await stub.SetGlobalCommonConfig(agent_pb2.SetGlobalCommonConfigRequest(
  commonConfig=agent_pb2.CommonConfig(
    id="global",
    backend="lybic",
    mode=agent_pb2.FAST,
    steps=40,
    authorizationInfo=agent_pb2.Authorization(orgID="org_123", apiKey="sk_live"),
    stageModelConfig=agent_pb2.StageModelConfig(
      groundingModel=agent_pb2.LLMConfig(modelName="doubao-1-5-ui-tars-250428"),
      actionGeneratorModel=agent_pb2.LLMConfig(modelName="claude-sonnet-4-20250514")
    )
  )
))

查询任务状态(仅轮询)

status = await stub.QueryTaskStatus(agent_pb2.QueryTaskStatusRequest(taskId=task_id))
print(status.status.name, status.result)
if status.executionStatistics:
    print("Cost", status.executionStatistics.cost, status.executionStatistics.currencySymbol)

最小One-Shot Helper

async def run_one_shot(instruction: str):
    async with grpc.aio.insecure_channel("localhost:50051") as channel:
        stub = agent_pb2_grpc.AgentStub(channel)
        async for ev in stub.RunAgentInstruction(agent_pb2.RunAgentInstructionRequest(instruction=instruction)):
            if ev.taskStream.stage == "final":
                print("Result:", ev.taskStream.message)

最佳实践

  1. 临时容器配置:运行 Docker 时,避免在镜像中嵌入 API 密钥或模型凭证,确保镜像无敏感信息。
  2. 按请求传递凭证:在 RunAgentInstructionRequest.runningConfig 中传递 authorizationInfo 和分阶段 LLMConfig(如需则包含 apiKey);仅在可信隔离部署中使用全局配置。
  3. 持久化存储:优先使用 PostgreSQL 后端,确保任务元数据与统计信息在服务重启后不丢失,且支持审计。
  4. 水平扩展::多副本部署,避免单点故障。
  5. 不可变默认配置:将全局 CommonConfig 视为基线,通过任务级配置覆盖,防止跨租户信息泄露。
  6. 最小权限原则:为不同环境(开发/测试/生产)分配独立密钥;定期轮换密钥,且绝不在镜像中包含生产环境密钥。
  7. 可观测性:启用 Prometheus 监控,聚合日志,对“失败/取消”状态激增或沙箱创建错误设置告警。
  8. 优雅取消:在客户端实现超时机制,尽早调用 CancelTask 释放沙箱资源。
  9. 版本锁定:使用镜像摘要(Digest)指定版本,生产环境避免使用 latest 标签,确保可复现性。
  10. 沙箱策略:仅对延迟敏感的任务使用预创建沙箱;其他场景允许自动创建沙箱,以获得更好的隔离性。

扩展模式

    1. 水平扩展:在服务后部署多个副本,每个副本管理独立的沙箱实例。
    1. 分片:按项目/组织路由任务至专用部署实例。
    1. 持久化:启用 PostgreSQL 后端,实现 Pod 重启后任务状态恢复。
    1. 可观测性:抓取指标数据,添加日志聚合(标准输出结构化日志)。

安全和密钥管理

  • 将 API 密钥存储在密钥管理器中(K8s Secrets、HashiCorp Vault、AWS/GCP 密钥服务)。
  • 使用本地后端限制网络出口。
  • 每个环境(dev/staging/prod)使用单独的服务账户。

健康检查和就绪探针

  • 对 50051 端口执行 gRPC TCP 探针(就绪探针与存活探针)。
  • 未来将支持自定义健康检查 RPC,用于更深度的诊断。
  • 对沙箱创建错误率激增设置警报。

常见部署问题

问题原因修复
沙箱无法绑定缺少 LYBIC_API_KEY / ORG 或配额不足检查环境变量配置,确认账户剩余配额
冷启动时间长按需创建沙箱(首次创建需耗时)使用预创建沙箱(配置 LYBIC_PRECREATE_SID)或预热沙箱池
任务历史丢失使用内存(memory)作为存储后端切换到 postgres 后端
指标为空未设置 ENABLE_PROMETHEUS设置环境变量 + 打开端口 8000

版本升级

拉取新镜像并滚动重启:

kubectl set image deployment/lybic-agent-grpc agent=agenticlybic/guiagent:latest

使用固定版本以获得可复现性,在生产环境中避免 latest

下一步

  • 与 MCP 服务器集成,实现基于 LLM 的指令流驱动。
  • 后续版本将添加分布式追踪(OpenTelemetry)。
  • 构建高层级编排器,协调多个智能体副本工作。

本页内容