使用说明
bbsbot
基于FastMCP的telnet客户端,用于BBS(公告板系统)交互,具有自动学习功能。使AI代理能够通过模型上下文协议(MCP)与基于传统telnet的系统进行交互。
⚠️ AI生成代码免责声明
该项目是在人工智能的帮助下生成的。虽然功能正常,但它可能包含错误、安全漏洞或意外行为。使用风险自负。对于因使用本软件而导致的任何问题、损害或损失,作者不承担任何责任。在任何生产环境中使用之前,请彻底检查代码。
概述
bbsbot通过提供:
- 支持ANSI/CP437的全终端仿真
- 基于模式的屏幕阅读和导航
- 自动发现和记录菜单和提示
- 会话日志记录,用于分析和回放
- MCP工具曝光,实现无缝AI集成
建筑
bbsbot使用一个干净的分层架构,并适当分离关注点:
graph TB
subgraph "AI Agent"
LLM[Claude/LLM]
MCP[MCP Client]
end
subgraph "bbsbot Server"
App[FastMCP App]
SM[SessionManager]
subgraph "Core Layer"
Session[Session]
end
subgraph "Transport Layer"
Transport[TelnetTransport]
end
subgraph "Terminal Layer"
Emulator[TerminalEmulator<br/>pyte]
end
subgraph "Learning Layer"
Engine[LearningEngine]
Discovery[Menu Discovery]
end
subgraph "Logging Layer"
Logger[SessionLogger]
end
end
subgraph "BBS System"
Telnet[Telnet Server :23]
BBS[BBS Software]
end
subgraph "Knowledge Base"
Prompts[prompt-catalog.md]
Menus[menu-map.md]
Flows[navigation-flows.md]
end
LLM --> MCP
MCP -->|MCP Tools| App
App --> SM
SM --> Session
Session --> Transport
Session --> Emulator
Session --> Engine
Session --> Logger
Transport -->|RFC 854 + IAC Escaping| Telnet
Telnet --> BBS
BBS -->|ANSI/CP437| Telnet
Telnet -->|Raw Bytes| Transport
Transport --> Emulator
Engine --> Discovery
Engine --> Prompts
Engine --> Menus
Engine --> Flows
架构层
- 传输层 (
transport/):协议抽象(符合RFC 854的telnet,IAC字节转义) - 端子层 (
terminal/):使用pyte进行ANSI/CP437终端仿真 - 核心层 (
core/):具有资源限制和状态隔离的会话管理 - 学习层 (
learning/):自动发现菜单/提示,知识库管理 - 测井层 (
logging/):使用原始字节的结构化JSONL会话日志记录
特性
- 远程登录客户端:具有选项协商的完整RFC 854 telnet协议(BINARY、SGA、NAWS、TTYPE)
- 终端仿真:配备80x25(可配置)屏幕缓冲区的完整ANSI/CP437终端
- 屏幕阅读:提取文本、匹配模式、等待具有超时控制的提示
- 自动学习:发现菜单
[A] Option,提示Enter name:,以及文档导航流 - 会话日志记录:JSONL格式,带有时间戳、上下文和原始字节,用于回放/分析
- MCP集成:25多种用于连接、导航、学习和会话管理的工具
- 保持连接:可配置间隔以防止空闲断开连接
安装
先决条件
安装 紫外线 (推荐的软件包安装程序):
curl -LsSf https://astral.sh/uv/install.sh | sh
或者看看 紫外线安装文档 对于其他方法。
安装bbsbot
bbsbot是必须在MCP客户端(Claude Desktop、Cline等)中配置的MCP服务器。
选项1:作为工具安装(推荐)
uv tool install bbsbot
然后添加到MCP客户端配置中:
{
"mcpServers": {
"bbsbot_local_tw2002": {
"command": "bbsbot"
}
}
}
本地TW2002 MCP与外部MCP连接器
bbsbot 在本地提供TW2002工具,但这些工具仅存在于MCP中
您从这个存储库/环境启动的服务器进程。在多连接器中
客户端,您也可能安装了无关的MCP连接器;那些不会
暴露 tw2002_* 工具。
有关群集运行时/ROI诊断和防崩溃控制参考,请参阅:
对TW2002操作使用显式的本地别名和工具筛选器:
{
"mcpServers": {
"bbsbot_local_tw2002": {
"command": "bbsbot",
"args": ["serve", "--tools", "tw2002"]
}
}
}
如果 tw2002_* 缺少工具,首先验证配置的命令是否包括
serve --tools tw2002.
选项2:使用pip安装
pip install bbsbot
然后配置MCP客户端以运行 bbsbot 作为服务器。
开发安装
git clone https://github.com/livingstaccato/bbsbot.git
cd bbsbot
uv pip install -e ".[dev]"
快速入门示例
以下是一个完整的AI代理连接到BBS、导航菜单和阅读消息的示例:
from fastmcp import Client
from fastmcp.mcp_config import StdioMCPServer
# Start bbsbot server
server = StdioMCPServer(command="bbsbot", args=[])
async with Client(server.to_transport()) as client:
# Connect to BBS
await client.call_tool("bbs_connect", {
"host": "bbs.example.com",
"port": 23,
"cols": 80,
"rows": 25,
"term": "ANSI",
"send_newline": True
})
# Wait for main menu
screen = await client.call_tool("bbs_read_until_pattern", {
"pattern": r"\[M\] Main Menu",
"timeout_ms": 5000
})
# Navigate to messages
await client.call_tool("bbs_send", {"keys": "M\r"})
# Read until message list appears
screen = await client.call_tool("bbs_read_until_pattern", {
"pattern": r"Message #\d+",
"timeout_ms": 3000
})
print(screen["screen"]) # Display the screen
# Disconnect
await client.call_tool("bbs_disconnect", {})
用法
作为MCP服务器
作为MCP服务器运行以公开BBS工具:
# Start the server (stdio transport)
bbsbot
# Or specify config
bbsbot --host localhost --port 2002
程序化使用
在没有MCP的情况下直接使用Python API:
from bbsbot.core.session_manager import SessionManager
manager = SessionManager(max_sessions=10)
# Connect and create session
session_id = await manager.create_session(
host="bbs.example.com",
port=23,
cols=80,
rows=25,
term="ANSI",
send_newline=True,
reuse=False
)
# Get session
session = await manager.get_session(session_id)
# Read screen with timeout
snapshot = await session.read(timeout_ms=250, max_bytes=8192)
# Snapshot contains:
# - screen: formatted text (80x25)
# - screen_hash: SHA256 of screen text
# - cursor: {x, y} position
# - cols, rows, term
print(snapshot["screen"])
print(f"Cursor at: {snapshot['cursor']}")
# Send keys
await session.send("A\r\n")
# Wait for specific pattern (manual implementation)
import re
import asyncio
pattern = re.compile(r"Enter your name:")
timeout = 5.0
interval = 0.1
start_time = asyncio.get_event_loop().time()
matched = False
while asyncio.get_event_loop().time() - start_time < timeout:
snapshot = await session.read(timeout_ms=int(interval * 1000), max_bytes=8192)
if pattern.search(snapshot["screen"]):
matched = True
break
await asyncio.sleep(interval)
if matched:
print("Found prompt!")
await session.send("Alice\r")
# Disconnect
await manager.close_session(session_id)
注: 为了方便起见,使用MCP工具,它提供更高级的操作,如 bbs_read_until_pattern.直接API是较低级别的,并且需要手动模式匹配循环。
MCP工具参考
当作为MCP服务器运行时,会公开以下工具:
注: 在v0.2.0中,我们删除了重复项 *_screen 变体和实用程序包装器,以简化API。使用 bbs_read()["screen"] 提取屏幕文本并组合操作,而不是使用方便的包装器,如 bbs_expect 或 bbs_play_step.
连接管理
bbs_connect
通过telnet连接到BBS。
{
"host": "bbs.example.com",
"port": 23,
"cols": 80,
"rows": 25,
"term": "ANSI",
"send_newline": true,
"reuse": false
}
bbs_disconnect
断开与BBS的连接。退出前一定要打电话。
{}
bbs_status
获取连接状态、会话ID、最后RX/TX时间戳、保活信息。
{}
屏幕交互
bbs_read
主要的读取方法。 从telnet流中读取并返回包含屏幕文本、原始输出、光标位置和哈希的完整快照。 始终将原始字节记录到JSONL 因此,如果LLM对屏幕内容不确定,可以参考。
使用 timeout_ms=0 无需等待新数据即可获取当前屏幕状态。
{
"timeout_ms": 250,
"max_bytes": 8192
}
退货:
{
"screen": "formatted 80x25 text...",
"raw": "raw terminal output",
"raw_bytes_b64": "base64 encoded raw bytes",
"screen_hash": "sha256 of screen text",
"cursor": {"x": 0, "y": 0},
"cols": 80,
"rows": 25,
"term": "ANSI"
}
重要提示: 每个 bbs_read 调用日志记录完整快照,包括 raw_bytes_b64 转到session.json(如果启用了日志记录)。如果LLM误解了屏幕内容,它可以查阅日志文件以获取收到的确切原始字节数。
bbs_read_until_nonblank
继续阅读,直到屏幕上有非空白内容或超时。
{
"timeout_ms": 5000,
"interval_ms": 100,
"max_bytes": 8192
}
bbs_read_until_pattern
读取,直到屏幕匹配正则表达式模式。
{
"pattern": "Enter your name:",
"timeout_ms": 5000,
"interval_ms": 100,
"max_bytes": 8192
}
返回:带有附加值的快照 "matched": true/false
bbs_send
向BBS发送按键(CP437编码)。
{
"keys": "A\r\n"
}
使用 \r 对于Enter, \n 对于线路馈电, \x1b 逃跑。
bbs_wake
尝试多个按键序列,直到屏幕发生变化(对空闲超时有用)。
{
"timeout_ms": 5000,
"interval_ms": 250,
"max_bytes": 8192,
"keys_sequence": ["\r", " ", "\r\n"]
}
自动学习
bbs_auto_learn_enable
启用/禁用提示和菜单的自动学习。
{
"enabled": true
}
bbs_auto_learn_prompts
配置规则以自动检测提示。
{
"rules": [
{
"prompt_id": "username",
"regex": "Enter your name:",
"input_type": "text",
"example_input": "Alice"
}
]
}
bbs_auto_learn_menus
配置规则以自动检测菜单选项。
{
"rules": [
{
"menu_id": "main",
"regex": "\\[M\\] Main Menu"
}
]
}
bbs_auto_learn_discover
启用自动发现 [X] 样式菜单选项。
{
"enabled": true
}
bbs_learn_menu
手动记录菜单。
{
"menu_id": "main",
"title": "Main Menu",
"options": [
{"key": "M", "label": "Read Messages"},
{"key": "P", "label": "Post Message"},
{"key": "Q", "label": "Quit"}
],
"prompt": "Your choice:"
}
bbs_learn_prompt
手动记录提示。
{
"prompt_id": "username",
"pattern": "Enter your name:",
"input_type": "text",
"example_input": "Alice",
"notes": "Username for login"
}
bbs_learn_flow
屏幕之间的文档导航。
{
"from_screen": "main_menu",
"action": "M",
"to_screen": "message_list",
"notes": "Press M to read messages"
}
会话管理
bbs_log_start
启动JSONL会话日志记录。 强烈推荐 -如果LLM误读了屏幕,则允许LLM返回原始会话数据。
{
"path": "session.jsonl"
}
bbs_log_stop
停止会话日志记录。
{}
bbs_log_note
在日志中添加结构化注释以进行调试。
{
"note": "Starting message read loop",
"context": "messages"
}
bbs_set_context
设置附加到所有后续日志条目的元数据。
{
"context": {
"menu": "main",
"action": "reading_messages"
}
}
保持连接
bbs_keepalive
配置自动保活以防止空闲超时。
{
"interval_s": 30.0,
"keys": "\r"
}
集 interval_s 到 0 或 null 禁用。
典型工作流程
sequenceDiagram
participant LLM as AI Agent (LLM)
participant MCP as bbsbot
participant BBS as BBS System
participant Log as session.jsonl
participant KB as Knowledge Base
LLM->>MCP: bbs_log_start("session.jsonl")
MCP->>Log: Create log file
LLM->>MCP: bbs_connect(host, port, ...)
MCP->>BBS: Telnet connection
BBS-->>MCP: Welcome screen (ANSI)
MCP->>Log: Log connection + raw bytes
LLM->>MCP: bbs_auto_learn_enable(true)
LLM->>MCP: bbs_auto_learn_discover(true)
LLM->>MCP: bbs_read_until_pattern("Main Menu")
MCP->>BBS: Read telnet stream
BBS-->>MCP: Raw bytes + ANSI codes
MCP->>MCP: Parse terminal, extract text
MCP->>Log: Log screen + raw bytes
MCP->>KB: Discover menu options [A], [B]
MCP-->>LLM: screen + cursor + hash
Note over LLM: LLM analyzes screen,<br/>decides to press 'M'
LLM->>MCP: bbs_send("M\r")
MCP->>BBS: Send 'M' + Enter
MCP->>Log: Log keystroke
LLM->>MCP: bbs_read(250, 8192)
BBS-->>MCP: Message list screen
MCP->>Log: Log screen + raw bytes
MCP-->>LLM: Full snapshot
Note over LLM: If LLM is uncertain about<br/>screen content, it can<br/>refer to session.jsonl<br/>for raw bytes
LLM->>MCP: bbs_disconnect()
MCP->>BBS: Close connection
MCP->>Log: Log disconnect
LLM->>MCP: bbs_log_stop()
要点
- 始终启动会话日志记录 (
bbs_log_start)-使用原始字节创建完整记录 - 使用
bbs_read对于一切 -始终以JSONL格式记录原始数据的单一方法 - 启用自动学习 早期-为未来的会议建立知识库
- 如果不确定,LLM可以参考日志 -每一个
bbs_read包括raw_bytes_b64会话日志 - 没有单独的“获取屏幕”方法 -使用
bbs_read(timeout_ms=0)获取当前状态 - 知识库积累 -菜单、提示、流程记录在
.bbs-knowledge/
为什么是单读法?
以前,读取新数据和获取当前屏幕有不同的方法。这令人困惑且容易出错。现在:
- 单一真相来源:
bbs_read始终读取,始终记录原始字节 - LLM安全: 如果不确定屏幕内容,LLM可以检查
raw_bytes_b64来自session.jsonl - 一致的日志记录: 每次屏幕观察都会完整记录
- 更简单的API: 不混淆使用哪种方法
配置
知识库
默认情况下,学习到的知识按照XDG基本目录规范存储在特定于平台的用户数据目录中:
- Linux/BSD:
~/.local/share/bbsbot(或$XDG_DATA_HOME/bbsbot) - macOS:
~/Library/Application Support/bbsbot - 视窗:
%LOCALAPPDATA%\bbsbot
用以下内容覆盖默认位置:
export BBSBOT_KNOWLEDGE_ROOT=/path/to/knowledge
保持每个项目的知识库(而不是整个用户):
export BBSBOT_KNOWLEDGE_ROOT=$(pwd)/.bbs-knowledge
终端设置
通过MCP工具配置终端大小和保活:
# Using MCP client
await client.call_tool("bbs_set_size", {"cols": 80, "rows": 25})
await client.call_tool("bbs_keepalive", {"interval_s": 30.0, "keys": "\r"})
或者以编程方式:
# Using SessionManager
session = await manager.get_session(session_id)
await session.set_size(cols=80, rows=25)
# Keepalive is configured per-session through the session manager
发展
设置
uv pip install -e ".[dev]"
代码质量
该项目使用现代Python 3.11+功能和严格的质量工具:
- 类型检查:
mypy src/bbsbot - 掉毛:
ruff check src/bbsbot - 格式化:
ruff format src/bbsbot - 测试:
pytest - 类型验证:
ty src/bbsbot
运行所有检查
ruff check src/bbsbot
ruff format --check src/bbsbot
mypy src/bbsbot
pytest
重新生成图表
架构和工作流程图是使用Mermaid文件生成的 mermaid-py.
使用make生成SVG图:
make diagrams
可用目标:
make diagrams或make diagrams-svg-生成SVG图(默认)make diagrams-png-生成PNG图表make clean-删除所有生成的图表文件make help-显示所有可用目标
或者,直接运行脚本:
python3 docs/generate_diagrams.py --format svg
源文件:
docs/diagrams/architecture.mmd→architecture.svgdocs/diagrams/workflow.mmd→workflow.svgdocs/diagrams/session-flow.mmd→session-flow.svg
智能机器人与模式测试
bbsbot包括一个智能机器人系统,该系统使用提示检测来自主导航BBS游戏并测试提示模式。
TW2002交易机器人
运行TW2002交易机器人:
bbsbot tw2002 bot -c tw2002_bot_config.yaml
目标可视化(人工智能策略)
当 trading.strategy: ai_strategy 处于活动状态,显示目标进度:
- 紧凑的状态线
trading.ai_strategy.visualization_interval回合 - 目标发生变化时的完整时间表
- 会议结束时的总结报告
要禁用所有目标可视化输出,请执行以下操作:
trading:
ai_strategy:
show_goal_visualization: false
间谍/监视插座
您可以通过TCP广播实时终端流,并从另一个终端连接到它:
# Start bot with watch socket enabled (raw ANSI stream)
bbsbot tw2002 bot -c tw2002_bot_config.yaml --watch-socket
# Attach viewer
bbsbot spy
如果你想要结构化的JSON事件(包括目标可视化事件),请使用JSON协议:
# Start bot with JSON watch protocol
bbsbot tw2002 bot -c tw2002_bot_config.yaml --watch-socket --watch-socket-protocol json
# Attach and view JSON lines (the "viz" events include compact/timeline/summary text)
bbsbot spy --encoding utf-8
目标可视化观察事件如下:
{"event":"viz","data":{"kind":"compact|timeline|summary","text":"...","turn":123,"character_name":"..."}}
MCP“间谍”工具(进行中)
如果你在MCP服务器进程中运行机器人,你可以按需查询目标进度:
tw2002_get_goal_visualization(呈现压缩/时间线/摘要)tw2002_get_goal_phases(原始相位数据)tw2002_capabilities(返回分组工具图+快速入口点)tw2002_list_sessions/tw2002_set_active_session(确定性会话定位)tw2002_bootstrap(一次通话连接+登录)
快速开始
# Run intelligent bot with pattern testing
bbsbot script play_tw2002_intelligent
# Run systematic pattern validation
bbsbot script test_all_patterns
特性
- 反应性检测:Bot等待提示,检测它们,并做出适当的响应
- 自动分页:自动处理“更多”提示和分页
- 模式验证:测试所有13个定义的提示模式
- 流量跟踪:记录操作→提示序列
- 综合报告:生成JSON和Markdown结果
建筑
智能机器人使用 混合反应方法:
- 第一阶段:纯反应式-检测出现的提示
- 第2阶段:跟踪提示序列和流程
- 第三期:添加常见模式的预测(未来)
看 docs/guides/INTELLIGENT_BOT.md 以获取完整的文档。
机器人使用示例
from bbsbot.commands.scripts.play_tw2002_intelligent import IntelligentTW2002Bot
bot = IntelligentTW2002Bot()
await bot.connect()
# Navigate to game
await bot.navigate_twgs_to_game()
await bot.enter_game_as_player("BotName")
# Test commands with automatic prompt detection
await bot.test_command("D\r", "Display computer")
await bot.test_command("I\r", "Show inventory")
# Auto-handles pagination
snapshot = await bot.send_and_wait("L\r", "Long range scan")
snapshot = await bot.handle_pagination(snapshot)
# Generate results
await bot.generate_report()
模式测试
测试了13种模式:
login_username,login_passwordtwgs_main_menu,twgs_select_gamemain_menu,command_prompt_genericsector_command,planet_commandpress_any_key,more_promptyes_no_prompt,quit_confirmenter_number
结果保存到 logs/reports/intelligent-bot-{timestamp}.json
已知警告
- 你可以看到
UserWarning: Field name "validate" ... shadows an attribute从Pydantic开始bbsbot。这目前是无害的,不会影响运行时行为。
许可证
GNU Affero通用公共许可证v3或更高版本-版权所有(c)2025-2026 provide.io llc
看 许可证 了解详情。