- AI Agent
- Agent 框架
- AI 应用
【免费下载链接】marvin
an ambient intelligence library
本篇技术指南以仓库内 examples/slackbot/README.md 为主体骨架,结合
examples/slackbot/目录下的完整源码(api.py、core.py、settings.py、slack.py 等)深度展开。读者将掌握:如何从零搭建一个具备长期记忆、用户画像、Prefect 知识检索、GitHub 问题搜索与社区线程检索能力的 AI Slack 机器人,理解其「FastAPI + Prefect Flow + pydantic-ai Agent + 向量存储」的整体架构,并能独立完成本地开发、配置、测试与生产部署。
项目定位:一个"有记忆、懂 Prefect"的 AI Slack 机器人
slackbot是 Marvin 仓库中一个完整可运行的生产级示例应用,定位是为 Prefect 社区 Slack 提供 AI 驱动的支持服务。它由 AI 模型(GPT-5 或 Claude 系列)驱动,具备两类核心能力:
- 记忆能力:跨会话持久化用户画像(user facts),通过向量存储(TurboPuffer)实现用户上下文检索;
- 领域知识能力:内置 Prefect 特定的知识检索工具,可搜索 Prefect 官方文档、GitHub issues、最新 release notes,并可通过外部 MCP 服务器检索社区 Slack 历史线程。
从源码结构看(examples/slackbot/pyproject.toml),它依赖marvin(工作区内置)、prefect>=3.6.12(Flow/Task 编排)、pydantic-ai(Agent 运行时)、raggy[tpuf](TurboPuffer 向量存储)、claude-agent-sdk(Claude 研究子代理)与logfire[fastapi](可观测性)。
项目结构:四个模块撑起一条完整事件处理链路
README 给出了顶层结构,结合源码可细化为:
examples/slackbot/ ├── src/slackbot/ │ ├── api.py # FastAPI 应用与 Slack 事件处理器(/chat 端点) │ ├── core.py # 数据库、Agent 与记忆管理(create_agent、build_user_context) │ ├── settings.py # 配置管理(环境变量 + Prefect Secrets/Variables) │ ├── __main__.py # 入口点(uvicorn 启动) │ ├── slack.py # Slack API 集成:发消息、取线程、进度消息、图片下载 │ ├── search.py # Prefect 知识检索(文档、CLI、release notes) │ ├── assets.py # 用户事实(user facts)的存储/读取/修正/删除 │ ├── research_agent.py # Claude Agent SDK 研究子代理 │ ├── strings.py # token 估算与截断工具 │ ├── wrap.py # Prefect 与 pydantic-ai 工具调用监控桥接 │ └── _internal/ # 内部实现:模板、线程状态、消息存储、个性化、可观测性等 ├── Dockerfile.slackbot # 生产容器镜像 ├── pyproject.toml # 依赖与打包配置 └── README.md事件处理链路(源自 api.py):
- Slack 将事件 POST 到 FastAPI 的
/chat端点; - 端点解析
SlackPayload,对url_verification返回challenge,对event_callback分发处理:team_join发送欢迎消息,其余走handle_messagePrefect Flow; handle_message(api.py)执行消息去重、频道限制检查、用户上下文构建、并发加载个人摘要与 Slack 线程上下文,最后调用run_agent执行 Agent 推理并回帖。
本地开发环境搭建
README 说明 slackbot 可以极简配置在本地运行。依赖安装(在仓库根目录执行):
uv sync --extra slackbot该命令通过pyproject.toml中的[tool.hatch.build.targets.wheel]打包src/slackbot,并拉取 pyproject.toml 中声明的全部依赖(含marvin、prefect>=3.6.12、raggy[tpuf]等)。
启动机器人(另一终端):
uv run --extra slackbot -m slackbot__main__.py(examples/slackbot/src/slackbot/main.py)在启动时从 Prefect Secret 加载 OpenAI/Anthropic API Key(缺少环境变量时),然后以uvicorn.run("slackbot.api:app", ...)启动 FastAPI 服务,test_mode开启时启用--reload热重载(reload 目录指向examples/slackbot)。
配置体系:环境变量 + Prefect Secrets/Variables 双通道
配置管理集中在 settings.py,核心类SlackbotSettings(BaseSettings)使用env_prefix="MARVIN_SLACKBOT_",支持.env文件。
必需配置(Prefect Secrets)
README 列出 5 个必需 Secret,建议在 Prefect Cloud 或本地 Prefect 服务器中通过 UI/CLI 配置:
| Secret 名称 | 用途 |
|---|---|
test-slack-api-token | Slack Bot User OAuth Token(Bot Token,形如xoxb-...) |
openai-api-key | OpenAI 模型密钥(使用 GPT 系列模型时) |
anthropic-api-key | Claude 系列模型密钥 |
marvin-slackbot-github-token | GitHub API Token,用于搜索 GitHub issues |
tpuf-api-key | TurboPuffer 向量存储 API Key |
源码印证:SlackbotSettings为每个 Secret 定义了默认名称字段(如github_token_secret_name、openai_api_key_secret_name、anthropic_key_secret_name);_apply_post_validation_defaults(settings.py)会在启动时若环境变量TURBOPUFFER_API_KEY缺失,则自动尝试Secret.load("tpuf-api-key")注入。
必需配置(Prefect Variables)
模型分层通过 Prefect Variables 配置,三个层级各司其职(README 注释 + settings.py 三处 property 共同印证):
| Variable 名称 | 用途 | 默认值 | 回退 Variable |
|---|---|---|---|
marvin_bot_model | 主回答 Agent(产品面向的"人声") | anthropic:claude-sonnet-5 | marvin_ai_model |
marvin_utility_model | 结构化非语音工作:记忆综合、线程总结(便宜档) | anthropic:claude-haiku-4-5 | marvin_memory_synthesis_model |
marvin_research_model | Claude Agent SDK 研究子代理 | anthropic:claude-haiku-4-5 | 无 |
marvin_system_prompt | 基础系统提示词覆盖 | DEFAULT_SYSTEM_PROMPT(定义于 _internal/templates.py) | 无 |
admin-slack-id | 管理员 Slack 用户 ID,用于创建讨论/错误时通知 | 空(可选) | 无 |
关键机制:Provider 归一化。所有模型值支持完整的 pydantic-aiprovider:model字符串;若为裸名称,_ensure_provider(settings.py)自动按前缀映射:claude-*→anthropic:...,gpt-*→openai-responses:...(后者因为 OpenAI reasoning 模型在/v1/chat/completions上拒绝 function tools + reasoning 组合,必须走 Responses API)。
热更新系统提示词:marvin_system_prompt逐消息读取(_base_system_prompt见 core.py),修改后无需重新部署即可生效。
可选环境变量(MARVIN_SLACKBOT_ 前缀)
MARVIN_SLACKBOT_TEST_MODE=true # 启用热重载(开发模式) MARVIN_SLACKBOT_HOST=0.0.0.0 # 服务监听地址(默认 0.0.0.0) MARVIN_SLACKBOT_PORT=4200 # 服务端口(默认 4200) MARVIN_SLACKBOT_LOG_LEVEL=INFO # 日志级别(自动转大写) MARVIN_SLACKBOT_SLACK_API_TOKEN=xoxb-... # Slack Bot Token(或用 test-slack-api-token Secret) MARVIN_SLACKBOT_MAX_TOOL_CALLS_PER_TURN=50 # 单轮最大工具调用数(默认 50) MARVIN_SLACKBOT_USER_MESSAGE_MAX_TOKENS=500 # 用户消息最大 token 数(默认 500) TURBOPUFFER_API_KEY=abcd1234 # 向量存储密钥(未设置时回退到 tpuf-api-key Secret)补充源码中未写入 README 但同样生效的字段:settings.py 还支持MARVIN_SLACKBOT_DB_FILE(SQLite 路径,默认marvin_chat.sqlite,仅用于线程去重状态)、MARVIN_SLACKBOT_LOG_FORMAT(彩色日志格式)、MARVIN_SLACKBOT_VECTOR_STORE_TYPE(向量存储类型,当前限定turbopuffer)、MARVIN_SLACKBOT_USER_FACTS_NAMESPACE_PREFIX(用户事实命名空间前缀,默认user-facts-)、MARVIN_SLACKBOT_LOGFIRE_*(Logfire 可观测性配置)。
Slack App 配置:五步接入 Slack 事件
按 README 步骤创建应用:
- 在 https://api.slack.com/apps 创建新 Slack App;
- 添加 Bot User,授予所需 OAuth Scopes:
app_mentions:read—— 接收 @提及事件channels:read/groups:read—— 读取频道与私人群组信息chat:write—— 发送消息im:read/mpim:read—— 读取私聊与多人私聊- (源码补充)若要支持用户共享图片,还需要
files:readScope——slack.py 的fetch_shared_images依赖它下载私有文件 URL;缺少该 Scope 时 Slack 会返回 HTML 登录页而非错误状态,代码通过校验content-type是否以image/开头来兜底跳过;
- 配置事件订阅:
- Request URL:
https://{YOUR_DOMAIN}/chat - Bot Events:
app_mention(被提及)、team_join(新成员加入)
- Request URL:
- 安装应用到工作区,将 Bot Token 填入
MARVIN_SLACKBOT_SLACK_API_TOKEN或test-slack-api-tokenSecret; - 将机器人邀请到目标频道。
源码中对事件类型的处理(api.py):team_join会向新成员私发WELCOME_MESSAGE(模板见 _internal/templates.py);message_changed编辑事件会被识别(_extract_message_context,api.py);针对私聊(channel 名以D开头)的直发消息会被拒绝并通知管理员。
本地运行:ngrok 隧道 + uvicorn 双进程
Slack 事件订阅要求公网可达的 HTTPS 端点,本地开发用 ngrok 暴露端口:
# 终端 1:暴露本地服务端口(与 MARVIN_SLACKBOT_PORT 保持一致) ngrok http 4200 # 终端 2:启动机器人 uv run --extra slackbot -m slackbot将 ngrok 生成的 HTTPS 地址填入 Slack App 的 Request URL(追加/chat路径)。机器人启动日志会打印当前使用的模型(__main__.py中的logger.debug(f"Starting Slackbot with model: {settings.bot_model}"))。
测试机器人:一条 @提及触发完整推理链路
在机器人已加入的任意频道发起:
@Marvin What's new in Prefect?机器人随后的行为(README 概述,源码印证):
- 搜索 Prefect 文档:
research_prefect_topic工具(Claude Agent SDK 研究子代理,research_agent.py); - 查看 GitHub issues:
read_github_issues工具(search.py); - 验证 CLI 命令与函数签名:
check_cli_command、display_callable_signature、explore_module_offerings工具,避免凭记忆给出错误 API; - 检索最新 release notes:
get_latest_prefect_release_notes; - 搜索社区 Slack 历史线程:通过
MCPServerStreamableHTTP连接外部 MCP 服务器(core.py),并用TolerantToolset包裹——远程工具集可能缺失,缺了照常回答而不是叙述失败; - 回忆先前交互:
build_user_context(core.py)加载用户的持久化画像与相关记忆,以UserContext作为 Agent 依赖注入; - 提供上下文感知的回复:回答经
post_slack_message发送回线程,Markdown 链接与加粗自动转换为 Slack mrkdwn(convert_md_links_to_slack,slack.py)。
进度消息与工具追踪
用户视角下,机器人会先展示🔄 _thinking..._占位符(PROGRESS_PLACEHOLDER),随后由_personality_blurb用便宜档模型(utility_model)把标题改写成 Marvin 风格的吐槽(模板见 _internal/templates.py,超时 10 秒、失败则保留静态文案)。工具调用过程中,进度消息会实时渲染工具使用统计——这一机制由 wrap.py 的WatchToolCalls上下文管理器实现:通过 monkey-patch pydantic-ai 的AbstractToolset.call_tool,将每次工具调用包装为 Prefect task 并计数,超过max_tool_calls_per_turn(默认 50)即强制终止,防止 Agent 失控循环。回答完成后进度消息更新为✅ thought for X.X seconds。
消息长度与去重保护
- 长度限制:
count_tokens估算用户消息 token 数(strings.py),超过user_message_max_tokens(默认 500)时返回截断后的消息提示超限; - 重复事件去重:Slack 可能重复投递事件,
handle_message通过try_acquire_thread(SQLite 表slack_thread_status,跨进程协调)按message_ts加锁;若正在处理中收到编辑事件,机器人会回帖提醒"已在处理你的第一版消息"(api.py)。
记忆系统:用户事实 + 个人摘要双层持久化
这是该示例区别于普通 Chatbot 的关键特性:
- 用户事实(User Facts):Agent 内置四个工具——
store_facts_about_user、read_fact_about_user、correct_fact_about_user、delete_facts_about_user(core.py)。模型自行判断何时将"下周仍然成立"的环境、目标、偏好写入向量存储(命名空间user-facts-{user_id});写入时按语义去重并打时间戳,读取时校验归属(只能读本人事实),修正时保留被取代的旧版本作为溯源证据,删除按主题语义近似匹配并如实汇报删除内容; - 个人摘要(Person Summary):
load_person_summary/update_person_summary(_internal/person_summary.py)在对话结束后用便宜档模型合成用户画像摘要,供下次对话注入; - 记忆容错:记忆存储不可用时只降级为"更薄的 prompt",绝不导致回复失败(core.py);
- 线程消息历史:保存在 Prefect 的
WritableFileSystemblock 中(_internal/message_store.py),SQLite 仅用于去重状态;summarize_thread每 4 条消息自动总结一次线程(handle_message.on_completion钩子,api.py)。
频道限制:工作区到指定频道的映射
机器人可按工作区限制只响应指定频道,其他频道提及会收到重定向提示。README 示例的映射表位于_internal/constants.py:
WORKSPACE_TO_CHANNEL_ID = { "TL09B008Y": "C04DZJC94DC", # Prefect Community -> #ask-marvin "TAN3D79AL": "C046WGGKF4P", # Prefect -> #ask-marvin-tests # 按需追加更多工作区映射 }需要注意:当前仓库中的 constants.py 实际为WORKSPACE_TO_CHANNEL_ID: dict[str, str] = {}(空映射),README 中的示例是生产环境的配置形态。结合 api.py 的逻辑:若某工作区未配置映射,check_if_designated_channel返回True,即默认允许所有频道;仅当映射存在时才校验频道一致性,不匹配时发送CHANNEL_REDIRECT_MESSAGE("Please post this question in <#channel_id> for assistance.",见 _internal/templates.py)并记录REDIRECTED状态。
开发特性速览
- 热重载:
MARVIN_SLACKBOT_TEST_MODE=true时 uvicorn 自动监听文件变化重启; - 彩色日志:默认
log_format带 ANSI 颜色(时间、模块名、级别),日志级别校验自动转大写; - SQLite 消息历史:
marvin_chat.sqlite记录线程去重状态; - TurboPuffer 向量存储:用户上下文与用户事实的持久化载体;
- 灵活配置:环境变量 /
.env文件 / Prefect Secrets / Prefect Variables 四种途径。
生产部署:Dockerfile 与容器化要点
生产环境可部署到 Cloud Run 等容器平台,参考 Dockerfile.slackbot。要点(源自 Dockerfile):
- 基于
python:3.13-slim,内置uv与bun; - 构建时执行
uv sync --extra slackbot --no-dev安装依赖; - 预生成 tiktoken 缓存(
TIKTOKEN_CACHE_DIR=/app/.cache/tiktoken),避免首个 Slack 请求时现场下载 tokenizer; - 安装
@anthropic-ai/claude-code(研究子代理依赖); - 暴露端口
4200,启动命令uv run --no-sync -m slackbot。
README 提到的 CI/CD 配置位于/.github/workflows/image-build-and-push-community.yaml(当前仓库目录列表未包含.github目录,可确认该工作流属于上游生产仓库的组织配置)。
测试覆盖
仓库测试目录 tests/ 提供可参考的验证路径(均与 slackbot 子模块直接相关):
- test_slack_format.py:验证 Markdown → Slack mrkdwn 转换;
- test_progress_blurb.py:进度消息改写逻辑;
- test_settings.py 与 test_agent_settings.py:配置解析与模型分层;
- test_prompt_sync.py:系统提示词热更新同步;
- test_memory_recall.py:记忆召回;
- test_person_context.py:个人上下文注入;
- test_thread_summary.py:线程总结;
- test_mcp_startup.py:MCP 工具集启动容错;
- test_fact_corrections.py:用户事实修正;
- test_provider_retries.py:模型提供商重试。
小结
slackbot是一个架构完整、可直接上线的 Marvin 应用范本:FastAPI 负责 Webhook 接入,Prefect Flow/Task 提供可靠编排与可观测性,pydantic-ai Agent + 分层模型(回答/工具/研究)承担推理,TurboPuffer 向量存储承载跨会话记忆,MCP 工具集扩展社区知识检索。它演示了 Marvin 生态中"AI 应用"的完整落地形态——从本地uv sync --extra slackbot到 Cloud Run 容器部署,从 Slack App 配置到生产级频道治理,均可在本仓库中直接复现与二次开发。
- AI Agent
- Agent 框架
- AI 应用
【免费下载链接】marvin
an ambient intelligence library
相关推荐
基于Gradio构建Slack聊天机器人的完整指南
基于Gradio构建Slack聊天机器人的完整指南 前言 在现代工作场景中,Slack已经成为团队协作的重要工具。本文将详细介绍如何利用Gradio框架快速构建
前端后端AI 应用botbuilder-adapter-slack 完全指南:基于 Botkit / BotBuilder 构建 Slack 机器人
botbuilder adapter slack 完全指南:基于 Botkit / BotBuilder 构建 Slack 机器人 botbuilder ada
后端即时通讯基于开源框架构建智能机器人系统的完整指南:从概念解析到实战部署
在当今技术快速发展的时代, 开源机器人 框架正在彻底改变我们构建和部署 智能控制 系统的方式。无论是工业自动化、服务机器人还是教育应用, 开源生态 为我们提供了
人工智能机器学习深度学习机器人具身智能强化学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考