系列导航:系列目录 | 上一篇:从零实现 Harness Agent:可恢复 Plan Mode 设计 | 下一篇:从零实现 Harness Agent:上下文压缩器设计

本节目标

导读:本篇进入第四部分「外部集成与审批恢复」,先说明 Feishu 只是入口适配层,不能变成第二套 Agent runtime。

本节要实现的是统一 HTTP 事件服务中的 Feishu 回调入口:让 Feishu 消息可以进入同一套 Application.run()MainLoop,而不是为外部平台复制一套 Agent runtime。

完成这一节后,系统会具备下面这些能力:

  • tiny-claw serve 可以启动 HTTP 服务。
  • 服务提供 GET /healthPOST /api/events/feishu
  • Feishu 文本消息会按 chat_id 解析成独立 session。
  • Feishu 运行过程通过 FeishuChannel 发送开始、处理中、工具调用和最终回复。
  • 外部平台默认使用 integration app,并在 OpenAI 配置缺失时给出明确提示。

这一节的关键目标是让 Feishu 成为“入口适配层”,而不是第二套 Agent 实现。

摘要

外部平台接入最容易犯的错,是把平台 adapter 写成另一套 Agent。tiny-claw serve 提供统一 HTTP 事件服务,当前支持健康检查和 Feishu 事件回调。本文介绍 Feishu webhook 如何被转换成 session-scoped Agent 请求,并通过 Channel 把运行进度和最终回复发送回外部平台。

背景与问题

一个 Agent CLI 一旦能在终端运行,下一步常见需求就是接入外部平台,例如 Feishu、Slack 或 Web UI。最容易走偏的实现是为每个平台写一套独立 Agent 逻辑。

这样会带来几个问题:

  • CLI 和 Feishu 行为不一致。
  • 外部平台绕过 session、memory、tools 和 provider 配置。
  • 平台消息发送逻辑和 Agent 主循环耦合。
  • 缺少 provider 配置时,服务启动和事件处理边界不清。

tiny-claw 的设计是:外部平台只做 adapter 和 channel,真正的运行仍然复用 Application.run()

设计目标

  • 统一入口:HTTP server 提供外部事件接入点。
  • 复用运行时:Feishu 不实现自己的 Agent loop。
  • 会话隔离:Feishu 按 chat_id 映射 session。
  • 进度可见:通过 Channel 输出开始、思考、工具调用、完成等事件。
  • 配置兜底:缺 OpenAI key 时 server 可启动,消息进来时回复明确错误。
  • 可扩展:未来 Slack 等平台复用 integration app 思路。

整体方案

HTTP 服务由 server.py 创建,Feishu 相关逻辑由 FeishuEventAdapterFeishuChannel 处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sequenceDiagram
participant Feishu
participant Server as HTTP server
participant Adapter as FeishuEventAdapter
participant App as Application
participant Loop as MainLoop
participant Channel as FeishuChannel

Feishu->>Server: POST /api/events/feishu
Server->>Adapter: handle_webhook_request()
Adapter->>Adapter: extract text + chat_id
Adapter->>App: resolve_feishu_chat(chat_id)
Adapter->>App: run(prompt, session, channel)
App->>Loop: MainLoop.run()
Loop->>Channel: on_start / on_tool_call / on_done
Channel->>Feishu: send_text()

核心实现

关键文件:

  • src/tiny_claw/_internal/server.py
  • src/tiny_claw/_internal/integrations/feishu/events.py
  • src/tiny_claw/_internal/integrations/feishu/bot.py
  • src/tiny_claw/_internal/engine/channel.py
  • tests/test_feishu_integration.py

HTTP 路由:

1
2
web_app.router.add_get("/health", _health)
web_app.router.add_post(config.feishu_event_path, _feishu_events)

Feishu 配置存在时创建 adapter:

1
2
3
if _is_feishu_configured(app.settings):
integration_app = _build_optional_integration_app(app.settings)
feishu_adapter = FeishuEventAdapter.from_settings(...)

外部平台运行时默认使用 OpenAI:

1
2
3
def build_integration_application(settings: Settings) -> Application:
provider = OpenAIProvider(...)
return build_application(settings, provider=provider)

Feishu 消息进入后按 chat id 解析 session:

1
session = self.app.session_manager.resolve_feishu_chat(message.chat_id)

然后复用 Application.run()

1
2
3
4
5
6
7
self.app.run(
prompt=text,
max_steps=self.max_steps,
mode=self.mode,
session=session,
channel=channel,
)

如果 integration app 未配置,adapter 不进入 MainLoop,而是直接回复配置错误。

使用方式

启动 HTTP 服务:

1
uv run tiny-claw serve --host 0.0.0.0 --port 8000

健康检查:

1
curl http://127.0.0.1:8000/health

默认接口:

1
2
GET  /health
POST /api/events/feishu

Feishu 配置示例:

1
2
3
4
5
6
FEISHU_APP_ID=cli_xxx \
FEISHU_APP_SECRET=xxx \
FEISHU_VERIFICATION_TOKEN=xxx \
FEISHU_ENCRYPT_KEY=xxx \
OPENAI_API_KEY=<your-openai-api-key> \
uv run tiny-claw serve --host 0.0.0.0 --port 8000

如果 Feishu 后台没有配置 Encrypt Key 或 Verification Token,可以省略对应环境变量。

自定义回调路径:

1
uv run tiny-claw serve --feishu-path /api/events/feishu-test

本地调试时,Feishu 需要公网 HTTPS URL,可用隧道工具把本地端口暴露出去。

测试与验证

Feishu 集成测试:

1
uv run pytest tests/test_feishu_integration.py

CLI server help:

1
uv run tiny-claw serve --help

HTTP smoke test:

1
2
uv run tiny-claw serve --host 127.0.0.1 --port 8000
curl http://127.0.0.1:8000/health

完整验证:

1
2
3
4
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest

设计取舍与注意事项

Feishu adapter 不拼 prompt、不执行工具、不直接调用 provider。它只做平台协议转换:提取文本、解析 chat session、创建 channel,然后把请求交给 Application.run()。这样 CLI 和 Feishu 才能共享同一套 Agent runtime。

Feishu 使用 chat_id 隔离上下文,而不是 message_id。一条消息只是对话中的一个事件,chat 才是长期上下文边界。缺 OpenAI key 时,server 仍可启动,这是为了让 HTTP 服务和平台配置可以先验证;真正的运行时错误会在消息进入时回复给用户。

Channel 只发送简短进度,不把完整内部日志刷到聊天窗口。外部平台是用户交互面,不是调试控制台。当前只实现 Feishu,Slack 等平台属于后续扩展,不能把 integration app 的预留能力写成已完成平台。

总结

  • 外部平台入口应该复用 ApplicationMainLoop,而不是复制 Agent 逻辑。
  • Feishu adapter 负责协议转换,FeishuChannel 负责消息发送。
  • Integration app 让外部平台默认使用真实 Provider。
  • HTTP 服务提供了未来接入更多事件平台的统一位置。

按编号继续阅读:11:上下文压缩器 会回到上下文工程;按外部集成专题继续,可以跳到 19:审批 checkpoint 暂停恢复


来源:本文整理自 tiny-claw/docs/tutorial/10-飞书事件服务.md
项目地址:barry166/tiny-claw