LingCode 为自身聊天面板所做的一切——agent 循环、工具调度、流式输出——都可以作为本地 HTTP API 使用。运行 lingcode serve,你就拥有了一个可以在上面构建自己的 UI 和机器人的后端服务。
当你使用 agent 一段时间后,你会开始发现那些希望 agent 能够触及的地方:一个能回答代码库问题的 Slack 机器人、一个接受提示并将回答输送到剪贴板的 Raycast 扩展、一个让朋友针对特定任务访问 agent 的小网页,或者一个让 agent 审阅 PR 的 CI 步骤。agent 很强大,它理应出现在你需要的每一个地方。
上述大多数项目并不需要一个全新的 agent 循环。它们需要的是一种调用已有 agent 循环的方式——带鉴权、支持流式传输、像其他服务一样通过网络通信。这正是 lingcode serve 的用途。Swift CLI 将 Mac 应用和 REPL 所使用的三个独立循环——Claude(Anthropic SDK)、DeepSeek 原生、OpenAI 兼容——以 Server-Sent Events API 的形式暴露出来,通过 bearer token 鉴权,监听本地回环地址。
选择在本地运行而非作为托管服务的意义在于凭据边界:你的 API 密钥留在 Keychain 里,文件访问权限留在你的机器上。lingcode serve 不会改变这些,它只是让你的其他工具能够通过 HTTP 调用 agent,而无需再生成子进程。本教程涵盖:启动服务器、用 curl 与之通信,以及将本地后端打磨成真正可用产品时需要考虑的关键问题。
POST /v1/agent/ask 的请求格式及其 SSE 流结构假设已安装 CLI,运行以下命令启动:
lingcode serve
服务器启动后会打印监听地址(本地端口),并读取 ~/.lingcode/server.token——若该文件不存在则自动生成。token 文件权限为 chmod 600,请像对待 SSH 密钥一样保管它。可使用 --port <N> 覆盖端口,使用 --token-file <path> 指定其他路径的 token 文件。
服务器基于 NWListener——Apple 的原生网络栈,而非第三方 HTTP 框架。默认绑定到 127.0.0.1,在没有显式标志的情况下,它会拒绝绑定到任何其他网络接口,这是有意为之的设计。
主要端点为 POST /v1/agent/ask。最简请求示例:
TOKEN=$(cat ~/.lingcode/server.token)
curl -N -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"prompt":"What does package.json declare?","provider":"claude"}' \
http://127.0.0.1:<port>/v1/agent/ask
响应是一个 Server-Sent Events 流。每一行 data: 对应一个事件——文本增量、工具调用、工具结果、最终助手消息。你的客户端读取流后,可以按照自己的方式渲染这些事件。其格式与 Mac 应用聊天面板内部渲染的格式一致。
-N 标志告诉 curl 不要缓冲——你希望在流到达时即时接收,而不是等到全部完成后再处理。
流会发出少量几种事件类型:
对于最简 UI,你可以忽略除 text_delta 和 message_stop 之外的所有事件。若要打造更丰富的界面,可内联渲染工具调用。完整格式请参阅服务器在 /openapi.json 暴露的 OpenAPI 规范。
默认绑定到 127.0.0.1 是有意为之的。~/.lingcode/server.token 中的 bearer token 足以约束本地进程——你的工具与你的服务器通信,机器上的其他用户无法访问。但它并非为抵御公网威胁而设计:服务器不做速率限制、不在鉴权失败后锁定、也不拒绝异常格式的请求。
如果你需要将 agent 暴露到网络上,请通过真正的反向代理来做,配备 TLS、IP 白名单和速率限制。或者,更实用的做法是:让每位用户在自己的机器上运行 lingcode serve,然后让共享工具在每位开发者的机器上对 localhost 发起调用。这样可以保持 API 密钥的按用户隔离,将攻击面降到最低。
~/.lingcode/server.token 并重启 lingcode serve 即可重新生成一个新 token。
当你的客户端向 /v1/agent/ask 发送带有 provider:"claude" 的请求时,服务器不会从请求中读取 API 密钥——它会从你的 macOS Keychain 中提取。客户端只需说"使用 Claude",服务器负责完成凭据处理。
这意味着:bearer token 用于鉴权请求,而 API 密钥归属于运行 lingcode serve 的账户。如果你和队友都想用自己的密钥访问服务器,就各自运行自己的服务器实例。这里没有密钥委托机制——你无法把 token 交给队友并让它使用他们的 Claude 密钥。
按用户。每位开发者在自己的机器上运行 lingcode serve。共享工具(Slack 机器人、编辑器扩展)按开发者配置,指向各自的 localhost。每位开发者的 token 归其本人所有,用量归因准确。适合个人生产力工具。
共享。在团队服务器上运行一个 lingcode serve,通过真正的反向代理提供 TLS 和正式鉴权。密钥归属于服务账户,所有用量汇总到该账户。适合团队共享机器人和 CI 集成,费用与速率限制集中管理。
根据使用场景选择合适的模式。同一个服务器二进制文件支持两种模式——区别在于部署方式,而非代码本身。
lingcode serve,不妨编写一个在登录时自动启动的 launchd plist。lingcode serve --background 在完成守护进程分离后退出;配合 launchd 的 keepalive 选项可实现高可用。