解决方案设计
技术研究 人工智能 OpenCode
理想状态:如果 OpenCode 提供以下能力,原生集成方案将可行:
方案A:原生集成方案(评估结果:不可行)
前提条件分析
理想状态:如果 OpenCode 提供以下能力,原生集成方案将可行:
-
任务完成钩子(Task Completion Hooks)
// opencode.json 配置示例 { "hooks": { "onComplete": "curl -X POST https://api.example.com/notify?status=success", "onFailure": "curl -X POST https://api.example.com/notify?status=error" } } -
进程状态 API
# 查询任务状态 curl http://localhost:4096/v1/status?task_id=xyz # 强制终止任务 curl -X DELETE http://localhost:4096/v1/tasks/xyz -
会话管理 API
# 程序化创建新会话 curl -X POST http://localhost:4096/v1/session/new
实际评估结果
❌ 结论:方案A在当前 OpenCode 版本中不可行
经过对官方文档和实际能力的验证,OpenCode 不提供上述任何一种机制。原生集成方案无法满足需求,必须采用变通方案(Workaround)。
方案B:变通方案(推荐)
方案概述
既然 OpenCode 不提供原生支持,我们需要在 OpenCode 外部构建一层包装器(Wrapper)来实现:
- 进程生命周期管理 - 启动、监控、终止 opencode 进程
- 状态捕获与通知 - 检测进程退出并发送 Telegram 通知
- 会话重置机制 - 通过进程重启模拟
/new功能
实现方式对比
我们设计了三种不同复杂度的变通方案,适用于不同的可靠性要求和资源投入。
方案B1:进程包装器(Shell Wrapper)- ⭐ 推荐
核心思想:使用 Shell 脚本包装 opencode 执行,捕获退出状态并触发后续操作。
工作流程:
┌─────────────────────────────────────────────────────────────────┐
│ 仓库A (Telegram Bot) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ 接收 /research │───▶│ 解析研究主题 │───▶│ 执行包装脚本 │ │
│ │ 命令 │ │ "电动车行业" │ │ trigger.sh │ │
│ └─────────────────┘ └─────────────────┘ └──────┬──────┘ │
└───────────────────────────────────────────────────────┼──────────┘
│
▼ SSH/本地
┌─────────────────────────────────────────────────────────────────┐
│ 仓库B (Research) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ research_ │───▶│ opencode run │───▶│ 检测退出码 │ │
│ │ wrapper.sh │ │ "电动车..." │ │ (0=成功) │ │
│ └─────────────────┘ └─────────────────┘ └──────┬──────┘ │
│ │ │
│ ┌────────────────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ 发送 Telegram │───▶│ 可选:清理进程 │───▶│ 可选:新会话 │ │
│ │ 通知 │ │ pkill opencode │ │ 重启opencode │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
优点:
- ✅ 实现简单,仅需 Shell 脚本知识
- ✅ 无额外依赖(仅需 curl、ps 等标准工具)
- ✅ 与 OpenCode 版本无关,兼容性好
- ✅ 可快速部署验证
缺点:
- ❌ 耦合度较高,逻辑分散在 Shell 脚本中
- ❌ 难以处理并发任务(需要 PID 管理)
- ❌ 错误处理相对简单
- ❌ 无法获取 opencode 内部详细错误信息
适用场景:
- 单个或少量的研究任务
- 对可靠性要求不是极端严格的场景
- 需要快速实现的 MVP 阶段
方案B2:文件信号机制(File Signal)
核心思想:使用文件系统作为进程间通信媒介,通过文件创建/修改来传递状态信号。
工作流程:
┌─────────────────────────────────────────────────────────────────┐
│ 仓库A (Telegram Bot) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ 文件监听器 │◀───│ 检测到完成信号 │◀───│ /tmp/ │ │
│ │ (watchdog) │ │ 文件变化 │ │ research_ │ │
│ └────────┬────────┘ └─────────────────┘ │ complete │ │
│ │ │ .signal │ │
│ │ └─────────────┘ │
│ ▼ SSH/本地 │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 发送 Telegram │ │ 触发清理/新会话 │ │
│ │ 通知 │ │ 操作 │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 仓库B (Research) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ opencode run │───▶│ 研究执行完成 │───▶│ 创建信号文件 │ │
│ │ "电动车..." │ │ (成功或失败) │ │ echo done > │ │
│ └─────────────────┘ └─────────────────┘ │ /tmp/... │ │
└─────────────────────────────────────────────────────────────────┘
实现细节:
仓库B的研究脚本需要添加信号写入逻辑:
#!/bin/bash
# research_task.sh
RESEARCH_TOPIC="$1"
SIGNAL_FILE="/tmp/research_complete.signal"
echo "开始研究: $RESEARCH_TOPIC"
# 执行研究
if opencode run "$RESEARCH_TOPIC"; then
echo "success" > "$SIGNAL_FILE"
else
echo "failure:$?" > "$SIGNAL_FILE"
fi
仓库A的文件监听器(Python 示例):
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import subprocess
class ResearchCompleteHandler(FileSystemEventHandler):
def on_modified(self, event):
if event.src_path == "/tmp/research_complete.signal":
with open(event.src_path, 'r') as f:
status = f.read().strip()
if status == "done":
subprocess.run(["python", "send_notification.py"])
subprocess.run(["bash", "start_new_session.sh"])
# 启动监听
observer = Observer()
observer.schedule(ResearchCompleteHandler(), path='/tmp')
observer.start()
优点:
- ✅ 仓库A和仓库B解耦,通过文件系统间接通信
- ✅ 即使仓库B的进程崩溃,信号文件仍然保留状态
- ✅ 支持更复杂的协调逻辑(多个任务排队)
缺点:
- ❌ 需要额外的文件监控进程(消耗资源)
- ❌ 实时性稍差(依赖文件系统事件延迟)
- ❌ 需要处理文件锁和并发写入问题
- ❌ 信号文件需要定期清理,否则可能积累
适用场景:
- 需要解耦仓库A和仓库B的场景
- 研究任务执行时间较长(分钟级)
- 需要支持任务队列和重试机制
方案B3:消息队列(Redis/Message Queue)
核心思想:使用 Redis 或消息队列作为中间件,实现可靠的异步通信。
工作流程:
┌─────────────────────────────────────────────────────────────────┐
│ 仓库A (Telegram Bot) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ Redis 消费者 │◀───│ 监听研究完成 │◀───│ Redis │ │
│ │ (subscriber) │ │ 频道消息 │ │ Channel │ │
│ └────────┬────────┘ └─────────────────┘ └──────┬──────┘ │
│ │ │ │
│ ▼ │ │
│ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ 发送 Telegram │ │ 触发清理/新会话 │◀─────────┘ │
│ │ 通知 │ │ 操作 │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 仓库B (Research) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ opencode run │───▶│ 研究执行完成 │───▶│ 发布消息到 │ │
│ │ "电动车..." │ │ (成功或失败) │ │ Redis 频道 │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
实现细节:
仓库B发布消息:
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def publish_completion(status, result=None):
message = {
'type': 'research_complete',
'status': status,
'result': result
}
r.publish('opencode_research', json.dumps(message))
# 执行研究后
publish_completion('success' if exit_code == 0 else 'failure')
仓库A消费消息:
import redis
import json
import subprocess
r = redis.Redis(host='localhost', port=6379, db=0)
def handle_message(message):
data = json.loads(message['data'])
if data['type'] == 'research_complete':
subprocess.run(['curl', '-X', 'POST', 'https://api.telegram.org/bot...'])
pubsub = r.pubsub()
pubsub.subscribe(**{'opencode_research': handle_message})
pubsub.run_in_thread()
优点:
- ✅ 高可靠性,消息持久化
- ✅ 支持多消费者(可扩展多个仓库A实例)
- ✅ 消息可携带丰富的元数据
- ✅ 支持消息确认和重试机制
缺点:
- ❌ 需要部署 Redis 或消息队列服务
- ❌ 架构复杂度最高
- ❌ 需要处理 Redis 连接失败等异常情况
- ❌ 运维成本增加
适用场景:
- 高并发研究任务(每秒多个任务)
- 需要任务持久化和重试的企业级场景
- 多个消费者需要同时接收通知的场景
优缺点对比总结
| 方案 | 复杂度 | 可靠性 | 实时性 | 资源消耗 | 扩展性 | 推荐度 |
|---|---|---|---|---|---|---|
| B1 Shell包装器 | ⭐ 低 | ⭐⭐ 中 | ⭐⭐⭐ 高 | ⭐ 极低 | ⭐ 低 | ⭐⭐⭐⭐⭐ |
| B2 文件信号 | ⭐⭐ 中 | ⭐⭐⭐ 高 | ⭐⭐ 中 | ⭐⭐ 中 | ⭐⭐ 中 | ⭐⭐⭐ |
| B3 消息队列 | ⭐⭐⭐ 高 | ⭐⭐⭐⭐⭐ 极高 | ⭐⭐⭐ 高 | ⭐⭐⭐ 高 | ⭐⭐⭐⭐⭐ 极高 | ⭐⭐⭐ |
选择建议:
- 快速验证/MVP:选择方案B1
- 生产环境/中等规模:选择方案B2
- 企业级/大规模:选择方案B3
架构图
graph TB
subgraph "仓库A - Telegram Bot服务"
A1[用户发送<br/>/research 命令]
A2[消息解析器<br/>提取研究主题]
A3[触发器<br/>调用仓库B]
A4[通知发送器<br/>Telegram API]
A5[会话管理器<br/>/new 或清理]
end
subgraph "通信层"
C1["方案B1: 直接调用<br/>subprocess.run"]
C2["方案B2: 文件信号<br/>/tmp/*.signal"]
C3["方案B3: 消息队列<br/>Redis Pub/Sub"]
end
subgraph "仓库B - Research执行器"
B1[Shell包装器<br/>research_wrapper.sh]
B2[OpenCode CLI<br/>opencode run]
B3[GitHub提交<br/>git push]
B4[状态报告<br/>exit code]
end
A1 --> A2
A2 --> A3
A3 --> C1
A3 -.-> C2
A3 -.-> C3
C1 --> B1
C2 -.-> B1
C3 -.-> B1
B1 --> B2
B2 --> B3
B2 --> B4
B4 --> C1
B4 -.-> C2
B4 -.-> C3
C1 --> A4
C2 -.-> A4
C3 -.-> A4
A4 --> A5
A5 --> A1
推荐方案
最终建议
主要推荐:方案B1(Shell包装器)
理由:
- 快速实施:可在1-2小时内完成开发和测试
- 低维护成本:无需额外服务(Redis、文件监控等)
- 足够可靠:对于当前描述的用例(单个研究任务),Shell 脚本的可靠性已足够
- 易于调试:Shell 脚本便于查看日志和排查问题
实施路线图:
阶段1(第1周):方案B1实施
├─ 开发 research_wrapper.sh
├─ 集成 Telegram Bot 通知
└─ 测试完整流程
阶段2(第2-4周):监控与优化
├─ 收集运行日志
├─ 识别边界情况
└─ 优化错误处理
阶段3(视需求):升级到方案B2或B3
├─ 如果出现并发需求,升级到B2
└─ 如果需要高可靠性,升级到B3
备选方案触发条件:
- 如果需要同时处理5个以上的并发研究任务 → 考虑方案B2
- 如果需要99.9%以上的可靠性保证 → 考虑方案B3
- 如果研究任务执行时间超过30分钟 → 考虑方案B2(避免SSH连接超时)