分布式AI工具平台

FlowCentral是一个基于MCP协议的分布式AI工具平台,支持动态加载Python函数和第三方MCP工具,用于构建协作式AI代理网络。

  • by FlowCentralAI
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 FlowCentralAI/flowcentral-mcp-server

使用说明

FlowCentral MCP服务器

在以下网址创建帐户 flowcentral.ai 机器人会引导你完成设置。

基本上,我们有一个分布式linux风格的系统,为机器人提供工具基础设施。工具排列在文件夹中,便于跨职能和团队进行管理。团队可以直接调用彼此的功能,当然机器人也可以自己做事情。下面是一个符合MCP标准的系统,但我们支持热加载等,而不需要不断更新MCP工具的一些繁琐开销。

首先,克隆repo,执行Python env操作,将API键设置为环境变量(OPENROUTER_API_KEY、ANTHROPIC_API_KEY等),并将本地Python服务器连接到主服务器(请参见runServer)。我们给你所有的源代码来构建你自己的工具调用聊天机器人,就像克劳德一样。看 Games/FlowCentral/Bots/Atlas/ 对于bot角色配置和 Home/chat.py 对于共享聊天循环,机器人通过搜索/dir动态发现工具,而不是预先加载它们。

*请注意 game_set("FlowCentral") 将服务器锁定到游戏,然后 character_bot() 为机器人分配角色, move_bot()/move_human() 处理位置之间的移动,以及 bot_spawn() 进行完整的一次性设置(角色+位置)

FlowCentral网络

每个MCP服务器都是人工智能代理和开发人员协作网络的一部分。使用模型上下文协议,该平台创建了一个生态系统,在这个生态系统中,代理可以在网络中发现和使用彼此的能力。工具和功能可以在代理之间共享、发现和协调,无论是用于企业自动化、工作流编排还是任何其他应用程序。网络架构使代理能够找到并利用其他用户的工具,从而创建一个共享功能的去中心化生态系统。

该项目的核心是一个Python MCP主机(称为“远程”),它允许您动态安装函数和第三方MCP工具

快速开始

  1. 先决条件-需要为服务器安装Python,为Lobster(MCP客户端)安装Node;您还应该安装uv/uvx和node/npx,因为MCP似乎需要两者

  2. 由于异步支持,Python 3.13现在似乎是最稳定的

  3. 设置Python虚拟环境并安装依赖项:

cd python-server
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
  1. 设置API密钥。在中创建脚本 python-server/ 导出您的密钥(这些密钥是gitignored的,因此您的密钥不会被提交)。例如,创建 set_OPENROUTER.bat:
#!/bin/bash
# Usage: source set_OPENROUTER.bat

export OPENROUTER_API_KEY="sk-or-v1-your-key-here"

echo "OPENROUTER_API_KEY has been set"

为您需要的每个提供商创建一个(set_ANTHROPIC.bat, set_GOOGLE.bat等等)遵循相同的模式。激活venv后获取它们:

source venv/bin/activate
source set_OPENROUTER.bat
source set_ANTHROPIC.bat      # if using Anthropic models
source set_GOOGLE.bat         # if using Google APIs

您只需要计划使用的提供商的密钥。至少, OPENROUTER_API_KEY 默认bot(Atlas)需要。

  1. 在中编辑runServer脚本 python-server 文件夹并设置电子邮件和服务名称(实际上,最佳做法是创建一个副本“runServerFoo”,您可以在我们进行更新时用它替换runServer文件):
python server.py  \
  --email=youremail@gmail.com  \             # email you use for flowcentral
  --api-key=foobar \                         # should change online
  --host=localhost \                         # npx MCP will be looking here to connect to remote (assumes there is at least one running locally)
  --port=8000  \
  --cloud-host=wss://flowcentral.ai  \   # points to cloud
  --cloud-port=443  \
  --service-name=home                        # remote name, can be anything but must be unique across all machines
  1. MCP客户端现在被调用 龙虾。要将其用作常规的独立MCP服务器,请将以下配置添加到Windsurf或Cursor或其他任何服务器中:
   "mcpServers": {
      "atlantis": {
         "command": "npx",
         "args": [
            "atlantis-mcp",
            "--port",
            "8000"
            ]
      }
   }

要将亚特兰蒂斯添加到克劳德代码:

claude mcp add atlantis -- npx atlantis-mcp --port 8000

要连接到Codex:

codex mcp add atlantis -- npx atlantis-mcp --port 8000

要添加亚特兰蒂斯开放天气进行测试:

claude mcp add --transport stdio weather_forecast --env OPENWEATHER_API_KEY=mykey123 -- uvx --from atlantis-open-weather-mcp start-weather-server

  1. 要连接到FlowCentral,请登录https://www.flowcentral.ai在同一封电子邮件下

  2. 您的远程设备应使用电子邮件和默认api key='foobar'自动连接(请参阅稍后生成新密钥的'api'命令)。除非您稍后手动更改,否则将为要连接的第一台服务器分配“默认”服务器

  3. 最初,除了一些示例外,函数和服务器文件夹将为空

  4. 您可以运行这个独立的MCP,也可以从云端访问,或者两者兼而有之

建筑

警告:MCP术语已经很糟糕了,称之为“服务器”或“主机”只会让人更加困惑,因为MCP本质上就是p2p

系统部件:

  • 云:FlowCentral云服务器;一个分享工具并让用户使用它们的地方
  • 远程:此仓库中的Python服务器进程,正式称为MCP“主机”(您可以在同一台机器或不同的机器上运行>1,只需指定不同的服务名称)
  • 动态函数:你编写的一个简单的Python函数,充当一个工具
  • 动态MCP服务器:任何第三方MCP,存储为JSON配置文件

请注意,MCP身份验证和安全性仍在研究中,因此现在使用云进行身份验证更容易

目录

  1. Python远程(MCP P2P服务器) (python-server/)

    • 我们的“远程”位置。在本地运行,但可以远程控制
  2. 龙虾(MCP客户端) (client/)

    • 允许Claude Code或Codex运行Atlantis命令或通过MCP聊天
    • 使用npx(易于安装到Claude Code或Codex中)
    • 不需要云连接-尽管它可能会抱怨
    • 仅支持规范的一个子集
    • 只能看到本地框上的工具(至少现在)或共享的工具 工具设置为“公共”

Python服务器布局

如果你想了解Python源代码,请从 python-server/server.py 然后从那里分支出来:

  • server.py -主要入口点和协议主机。它启动Starlette应用程序,拥有 DynamicAdditionServer 类,管理WebSocket和云Socket。IO连接和将功能/服务器管理器连接在一起。如果您正在跟踪工具调用,则整合的MCP tools/call 处理者住在这里 DynamicAdditionServer._handle_tools_call(),然后委托给 _execute_tool().
  • DynamicFunctionManager.py -拥有动态Python工具系统 dynamic_functions/这就是定义函数装饰器的地方(@visible, @public, @protected, @exclude等),扫描和验证文件,加载/重新加载Python模块,并将工具调用分派到用户代码中。
  • DynamicServerManager.py -管理第三方MCP服务器配置 dynamic_servers/。它保存/加载JSON配置,启动stdio MCP服务器,保持会话活动,并获取其工具列表。
  • atlantis.py -注入到动态函数中的动态函数利用/运行时API。这是工具代码使用的桥梁 client_log、流媒体、HTML/图像/视频响应、点击/上传回调、请求上下文和持久共享状态。请参阅 动态函数文档 用于此API的功能授权端。
  • lobster.py -本地Atlantis MCP客户端的兼容层。它定义了 readme / command / chat 工具,并将这些本地调用转换为云支持的命令流。
  • state.py -中央配置和全流程状态。它设置日志记录,定义 FUNCTIONS_DIR 和 SERVERS_DIR,并存储主机/端口和请求超时等基本服务器常数。
  • utils.py -跨服务器和动态函数共享的低级助手。它包含搜索词解析、JSON/log格式化、全局服务器实例桥和客户端命令/日志管道 atlantis.py.
  • PIDManager.py -通过PID文件为Python服务器进程提供单实例保护。
  • ColoredFormatter.py -日志格式化程序和请求上下文过滤器 state.py.

运行时分割基本上是:

  1. server.py 接收MCP流量。
  2. server.py 路由MCP tools/call 通过 DynamicAdditionServer._handle_tools_call().
  3. _handle_tools_call() 将Python工具的执行委托给 DynamicFunctionManager.py 并代理MCP工具的执行 DynamicServerManager.py.
  4. 动态函数通过以下方式回调到主机 atlantis.py 和 utils.py.

有关动态函数编写的详细信息,请参见 动态函数文档.

特性

动态函数

动态函数使用户能够创建和维护作为工具的自定义函数,这些函数保存在 dynamic_functions/ 文件夹。函数在启动时加载,修改后自动重新加载。

有关创建和使用动态函数的详细信息,请参阅 动态函数文档.

动态MCP服务器

  • 使用户能够安装和管理第三方MCP服务器工具;JSON配置文件保存在 dynamic_servers/ 文件夹

  • 每个MCP服务器都需要先“启动”才能获取工具列表

  • 每个服务器配置都遵循通常的JSON结构,其中包含一个“mcpServers”元素;例如,这将安装一个openweather MCP服务器:

    {
       "mcpServers": {
          "openweather": {
             "command": "uvx",
             "args": [
             "--from",
             "atlantis-open-weather-mcp",
             "start-weather-server",
             "--api-key",
             "<your openweather api key>"
             ]
          }
       }
    }
    

气象MCP服务只是移植到uvx的现有服务。看 这里

云

云服务在https://www.flowcentral.ai提供了一个集中式中心,用于管理远程服务器和跨机器共享工具。

应用程序组织

动态功能通过以下方式组织到应用程序中 文件夹结构。只需放置您的 .py 子目录中的文件:

dynamic_functions/
├── Home/                    # App: "Home"
│   └── atlas.py
├── Accounting/              # App: "Accounting"
│   ├── accounting.py
│   └── foo.py
└── FilmFromImage/          # App: "FilmFromImage"
    └── qwen_image_edit_local.py

文件夹名称就是应用程序名称。 功能在 Home 相应地分配文件夹。

嵌套应用程序(子文件夹)

使用子文件夹创建嵌套应用程序结构:

dynamic_functions/
└── MyApp/
    └── SubModule/
        └── Feature/
            └── my_function.py

这将创建应用程序名称: MyApp/SubModule/Feature

最佳实践:

  • 保持简单——一级文件夹通常就足够了
  • 使用描述性文件夹名称(例如。, Chat, Admin, Tools)
  • 将相关功能组合在同一文件夹中
  • 文件夹结构使您的代码保持有序和清晰

使用搜索词调用工具

调用工具时,您可以使用 复合工具名称 以消除功能歧义。 仅包含唯一标识函数所需的路径。

格式: remote_owner*remote_name*app*location*function

关键原则:使用唯一解析的最简单形式

# If you have these functions:
# - dynamic_functions/Chat/send_message.py
# - dynamic_functions/Email/send_message.py
# - dynamic_functions/SMS/send_message.py

send_message              ❌ Ambiguous! Which one?
**Chat**send_message      ✅ Clear! The one in Chat
**Email**send_message     ✅ Clear! The one in Email

示例:

update_image                          → Simple call (only works if unique)
**MyApp**update_image                 → Specify app to disambiguate
**MyApp/SubModule**process_data       → Nested app path
alice*prod*Admin**restart             → Full routing: owner + remote + app + function
***office*print                       → Just location context

它是如何工作的:

  • 领域: remote_owner*remote_name*app*location*function
  • 用以下内容分隔字段 * (星号)
  • 省略不需要的字段 (使用空字符串: **App**func)
  • 应用程序字段支持嵌套应用程序的斜线表示法(MyApp/SubModule)
  • 最后一个字段始终是函数名
  • 无星号=将整个名称视为函数名称

何时使用化合物名称:

  • 名称冲突:多个应用程序具有同名功能
  • 远程定位:从云端调用特定遥控器上的功能
  • 位置路线:特定物理位置的目标功能
  • 多用户设置:在共享环境中指定所有者和远程

最佳实践: 简单开始(update_image)仅在需要解决歧义时添加上下文(**ImageTools**update_image).

例子:

# File: dynamic_functions/ImageTools/process.py
@visible
async def update_image(image_path: str):
    """Update an image."""
    return "updated"

# If this is the ONLY update_image:
update_image                          ✅ Works fine!

# If Chat app ALSO has update_image:
**ImageTools**update_image            ✅ Now we need to specify the app

机器人:阿特拉斯

Atlas是FlowCentral的前台聊天机器人。机器人角色现在位于每个游戏文件夹中,共享运行时位于 Home/:

Games/FlowCentral/                   # Game definition
├── Bots/                            # Bot personas for this game
│   ├── Atlas/
│   │   ├── config.json              # Model, provider, greeting, handler references
│   │   ├── system_prompt.md         # Base system prompt (markdown)
│   │   ├── prompt.py                # System prompt builder with context injection
│   │   ├── main.py                  # Index placeholder
│   │   └── atlas_face.jpg           # Bot avatar
│   └── Celeste/                     # Executive concierge
│       ├── config.json
│       ├── system_prompt.md
│       ├── prompt.py
│       ├── main.py
│       └── celeste_face.jpg
├── Locations/                       # Rooms players can move between
│   ├── Lobby.json                   # Location metadata + adjacency
│   ├── Lobby.jpg                    # Background image
│   ├── Lounge.json
│   └── Lounge.jpg
└── Roles/                           # NPC role definitions
    ├── Greeter/                     # Atlas's role
    │   ├── system_prompt.md         # Role-specific system prompt
    │   └── prompt.py
    └── Concierge/                   # Celeste's role
        ├── system_prompt.md
        └── prompt.py

Home/                                # Shared bot + game runtime
├── main.py                          # Entry point: index(), show_tools()
├── game.py                          # Game state: game_set(), game_show(), game_list()
├── bot.py                           # Bot listing with thumbnails, bot_spawn()
├── character.py                     # Character CRUD, roles, role_list()
├── location.py                      # Locations, positions, movement: move_bot(), move_human(), go(), look()
├── camera.py                        # Per-game camera location tracking
├── map.py                           # Interactive visual map of locations
├── common.py                        # Shared helpers: bot config, thumbnails, game data I/O
├── chat.py                          # Bot chat runtime: BotChatContext, dispatch_chat, system prompt builder
├── chat_callback.py                 # Routes room chat to correct bot, interaction tracking
├── chat_common.py                   # Transcript fetch, tool discovery, pseudo-tools (search, dir, todo)
├── turn.py                          # Multi-turn LLM conversation loop with tool calls
├── todo.py                          # Per-session todo pseudo-tool for bot task tracking
├── GAME.md                          # ER diagram of the game data model
├── MULTIX.md                        # User-facing CLI documentation
└── README.py                        # Serves MULTIX.md and GAME.md via MCP

游戏系统

游戏管理机器人任务、角色、位置和移动。每个游戏的范围都是:

  • game_set(name) --将服务器锁定到游戏(例如。 "FlowCentral")
  • character_bot(sid, role) --为机器人分配角色(例如。 character_bot("atlas", "Greeter"))
  • character_human(sid, role, name) --为人类玩家分配角色
  • character_self(role, name) --将呼叫者指定为人类角色
  • move_bot(sid, location) / move_human(sid, location) --在位置之间移动字符
  • go(location) --移动呼叫者的角色并更新背景
  • game_show() --呈现游戏状态的实时ER图
  • map(location) --显示当前位置和相邻区域的视觉地图

位置定义为JSON文件 Games/<game>/Locations/ 带有邻接图(connects_to).只允许沿着连接的边缘移动。新玩家从默认位置开始(标记为 "default": true).

玩家数据

所有游戏状态都在以下范围内 Data/{game_id}/.数据I/O助手(game_dir, _read_json, _write_json等)住在 Home/common.py.

Data/
├── main.py                          # Index placeholder, imports list_games from Home/common
└── {game_id}/                       # Per-game data (created at runtime)
    ├── characters.json              # Bot and human role assignments
    ├── positions.json               # Current location of each character
    ├── camera.json                  # Current camera location
    ├── bot_interactions.json        # Per-bot interaction history (timestamps, counts)
    └── api_payload.json             # Debug: last LLM API payload

关键文件

  • python-server/dynamic_functions/Home/MULTIX.md --FlowCentral MCP工具的面向用户的文档(命令、搜索词、工具前缀等)。这是由 readme MCP工具。
  • Games/FlowCentral/Bots/Atlas/config.json --机器人配置:模型(minimax-m2.7)、提供者(OpenRouter)、问候消息以及聊天处理程序和系统提示的参考。
  • Home/main.py --入口点: index(), show_tools().
  • Home/game.py --游戏生命周期: game_set(), game_show(), game_list(), game_entry() 欢迎模式。
  • Home/bot.py --机器人列表与缩略图生成, bot_spawn().
  • Home/character.py --字符系统: character_bot(), character_human(), character_self(), character_list(), role_list().
  • Home/location.py --位置、方位和移动: move_bot(), move_human(), go(), look(), position_get().
  • Home/camera.py --每场比赛的摄像机位置跟踪: camera_get(), camera_set().
  • Home/map.py --ELK.js布局的交互式可视化位置地图。
  • Home/common.py --共享助手:机器人配置加载、缩略图生成、游戏数据I/O(game_dir, _read_json, _write_json).
  • Home/chat.py --机器人聊天运行时: BotChatContext, dispatch_chat(),系统提示生成器,OpenAI客户端。
  • Home/chat_callback.py --聊天路由:检测哪个机器人在房间里,构建上下文,分派给聊天处理程序,跟踪交互。
  • Home/chat_common.py --转录获取、工具转换、参与者分析、伪工具(搜索、目录、待办事项)。
  • Home/turn.py --具有工具调用执行功能的多回合LLM流式对话循环。
  • Home/todo.py --每会话todo伪工具:机器人在对话中内部使用此工具来跟踪任务。与search/dir.Storage一起注入LLM工具列表: Data/{game_id}/todos/{sid}/.
  • Data/main.py --游戏数据文件夹的索引占位符。

让机器人聊天(快速入门)

如果你只是想让机器人尽快回复消息:

1.开始游戏 --类型 @game 在聊天中。这运行 Home/game.py 其中:

  • 将服务器锁定到FlowCentral游戏(game_set)
  • 在大堂产卵Atlas(bot_spawn)
  • 设置聊天回拨(/callback set chat chat_callback)
  • 显示欢迎模式

2.以字符形式输入 --在欢迎模式中填写您的姓名,然后单击Enter。这个:

  • 为您分配访问者角色(character_self)
  • 将您移至大厅(go)

3.聊天 --键入任何消息。聊天回调会自动触发:

  • 在大厅找到你
  • 在大厅找到阿特拉斯
  • 将您的消息发送到Atlas的LLM
  • Atlas通过流媒体进行响应

如果阿特拉斯没有回应,请检查:你们俩在同一个房间吗? (@game_show 呈现位置的ER图)。聊天回拨设置好了吗?(你应该看看 Chat callback set to ...chat_callback 在日志中)。

机器人需要什么才能做出回应:

  1. 必须设置游戏(game_set)
  2. 机器人必须有一个角色分配(character_bot 或 bot_spawn)
  3. 机器人必须放置在房间里(move_bot 或 bot_spawn)
  4. 用户必须与机器人在同一个房间(go 或 move_human)
  5. 聊天回拨必须指向 chat_callback (/callback set chat chat_callback)
  6. 机器人的 config.json 必须具有有效 apiKeyEnv, model, baseUrl
  7. API密钥环境变量必须在服务器的外壳程序中设置

故障排除

请先检查服务器日志。 Python服务器将详细日志写入 python-server/runServer.log:

tail -1000 python-server/runServer.log

常见错误及其含义:

错误 原因 修复
module 'atlantis' has no attribute 'X' atlantis.py 已更改,但服务器未重新启动。与动态函数不同, atlantis.py 是SDK——它在启动时只加载一次。 重新启动Python服务器
name 'X' is not defined 动态函数文件中缺少导入。Python在模块加载时捕获了它。 添加缺失的导入(例如。 from typing import Any)
Role folder not found: X character_bot/character_self 被调用的角色名称在中不存在 Games/<game>/Roles/ 创建角色文件夹或修改角色名称
No active game_id in context game_set 已被呼叫,但没有游戏会话。服务器需要一个活动会话才能拥有game_id。 请确保您已连接并拥有会话
X environment variable is not set 机器人 apiKeyEnv (例如。 OPENROUTER_API_KEY)未导出到服务器的shell中 source set_OPENROUTER.bat 启动服务器之前
System prompt not found 机器人 systemPrompt 路径在 config.json 未解析为真实文件 检查相对于机器人文件夹的路径
Unknown tool: X LLM调用了工具查找中不存在的工具 检查 /dir 输出和工具名称
No FlowCentral bot is present in X 用户发送了一条消息,但其房间中没有具有有效配置的机器人 将机器人移动到具有 move_bot
Chat callback 'X' error 聊天回调函数崩溃。实际错误在冒号之后。 读取错误消息,检查功能

您可以在聊天中键入的关键调试命令:

命令 它的作用
@game 初始化游戏(设置游戏、生成Atlas、设置回调)
@game_show 渲染ER图——显示所有角色、位置和角色
@game_status 显示当前游戏锁定状态
@bot_list 列出所有机器人及其配置
@position_get(atlas) 检查字符的位置
@go(Lobby) 搬到一个房间
@move_bot(atlas, Lounge) 将机器人移动到其他房间
/callback 显示当前回拨设置
/dir 列出所有可用工具
/search chat 按关键字搜索工具

热重新加载与需要重新启动的内容:

  • 保存时热重新加载: 一切都在 dynamic_functions/ --全部 .py 文件修改后会自动重新加载
  • 需要重新启动服务器: atlantis.py, server.py, utils.py,以及外部的任何其他文件 dynamic_functions/

聊天时要查找的日志行:

Chat: session=X request=X game=X caller=admin        ← callback fired
Transcript fetched in 0.05s (12 raw, 8 filtered)      ← got conversation history
Game X: bot=atlas role=Greeter location=Lobby          ← found the bot
=== HANDING OFF TO Atlas (Greeter at Lobby) ===        ← dispatching to LLM
Sending to minimax/minimax-m2.7: 5 messages, 3 tools  ← API call
Stream opened in 0.8s                                  ← LLM responding
Stream done: turn=1 chunks=42 tool_calls=0             ← response complete

如何构建一个新的机器人

要创建新的机器人,您需要: Games/<game>/Bots/,在 Games/<game>/Roles/,以及可选的新位置。

步骤1:创建角色文件夹 (Games/FlowCentral/Bots/YourBot/)

您需要4-5个文件:

config.json --型号和标识:

{
  "sid": "yourbot",
  "displayName": "YourBot",
  "image": "yourbot_face.jpg",
  "provider": "openrouter",
  "model": "minimax/minimax-m2.7",
  "baseUrl": "https://openrouter.ai/api/v1",
  "apiKeyEnv": "OPENROUTER_API_KEY",
  "chatHandler": "dynamic_functions.Home.chat.handle_chat_completions",
  "systemPrompt": "system_prompt.md",
  "greeting": "Hi, I'm YourBot."
}
  • sid --唯一的机器人标识符,用于成绩单和字符系统
  • chatHandler --总是 dynamic_functions.Home.chat.handle_chat_completions (共享运行时)
  • systemPrompt --bot文件夹中包含基本系统提示的markdown文件
  • image --机器人文件夹中的头像图像文件名
  • apiKeyEnv -保存API密钥的环境变量
  • greeting --机器人首次出现时会说什么

system_prompt.md --机器人的个性以简单的标记显示:

You are YourBot, a [description of role and personality].

[Instructions for behavior, tone, tools, etc.]

prompt.py --构建交互上下文(时间感知、回访检测)。复制自 Games/FlowCentral/Bots/Atlas/prompt.py 并根据需要进行调整。

main.py --索引占位符,以便机器人在工具发现中显示:

import atlantis
import logging

logger = logging.getLogger("mcp_server")

@visible
async def index():
    """YourBot — [role description]."""
    pass

yourbot_face.jpg --头像。当机器人生成时显示。

第二步:创建角色 (Games/FlowCentral/Roles/YourRole/)

system_prompt.md --特定角色系统提示添加:

You are stationed at [location]. Your job is to [role description].

prompt.py --可选的特定角色提示生成器。如果需要,从现有角色复制。

main.py --索引占位符:

import atlantis
import logging

logger = logging.getLogger("mcp_server")

@visible
async def index():
    """YourRole — [description]."""
    pass

步骤3:添加位置 (可选)

如果你的机器人需要自己的房间,请在以下位置创建一个JSON文件 Games/FlowCentral/Locations/:

YourLocation.json:

{
  "name": "YourLocation",
  "description": "A brief description of this location.",
  "image": "YourLocation.jpg",
  "connects_to": ["Lobby"]
}

添加背景图像(YourLocation.jpg)相同 Locations/ 文件夹。然后更新大堂的 connects_to 数组包含 "YourLocation" 所以玩家可以在两者之间旅行。

步骤4:将您的机器人分配给其角色

一旦游戏被锁定到FlowCentral(通过 game_set),将您的机器人注册为角色,并将其分配给您创建的角色:

character_bot("yourbot", "YourRole")

这链接了机器人的 sid 到角色文件夹,这样系统就知道要使用哪个系统提示和行为。如果一个角色有这个 sid 已存在,它会更新角色而不是创建副本。

步骤5:将您的机器人移动到其位置

将你的机器人放在它应该迎接访客的房间里:

await game_move_bot("yourbot", "YourLocation")

新机器人必须先进入默认位置(大厅),然后才能移动到其他地方——这反映了玩家进入游戏的方式。如果你的机器人的位置是大厅本身,你可以省略位置参数。

第六步:生成机器人

展示机器人的头像,并让它通过配置的问候语进行自我介绍:

await spawn_bot("yourbot")

这将向客户端显示机器人的面部图像,并将问候语作为聊天消息发送,以便机器人出现在对话记录中。在此之后,聊天回调将根据房间里的人自动将传入消息路由到您的机器人。

把它们放在一起:

以下是您在会话中使新机器人上线的完整序列:

await game_set("FlowCentral")           # Lock server to the game (once per server)
character_bot("yourbot", "YourRole")     # Assign bot to role
await game_move_bot("yourbot")           # Enter the default lobby
await spawn_bot("yourbot")               # Show face + greeting

或使用 bot_spawn() 它将字符分配和放置结合在一个呼叫中:

await game_set("FlowCentral")
await bot_spawn("yourbot", "YourRole", "Lobby")

聊天管道是如何工作的

当用户发送消息时,会发生以下情况:

User types message
    │
    ▼
chat_callback.py  ← @chat decorator fires on any chat message
    │
    ├─ Fetches the transcript (raw + filtered)
    ├─ Finds the last speaker's SID
    ├─ Looks up their position (which room they're in)
    ├─ Queries who else is in that room
    ├─ Finds the first bot present with a valid config
    │
    ▼
chat.py  ← builds BotChatContext, calls dispatch_chat()
    │
    ├─ Loads the bot's config.json (model, provider, system prompt path)
    ├─ Loads the system prompt from the bot's folder
    ├─ If prompt.py exists, runs the prompt builder to inject interaction context
    │   (time of day, returning visitor detection, first name, interaction count)
    ├─ Builds the tool list (search, dir, todo pseudo-tools + any custom tools)
    ├─ Creates the OpenAI client using the bot's provider/API key
    │
    ▼
turn.py  ← runs the multi-turn LLM conversation loop
    │
    ├─ Sends system prompt + transcript + tools to the LLM
    ├─ Streams the response (thinking → text → tool calls)
    ├─ If the LLM calls a tool:
    │   ├─ search/dir/todo → handled as pseudo-tools (no MCP round-trip)
    │   └─ real tools → executed via atlantis.client_command()
    ├─ Appends tool results to transcript, loops back to LLM
    ├─ Repeats up to 10 turns until LLM responds with just text
    │
    ▼
chat_callback.py  ← records the interaction
    │
    ├─ Saves interaction count + timestamp to bot_interactions.json
    └─ Next time this user talks to this bot, the prompt builder
       knows it's a returning visitor and adjusts the greeting

关键概念:

  • 基于房间的路由:响应的机器人由物理共置决定。用户和机器人必须在同一个房间。将机器人移动到不同的房间,以控制谁在哪里响应。
  • @chat 装饰器:标记 chat_callback() 作为所有聊天消息的处理程序。服务器会自动调用它,而不是直接调用它。
  • BotChatContext:一个数据类,它捆绑了机器人运行时所需的一切——会话信息、调用者、机器人配置、角色、转录、交互历史。穿过整个管道。
  • dispatch_chat():已配置机器人的路由 chatHandler。默认值为 handle_chat_completions 它使用OpenAI兼容的流媒体。您可以编写一个自定义处理程序并指向它 config.json.
  • 伪工具: search, dir,以及 todo 自动注入到每个机器人的工具列表中。他们让机器人发现并调用真正的MCP工具,并在对话过程中跟踪任务。这些不需要MCP往返,它们是内联处理的 turn.py.
  • 交互跟踪:每个对话都记录在 Data/{game_id}/bot_interactions.json 带有计数和时间戳。提示构建器使用它来调整语气(第一次会议与回访者)。
  • 注射程序:角色可以定义 requiresCheckin: true 在他们的角色配置中,这会触发一个签入流,在LLM看到之前将额外的上下文注入到转录中。

自定义聊天处理程序:

如果默认 handle_chat_completions 如果不适合你的机器人,你可以编写一个自定义处理程序:

# In your bot's module or anywhere importable
async def my_custom_handler(context: BotChatContext) -> Optional[str]:
    # context.transcript has the conversation history
    # context.bot_cfg has your config.json fields
    # context.caller is who's talking
    # Return the bot's response text, or None
    ...

然后指向它 config.json:

{
  "chatHandler": "dynamic_functions.Games.FlowCentral.Bots.YourBot.handler.my_custom_handler"
}